[osx] Rewrote platform-osx and osxapp

platform-osx now vends a real NSView subclass, MGLMapView, that is readily embedded inside a Cocoa application for OS X. MGLMapView is backed by an NSOpenGLLayer for optimal performance and integration with other layer-backed views. It supports keyboard shortcuts and several gestures and hosts attribution, zooming, and rotation controls as subviews. osxapp is now a bona fide Cocoa application that embeds MGLMapView inside a XIB. osxapp has preferences and a share button for tight integration with custom styles.

Enabling asynchronous rendering would be more consistent with iOS but increases CPU usage so much, even when idle, that it isn’t worth any performance gain. The bigger issue is that VAOs aren’t being used.

make xpackage creates a static library similar to the one created by make ipackage. make clean cleans additional places where build output ends up.

The OS X minimum deployment target has been increased from 10.9 to 10.10. osxapp’s window has a full size content view, which requires 10.10. Lightweight generics require iOS 9+ and OS X 10.11 regardless, because it was only in that release that Foundation collection classes started adopting lightweight generics.

Shuffled files around and refactored annotations so that iOS and OS X share a good chunk of the annotations code, which now takes advantage of polymorphism. MGLMapView can now display annotations but cannot yet select them. In osxapp, a long press drops a pin, and so does the map view’s context menu.

Annotations have NSPopovers as callouts, and their view controllers can be customized. Annotation image alignment rects are respected for hit testing purposes and for positioning the callout anchor. Callouts in osxapp demonstrate the use of bindings to keep callouts in sync with underlying model objects.
This commit is contained in:
Minh Nguyễn
2015-11-22 18:07:06 -08:00
parent b59f087ea8
commit 0cab7809eb
86 changed files with 4424 additions and 582 deletions

View File

@@ -56,6 +56,10 @@ ipackage-sim: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh sim
ipackage-no-bitcode: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh no-bitcode
iframework: ipackage-strip ; ./scripts/ios/framework.sh
itest: ipackage-sim ; ./scripts/ios/test.sh
.PHONY: xpackage xpackage-strip
xpackage: Xcode/osx ; @JOBS=$(JOBS) ./scripts/osx/package.sh
xpackage-strip: Xcode/osx ; @JOBS=$(JOBS) ./scripts/osx/package.sh strip
endif
#### All platforms targets #####################################################
@@ -128,10 +132,12 @@ ifeq ($(BUILD), osx)
if [ $$CUSTOM_DD ]; then \
echo clearing files in $$CUSTOM_DD older than one day; \
find $$CUSTOM_DD/mapboxgl-app-* -mtime +1 | xargs rm -rf; \
find $$CUSTOM_DD/osxapp-* -mtime +1 | xargs rm -rf; \
fi; \
if [ -d ~/Library/Developer/Xcode/DerivedData/ ] && [ ! $$CUSTOM_DD ]; then \
echo 'clearing files in ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* older than one day'; \
echo 'clearing files in ~/Library/Developer/Xcode/DerivedData/{mapboxgl-app,osxapp}-* older than one day'; \
find ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* -mtime +1 | xargs rm -rf; \
find ~/Library/Developer/Xcode/DerivedData/osxapp-* -mtime +1 | xargs rm -rf; \
fi
endif

View File

@@ -19,7 +19,7 @@ If you want to use products _based on_ Mapbox GL, check out:
## Targets
* Ubuntu Linux
* OS X 10.9+
* OS X 10.10+
* iOS 7.0+
* iPhone 4S and above (5, 5c, 5s, 6, 6 Plus)
* iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2)

92
docs/BUILD_OSX Normal file
View File

@@ -0,0 +1,92 @@
# Building Mapbox GL Native for iOS
This section is for people contributing to Mapbox GL directly in the context of their own app.
### Build
1. Install [appledoc](http://appledoc.gentlebytes.com/appledoc/) for API docs generation.
```
curl -L -o appledoc.zip https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip
unzip appledoc.zip
cp appledoc /usr/local/bin
cp -Rf Templates/ ~/.appledoc
```
1. Run `make ipackage`. The packaging script will produce the statically-linked `libMapbox.a`, `Mapbox.bundle` for resources, a `Headers` folder, and a `Docs` folder with HTML API documentation.
### Access Tokens
_The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/)._
Set up the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`.
![edit scheme](https://cloud.githubusercontent.com/assets/98601/5460702/c4610262-8519-11e4-873a-8597821da468.png)
![setting access token in Xcode scheme](https://cloud.githubusercontent.com/assets/162976/5349358/0a086f00-7f8c-11e4-8433-bdbaccda2b58.png)
### Test
In the context of your own app, you can now either:
#### CocoaPods
Currently, until [#1437](https://github.com/mapbox/mapbox-gl-native/issues/1437) is completed, to install a _development version_ of Mapbox GL using CocoaPods you will need to build it from source manually per above.
1. Zip up the build product.
```
cd build/ios/pkg/static
ZIP=mapbox-ios-sdk.zip
rm -f ../${ZIP}
zip -r ../${ZIP} *
```
1. Modify a custom `Mapbox-iOS-SDK.podspec` to download this zip file.
```rb
{...}
m.source = {
:http => "http://{...}/mapbox-ios-sdk.zip",
:flatten => true
}
{...}
```
1. Update your app's `Podfile` to point to the `Mapbox-iOS-SDK.podspec`.
```rb
pod 'Mapbox-iOS-SDK', :podspec => 'http://{...}/Mapbox-iOS-SDK.podspec'
```
1. Run `pod update` to grab the newly-built library.
#### Binary
1. Built from source manually per above.
1. Copy the contents of `build/ios/pkg/static` into your project. It should happen automatically, but ensure that:
- `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting.
- `Mapbox.bundle` is in your target's *Copy Bundle Resources* build phase.
- `libMapbox.a` is in your target's *Link Binary With Libraries* build phase.
1. Add the following Cocoa framework dependencies to your target's *Link Binary With Libraries* build phase:
- `GLKit.framework`
- `ImageIO.framework`
- `MobileCoreServices.framework`
- `QuartzCore.framework`
- `SystemConfiguration.framework`
- `libc++.dylib`
- `libsqlite3.dylib`
- `libz.dylib`
- `CoreTelephony.framework` (optional, telemetry-only)
1. Add `-ObjC` to your target's "Other Linker Flags" build setting (`OTHER_LDFLAGS`).
## Troubleshooting
On OS X, you can also try clearing the Xcode cache with `make clear_xcode_cache`.

32
docs/BUILD_OSX.md Normal file
View File

@@ -0,0 +1,32 @@
# Building Mapbox GL Native for OS X
This project provides an OS X SDK analogous to the Mapbox iOS SDK. Mapbox does not officially support it to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome. This document explains how to build the OS X SDK and integrate it into your own Cocoa application.
### Build
1. Run `make xpackage`. The packaging script will produce the statically-linked `libMapbox.a`, `Mapbox.bundle` for resources, and a `Headers` folder.
### Install
1. Copy the contents of `build/osx/pkg/static` into your project. It should happen automatically, but ensure that:
- `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting.
- `Mapbox.bundle` is in your target's *Copy Bundle Resources* build phase.
- `libMapbox.a` is in your target's *Link Binary With Libraries* build phase.
1. Add the following Cocoa framework dependencies to your target's *Link Binary With Libraries* build phase:
- `SystemConfiguration.framework`
- `libc++.tbd`
- `libsqlite3.tbd`
- `libz.tbd`
1. Add `-ObjC` to your target's "Other Linker Flags" build setting (`OTHER_LDFLAGS`).
1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target. In the Info tab, set `MGLMapboxAccessToken` to your access token. You can obtain one from the [Mapbox account page](https://www.mapbox.com/account/apps/).
1. In a XIB or storyboard, add a Custom View and set its custom class to `MGLMapView`. If you need to manipulate the map view programmatically, import the `Mapbox` module (Swift) or `Mapbox.h` umbrella header (Objective-C).
## Troubleshooting
You can also try clearing the Xcode cache with `make clear_xcode_cache`.

View File

@@ -14,7 +14,7 @@ Run
make iproj
Which which will create and open an Xcode project which can build the entire library from source, as well as an Objective-C test app.
Which will create and open an Xcode project that can build the entire library from source, as well as an Objective-C test app.
If you don't have an Apple Developer account, change the destination from "My Mac" to a simulator such as "iPhone 6" before you run and build the app.

View File

@@ -2,7 +2,7 @@
To create projects, you can run:
- `make xproj`: Creates an Xcode project with OS X-specific handlers for HTTP downloads and settings storage. It uses [GLFW](http://www.glfw.org) for window handling.
- `make xproj`: Creates an Xcode project with a native OS X application for testing changes to mapbox-gl-native on the desktop.
- `make lproj`: Creates an Xcode project with platform-independent handlers for downloads and settings storage. This is what is also being built on Linux.
- `make osx run-osx`: Builds and runs the OS X application on the command line with `xcodebuild`.
@@ -10,14 +10,8 @@ Note that you can't have more than one project in Xcode open at a time because t
### Access Tokens
_The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._
Set up the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`.
![edit scheme](https://cloud.githubusercontent.com/assets/98601/5460702/c4610262-8519-11e4-873a-8597821da468.png)
![setting access token in Xcode scheme](https://cloud.githubusercontent.com/assets/162976/5349358/0a086f00-7f8c-11e4-8433-bdbaccda2b58.png)
The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). You will be prompted for this access token the first time you launch the demo application.
### Usage
Keyboard shortcuts for testing functionality are logged to the console when the test app is started.
Through the OS X SDK, the demo application supports a variety of standard gestures and keyboard shortcuts. For more details, open Mapbox GL Help from the Help menu.

View File

@@ -24,7 +24,7 @@
],
'GCC_WARN_PEDANTIC': 'YES',
'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE',
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'MACOSX_DEPLOYMENT_TARGET': '10.10',
},
}, {
'cflags_cc': [

View File

@@ -1,6 +1,6 @@
{
'includes': [
'../platform/osx/mapboxgl-app.gypi',
'../platform/osx/app/mapboxgl-app.gypi',
'../platform/linux/mapboxgl-app.gypi',
'../test/test.gypi',
'../bin/render.gypi',

View File

@@ -20,6 +20,29 @@
'../platform/darwin/image.mm',
'../platform/darwin/nsthread.mm',
'../platform/darwin/reachability.m',
'../platform/darwin/NSException+MGLAdditions.h',
'../platform/darwin/NSString+MGLAdditions.h',
'../platform/darwin/NSString+MGLAdditions.m',
'../include/mbgl/darwin/MGLTypes.h',
'../platform/darwin/MGLTypes.m',
'../include/mbgl/darwin/MGLStyle.h',
'../platform/darwin/MGLStyle.mm',
'../include/mbgl/darwin/MGLGeometry.h',
'../platform/darwin/MGLGeometry_Private.h',
'../platform/darwin/MGLGeometry.m',
'../include/mbgl/darwin/MGLAnnotation.h',
'../include/mbgl/darwin/MGLShape.h',
'../platform/darwin/MGLShape.m',
'../include/mbgl/darwin/MGLMultiPoint.h',
'../platform/darwin/MGLMultiPoint_Private.h',
'../platform/darwin/MGLMultiPoint.mm',
'../include/mbgl/darwin/MGLOverlay.h',
'../include/mbgl/darwin/MGLPointAnnotation.h',
'../platform/darwin/MGLPointAnnotation.m',
'../include/mbgl/darwin/MGLPolyline.h',
'../platform/darwin/MGLPolyline.mm',
'../include/mbgl/darwin/MGLPolygon.h',
'../platform/darwin/MGLPolygon.mm',
'../include/mbgl/ios/Mapbox.h',
'../platform/ios/MGLMapboxEvents.h',
'../platform/ios/MGLMapboxEvents.m',
@@ -31,41 +54,19 @@
'../include/mbgl/ios/MGLAccountManager.h',
'../platform/ios/MGLAccountManager_Private.h',
'../platform/ios/MGLAccountManager.m',
'../include/mbgl/ios/MGLAnnotation.h',
'../include/mbgl/ios/MGLUserLocation.h',
'../platform/ios/MGLUserLocation_Private.h',
'../platform/ios/MGLUserLocation.m',
'../platform/ios/MGLUserLocationAnnotationView.h',
'../platform/ios/MGLUserLocationAnnotationView.m',
'../include/mbgl/ios/MGLTypes.h',
'../platform/ios/MGLTypes.m',
'../include/mbgl/ios/MGLGeometry.h',
'../platform/ios/MGLGeometry.m',
'../include/mbgl/ios/MGLMultiPoint.h',
'../platform/ios/MGLMultiPoint_Private.h',
'../platform/ios/MGLMultiPoint.mm',
'../include/mbgl/ios/MGLOverlay.h',
'../include/mbgl/ios/MGLPointAnnotation.h',
'../platform/ios/MGLPointAnnotation.m',
'../include/mbgl/ios/MGLPolyline.h',
'../platform/ios/MGLPolyline.m',
'../include/mbgl/ios/MGLPolygon.h',
'../platform/ios/MGLPolygon.m',
'../include/mbgl/ios/MGLShape.h',
'../platform/ios/MGLShape.m',
'../include/mbgl/ios/MGLAnnotationImage.h',
'../platform/ios/MGLAnnotationImage.m',
'../include/mbgl/ios/MGLStyle.h',
'../platform/ios/MGLStyle.mm',
'../platform/ios/MGLCategoryLoader.h',
'../platform/ios/MGLCategoryLoader.m',
'../platform/ios/NSBundle+MGLAdditions.h',
'../platform/ios/NSBundle+MGLAdditions.m',
'../platform/ios/NSException+MGLAdditions.h',
'../platform/ios/NSProcessInfo+MGLAdditions.h',
'../platform/ios/NSProcessInfo+MGLAdditions.m',
'../platform/ios/NSString+MGLAdditions.h',
'../platform/ios/NSString+MGLAdditions.m',
'../platform/ios/vendor/SMCalloutView/SMCalloutView.h',
'../platform/ios/vendor/SMCalloutView/SMCalloutView.m',
'../platform/ios/vendor/Fabric/FABAttributes.h',
@@ -96,6 +97,8 @@
},
'include_dirs': [
'../include/mbgl/ios',
'../include/mbgl/darwin',
'../include',
'../src',
],
@@ -115,6 +118,8 @@
'direct_dependent_settings': {
'include_dirs': [
'../include/mbgl/ios',
'../include/mbgl/darwin',
'../include',
],
'mac_bundle_resources': [

View File

@@ -19,26 +19,76 @@
'../platform/darwin/asset_root.mm',
'../platform/darwin/image.mm',
'../platform/darwin/nsthread.mm',
'../platform/darwin/reachability.m',
'../platform/darwin/NSException+MGLAdditions.h',
'../platform/darwin/NSString+MGLAdditions.h',
'../platform/darwin/NSString+MGLAdditions.m',
'../include/mbgl/darwin/MGLTypes.h',
'../platform/darwin/MGLTypes.m',
'../include/mbgl/darwin/MGLStyle.h',
'../platform/darwin/MGLStyle.mm',
'../include/mbgl/darwin/MGLGeometry.h',
'../platform/darwin/MGLGeometry_Private.h',
'../platform/darwin/MGLGeometry.m',
'../include/mbgl/darwin/MGLAnnotation.h',
'../include/mbgl/darwin/MGLShape.h',
'../platform/darwin/MGLShape.m',
'../include/mbgl/darwin/MGLMultiPoint.h',
'../platform/darwin/MGLMultiPoint_Private.h',
'../platform/darwin/MGLMultiPoint.mm',
'../include/mbgl/darwin/MGLOverlay.h',
'../include/mbgl/darwin/MGLPointAnnotation.h',
'../platform/darwin/MGLPointAnnotation.m',
'../include/mbgl/darwin/MGLPolyline.h',
'../platform/darwin/MGLPolyline.mm',
'../include/mbgl/darwin/MGLPolygon.h',
'../platform/darwin/MGLPolygon.mm',
'../include/mbgl/osx/Mapbox.h',
'../include/mbgl/osx/MGLAccountManager.h',
'../platform/osx/sdk/MGLAccountManager_Private.h',
'../platform/osx/sdk/MGLAccountManager.m',
'../include/mbgl/osx/MGLMapView.h',
'../platform/osx/sdk/MGLMapView_Private.h',
'../platform/osx/sdk/MGLMapView.mm',
'../include/mbgl/osx/MGLMapView+IBAdditions.h',
'../platform/osx/sdk/MGLMapView+IBAdditions.m',
'../include/mbgl/osx/MGLMapViewDelegate.h',
'../platform/osx/sdk/MGLOpenGLLayer.h',
'../platform/osx/sdk/MGLOpenGLLayer.mm',
'../platform/osx/sdk/MGLCompassCell.h',
'../platform/osx/sdk/MGLCompassCell.m',
'../platform/osx/sdk/MGLAttributionButton.h',
'../platform/osx/sdk/MGLAttributionButton.m',
'../include/mbgl/osx/MGLAnnotationImage.h',
'../platform/osx/sdk/MGLAnnotationImage.m',
'../platform/osx/sdk/NSBundle+MGLAdditions.h',
'../platform/osx/sdk/NSBundle+MGLAdditions.m',
'../platform/osx/sdk/NSProcessInfo+MGLAdditions.h',
'../platform/osx/sdk/NSProcessInfo+MGLAdditions.m',
'../platform/osx/sdk/resources/',
],
'variables': {
'cflags_cc': [
'<@(libuv_cflags)',
'<@(boost_cflags)',
'<@(variant_cflags)',
],
'libraries': [
'<@(libuv_static_libs)',
],
'ldflags': [
'-framework Foundation',
'-framework ImageIO',
'-framework CoreServices',
'-framework Cocoa',
'-framework CoreLocation',
'-framework OpenGL',
'-framework ApplicationServices',
'-framework QuartzCore',
'-framework SystemConfiguration',
],
},
'include_dirs': [
'../include/mbgl/osx',
'../include/mbgl/darwin',
'../include',
'../src',
],
@@ -58,8 +108,13 @@
'direct_dependent_settings': {
'include_dirs': [
'../include/mbgl/osx',
'../include/mbgl/darwin',
'../include',
],
'mac_bundle_resources': [
'<!@(find ../platform/osx/sdk/resources -type f \! -name "README")',
],
},
},
],

View File

@@ -83,14 +83,12 @@ NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) {
}
/** Returns radians, converted from degrees. */
NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees)
{
NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) {
return (CGFloat)(degrees * M_PI) / 180;
}
/** Returns degrees, converted from radians. */
NS_INLINE CLLocationDegrees MGLDegreesFromRadians(CGFloat radians)
{
NS_INLINE CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) {
return radians * 180 / M_PI;
}

View File

@@ -0,0 +1,52 @@
#import <Foundation/Foundation.h>
#pragma once
#if !__has_feature(nullability)
#define NS_ASSUME_NONNULL_BEGIN
#define NS_ASSUME_NONNULL_END
#define nullable
#define nonnull
#define null_resettable
#endif
NS_ASSUME_NONNULL_BEGIN
extern NSString * const MGLErrorDomain;
/** The mode used to track the user location on the map. */
typedef NS_ENUM(NSUInteger, MGLUserTrackingMode) {
/** The map does not follow the user location. */
MGLUserTrackingModeNone = 0,
/** The map follows the user location. */
MGLUserTrackingModeFollow,
/** The map follows the user location and rotates when the heading changes. */
MGLUserTrackingModeFollowWithHeading,
/** The map follows the user location and rotates when the course changes. */
MGLUserTrackingModeFollowWithCourse,
};
NS_ASSUME_NONNULL_END
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wvariadic-macros"
#ifndef NS_ARRAY_OF
// Foundation collection classes adopted lightweight generics in iOS 9.0 and OS X 10.11 SDKs.
#if __has_feature(objc_generics) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
/** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */
#define NS_ARRAY_OF(ObjectClass...) NSArray <ObjectClass>
#define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray <ObjectClass>
#define NS_SET_OF(ObjectClass...) NSSet <ObjectClass>
#define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet <ObjectClass>
#define NS_DICTIONARY_OF(ObjectClass...) NSDictionary <ObjectClass>
#define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary <ObjectClass>
#else
#define NS_ARRAY_OF(ObjectClass...) NSArray
#define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray
#define NS_SET_OF(ObjectClass...) NSSet
#define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet
#define NS_DICTIONARY_OF(ObjectClass...) NSDictionary
#define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary
#endif
#endif
#pragma clang diagnostic pop

View File

@@ -1,49 +0,0 @@
#import <Foundation/Foundation.h>
#pragma once
#if !__has_feature(nullability)
#define NS_ASSUME_NONNULL_BEGIN
#define NS_ASSUME_NONNULL_END
#define nullable
#define nonnull
#define null_resettable
#endif
NS_ASSUME_NONNULL_BEGIN
extern NSString * const MGLErrorDomain;
/** The mode used to track the user location on the map. */
typedef NS_ENUM(NSUInteger, MGLUserTrackingMode) {
/** The map does not follow the user location. */
MGLUserTrackingModeNone = 0,
/** The map follows the user location. */
MGLUserTrackingModeFollow,
/** The map follows the user location and rotates when the heading changes. */
MGLUserTrackingModeFollowWithHeading,
/** The map follows the user location and rotates when the course changes. */
MGLUserTrackingModeFollowWithCourse,
};
NS_ASSUME_NONNULL_END
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wvariadic-macros"
#if __has_feature(objc_generics)
/** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */
#define NS_ARRAY_OF(ObjectClass...) NSArray <ObjectClass>
#define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray <ObjectClass>
#define NS_SET_OF(ObjectClass...) NSSet <ObjectClass>
#define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet <ObjectClass>
#define NS_DICTIONARY_OF(ObjectClass...) NSDictionary <ObjectClass>
#define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary <ObjectClass>
#else
#define NS_ARRAY_OF(ObjectClass...) NSArray
#define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray
#define NS_SET_OF(ObjectClass...) NSSet
#define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet
#define NS_DICTIONARY_OF(ObjectClass...) NSDictionary
#define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,26 @@
#import <Foundation/Foundation.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
/** The MGLAccountManager object provides a global way to set a Mapbox API access token, as well as other settings used framework-wide. */
@interface MGLAccountManager : NSObject
/** @name Authorizing Access */
/** Set the Mapbox API access token for the framework.
*
* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework.
* @param accessToken The Mapbox API access token. */
+ (void)setAccessToken:(nullable NSString *)accessToken;
/** Retreive the Mapbox API access token for the framework.
*
* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework.
* @return accessToken The Mapbox API access token. */
+ (nullable NSString *)accessToken;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
#import <AppKit/AppKit.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
@interface MGLAnnotationImage : NSObject
+ (instancetype)annotationImageWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier;
@property (nonatomic, readonly) NSImage *image;
@property (nonatomic, readonly) NSString *reuseIdentifier;
@property (nonatomic, getter=isSelectable) BOOL selectable;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,44 @@
#import <Foundation/Foundation.h>
#import "MGLMapView.h"
NS_ASSUME_NONNULL_BEGIN
@interface MGLMapView (IBAdditions)
// Core properties that can be manipulated in the Attributes inspector in
// Interface Builder. These redeclarations merely add the IBInspectable keyword.
// They appear here to ensure that they appear above the convenience properties;
// inspectables declared in MGLMapView.h are always sorted before those in
// MGLMapView+IBAdditions.h, due to ASCII sort order.
#if TARGET_INTERFACE_BUILDER
// We want this property to look like a URL bar in the Attributes inspector, but
// just calling it styleURL would violate Cocoa naming conventions and conflict
// with the existing NSURL property. Fortunately, IB strips out the two
// underscores for display.
@property (nonatomic, nullable) IBInspectable NSString *styleURL__;
#endif
// Convenience properties related to the initial viewport. These properties
// are not meant to be used outside of Interface Builder. latitude and longitude
// are backed by properties of type CLLocationDegrees, but these declarations
// must use the type double because Interface Builder is unaware that
// CLLocationDegrees is a typedef for double.
@property (nonatomic) IBInspectable double latitude;
@property (nonatomic) IBInspectable double longitude;
@property (nonatomic) IBInspectable double zoomLevel;
// Renamed properties. Interface Builder derives the display name of each
// inspectable from the runtime name, but runtime names don’t always make sense
// in UI.
@property (nonatomic) IBInspectable BOOL allowsZooming;
@property (nonatomic) IBInspectable BOOL allowsScrolling;
@property (nonatomic) IBInspectable BOOL allowsRotating;
@property (nonatomic) IBInspectable BOOL allowsTilting;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,85 @@
#import <Cocoa/Cocoa.h>
#import <CoreLocation/CoreLocation.h>
#import "MGLGeometry.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
MGLMapDebugTileBoundariesMask = 1 << 1,
MGLMapDebugTileInfoMask = 1 << 2,
MGLMapDebugTimestampsMask = 1 << 3,
MGLMapDebugCollisionBoxesMask = 1 << 4,
};
@class MGLAnnotationImage;
@protocol MGLAnnotation;
@protocol MGLMapViewDelegate;
@protocol MGLOverlay;
IB_DESIGNABLE
@interface MGLMapView : NSView
- (instancetype)initWithFrame:(CGRect)frame styleURL:(nullable NSURL *)styleURL;
@property (nonatomic, weak, nullable) IBOutlet id <MGLMapViewDelegate> delegate;
@property (nonatomic, null_resettable) NSURL *styleURL;
- (IBAction)reloadStyle:(id)sender;
@property (nonatomic, readonly) NSSegmentedControl *zoomControls;
@property (nonatomic, readonly) NSSlider *compass;
@property (nonatomic, readonly) NSImageView *logoView;
@property (nonatomic, readonly) NSView *attributionView;
@property (nonatomic) CLLocationCoordinate2D centerCoordinate;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
@property (nonatomic) double zoomLevel;
@property (nonatomic, readonly) double maximumZoomLevel;
@property (nonatomic, readonly) double minimumZoomLevel;
- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated;
@property (nonatomic) CLLocationDirection direction;
- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated;
@property (nonatomic) MGLCoordinateBounds visibleCoordinateBounds;
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, getter=isZoomEnabled) BOOL zoomEnabled;
@property (nonatomic, getter=isRotateEnabled) BOOL rotateEnabled;
@property (nonatomic, getter=isPitchEnabled) BOOL pitchEnabled;
@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
- (void)addAnnotation:(id <MGLAnnotation>)annotation;
- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
- (void)removeAnnotation:(id <MGLAnnotation>)annotation;
- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
- (nullable MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier;
@property (nonatomic, copy) NS_ARRAY_OF(id <MGLAnnotation>) *selectedAnnotations;
- (void)selectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated;
- (void)deselectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated;
- (void)addOverlay:(id <MGLOverlay>)overlay;
- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
- (void)removeOverlay:(id <MGLOverlay>)overlay;
- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
- (CLLocationCoordinate2D)convertPoint:(NSPoint)point toCoordinateFromView:(nullable NSView *)view;
- (NSPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable NSView *)view;
- (CLLocationDistance)metersPerPixelAtLatitude:(CLLocationDegrees)latitude;
@property (nonatomic) MGLMapDebugMaskOptions debugMask;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
#import <Foundation/Foundation.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
@class MGLAnnotationImage;
@class MGLPolygon;
@class MGLPolyline;
@class MGLShape;
@protocol MGLMapViewDelegate <NSObject>
@optional
- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
- (void)mapViewRegionIsChanging:(MGLMapView *)mapView;
- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
- (void)mapViewWillStartRenderingMap:(MGLMapView *)mapView;
- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
- (NSColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation;
- (NSColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation;
- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;
- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation;
- (nullable NSViewController *)mapView:(MGLMapView *)mapView calloutViewControllerForAnnotation:(id <MGLAnnotation>)annotation;
- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation;
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation;
@end
NS_ASSUME_NONNULL_END

15
include/mbgl/osx/Mapbox.h Normal file
View File

@@ -0,0 +1,15 @@
#import "MGLAccountManager.h"
#import "MGLAnnotation.h"
#import "MGLAnnotationImage.h"
#import "MGLGeometry.h"
#import "MGLMapView.h"
#import "MGLMapView+IBAdditions.h"
#import "MGLMapViewDelegate.h"
#import "MGLMultiPoint.h"
#import "MGLOverlay.h"
#import "MGLPointAnnotation.h"
#import "MGLPolygon.h"
#import "MGLPolyline.h"
#import "MGLShape.h"
#import "MGLStyle.h"
#import "MGLTypes.h"

View File

@@ -39,8 +39,10 @@
</dict>
<key>NSHumanReadableCopyright</key>
<string>(c) 2014 Mapbox</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>The map will ALWAYS display the user's location.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>The map will display the user&apos;s location.</string>
<string>The map will display the user's location.</string>
<key>UILaunchStoryboardName</key>
<string>Default</string>
<key>UIRequiredDeviceCapabilities</key>
@@ -60,7 +62,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSLocationAlwaysUsageDescription</key>
<string>The map will ALWAYS display the user&apos;s location.</string>
</dict>
</plist>

View File

@@ -0,0 +1,26 @@
#import "MGLGeometry.h"
#include <mbgl/util/geo.hpp>
NS_INLINE mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) {
return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
}
NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) {
return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
}
NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsFromLatLngBounds(mbgl::LatLngBounds latLngBounds) {
return MGLCoordinateBoundsMake(MGLLocationCoordinate2DFromLatLng(latLngBounds.sw),
MGLLocationCoordinate2DFromLatLng(latLngBounds.ne));
}
NS_INLINE mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coordinateBounds) {
return mbgl::LatLngBounds(MGLLatLngFromLocationCoordinate2D(coordinateBounds.sw),
MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
}
NS_INLINE BOOL MGLCoordinateInCoordinateBounds(CLLocationCoordinate2D coordinate, MGLCoordinateBounds coordinateBounds) {
mbgl::LatLngBounds bounds = MGLLatLngBoundsFromCoordinateBounds(coordinateBounds);
return bounds.contains(MGLLatLngFromLocationCoordinate2D(coordinate));
}

View File

@@ -1,8 +1,17 @@
#import "MGLMultiPoint.h"
#import "MGLGeometry.h"
#import "MGLMultiPoint_Private.h"
#import "MGLGeometry_Private.h"
#import <mbgl/util/geo.hpp>
mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
if (!cgColor) {
return {{ 0, 0, 0, 0 }};
}
NSCAssert(CGColorGetNumberOfComponents(cgColor) >= 4, @"Color must have at least 4 components");
const CGFloat *components = CGColorGetComponents(cgColor);
return {{ (float)components[0], (float)components[1], (float)components[2], (float)components[3] }};
}
@implementation MGLMultiPoint
{
CLLocationCoordinate2D *_coords;
@@ -100,4 +109,28 @@
return _bounds.intersects(area);
}
- (void)addShapeAnnotationObjectToCollection:(std::vector<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)delegate {
NSUInteger count = self.pointCount;
if (count == 0) {
return;
}
CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D));
NSAssert(coordinates, @"Unable to allocate annotation with %lu points", (unsigned long)count);
[self getCoordinates:coordinates range:NSMakeRange(0, count)];
mbgl::AnnotationSegment segment;
segment.reserve(count);
for (NSUInteger i = 0; i < count; i++) {
segment.push_back(MGLLatLngFromLocationCoordinate2D(coordinates[i]));
}
free(coordinates);
shapes.emplace_back(mbgl::AnnotationSegments {{ segment }},
[self shapeAnnotationPropertiesObjectWithDelegate:delegate]);
}
- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate {
return mbgl::ShapeAnnotation::Properties();
}
@end

View File

@@ -0,0 +1,38 @@
#import "MGLMultiPoint.h"
#import "MGLGeometry.h"
#import "MGLTypes.h"
#import <mbgl/annotation/shape_annotation.hpp>
#import <vector>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@class MGLPolygon;
@class MGLPolyline;
@protocol MGLMultiPointDelegate;
@interface MGLMultiPoint (Private)
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds;
- (void)addShapeAnnotationObjectToCollection:(std::vector<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)delegate;
- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate;
@end
@protocol MGLMultiPointDelegate <NSObject>
- (double)alphaForShapeAnnotation:(MGLShape *)annotation;
- (mbgl::Color)strokeColorForShapeAnnotation:(MGLShape *)annotation;
- (mbgl::Color)fillColorForPolygonAnnotation:(MGLPolygon *)annotation;
- (CGFloat)lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
#import "MGLPolygon.h"
#import "MGLMultiPoint_Private.h"
@implementation MGLPolygon
@dynamic overlayBounds;
+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords
count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
}
- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
mbgl::ShapeAnnotation::Properties shapeProperties = [super shapeAnnotationPropertiesObjectWithDelegate:delegate];
mbgl::FillAnnotationProperties fillProperties;
fillProperties.opacity = [delegate alphaForShapeAnnotation:self];
fillProperties.outlineColor = [delegate strokeColorForShapeAnnotation:self];
fillProperties.color = [delegate fillColorForPolygonAnnotation:self];
shapeProperties.set<mbgl::FillAnnotationProperties>(fillProperties);
return shapeProperties;
}
@end

View File

@@ -0,0 +1,28 @@
#import "MGLPolyline.h"
#import "MGLMultiPoint_Private.h"
@implementation MGLPolyline
@dynamic overlayBounds;
+ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords
count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
}
- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
mbgl::ShapeAnnotation::Properties shapeProperties = [super shapeAnnotationPropertiesObjectWithDelegate:delegate];
mbgl::LineAnnotationProperties lineProperties;
lineProperties.opacity = [delegate alphaForShapeAnnotation:self];
lineProperties.color = [delegate strokeColorForShapeAnnotation:self];
lineProperties.width = [delegate lineWidthForPolylineAnnotation:self];
shapeProperties.set<mbgl::LineAnnotationProperties>(lineProperties);
return shapeProperties;
}
@end

View File

@@ -1,8 +1,8 @@
#import "NSString+MGLAdditions.h"
@implementation NSString (MGLAdditions)
void mgl_linkStringCategory() {}
void mgl_linkStringCategory(){}
@implementation NSString (MGLAdditions)
- (nullable NSString *)mgl_stringOrNilIfEmpty
{

View File

@@ -26,6 +26,8 @@
#include <mbgl/util/default_styles.hpp>
#import "Mapbox.h"
#import "../darwin/MGLGeometry_Private.h"
#import "../darwin/MGLMultiPoint_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
@@ -79,34 +81,6 @@ enum { MGLAnnotationTagNotFound = UINT32_MAX };
/// the annotation itself.
typedef std::map<MGLAnnotationTag, MGLAnnotationContext> MGLAnnotationContextMap;
mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate)
{
return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
}
CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
{
return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
}
MGLCoordinateBounds MGLCoordinateBoundsFromLatLngBounds(mbgl::LatLngBounds latLngBounds)
{
return MGLCoordinateBoundsMake(MGLLocationCoordinate2DFromLatLng(latLngBounds.sw),
MGLLocationCoordinate2DFromLatLng(latLngBounds.ne));
}
mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coordinateBounds)
{
return mbgl::LatLngBounds(MGLLatLngFromLocationCoordinate2D(coordinateBounds.sw),
MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
}
BOOL MGLCoordinateInCoordinateBounds(CLLocationCoordinate2D coordinate, MGLCoordinateBounds coordinateBounds)
{
mbgl::LatLngBounds bounds = MGLLatLngBoundsFromCoordinateBounds(coordinateBounds);
return bounds.contains(MGLLatLngFromLocationCoordinate2D(coordinate));
}
mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function)
{
if ( ! function)
@@ -119,6 +93,17 @@ mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction
return { p1[0], p1[1], p2[0], p2[1] };
}
mbgl::Color MGLColorObjectFromUIColor(UIColor *color)
{
if (!color)
{
return {{ 0, 0, 0, 0 }};
}
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
return {{ (float)r, (float)g, (float)b, (float)a }};
}
/// Lightweight container for metadata about an annotation, including the annotation itself.
class MGLAnnotationContext {
public:
@@ -134,7 +119,8 @@ public:
GLKViewDelegate,
CLLocationManagerDelegate,
UIActionSheetDelegate,
SMCalloutViewDelegate>
SMCalloutViewDelegate,
MGLMultiPointDelegate>
@property (nonatomic) EAGLContext *context;
@property (nonatomic) GLKView *glView;
@@ -192,13 +178,18 @@ public:
BOOL _needsDisplayRefresh;
NSUInteger _changeDelimiterSuppressionDepth;
BOOL _delegateHasAlphasForShapeAnnotations;
BOOL _delegateHasStrokeColorsForShapeAnnotations;
BOOL _delegateHasFillColorsForShapeAnnotations;
BOOL _delegateHasLineWidthsForShapeAnnotations;
}
#pragma mark - Setup & Teardown -
@dynamic debugActive;
std::chrono::steady_clock::duration durationInSeconds(float duration)
std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
{
return std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<float, std::chrono::seconds::period>(duration));
}
@@ -538,6 +529,16 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
@"Implement -[%@ mapView:imageForAnnotation:] instead.",
NSStringFromClass([delegate class]), NSStringFromClass([delegate class])];
}
_delegateHasAlphasForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:alphaForShapeAnnotation:)];
_delegateHasStrokeColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)];
_delegateHasFillColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)];
_delegateHasLineWidthsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:lineWidthForPolylineAnnotation:)];
}
- (void)didReceiveMemoryWarning
{
_mbglMap->onLowMemory();
}
#pragma mark - Layout -
@@ -949,7 +950,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
if (drift)
{
CGPoint offset = CGPointMake(velocity.x * duration / 4, velocity.y * duration / 4);
_mbglMap->moveBy({ offset.x, offset.y }, durationInSeconds(duration));
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(duration));
}
[self notifyGestureDidEndWithDrift:drift];
@@ -1031,7 +1032,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
{
CGPoint pinchCenter = [pinch locationInView:pinch.view];
mbgl::PrecisionPoint center(pinchCenter.x, pinchCenter.y);
_mbglMap->setScale(newScale, center, durationInSeconds(duration));
_mbglMap->setScale(newScale, center, MGLDurationInSeconds(duration));
}
[self notifyGestureDidEndWithDrift:velocity];
@@ -1085,7 +1086,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
CGFloat newRadians = radians + velocity * duration * 0.1;
CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
_mbglMap->setBearing(newDegrees, durationInSeconds(duration));
_mbglMap->setBearing(newDegrees, MGLDurationInSeconds(duration));
[self notifyGestureDidEndWithDrift:YES];
@@ -1178,7 +1179,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
}
mbgl::PrecisionPoint center(zoomInPoint.x, zoomInPoint.y);
_mbglMap->scaleBy(2, center, durationInSeconds(MGLAnimationDuration));
_mbglMap->scaleBy(2, center, MGLDurationInSeconds(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -1217,7 +1218,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
}
mbgl::PrecisionPoint center(zoomOutPoint.x, zoomOutPoint.y);
_mbglMap->scaleBy(0.5, center, durationInSeconds(MGLAnimationDuration));
_mbglMap->scaleBy(0.5, center, MGLDurationInSeconds(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -1538,7 +1539,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
}
if (animated)
{
options.duration = durationInSeconds(duration);
options.duration = MGLDurationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(nil);
}
if (completion)
@@ -1655,7 +1656,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
}
if (duration > 0)
{
options.duration = durationInSeconds(duration);
options.duration = MGLDurationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
if (completion)
@@ -1702,7 +1703,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
CGFloat duration = animated ? MGLAnimationDuration : 0;
_mbglMap->setBearing(direction, durationInSeconds(duration));
_mbglMap->setBearing(direction, MGLDurationInSeconds(duration));
}
- (void)setDirection:(CLLocationDirection)direction
@@ -1856,7 +1857,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
}
if (duration > 0)
{
options.duration = durationInSeconds(duration);
options.duration = MGLDurationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
if (completion)
@@ -2016,7 +2017,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
newAppliedClasses.insert(newAppliedClasses.end(), [appliedClass UTF8String]);
}
_mbglMap->setDefaultTransitionDuration(durationInSeconds(transitionDuration));
_mbglMap->setDefaultTransitionDuration(MGLDurationInSeconds(transitionDuration));
_mbglMap->setClasses(newAppliedClasses);
}
@@ -2111,10 +2112,6 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
std::vector<mbgl::ShapeAnnotation> shapes;
BOOL delegateImplementsImageForPoint = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)];
BOOL delegateImplementsAlphaForShape = [self.delegate respondsToSelector:@selector(mapView:alphaForShapeAnnotation:)];
BOOL delegateImplementsStrokeColorForShape = [self.delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)];
BOOL delegateImplementsFillColorForPolygon = [self.delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)];
BOOL delegateImplementsLineWidthForPolyline = [self.delegate respondsToSelector:@selector(mapView:lineWidthForPolylineAnnotation:)];
for (id <MGLAnnotation> annotation in annotations)
{
@@ -2122,77 +2119,7 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
if ([annotation isKindOfClass:[MGLMultiPoint class]])
{
NSUInteger count = [(MGLMultiPoint *)annotation pointCount];
if (count == 0) break;
CGFloat alpha = (delegateImplementsAlphaForShape ?
[self.delegate mapView:self alphaForShapeAnnotation:annotation] :
1.0);
UIColor *strokeColor = (delegateImplementsStrokeColorForShape ?
[self.delegate mapView:self strokeColorForShapeAnnotation:annotation] :
[UIColor blackColor]);
assert(strokeColor);
CGFloat r,g,b,a;
[strokeColor getRed:&r green:&g blue:&b alpha:&a];
mbgl::Color strokeNativeColor({{ (float)r, (float)g, (float)b, (float)a }});
mbgl::ShapeAnnotation::Properties shapeProperties;
if ([annotation isKindOfClass:[MGLPolyline class]])
{
CGFloat lineWidth = (delegateImplementsLineWidthForPolyline ?
[self.delegate mapView:self lineWidthForPolylineAnnotation:(MGLPolyline *)annotation] :
3.0);
mbgl::LineAnnotationProperties lineProperties;
lineProperties.opacity = alpha;
lineProperties.color = strokeNativeColor;
lineProperties.width = lineWidth;
shapeProperties.set<mbgl::LineAnnotationProperties>(lineProperties);
}
else if ([annotation isKindOfClass:[MGLPolygon class]])
{
UIColor *fillColor = (delegateImplementsFillColorForPolygon ?
[self.delegate mapView:self fillColorForPolygonAnnotation:(MGLPolygon *)annotation] :
[UIColor blueColor]);
assert(fillColor);
[fillColor getRed:&r green:&g blue:&b alpha:&a];
mbgl::Color fillNativeColor({{ (float)r, (float)g, (float)b, (float)a }});
mbgl::FillAnnotationProperties fillProperties;
fillProperties.opacity = alpha;
fillProperties.outlineColor = strokeNativeColor;
fillProperties.color = fillNativeColor;
shapeProperties.set<mbgl::FillAnnotationProperties>(fillProperties);
}
else
{
[[NSException exceptionWithName:@"MGLUnknownShapeClassException"
reason:[NSString stringWithFormat:@"%@ is an unknown shape class", [annotation class]]
userInfo:nil] raise];
}
CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D));
[(MGLMultiPoint *)annotation getCoordinates:coordinates range:NSMakeRange(0, count)];
mbgl::AnnotationSegment segment;
segment.reserve(count);
for (NSUInteger i = 0; i < count; i++)
{
segment.push_back(mbgl::LatLng(coordinates[i].latitude, coordinates[i].longitude));
}
free(coordinates);
shapes.emplace_back(mbgl::AnnotationSegments {{ segment }}, shapeProperties);
[(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self];
}
else
{
@@ -2253,6 +2180,40 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
[self didChangeValueForKey:@"annotations"];
}
- (double)alphaForShapeAnnotation:(MGLShape *)annotation
{
if (_delegateHasAlphasForShapeAnnotations)
{
return [self.delegate mapView:self alphaForShapeAnnotation:annotation];
}
return 1.0;
}
- (mbgl::Color)strokeColorForShapeAnnotation:(MGLShape *)annotation
{
UIColor *color = (_delegateHasStrokeColorsForShapeAnnotations
? [self.delegate mapView:self strokeColorForShapeAnnotation:annotation]
: [UIColor blackColor]);
return MGLColorObjectFromUIColor(color);
}
- (mbgl::Color)fillColorForPolygonAnnotation:(MGLPolygon *)annotation
{
UIColor *color = (_delegateHasFillColorsForShapeAnnotations
? [self.delegate mapView:self fillColorForPolygonAnnotation:annotation]
: [UIColor blueColor]);
return MGLColorObjectFromUIColor(color);
}
- (CGFloat)lineWidthForPolylineAnnotation:(MGLPolyline *)annotation
{
if (_delegateHasLineWidthsForShapeAnnotations)
{
return [self.delegate mapView:self lineWidthForPolylineAnnotation:(MGLPolyline *)annotation];
}
return 3.0;
}
- (void)installAnnotationImage:(MGLAnnotationImage *)annotationImage
{
// retrieve pixels
@@ -3612,9 +3573,4 @@ class MBGLView : public mbgl::View
self.pitchEnabled = allowsTilting;
}
- (void)didReceiveMemoryWarning
{
_mbglMap->onLowMemory();
}
@end

View File

@@ -1,10 +0,0 @@
#import "MGLMultiPoint.h"
#import <CoreLocation/CoreLocation.h>
@interface MGLMultiPoint (Private)
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds;
@end

View File

@@ -1,15 +0,0 @@
#import "MGLPolygon.h"
#import "MGLMultiPoint_Private.h"
@implementation MGLPolygon
@dynamic overlayBounds;
+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords
count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
}
@end

View File

@@ -1,15 +0,0 @@
#import "MGLPolyline.h"
#import "MGLMultiPoint_Private.h"
@implementation MGLPolyline
@dynamic overlayBounds;
+ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords
count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
}
@end

View File

@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>0.0.1</string>
<key>CFBundleIconFile</key>
<string>Icon.icns</string>
<key>CFBundleIdentifier</key>
<string>com.mapbox.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>0.0.1</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>MBGL</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>0.0.1</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>mapboxgl</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,7 @@
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end

View File

@@ -0,0 +1,462 @@
#import "AppDelegate.h"
#import "DroppedPinAnnotation.h"
#import "LocationCoordinate2DTransformer.h"
#import "NSValue+Additions.h"
#import <mbgl/osx/Mapbox.h>
static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
@interface AppDelegate () <NSApplicationDelegate, NSSharingServicePickerDelegate, NSMenuDelegate, MGLMapViewDelegate>
@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet MGLMapView *mapView;
@property (weak) IBOutlet NSMenu *mapViewContextMenu;
@property (weak) IBOutlet NSWindow *preferencesWindow;
@end
@implementation AppDelegate {
NSPoint _mouseLocationForMapViewContextMenu;
}
#pragma mark Lifecycle
+ (void)load {
// Set access token, unless MGLAccountManager already read it in from Info.plist.
if (![MGLAccountManager accessToken]) {
NSString *accessToken = [NSProcessInfo processInfo].environment[@"MAPBOX_ACCESS_TOKEN"];
if (accessToken) {
// Store to preferences so that we can launch the app later on without having to specify
// token.
[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:MGLMapboxAccessTokenDefaultsKey];
} else {
// Try to retrieve from preferences, maybe we've stored them there previously and can reuse
// the token.
accessToken = [[NSUserDefaults standardUserDefaults] stringForKey:MGLMapboxAccessTokenDefaultsKey];
}
[MGLAccountManager setAccessToken:accessToken];
}
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:nil];
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Set access token, unless MGLAccountManager already read it in from Info.plist.
if (![MGLAccountManager accessToken]) {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Access token required";
alert.informativeText = @"To load Mapbox-hosted tiles and styles, enter your Mapbox access token in Preferences.";
[alert addButtonWithTitle:@"Open Preferences"];
[alert runModal];
[self showPreferences:nil];
}
NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)];
[self.mapView addGestureRecognizer:pressGestureRecognizer];
}
- (void)applicationWillTerminate:(NSNotification *)notification {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)userDefaultsDidChange:(NSNotification *)notification {
NSUserDefaults *userDefaults = notification.object;
NSString *accessToken = [userDefaults stringForKey:MGLMapboxAccessTokenDefaultsKey];
if (![accessToken isEqualToString:[MGLAccountManager accessToken]]) {
[MGLAccountManager setAccessToken:accessToken];
[self reload:self];
}
}
#pragma mark Services
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
NSURL *url = [NSURL URLWithString:[event paramDescriptorForKeyword:keyDirectObject].stringValue];
NS_MUTABLE_DICTIONARY_OF(NSString *, NSString *) *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url.query componentsSeparatedByString:@"&"]) {
NSArray *parts = [param componentsSeparatedByString:@"="];
if (parts.count >= 2) {
params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
}
NSString *centerString = params[@"center"];
if (centerString) {
NSArray *coordinateValues = [centerString componentsSeparatedByString:@","];
if (coordinateValues.count == 2) {
self.mapView.centerCoordinate = CLLocationCoordinate2DMake([coordinateValues[0] doubleValue],
[coordinateValues[1] doubleValue]);
}
}
NSString *zoomLevelString = params[@"zoom"];
if (zoomLevelString.length) {
self.mapView.zoomLevel = zoomLevelString.doubleValue;
}
NSString *directionString = params[@"bearing"];
if (directionString.length) {
self.mapView.direction = directionString.doubleValue;
}
}
- (IBAction)showShareMenu:(id)sender {
NSSharingServicePicker *picker = [[NSSharingServicePicker alloc] initWithItems:@[self.shareURL]];
picker.delegate = self;
[picker showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
}
- (NSURL *)shareURL {
NSArray *components = self.mapView.styleURL.pathComponents;
CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate;
return [NSURL URLWithString:
[NSString stringWithFormat:@"https://api.mapbox.com/styles/v1/%@/%@.html?access_token=%@#%.2f/%.5f/%.5f/%.f",
components[1], components[2], [MGLAccountManager accessToken],
self.mapView.zoomLevel, centerCoordinate.latitude, centerCoordinate.longitude, self.mapView.direction]];
}
#pragma mark View methods
- (IBAction)setStyle:(id)sender {
NSInteger tag;
if ([sender isKindOfClass:[NSMenuItem class]]) {
tag = [sender tag];
} else if ([sender isKindOfClass:[NSPopUpButton class]]) {
tag = [sender selectedTag];
}
NSURL *styleURL;
switch (tag) {
case 1:
styleURL = [MGLStyle streetsStyleURL];
break;
case 2:
styleURL = [MGLStyle emeraldStyleURL];
break;
case 3:
styleURL = [MGLStyle lightStyleURL];
break;
case 4:
styleURL = [MGLStyle darkStyleURL];
break;
case 5:
styleURL = [MGLStyle satelliteStyleURL];
break;
case 6:
styleURL = [MGLStyle hybridStyleURL];
break;
default:
NSAssert(NO, @"Cannot set style from control with tag %li", (long)tag);
break;
}
self.mapView.styleURL = styleURL;
[self.window.toolbar validateVisibleItems];
}
- (IBAction)chooseCustomStyle:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Apply custom style";
alert.informativeText = @"Enter the URL to a JSON file that conforms to the Mapbox GL style specification:";
NSTextField *textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
[textField sizeToFit];
NSRect textFieldFrame = textField.frame;
textFieldFrame.size.width = 300;
textField.frame = textFieldFrame;
NSString *savedURLString = [[NSUserDefaults standardUserDefaults] stringForKey:@"MBXCustomStyleURL"];
if (savedURLString) {
textField.stringValue = savedURLString;
}
alert.accessoryView = textField;
[alert addButtonWithTitle:@"Apply"];
[alert addButtonWithTitle:@"Cancel"];
if ([alert runModal] == NSAlertFirstButtonReturn) {
[[NSUserDefaults standardUserDefaults] setObject:textField.stringValue forKey:@"MBXCustomStyleURL"];
self.mapView.styleURL = [NSURL URLWithString:textField.stringValue];
[self.window.toolbar validateVisibleItems];
}
}
- (IBAction)zoomIn:(id)sender {
[self.mapView setZoomLevel:self.mapView.zoomLevel + 1 animated:YES];
}
- (IBAction)zoomOut:(id)sender {
[self.mapView setZoomLevel:self.mapView.zoomLevel - 1 animated:YES];
}
- (IBAction)snapToNorth:(id)sender {
[self.mapView setDirection:0 animated:YES];
}
- (IBAction)reload:(id)sender {
[self.mapView reloadStyle:sender];
}
- (IBAction)toggleTileBoundaries:(id)sender {
self.mapView.debugMask ^= MGLMapDebugTileBoundariesMask;
}
- (IBAction)toggleTileInfo:(id)sender {
self.mapView.debugMask ^= MGLMapDebugTileInfoMask;
}
- (IBAction)toggleTileTimestamps:(id)sender {
self.mapView.debugMask ^= MGLMapDebugTimestampsMask;
}
- (IBAction)toggleCollisionBoxes:(id)sender {
self.mapView.debugMask ^= MGLMapDebugCollisionBoxesMask;
}
#pragma mark Help methods
- (IBAction)showShortcuts:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Mapbox GL Help";
alert.informativeText = @"\
• To scroll, swipe with two fingers, drag the cursor, or press the arrow keys.\n\
• To zoom, pinch with two fingers, or hold down Shift while dragging the cursor up and down, or hold down Option while pressing the up and down arrow keys.\n\
• To rotate, move two fingers opposite each other in a circle, or hold down Option while dragging the cursor left and right, or hold down Option while pressing the left and right arrow keys.\n\
• To tilt, hold down Option while dragging the cursor up and down.\
• To drop a pin, click and hold.\
";
[alert runModal];
}
- (IBAction)giveFeedback:(id)sender {
CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate;
NSURL *feedbackURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.mapbox.com/map-feedback/#/%.5f/%.5f/%.0f",
centerCoordinate.longitude, centerCoordinate.latitude, round(self.mapView.zoomLevel)]];
[[NSWorkspace sharedWorkspace] openURL:feedbackURL];
}
- (IBAction)showPreferences:(id)sender {
[self.preferencesWindow makeKeyAndOrderFront:sender];
}
- (IBAction)openAccessTokenManager:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.mapbox.com/studio/account/tokens/"]];
}
#pragma mark Mouse events
- (void)handlePressGesture:(NSPressGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
NSPoint location = [gestureRecognizer locationInView:self.mapView];
[self dropPinAtPoint:location];
}
}
- (IBAction)dropPin:(NSMenuItem *)sender {
[self dropPinAtPoint:_mouseLocationForMapViewContextMenu];
}
- (void)dropPinAtPoint:(NSPoint)point {
DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init];
annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
annotation.title = @"Dropped Pin";
[self.mapView addAnnotation:annotation];
[self.mapView selectAnnotation:annotation animated:YES];
}
#pragma mark User interface validation
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
if (menuItem.action == @selector(setStyle:)) {
NSURL *styleURL = self.mapView.styleURL;
NSCellStateValue state;
switch (menuItem.tag) {
case 1:
state = [styleURL isEqual:[MGLStyle streetsStyleURL]];
break;
case 2:
state = [styleURL isEqual:[MGLStyle emeraldStyleURL]];
break;
case 3:
state = [styleURL isEqual:[MGLStyle lightStyleURL]];
break;
case 4:
state = [styleURL isEqual:[MGLStyle darkStyleURL]];
break;
case 5:
state = [styleURL isEqual:[MGLStyle satelliteStyleURL]];
break;
case 6:
state = [styleURL isEqual:[MGLStyle hybridStyleURL]];
break;
default:
return NO;
}
menuItem.state = state;
return YES;
}
if (menuItem.action == @selector(chooseCustomStyle:)) {
menuItem.state = self.indexOfStyleInToolbarItem == NSNotFound;
return YES;
}
if (menuItem.action == @selector(zoomIn:)) {
return self.mapView.zoomLevel < self.mapView.maximumZoomLevel;
}
if (menuItem.action == @selector(zoomOut:)) {
return self.mapView.zoomLevel > self.mapView.minimumZoomLevel;
}
if (menuItem.action == @selector(snapToNorth:)) {
return self.mapView.direction != 0;
}
if (menuItem.action == @selector(reload:)) {
return YES;
}
if (menuItem.action == @selector(dropPin:)) {
return YES;
}
if (menuItem.action == @selector(toggleTileBoundaries:)) {
BOOL isShown = self.mapView.debugMask & MGLMapDebugTileBoundariesMask;
menuItem.title = isShown ? @"Hide Tile Boundaries" : @"Show Tile Boundaries";
return YES;
}
if (menuItem.action == @selector(toggleTileInfo:)) {
BOOL isShown = self.mapView.debugMask & MGLMapDebugTileInfoMask;
menuItem.title = isShown ? @"Hide Tile Info" : @"Show Tile Info";
return YES;
}
if (menuItem.action == @selector(toggleTileTimestamps:)) {
BOOL isShown = self.mapView.debugMask & MGLMapDebugTimestampsMask;
menuItem.title = isShown ? @"Hide Tile Timestamps" : @"Show Tile Timestamps";
return YES;
}
if (menuItem.action == @selector(toggleCollisionBoxes:)) {
BOOL isShown = self.mapView.debugMask & MGLMapDebugCollisionBoxesMask;
menuItem.title = isShown ? @"Hide Collision Boxes" : @"Show Collision Boxes";
return YES;
}
if (menuItem.action == @selector(showShortcuts:)) {
return YES;
}
if (menuItem.action == @selector(giveFeedback:)) {
return YES;
}
if (menuItem.action == @selector(showPreferences:)) {
return YES;
}
return NO;
}
- (NSUInteger)indexOfStyleInToolbarItem {
if (![MGLAccountManager accessToken]) {
return NSNotFound;
}
NSArray *styleURLs = @[
[MGLStyle streetsStyleURL],
[MGLStyle emeraldStyleURL],
[MGLStyle lightStyleURL],
[MGLStyle darkStyleURL],
[MGLStyle satelliteStyleURL],
[MGLStyle hybridStyleURL],
];
return [styleURLs indexOfObject:self.mapView.styleURL];
}
- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem {
if (!self.mapView) {
return NO;
}
if (toolbarItem.action == @selector(showShareMenu:)) {
[(NSButton *)toolbarItem.view sendActionOn:NSLeftMouseDownMask];
return ([MGLAccountManager accessToken]
&& [self.mapView.styleURL.scheme isEqualToString:@"mapbox"]
&& [self.mapView.styleURL.pathComponents.firstObject isEqualToString:@"styles"]);
}
if (toolbarItem.action == @selector(setStyle:)) {
NSPopUpButton *popUpButton = (NSPopUpButton *)toolbarItem.view;
NSUInteger index = self.indexOfStyleInToolbarItem;
if (index == NSNotFound) {
[popUpButton addItemWithTitle:@"Custom"];
index = [popUpButton numberOfItems] - 1;
}
[popUpButton selectItemAtIndex:index];
}
return NO;
}
#pragma mark NSApplicationDelegate methods
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
#pragma mark NSSharingServicePickerDelegate methods
- (NS_ARRAY_OF(NSSharingService *) *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NS_ARRAY_OF(NSSharingService *) *)proposedServices {
NSURL *shareURL = self.shareURL;
NSURL *browserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:shareURL];
NSImage *browserIcon = [[NSWorkspace sharedWorkspace] iconForFile:browserURL.path];
NSString *browserName = [[NSFileManager defaultManager] displayNameAtPath:browserURL.path];
NSString *browserServiceName = [NSString stringWithFormat:@"Open in %@", browserName];
NSSharingService *browserService = [[NSSharingService alloc] initWithTitle:browserServiceName
image:browserIcon
alternateImage:nil
handler:^{
[[NSWorkspace sharedWorkspace] openURL:self.shareURL];
}];
NSMutableArray *sharingServices = [proposedServices mutableCopy];
[sharingServices insertObject:browserService atIndex:0];
return sharingServices;
}
#pragma mark NSMenuDelegate methods
- (void)menuWillOpen:(NSMenu *)menu {
if (menu == self.mapViewContextMenu) {
_mouseLocationForMapViewContextMenu = self.window.mouseLocationOutsideOfEventStream;
}
}
#pragma mark MGLMapViewDelegate methods
- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation {
return YES;
}
- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
DroppedPinAnnotation *droppedPin = annotation;
[droppedPin resume];
}
}
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id<MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
DroppedPinAnnotation *droppedPin = annotation;
[droppedPin pause];
}
}
@end
@interface ValidatedToolbarItem : NSToolbarItem
@end
@implementation ValidatedToolbarItem
- (void)validate {
[(AppDelegate *)self.toolbar.delegate validateToolbarItem:self];
}
@end

View File

@@ -0,0 +1,9 @@
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf130
{\fonttbl\f0\fnil\fcharset0 SFUIText-Regular;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww10800\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0
\f0\fs20 \cf0 Copyright \'a9 {\field{\*\fldinst{HYPERLINK "https://www.mapbox.com/about/maps/"}}{\fldrslt Mapbox}}.\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc\partightenfactor0
\cf0 Copyright \'a9 {\field{\*\fldinst{HYPERLINK "http://www.openstreetmap.org/about/"}}{\fldrslt OpenStreetMap contributors}}.}

View File

@@ -0,0 +1,10 @@
#import "MGLPointAnnotation.h"
@interface DroppedPinAnnotation : MGLPointAnnotation
@property (nonatomic, readonly) NSTimeInterval elapsedShownTime;
- (void)resume;
- (void)pause;
@end

View File

@@ -0,0 +1,63 @@
#import "DroppedPinAnnotation.h"
#import "LocationCoordinate2DTransformer.h"
#import "TimeIntervalTransformer.h"
#import "NSValue+Additions.h"
@implementation DroppedPinAnnotation {
NSTimer *_timer;
NSTimeInterval _priorShownTimeInterval;
NSDate *_dateShown;
NSValueTransformer *_coordinateTransformer;
NSValueTransformer *_timeIntervalTransformer;
}
- (instancetype)init {
if (self = [super init]) {
_coordinateTransformer = [NSValueTransformer valueTransformerForName:
NSStringFromClass([LocationCoordinate2DTransformer class])];
_timeIntervalTransformer = [NSValueTransformer valueTransformerForName:
NSStringFromClass([TimeIntervalTransformer class])];
[self update:nil];
}
return self;
}
- (void)dealloc {
[self pause];
}
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate {
super.coordinate = coordinate;
[self update:nil];
}
- (NSTimeInterval)elapsedShownTime {
return _priorShownTimeInterval - _dateShown.timeIntervalSinceNow;
}
- (void)resume {
_dateShown = [NSDate date];
_timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(update:)
userInfo:nil
repeats:YES];
}
- (void)pause {
[_timer invalidate];
_timer = nil;
_priorShownTimeInterval -= _dateShown.timeIntervalSinceNow;
_dateShown = nil;
}
- (void)update:(NSTimer *)timer {
NSString *coordinate = [_coordinateTransformer transformedValue:
[NSValue valueWithCLLocationCoordinate2D:self.coordinate]];
NSString *elapsedTime = [_timeIntervalTransformer transformedValue:@(self.elapsedShownTime)];
self.subtitle = [NSString stringWithFormat:@"%@\nSelected for %@", coordinate, elapsedTime];
}
@end

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>0.1.0</string>
<key>CFBundleIconFile</key>
<string>Icon.icns</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>0.1.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<key>CFBundleSignature</key>
<string>MBGL</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>mapboxgl</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>0.1.0</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface LocationCoordinate2DTransformer : NSValueTransformer
@end

View File

@@ -0,0 +1,42 @@
#import "LocationCoordinate2DTransformer.h"
#import "NSValue+Additions.h"
NSString *StringFromDegrees(CLLocationDegrees degrees, char positiveDirection, char negativeDirection) {
double minutes = (degrees - floor(degrees)) * 60;
double seconds = (minutes - floor(minutes)) * 60;
NSMutableString *string = [NSMutableString stringWithFormat:@"%.0f°", fabs(degrees)];
if (floor(minutes) || floor(seconds)) {
[string appendFormat:@"%.0f′", minutes];
}
if (floor(seconds)) {
[string appendFormat:@"%.0f″", seconds];
}
if (degrees) {
[string appendFormat:@"%c", degrees > 0 ? positiveDirection : negativeDirection];
}
return string;
}
@implementation LocationCoordinate2DTransformer
+ (Class)transformedValueClass {
return [NSString class];
}
+ (BOOL)allowsReverseTransformation {
return NO;
}
- (id)transformedValue:(id)value {
if (![value isKindOfClass:[NSValue class]]) {
return nil;
}
CLLocationCoordinate2D coordinate = [value CLLocationCoordinate2DValue];
return [NSString stringWithFormat:@"%@, %@",
StringFromDegrees(coordinate.latitude, 'N', 'S'),
StringFromDegrees(coordinate.longitude, 'E', 'W')];
}
@end

View File

@@ -0,0 +1,683 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="z9N-Fm-MUP"/>
</connections>
</customObject>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
<connections>
<outlet property="mapView" destination="v1Z-oA-oHU" id="70S-xO-QIP"/>
<outlet property="mapViewContextMenu" destination="6rZ-M1-uTn" id="wl2-03-9Z8"/>
<outlet property="preferencesWindow" destination="UWc-yQ-qda" id="Ota-aT-Mz2"/>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="Mapbox GL" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Mapbox GL" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About Mapbox GL" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW">
<connections>
<action selector="showPreferences:" target="-1" id="Llx-Uy-HTS"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide Mapbox GL" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit Mapbox GL" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="KaW-ft-85H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Streets" state="on" tag="1" keyEquivalent="1" id="17N-yz-NNo">
<connections>
<action selector="setStyle:" target="-1" id="I4L-Wx-UXA"/>
</connections>
</menuItem>
<menuItem title="Emerald" tag="2" keyEquivalent="2" id="BBa-Qa-SQr">
<connections>
<action selector="setStyle:" target="-1" id="rM1-yG-t5u"/>
</connections>
</menuItem>
<menuItem title="Light" tag="3" keyEquivalent="3" id="HWe-7u-UVJ">
<connections>
<action selector="setStyle:" target="-1" id="Q9V-O1-oRz"/>
</connections>
</menuItem>
<menuItem title="Dark" tag="4" keyEquivalent="4" id="6HI-q6-AeV">
<connections>
<action selector="setStyle:" target="-1" id="YfH-1I-G50"/>
</connections>
</menuItem>
<menuItem title="Satellite" tag="5" keyEquivalent="5" id="h0J-5X-kgF">
<connections>
<action selector="setStyle:" target="-1" id="GXt-oK-Hy1"/>
</connections>
</menuItem>
<menuItem title="Hybrid" tag="6" keyEquivalent="6" id="9BL-00-HFt">
<connections>
<action selector="setStyle:" target="-1" id="oL4-AC-waq"/>
</connections>
</menuItem>
<menuItem title="Custom Style…" id="L0h-86-2cU">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="chooseCustomStyle:" target="-1" id="QJF-fM-Ty3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="BMF-ml-0Bd"/>
<menuItem title="Zoom In" keyEquivalent="+" id="W82-WO-xvB">
<connections>
<action selector="zoomIn:" target="-1" id="g33-vK-zUu"/>
</connections>
</menuItem>
<menuItem title="Zoom Out" keyEquivalent="-" id="j7h-PY-edM">
<connections>
<action selector="zoomOut:" target="-1" id="0pP-tO-9ex"/>
</connections>
</menuItem>
<menuItem title="Snap to North" keyEquivalent="" id="Zss-3w-wkz">
<connections>
<action selector="snapToNorth:" target="-1" id="Ayq-GE-Lb5"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="mkP-YN-G0w"/>
<menuItem title="Reload" keyEquivalent="r" id="JvI-nv-KaE">
<connections>
<action selector="reload:" target="-1" id="xkh-9F-mOe"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="CyM-Wv-Bnc"/>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Debug" id="ZNC-5r-eBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Debug" id="McE-ka-r79">
<items>
<menuItem title="Show Tile Boundaries" id="rDE-dG-rTR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleTileBoundaries:" target="-1" id="LAO-88-F7h"/>
</connections>
</menuItem>
<menuItem title="Show Tile Info" id="LoH-qD-kb0">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleTileInfo:" target="-1" id="KCn-0G-V87"/>
</connections>
</menuItem>
<menuItem title="Show Tile Timestamps" id="bY0-2E-LZ7">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleTileTimestamps:" target="-1" id="tBs-2N-KEG"/>
</connections>
</menuItem>
<menuItem title="Show Collision Boxes" id="Y0b-3K-mJE">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleCollisionBoxes:" target="-1" id="EYa-7n-iWZ"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" keyEquivalent="z" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="Mapbox GL Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showShortcuts:" target="-1" id="hNZ-sm-X2q"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="EpY-wQ-SjH"/>
<menuItem title="Improve This Map" id="xu5-WN-qYK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="giveFeedback:" target="-1" id="cil-i9-r39"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<window title="Mapbox GL" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="Mapbox" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="388" y="211" width="512" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="512" height="360"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="v1Z-oA-oHU" customClass="MGLMapView">
<rect key="frame" x="0.0" y="0.0" width="512" height="360"/>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="qJ7-fL-iw1"/>
<outlet property="menu" destination="6rZ-M1-uTn" id="4sB-UN-zuc"/>
</connections>
</customView>
</subviews>
<constraints>
<constraint firstItem="v1Z-oA-oHU" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="Z3O-xb-fah"/>
<constraint firstAttribute="trailing" secondItem="v1Z-oA-oHU" secondAttribute="trailing" id="oYw-bk-P2l"/>
<constraint firstItem="v1Z-oA-oHU" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="r4Z-4m-bgA"/>
<constraint firstAttribute="bottom" secondItem="v1Z-oA-oHU" secondAttribute="bottom" id="w3h-H1-baQ"/>
</constraints>
</view>
<toolbar key="toolbar" implicitIdentifier="A3AC6577-4712-4628-813D-113498171A84" allowsUserCustomization="NO" displayMode="iconOnly" sizeMode="regular" id="8nY-8B-Om5">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="zzK-Oz-JV8"/>
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="SMs-8a-x2h"/>
<toolbarItem implicitItemIdentifier="2CB58C0A-7B95-4233-8DD3-F94BFE7D3061" label="Share" paletteLabel="Share" image="NSShareTemplate" id="HtT-hs-jWY" customClass="ValidatedToolbarItem">
<nil key="toolTip"/>
<size key="minSize" width="40" height="32"/>
<size key="maxSize" width="40" height="32"/>
<button key="view" verticalHuggingPriority="750" id="l0U-ql-5hn">
<rect key="frame" x="0.0" y="14" width="48" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSShareTemplate" imagePosition="only" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vxZ-hj-hV2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="showShareMenu:" target="-1" id="vDU-9Y-DkS"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="BA3542AF-D63A-4893-9CC7-8F67EF2E82B0" label="Style" paletteLabel="Style" id="ge5-0H-wyr" customClass="ValidatedToolbarItem">
<nil key="toolTip"/>
<size key="minSize" width="100" height="26"/>
<size key="maxSize" width="100" height="26"/>
<popUpButton key="view" verticalHuggingPriority="750" id="5Cd-Lw-cWm">
<rect key="frame" x="0.0" y="14" width="100" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Streets" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="ZnV-nK-Bri" id="esr-2z-V4Y">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="uxq-U6-EQW">
<items>
<menuItem title="Streets" state="on" tag="1" id="ZnV-nK-Bri"/>
<menuItem title="Emerald" tag="2" id="LLa-jX-Dox"/>
<menuItem title="Light" tag="3" id="jDf-NE-hMn"/>
<menuItem title="Dark" tag="4" id="etJ-y7-M5R">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Satellite" tag="5" id="xYa-J8-bLe">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Hybrid" tag="6" id="1Uq-Nl-FSZ">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<connections>
<action selector="setStyle:" target="-1" id="qb2-E8-7pE"/>
</connections>
</toolbarItem>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="HtT-hs-jWY"/>
<toolbarItem reference="SMs-8a-x2h"/>
<toolbarItem reference="ge5-0H-wyr"/>
</defaultToolbarItems>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="ciT-Nf-Dtm"/>
</connections>
</toolbar>
<connections>
<binding destination="Voe-Tx-rLC" name="title" keyPath="mapView.centerCoordinate" id="XFo-sp-PtR">
<dictionary key="options">
<string key="NSValueTransformerName">LocationCoordinate2DTransformer</string>
</dictionary>
</binding>
</connections>
</window>
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="Preferences" animationBehavior="default" id="UWc-yQ-qda">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="109" y="131" width="350" height="62"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
<view key="contentView" id="eA4-n3-qPe">
<rect key="frame" x="0.0" y="0.0" width="350" height="62"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0IK-AW-Gg3">
<rect key="frame" x="18" y="23" width="89" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Access token:" id="Ptd-FI-M5A">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<accessibilityConnection property="link" destination="7sb-sf-oJU" id="U0t-jC-oQ7"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7sb-sf-oJU">
<rect key="frame" x="113" y="20" width="197" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="jlV-TC-NUv">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="45S-yT-WUN" name="value" keyPath="values.MGLMapboxAccessToken" id="iJE-S2-ALY"/>
</connections>
</textField>
<button translatesAutoresizingMaskIntoConstraints="NO" id="c3S-LC-PoX">
<rect key="frame" x="318" y="25" width="12" height="12"/>
<constraints>
<constraint firstAttribute="width" constant="12" id="M3J-pU-gKn"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="NSFollowLinkFreestandingTemplate" imagePosition="only" alignment="center" controlSize="small" imageScaling="proportionallyUpOrDown" inset="2" id="38x-37-Ay0">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="smallSystem"/>
</buttonCell>
<connections>
<action selector="openAccessTokenManager:" target="-1" id="1LX-4G-roC"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="c3S-LC-PoX" secondAttribute="trailing" constant="20" symbolic="YES" id="7QU-Jd-Rg6"/>
<constraint firstItem="c3S-LC-PoX" firstAttribute="top" secondItem="eA4-n3-qPe" secondAttribute="top" constant="25" id="JOS-HU-27c"/>
<constraint firstItem="7sb-sf-oJU" firstAttribute="leading" secondItem="0IK-AW-Gg3" secondAttribute="trailing" constant="8" symbolic="YES" id="SS6-VQ-sLK"/>
<constraint firstItem="0IK-AW-Gg3" firstAttribute="leading" secondItem="eA4-n3-qPe" secondAttribute="leading" constant="20" symbolic="YES" id="TYG-io-qfV"/>
<constraint firstItem="7sb-sf-oJU" firstAttribute="top" secondItem="eA4-n3-qPe" secondAttribute="top" constant="20" symbolic="YES" id="Vzb-q8-ecP"/>
<constraint firstItem="c3S-LC-PoX" firstAttribute="leading" secondItem="7sb-sf-oJU" secondAttribute="trailing" constant="8" symbolic="YES" id="pjl-9u-IgM"/>
<constraint firstItem="7sb-sf-oJU" firstAttribute="baseline" secondItem="0IK-AW-Gg3" secondAttribute="baseline" id="qIY-Jr-9Ws"/>
<constraint firstItem="7sb-sf-oJU" firstAttribute="centerY" secondItem="c3S-LC-PoX" secondAttribute="centerY" id="zej-gw-fC0"/>
</constraints>
</view>
<connections>
<outlet property="initialFirstResponder" destination="7sb-sf-oJU" id="UZe-di-dnA"/>
</connections>
<point key="canvasLocation" x="754" y="210"/>
</window>
<userDefaultsController representsSharedInstance="YES" id="45S-yT-WUN"/>
<menu title="Map View" id="6rZ-M1-uTn">
<items>
<menuItem title="Drop Pin" id="fxQ-3P-E7l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="dropPin:" target="Voe-Tx-rLC" id="eDR-iw-JUG"/>
</connections>
</menuItem>
</items>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="MsV-YU-f4X"/>
</connections>
<point key="canvasLocation" x="820" y="254.5"/>
</menu>
</objects>
<resources>
<image name="NSFollowLinkFreestandingTemplate" width="14" height="14"/>
<image name="NSShareTemplate" width="11" height="16"/>
</resources>
</document>

View File

@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface NSValue (Additions)
+ (instancetype)valueWithCLLocationCoordinate2D:(CLLocationCoordinate2D)coordinate;
@property (readonly) CLLocationCoordinate2D CLLocationCoordinate2DValue;
@end

View File

@@ -0,0 +1,15 @@
#import "NSValue+Additions.h"
@implementation NSValue (Additions)
+ (instancetype)valueWithCLLocationCoordinate2D:(CLLocationCoordinate2D)coordinate {
return [self valueWithBytes:&coordinate objCType:@encode(CLLocationCoordinate2D)];
}
- (CLLocationCoordinate2D)CLLocationCoordinate2DValue {
CLLocationCoordinate2D coordinate;
[self getValue:&coordinate];
return coordinate;
}
@end

View File

@@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface TimeIntervalTransformer : NSValueTransformer
@end

View File

@@ -0,0 +1,55 @@
#import "TimeIntervalTransformer.h"
#import "NSValue+Additions.h"
@implementation TimeIntervalTransformer
+ (Class)transformedValueClass {
return [NSString class];
}
+ (BOOL)allowsReverseTransformation {
return NO;
}
NSString *NumberAndUnitString(NSInteger quantity, NSString *singular, NSString *plural) {
return [NSString stringWithFormat:@"%ld %@", quantity, quantity == 1 ? singular : plural];
}
- (id)transformedValue:(id)value {
if (![value isKindOfClass:[NSValue class]]) {
return nil;
}
NSTimeInterval timeInterval = [value doubleValue];
NSInteger seconds = floor(timeInterval);
NSInteger minutes = floor(seconds / 60);
seconds -= minutes * 60;
NSInteger hours = floor(minutes / 60);
minutes -= hours * 60;
NSInteger days = floor(hours / 24);
hours -= days * 24;
NSInteger weeks = floor(days) / 7;
days -= weeks * 7;
NSMutableArray *components = [NSMutableArray array];
if (seconds || timeInterval < 60) {
[components addObject:NumberAndUnitString(seconds, @"second", @"seconds")];
}
if (minutes) {
[components insertObject:NumberAndUnitString(minutes, @"minute", @"minutes") atIndex:0];
}
if (hours) {
[components insertObject:NumberAndUnitString(hours, @"hour", @"hours") atIndex:0];
}
if (days) {
[components insertObject:NumberAndUnitString(days, @"day", @"days") atIndex:0];
}
if (weeks) {
[components insertObject:NumberAndUnitString(weeks, @"week", @"weeks") atIndex:0];
}
return [components componentsJoinedByString:@", "];
}
@end

5
platform/osx/app/main.m Normal file
View File

@@ -0,0 +1,5 @@
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}

View File

@@ -0,0 +1,48 @@
{
'includes': [
'../../../gyp/common.gypi',
],
'targets': [
{ 'target_name': 'osxapp',
'product_name': 'Mapbox GL',
'type': 'executable',
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'Credits.rtf',
'Icon.icns',
'MainMenu.xib',
],
'dependencies': [
'mbgl.gyp:core',
'mbgl.gyp:platform-<(platform_lib)',
'mbgl.gyp:http-<(http_lib)',
'mbgl.gyp:asset-<(asset_lib)',
'mbgl.gyp:cache-<(cache_lib)',
],
'sources': [
'./AppDelegate.h',
'./AppDelegate.m',
'./DroppedPinAnnotation.h',
'./DroppedPinAnnotation.m',
'./LocationCoordinate2DTransformer.h',
'./LocationCoordinate2DTransformer.m',
'./TimeIntervalTransformer.h',
'./TimeIntervalTransformer.m',
'./NSValue+Additions.h',
'./NSValue+Additions.m',
'./main.m',
],
'xcode_settings': {
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':'macosx',
'OTHER_LDFLAGS': [ '-stdlib=libc++', '-lstdc++' ],
'INFOPLIST_FILE': '../platform/osx/app/Info.plist',
'CLANG_ENABLE_OBJC_ARC': 'YES',
},
}
]
}

View File

@@ -1,212 +0,0 @@
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/platform/darwin/settings_nsuserdefaults.hpp>
#include <mbgl/platform/darwin/reachability.h>
#include <mbgl/platform/default/glfw_view.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/sqlite_cache.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/default_styles.hpp>
#import <Foundation/Foundation.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop
#include <iostream>
namespace po = boost::program_options;
@interface URLHandler : NSObject
@property (nonatomic) mbgl::Map *map;
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
@end
@implementation URLHandler
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
(void)replyEvent;
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [[url query] componentsSeparatedByString:@"&"]) {
NSArray *parts = [param componentsSeparatedByString:@"="];
if([parts count] < 2) continue;
[params setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]];
}
mbgl::LatLng latLng = mbgl::LatLng(0, 0);
double zoom = 0, bearing = 0;
bool hasCenter = false, hasZoom = false, hasBearing = false;
NSString *centerString = [params objectForKey:@"center"];
if (centerString) {
NSArray *latLngValues = [centerString componentsSeparatedByString:@","];
if ([latLngValues count] == 2) {
latLng.latitude = [latLngValues[0] doubleValue];
latLng.longitude = [latLngValues[1] doubleValue];
hasCenter = true;
}
}
NSString *zoomString = [params objectForKey:@"zoom"];
if (zoomString) {
zoom = [zoomString doubleValue];
hasZoom = true;
}
NSString *bearingString = [params objectForKey:@"bearing"];
if (bearingString) {
bearing = [bearingString doubleValue];
hasBearing = true;
}
if ([self map]) {
if (hasCenter && hasZoom) {
[self map]->setLatLngZoom(latLng, zoom);
} else if (hasCenter) {
[self map]->setLatLng(latLng);
} else if (hasZoom) {
[self map]->setZoom(zoom);
}
if (hasBearing) {
[self map]->setBearing(bearing);
}
}
}
@end
// Returns the path to the default cache database on this system.
const std::string &defaultCacheDatabase() {
static const std::string path = []() -> std::string {
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES);
if ([paths count] == 0) {
// Disable the cache if we don't have a location to write.
return "";
}
NSString *p = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"];
if (![[NSFileManager defaultManager] createDirectoryAtPath:p
withIntermediateDirectories:YES
attributes:nil
error:nil]) {
// Disable the cache if we couldn't create the directory.
return "";
}
return [[p stringByAppendingPathComponent:@"cache.db"] UTF8String];
}();
return path;
}
int main(int argc, char* argv[]) {
bool fullscreen = false;
bool benchmark = false;
std::string style;
po::options_description desc("Allowed options");
desc.add_options()
("fullscreen,f", po::bool_switch(&fullscreen)->default_value(fullscreen), "Fullscreen mode")
("style,s", po::value(&style)->value_name("json"), "Map stylesheet")
("benchmark,b", po::bool_switch(&benchmark)->default_value(benchmark), "Benchmark mode")
;
try {
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
po::variables_map vm;
po::store(parsed, vm);
po::notify(vm);
} catch(std::exception& e) {
std::cout << "Error: " << e.what() << std::endl << desc;
exit(1);
}
if (benchmark) {
mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled.");
}
GLFWView view(fullscreen, benchmark);
mbgl::SQLiteCache cache(defaultCacheDatabase());
mbgl::DefaultFileSource fileSource(&cache);
// Set access token if present
NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
if (!accessToken) mbgl::Log::Warning(mbgl::Event::Setup, "No access token set. Mapbox vector tiles won't work.");
if (accessToken) fileSource.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]);
mbgl::Map map(view, fileSource);
URLHandler *handler = [[URLHandler alloc] init];
[handler setMap:&map];
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:handler andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
// Notify map object when network reachability status changes.
MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection];
reachability.reachableBlock = ^(MGLReachability *) {
mbgl::NetworkStatus::Reachable();
};
[reachability startNotifier];
// Load settings
mbgl::Settings_NSUserDefaults settings;
map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom);
map.setBearing(settings.bearing);
map.setPitch(settings.pitch);
map.setDebug(mbgl::MapDebugOptions(settings.debug));
view.setChangeStyleCallback([&map, &view] () {
static uint8_t currentStyleIndex;
if (++currentStyleIndex == mbgl::util::default_styles::numOrderedStyles) {
currentStyleIndex = 0;
}
mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[currentStyleIndex];
map.setStyleURL(newStyle.url);
view.setWindowTitle(newStyle.name);
mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name);
});
// Load style
if (style.empty()) {
mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[0];
style = newStyle.url;
view.setWindowTitle(newStyle.name);
}
map.setStyleURL(style);
view.run();
[reachability stopNotifier];
// Save settings
mbgl::LatLng latLng = map.getLatLng();
settings.latitude = latLng.latitude;
settings.longitude = latLng.longitude;
settings.zoom = map.getZoom();
settings.bearing = map.getBearing();
settings.pitch = map.getPitch();
settings.debug = uint32_t(map.getDebug());
settings.save();
return 0;
}

View File

@@ -1,63 +0,0 @@
{
'includes': [
'../../gyp/common.gypi',
],
'targets': [
{ 'target_name': 'osxapp',
'product_name': 'Mapbox GL',
'type': 'executable',
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'Icon.icns'
],
'dependencies': [
'mbgl.gyp:core',
'mbgl.gyp:platform-<(platform_lib)',
'mbgl.gyp:http-<(http_lib)',
'mbgl.gyp:asset-<(asset_lib)',
'mbgl.gyp:cache-<(cache_lib)',
],
'sources': [
'./main.mm',
'../darwin/settings_nsuserdefaults.hpp',
'../darwin/settings_nsuserdefaults.mm',
'../darwin/reachability.m',
'../default/glfw_view.hpp',
'../default/glfw_view.cpp',
],
'variables' : {
'cflags_cc': [
'<@(boost_cflags)',
'<@(glfw_cflags)',
'<@(variant_cflags)',
],
'ldflags': [
'-framework SystemConfiguration', # For NSUserDefaults and Reachability
'<@(glfw_ldflags)',
],
'libraries': [
'<@(glfw_static_libs)',
'<@(boost_libprogram_options_static_libs)'
],
},
'libraries': [
'<@(libraries)',
],
'xcode_settings': {
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':'macosx',
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
'SDKROOT': 'macosx',
'INFOPLIST_FILE': '../platform/osx/Info.plist',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
}
]
}

View File

@@ -0,0 +1,66 @@
#import "MGLAccountManager_Private.h"
#import <mbgl/osx/MGLMapView.h>
#import "NSBundle+MGLAdditions.h"
#import "NSProcessInfo+MGLAdditions.h"
#import "../../darwin/NSString+MGLAdditions.h"
@interface MGLAccountManager ()
@property (atomic) NSString *accessToken;
@end
@implementation MGLAccountManager
#pragma mark - Internal
+ (void)load {
mgl_linkBundleCategory();
mgl_linkStringCategory();
mgl_linkProcessInfoCategory();
[MGLMapView restorableStateKeyPaths];
// Read the initial configuration from Info.plist.
NSString *accessToken = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxAccessToken"];
if (accessToken.length) {
self.accessToken = accessToken;
}
}
// Can be called from any thread.
//
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
static MGLAccountManager *_sharedManager;
void (^setupBlock)() = ^{
dispatch_once(&onceToken, ^{
_sharedManager = [[self alloc] init];
});
};
if (![[NSThread currentThread] isMainThread]) {
dispatch_sync(dispatch_get_main_queue(), ^{
setupBlock();
});
}
else {
setupBlock();
}
return _sharedManager;
}
+ (void)setAccessToken:(NSString *)accessToken {
accessToken = [accessToken stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (![accessToken length]) return;
[MGLAccountManager sharedManager].accessToken = accessToken;
}
+ (NSString *)accessToken {
return [MGLAccountManager sharedManager].accessToken;
}
@end

View File

@@ -0,0 +1,10 @@
#import <mbgl/osx/MGLAccountManager.h>
@interface MGLAccountManager (Private)
/** Returns the shared instance of the `MGLAccountManager` class. */
+ (instancetype)sharedManager;
@property (atomic) NSString *accessToken;
@end

View File

@@ -0,0 +1,25 @@
#import <mbgl/osx/MGLAnnotationImage.h>
@interface MGLAnnotationImage ()
@property (nonatomic) NSImage *image;
@property (nonatomic) NSString *reuseIdentifier;
@end
@implementation MGLAnnotationImage
+ (instancetype)annotationImageWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier {
return [[self alloc] initWithImage:image reuseIdentifier:reuseIdentifier];
}
- (instancetype)initWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super init]) {
_image = image;
_reuseIdentifier = [reuseIdentifier copy];
_selectable = YES;
}
return self;
}
@end

View File

@@ -0,0 +1,11 @@
#import <Cocoa/Cocoa.h>
@interface MGLAttributionButton : NSButton
- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url;
@property (nonatomic) NSURL *URL;
- (IBAction)openURL:(id)sender;
@end

View File

@@ -0,0 +1,46 @@
#import "MGLAttributionButton.h"
@implementation MGLAttributionButton {
NSTrackingRectTag _trackingAreaTag;
}
- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url {
if (self = [super initWithFrame:NSZeroRect]) {
self.bordered = NO;
self.bezelStyle = NSRegularSquareBezelStyle;
NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:@"© "
attributes:@{
NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]],
}];
[attributedTitle appendAttributedString:
[[NSAttributedString alloc] initWithString:title
attributes:@{
NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]],
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
}]];
self.attributedTitle = attributedTitle;
[self sizeToFit];
_URL = url;
self.toolTip = _URL.absoluteString;
self.target = self;
self.action = @selector(openURL:);
}
return self;
}
- (BOOL)wantsLayer {
return YES;
}
- (void)resetCursorRects {
[self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]];
}
- (IBAction)openURL:(__unused id)sender {
[[NSWorkspace sharedWorkspace] openURL:self.URL];
}
@end

View File

@@ -0,0 +1,5 @@
#import <Cocoa/Cocoa.h>
@interface MGLCompassCell : NSSliderCell
@end

View File

@@ -0,0 +1,31 @@
#import "MGLCompassCell.h"
@implementation MGLCompassCell
- (instancetype)init {
if (self = [super init]) {
self.sliderType = NSCircularSlider;
self.numberOfTickMarks = 4;
self.minValue = -360;
self.maxValue = 0;
}
return self;
}
- (void)drawKnob:(NSRect)knobRect {
NSBezierPath *trianglePath = [NSBezierPath bezierPath];
[trianglePath moveToPoint:NSMakePoint(NSMinX(knobRect), NSMaxY(knobRect))];
[trianglePath lineToPoint:NSMakePoint(NSMaxX(knobRect), NSMaxY(knobRect))];
[trianglePath lineToPoint:NSMakePoint(NSMidX(knobRect), NSMinY(knobRect))];
[trianglePath closePath];
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:NSMidX(knobRect) yBy:NSMidY(knobRect)];
[transform scaleBy:0.8];
[transform rotateByDegrees:self.doubleValue];
[transform translateXBy:-NSMidX(knobRect) yBy:-NSMidY(knobRect)];
[trianglePath transformUsingAffineTransform:transform];
[[NSColor redColor] setFill];
[trianglePath fill];
}
@end

View File

@@ -0,0 +1,114 @@
#import <mbgl/osx/MGLMapView+IBAdditions.h>
#import "MGLMapView_Private.h"
@implementation MGLMapView (IBAdditions)
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL__ {
return [NSSet setWithObject:@"styleURL"];
}
- (nullable NSString *)styleURL__ {
return self.styleURL.absoluteString;
}
- (void)setStyleURL__:(nullable NSString *)URLString {
URLString = [URLString stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *url = URLString.length ? [NSURL URLWithString:URLString] : nil;
if (URLString.length && !url) {
[NSException raise:@"Invalid style URL"
format:@"“%@” is not a valid style URL.", URLString];
}
self.styleURL = url;
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude {
return [NSSet setWithObjects:@"centerCoordinate", nil];
}
- (double)latitude {
return self.centerCoordinate.latitude;
}
- (void)setLatitude:(double)latitude {
if (!isnan(self.pendingLongitude)) {
self.centerCoordinate = CLLocationCoordinate2DMake(latitude, self.pendingLongitude);
self.pendingLatitude = NAN;
self.pendingLongitude = NAN;
} else {
// Not enough info to make a valid center coordinate yet. Stash this
// latitude away until the longitude is set too.
self.pendingLatitude = latitude;
}
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude {
return [NSSet setWithObjects:@"centerCoordinate", nil];
}
- (double)longitude {
return self.centerCoordinate.longitude;
}
- (void)setLongitude:(double)longitude {
if (!isnan(self.pendingLatitude)) {
self.centerCoordinate = CLLocationCoordinate2DMake(self.pendingLatitude, longitude);
self.pendingLatitude = NAN;
self.pendingLongitude = NAN;
} else {
// Not enough info to make a valid center coordinate yet. Stash this
// longitude away until the latitude is set too.
self.pendingLongitude = longitude;
}
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming {
return [NSSet setWithObject:@"zoomEnabled"];
}
- (BOOL)allowsZooming {
return self.zoomEnabled;
}
- (void)setAllowsZooming:(BOOL)allowsZooming {
self.zoomEnabled = allowsZooming;
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling {
return [NSSet setWithObject:@"scrollEnabled"];
}
- (BOOL)allowsScrolling {
return self.scrollEnabled;
}
- (void)setAllowsScrolling:(BOOL)allowsScrolling {
self.scrollEnabled = allowsScrolling;
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating {
return [NSSet setWithObject:@"rotateEnabled"];
}
- (BOOL)allowsRotating {
return self.rotateEnabled;
}
- (void)setAllowsRotating:(BOOL)allowsRotating {
self.rotateEnabled = allowsRotating;
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsTilting {
return [NSSet setWithObject:@"pitchEnabled"];
}
- (BOOL)allowsTilting {
return self.pitchEnabled;
}
- (void)setAllowsTilting:(BOOL)allowsTilting {
self.pitchEnabled = allowsTilting;
}
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#import <mbgl/osx/MGLMapView.h>
@interface MGLMapView (Private)
@property (nonatomic, readonly, getter=isDormant) BOOL dormant;
@property (nonatomic) CLLocationDegrees pendingLatitude;
@property (nonatomic) CLLocationDegrees pendingLongitude;
- (void)renderSync;
@end

View File

@@ -0,0 +1,10 @@
#import <Cocoa/Cocoa.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
@interface MGLOpenGLLayer : NSOpenGLLayer
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,49 @@
#import "MGLOpenGLLayer.h"
#import "MGLMapView_Private.h"
#import <mbgl/platform/gl.hpp>
@implementation MGLOpenGLLayer
- (MGLMapView *)mapView {
return (MGLMapView *)super.view;
}
//- (BOOL)isAsynchronous {
// return YES;
//}
- (BOOL)needsDisplayOnBoundsChange {
return YES;
}
- (CGRect)frame {
return self.view.bounds;
}
- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask {
NSOpenGLPixelFormatAttribute pfas[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAClosestPolicy,
NSOpenGLPFAAccumSize, 32,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFADepthSize, 16,
NSOpenGLPFAStencilSize, 8,
NSOpenGLPFAScreenMask, mask,
0
};
return [[NSOpenGLPixelFormat alloc] initWithAttributes:pfas];
}
- (BOOL)canDrawInOpenGLContext:(__unused NSOpenGLContext *)context pixelFormat:(__unused NSOpenGLPixelFormat *)pixelFormat forLayerTime:(__unused CFTimeInterval)t displayTime:(__unused const CVTimeStamp *)ts {
return !self.mapView.dormant;
}
- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat forLayerTime:(CFTimeInterval)t displayTime:(const CVTimeStamp *)ts {
[self.mapView renderSync];
[super drawInOpenGLContext:context pixelFormat:pixelFormat forLayerTime:t displayTime:ts];
}
@end

View File

@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
void mgl_linkBundleCategory();
@interface NSBundle (MGLAdditions)
+ (instancetype)mgl_resourceBundle;
+ (NSString *)mgl_resourceBundlePath;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
#import "NSBundle+MGLAdditions.h"
#import "MGLAccountManager.h"
void mgl_linkBundleCategory() {}
@implementation NSBundle (MGLAdditions)
+ (instancetype)mgl_resourceBundle {
return [self bundleWithPath:[self mgl_resourceBundlePath]];
}
+ (NSString *)mgl_resourceBundlePath {
NSString *resourceBundlePath = [[self bundleForClass:[MGLAccountManager class]]
pathForResource:@"Mapbox" ofType:@"bundle"];
if (!resourceBundlePath) {
resourceBundlePath = [[self mainBundle] bundlePath];
}
return resourceBundlePath;
}
@end

View File

@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
void mgl_linkProcessInfoCategory();
@interface NSProcessInfo (MGLAdditions)
- (BOOL)mgl_isInterfaceBuilderDesignablesAgent;
@end

View File

@@ -0,0 +1,11 @@
#import "NSProcessInfo+MGLAdditions.h"
void mgl_linkProcessInfoCategory() {}
@implementation NSProcessInfo (MGLAdditions)
- (BOOL)mgl_isInterfaceBuilderDesignablesAgent {
return [self.processName isEqualToString:@"IBDesignablesAgent"];
}
@end

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSViewController">
<connections>
<outlet property="view" destination="c22-O7-iKe" id="QAM-0O-WIj"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="270" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="k5x-ao-Pz3">
<rect key="frame" x="18" y="25" width="234" height="17"/>
<textFieldCell key="cell" selectable="YES" sendsActionOnEndEditing="YES" title="Title" id="nVE-Zi-KcG">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="representedObject.title" id="3nD-YS-gzq"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e9C-Ve-ccw">
<rect key="frame" x="18" y="8" width="234" height="14"/>
<textFieldCell key="cell" controlSize="small" selectable="YES" sendsActionOnEndEditing="YES" title="Subtitle" id="eKw-tQ-dw8">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="representedObject.subtitle" id="RQf-48-DyH"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="e9C-Ve-ccw" firstAttribute="leading" secondItem="k5x-ao-Pz3" secondAttribute="leading" id="ApT-ew-CYb"/>
<constraint firstAttribute="bottom" secondItem="e9C-Ve-ccw" secondAttribute="bottom" constant="8" id="CWV-Dd-8oi"/>
<constraint firstItem="k5x-ao-Pz3" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="20" id="UUL-GB-Jtv"/>
<constraint firstItem="e9C-Ve-ccw" firstAttribute="top" secondItem="k5x-ao-Pz3" secondAttribute="bottom" constant="3" id="Urc-wn-m8X"/>
<constraint firstItem="e9C-Ve-ccw" firstAttribute="trailing" secondItem="k5x-ao-Pz3" secondAttribute="trailing" id="gss-6G-9GF"/>
<constraint firstAttribute="trailing" secondItem="k5x-ao-Pz3" secondAttribute="trailing" constant="20" id="xCZ-s9-HaP"/>
<constraint firstItem="k5x-ao-Pz3" firstAttribute="top" secondItem="c22-O7-iKe" secondAttribute="top" constant="8" id="xcm-oY-jjy"/>
</constraints>
<point key="canvasLocation" x="257" y="355"/>
</customView>
</objects>
</document>

Binary file not shown.

Binary file not shown.

View File

@@ -99,6 +99,9 @@ echo "Created ${OUTPUT}/static/lib${NAME}.a"
step "Copying Headers..."
mkdir -p "${OUTPUT}/static/Headers"
for i in `ls -R include/mbgl/darwin | grep -vi private`; do
cp -pv include/mbgl/darwin/$i "${OUTPUT}/static/Headers"
done
for i in `ls -R include/mbgl/ios | grep -vi private`; do
cp -pv include/mbgl/ios/$i "${OUTPUT}/static/Headers"
done

78
scripts/osx/package.sh Executable file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/env bash
set -e
set -o pipefail
set -u
NAME=Mapbox
OUTPUT=build/osx/pkg
OSX_SDK_VERSION=`xcrun --sdk macosx --show-sdk-version`
LIBUV_VERSION=1.7.5
if [[ ${#} -eq 0 ]]; then # e.g. "make ipackage"
BUILDTYPE="Release"
GCC_GENERATE_DEBUGGING_SYMBOLS="YES"
else # e.g. "make ipackage-strip"
BUILDTYPE="Release"
GCC_GENERATE_DEBUGGING_SYMBOLS="NO"
fi
function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
function finish { >&2 echo -en "\033[0m"; }
trap finish EXIT
rm -rf ${OUTPUT}
mkdir -p "${OUTPUT}"/static
step "Recording library version..."
VERSION="${OUTPUT}"/static/version.txt
echo -n "https://github.com/mapbox/mapbox-gl-native/commit/" > ${VERSION}
HASH=`git log | head -1 | awk '{ print $2 }' | cut -c 1-10` && true
echo -n "mapbox-gl-native "
echo ${HASH}
echo ${HASH} >> ${VERSION}
step "Creating build files..."
export MASON_PLATFORM=osx
export BUILDTYPE=${BUILDTYPE:-Release}
export HOST=osx
make Xcode/osx
step "Building OS X targets..."
xcodebuild -sdk macosx${OSX_SDK_VERSION} \
ARCHS="x86_64" \
ONLY_ACTIVE_ARCH=NO \
GCC_GENERATE_DEBUGGING_SYMBOLS=${GCC_GENERATE_DEBUGGING_SYMBOLS} \
-project ./build/osx-x86_64/gyp/mbgl.xcodeproj \
-configuration ${BUILDTYPE} \
-target everything \
-jobs ${JOBS}
step "Building static library..."
LIBS=(core.a platform-osx.a asset-fs.a cache-sqlite.a http-nsurl.a)
libtool -static -no_warning_for_no_symbols \
`find mason_packages/osx-${OSX_SDK_VERSION} -type f -name libuv.a` \
`find mason_packages/osx-${OSX_SDK_VERSION} -type f -name libgeojsonvt.a` \
-o ${OUTPUT}/static/lib${NAME}.a \
${LIBS[@]/#/gyp/build/${BUILDTYPE}/libmbgl-}
echo "Created ${OUTPUT}/static/lib${NAME}.a"
step "Copying Headers..."
mkdir -p "${OUTPUT}/static/Headers"
for i in `ls -R include/mbgl/darwin | grep -vi private`; do
cp -pv include/mbgl/darwin/$i "${OUTPUT}/static/Headers"
done
for i in `ls -R include/mbgl/osx | grep -vi private`; do
cp -pv include/mbgl/osx/$i "${OUTPUT}/static/Headers"
done
step "Copying Resources..."
cp -pv LICENSE.md "${OUTPUT}/static"
mkdir -p "${OUTPUT}/static/${NAME}.bundle"
cp -pv platform/osx/resources/* "${OUTPUT}/static/${NAME}.bundle"

View File

@@ -11,6 +11,12 @@ BUILDTYPE=${BUILDTYPE:-Release}
# Build
################################################################################
mapbox_time "package_osx_symbols" \
make xpackage
mapbox_time "package_osx_stripped" \
make xpackage-strip
mapbox_time "compile_program" \
make xosx -j${JOBS} BUILDTYPE=${BUILDTYPE}