From 5782c9a6baa4a6cf23f54289032aaa757d40861e Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 9 Jun 2016 10:26:40 +0200 Subject: [android] #5285 - bring selected MarkerView to the front Fixes #5285 --- .../main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java | 1 + .../mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index bcb3176bfd..01fb5d8a72 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -210,6 +210,7 @@ public class MarkerViewManager { mapboxMap.selectMarker(marker); } marker.setSelected(true); + convertView.bringToFront(); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java index 2b5ec2ef80..19ae121e82 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java @@ -55,7 +55,8 @@ public class MarkerViewActivity extends AppCompatActivity { new LatLng(38.909698, -77.029642), new LatLng(38.907227, -77.036530), new LatLng(38.905607, -77.031916), - new LatLng(38.889441, -77.050134) + new LatLng(38.889441, -77.050134), + new LatLng(38.888000, -77.050000) //Slight overlap to show re-ordering on selection }; @Override -- cgit v1.2.1 From 8c8625210324eaad6cd926ea823fa77d75512966 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 9 Jun 2016 12:26:53 +0200 Subject: [android] #5296 - Add a container ViewGroup for MarkerViews Fixes #5296 --- .../com/mapbox/mapboxsdk/annotations/MarkerViewManager.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/maps/MapView.java | 11 +++++++++++ .../src/main/res/layout/mapview_internal.xml | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index 01fb5d8a72..f1794b808f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -387,7 +387,7 @@ public class MarkerViewManager { markerViewMap.put(marker, adaptedView); if (convertView == null) { - mapView.addView(adaptedView); + mapView.getMarkerViewContainer().addView(adaptedView); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 68a2a47cf7..b42e764c3b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -48,6 +48,7 @@ import android.view.Surface; import android.view.TextureView; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.FrameLayout; @@ -124,6 +125,7 @@ public class MapView extends FrameLayout { private NativeMapView mNativeMapView; private boolean mHasSurface = false; + private ViewGroup mMarkerViewContainer; private CompassView mCompassView; private ImageView mLogoView; private ImageView mAttributionsView; @@ -224,6 +226,8 @@ public class MapView extends FrameLayout { // Connectivity onConnectivityChanged(isConnected()); + mMarkerViewContainer = (ViewGroup) view.findViewById(R.id.markerViewContainer); + mMyLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); mMyLocationView.setMapboxMap(mMapboxMap); @@ -1132,6 +1136,13 @@ public class MapView extends FrameLayout { return new ArrayList<>(annotations); } + /** + * @return the ViewGroup containing the marker views + */ + public ViewGroup getMarkerViewContainer() { + return mMarkerViewContainer; + } + int getTopOffsetPixelsForIcon(Icon icon) { if (mDestroyed) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml index e944a5b4d1..8787b0ba76 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml @@ -6,6 +6,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + Date: Mon, 13 Jun 2016 16:20:21 -0400 Subject: [android] #4159 - expose an api to enable selection/deselection of markers on map tap (#5312) --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 6 ++++-- .../java/com/mapbox/mapboxsdk/maps/UiSettings.java | 22 ++++++++++++++++++++++ .../activity/infowindow/InfoWindowActivity.java | 8 ++++++++ .../src/main/res/menu/menu_infowindow.xml | 6 ++++++ .../src/main/res/values/strings.xml | 3 ++- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index b42e764c3b..658d67e756 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -1688,8 +1688,10 @@ public class MapView extends FrameLayout { } } } else { - // deselect any selected marker - mMapboxMap.deselectMarkers(); + if (mMapboxMap.getUiSettings().isDeselectMarkersOnTap()) { + // deselect any selected marker + mMapboxMap.deselectMarkers(); + } // notify app of map click MapboxMap.OnMapClickListener listener = mMapboxMap.getOnMapClickListener(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 3cd9efb13e..0a20d13b64 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -33,6 +33,8 @@ public class UiSettings { private boolean zoomControlsEnabled; + private boolean deselectMarkersOnTap = true; + UiSettings(@NonNull MapView mapView) { this.mapView = mapView; this.compassSettings = new ViewSettings(); @@ -483,6 +485,26 @@ public class UiSettings { return zoomControlsEnabled; } + /** + * Gets whether the markers are automatically deselected (and therefore, their infowindows + * closed) when a map tap is detected. + + * @return If true, markers are deselected on a map tap. + */ + public boolean isDeselectMarkersOnTap() { + return deselectMarkersOnTap; + } + + /** + * Sets whether the markers are automatically deselected (and therefore, their infowindows + * closed) when a map tap is detected. + * + * @param deselectMarkersOnTap + */ + public void setDeselectMarkersOnTap(boolean deselectMarkersOnTap) { + this.deselectMarkersOnTap = deselectMarkersOnTap; + } + /** *

* Changes whether the user may scroll around the map. diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java index 7ac3c59667..a496fc3f9d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java @@ -82,6 +82,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(allowConcurrentInfoWindow); } + private void toggleDeselectMarkersOnTap(boolean deselectMarkersOnTap) { + mapboxMap.getUiSettings().setDeselectMarkersOnTap(deselectMarkersOnTap); + } + @Override public boolean onInfoWindowClick(@NonNull Marker marker) { Toast.makeText(getApplicationContext(), "OnClick: " + marker.getTitle(), Toast.LENGTH_LONG).show(); @@ -157,6 +161,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC toggleConcurrentInfoWindow(!item.isChecked()); item.setChecked(!item.isChecked()); return true; + case R.id.action_toggle_deselect_markers_on_tap: + toggleDeselectMarkersOnTap(!item.isChecked()); + item.setChecked(!item.isChecked()); + return true; case android.R.id.home: onBackPressed(); return true; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml index 583b760d7c..adca8d2e00 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml @@ -8,6 +8,12 @@ android:id="@+id/action_toggle_concurrent_infowindow" app:showAsAction="never" android:checkable="true"/> + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index ce57e160c3..b856e7579a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -81,7 +81,8 @@ Restart map view after temporarily leaving to another activity Use an Android SDK View as marker - Concurrent Open InfoWindowsr + Concurrent Open InfoWindows + Deselect Markers On Tap Dismiss location tracking on gesture Dismiss bearing tracking on gesture Reset -- cgit v1.2.1 From b3467a555ac48d34470210bab0c7172161b0540c Mon Sep 17 00:00:00 2001 From: Tobrun Van Nuland Date: Mon, 13 Jun 2016 14:11:18 +0200 Subject: [android] #4924 - Make Gesture Focal Point Configurable --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 68 ++++++++++++++-------- .../java/com/mapbox/mapboxsdk/maps/UiSettings.java | 23 ++++++++ .../activity/annotation/MarkerViewActivity.java | 3 + 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 658d67e756..ae71ee384a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -152,6 +152,8 @@ public class MapView extends FrameLayout { private int mContentPaddingRight; private int mContentPaddingBottom; + private PointF mFocalPoint; + private StyleInitializer mStyleInitializer; private List mOnMapReadyCallbackList; @@ -566,6 +568,18 @@ public class MapView extends FrameLayout { } } + void setFocalPoint(PointF focalPoint) { + if (focalPoint == null) { + // resetting focal point, + UiSettings uiSettings = mMapboxMap.getUiSettings(); + // need to validate if we need to reset focal point with user provided one + if (uiSettings.getFocalPoint() != null) { + focalPoint = uiSettings.getFocalPoint(); + } + } + mFocalPoint = focalPoint; + } + /** * You must call this method from the parent's {@link Activity#onLowMemory()} or {@link Fragment#onLowMemory()}. */ @@ -1548,8 +1562,12 @@ public class MapView extends FrameLayout { || mShoveGestureDetector.isInProgress(); if (mTwoTap && isTap && !inProgress) { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - zoom(false, focalPoint.x, focalPoint.y); + if (mFocalPoint != null) { + zoom(false, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else { + PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); + zoom(false, focalPoint.x, focalPoint.y); + } mTwoTap = false; return true; } @@ -1608,12 +1626,12 @@ public class MapView extends FrameLayout { } // Single finger double tap - if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // User provided focal point + zoom(true, mFocalPoint.x, mFocalPoint.y); + } else { // Zoom in on gesture zoom(true, e.getX(), e.getY()); - } else { - // Zoom in on user location view - zoom(true, mMyLocationView.getCenterX(), mMyLocationView.getCenterY()); } break; } @@ -1839,23 +1857,18 @@ public class MapView extends FrameLayout { // Gesture is a quickzoom if there aren't two fingers mQuickZoom = !mTwoTap; - TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings(); - // Scale the map - if (uiSettings.isScrollGesturesEnabled() && !mQuickZoom && trackingSettings.isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // arround user provided focal point + mNativeMapView.scaleBy(detector.getScaleFactor(), mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else if (mQuickZoom) { + // around center map + mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity); + } else { // around gesture mNativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); - } else { - if (trackingSettings.isLocationTrackingDisabled()) { - // around center map - mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity); - } else { - // around user location view - float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2; - float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2; - mNativeMapView.scaleBy(detector.getScaleFactor(), x / mScreenDensity, y / mScreenDensity); - } } + return true; } } @@ -1925,16 +1938,14 @@ public class MapView extends FrameLayout { bearing += detector.getRotationDegreesDelta(); // Rotate the map - if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // User provided focal point + mNativeMapView.setBearing(bearing, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else { // around gesture mNativeMapView.setBearing(bearing, detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); - } else { - // around center userlocation - float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2; - float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2; - mNativeMapView.setBearing(bearing, x / mScreenDensity, y / mScreenDensity); } return true; } @@ -2426,6 +2437,13 @@ public class MapView extends FrameLayout { mMapboxMap.setMyLocationEnabled(true); } mMyLocationView.setMyLocationTrackingMode(myLocationTrackingMode); + + if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + setFocalPoint(new PointF(mMyLocationView.getCenterX(), mMyLocationView.getCenterY())); + } else { + setFocalPoint(null); + } + MapboxMap.OnMyLocationTrackingModeChangeListener listener = mMapboxMap.getOnMyLocationTrackingModeChangeListener(); if (listener != null) { listener.onMyLocationTrackingModeChange(myLocationTrackingMode); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 0a20d13b64..4ce631fc3e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -1,7 +1,9 @@ package com.mapbox.mapboxsdk.maps; +import android.graphics.PointF; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.view.Gravity; import android.view.View; @@ -35,6 +37,8 @@ public class UiSettings { private boolean deselectMarkersOnTap = true; + private PointF focalPoint; + UiSettings(@NonNull MapView mapView) { this.mapView = mapView; this.compassSettings = new ViewSettings(); @@ -563,6 +567,25 @@ public class UiSettings { setZoomGesturesEnabled(enabled); } + /** + * Sets the focal point used as center for a gesture + * + * @param focalPoint the focal point to be used. + */ + public void setFocalPoint(@Nullable PointF focalPoint) { + this.focalPoint = focalPoint; + mapView.setFocalPoint(focalPoint); + } + + /** + * Returns the gesture focal point + * + * @return The focal point + */ + public PointF getFocalPoint() { + return focalPoint; + } + /** * Returns the measured height of the MapView * diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java index 19ae121e82..0f08c6ae86 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java @@ -5,6 +5,7 @@ import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.PointF; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; @@ -161,6 +162,8 @@ public class MarkerViewActivity extends AppCompatActivity { .icon(IconFactory.getInstance(mMapView.getContext()) .fromResource(R.drawable.ic_arsenal)) ); + + mMapboxMap.getUiSettings().setFocalPoint(new PointF(mMapView.getMeasuredWidth() / 2, mMapView.getMeasuredHeight() / 4)); } }); } -- cgit v1.2.1 From 4f622a75dba03fe3f8dfb73c470b42eee676a576 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Mon, 13 Jun 2016 14:53:30 -0500 Subject: [android] #4959 - Dynamic Sizing Of Default InfoWindow Based On Availability Of Title And Snippet Data --- .../com/mapbox/mapboxsdk/annotations/InfoWindow.java | 18 ++++++++++++++++-- .../activity/infowindow/InfoWindowActivity.java | 8 ++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index 7452ab8fac..aaa5525b4d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations; import android.content.res.Resources; import android.graphics.PointF; import android.support.annotation.LayoutRes; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -222,9 +223,22 @@ public class InfoWindow { } mMapboxMap = new WeakReference<>(mapboxMap); String title = overlayItem.getTitle(); - ((TextView) view.findViewById(R.id.infowindow_title)).setText(title); + TextView titleTextView = ((TextView) view.findViewById(R.id.infowindow_title)); + if (!TextUtils.isEmpty(title)) { + titleTextView.setText(title); + titleTextView.setVisibility(View.VISIBLE); + } else { + titleTextView.setVisibility(View.GONE); + } + String snippet = overlayItem.getSnippet(); - ((TextView) view.findViewById(R.id.infowindow_description)).setText(snippet); + TextView snippetTextView = ((TextView) view.findViewById(R.id.infowindow_description)); + if (!TextUtils.isEmpty(snippet)) { + snippetTextView.setText(snippet); + snippetTextView.setVisibility(View.VISIBLE); + } else { + snippetTextView.setVisibility(View.GONE); + } } InfoWindow setBoundMarker(Marker boundMarker) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java index a496fc3f9d..7ff0acdb29 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java @@ -8,7 +8,6 @@ import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; - import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; @@ -16,7 +15,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.maps.MapView; - import java.text.DecimalFormat; public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnInfoWindowCloseListener, MapboxMap.OnMapLongClickListener, MapboxMap.OnInfoWindowClickListener, MapboxMap.OnInfoWindowLongClickListener { @@ -61,6 +59,12 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC .snippet("E St NW with 17th St NW") .position(new LatLng(38.8954236, -77.0394623))); + mapboxMap.addMarker(new MarkerOptions().title("The Ellipse").position(new LatLng(38.89393, -77.03654))); + + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(38.89596, -77.03434))); + + mapboxMap.addMarker(new MarkerOptions().snippet("Lafayette Square").position(new LatLng(38.89949, -77.03656))); + Marker marker = mapboxMap.addMarker(new MarkerOptions() .title("White House") .snippet("The official residence and principal workplace of the President of the United States, located at 1600 Pennsylvania Avenue NW in Washington, D.C. It has been the residence of every U.S. president since John Adams in 1800.") -- cgit v1.2.1 From 7942ce94558739b0171abcee1281e1aa4c60d409 Mon Sep 17 00:00:00 2001 From: Tobrun Van Nuland Date: Mon, 13 Jun 2016 13:05:25 +0200 Subject: [android] #5279 - expose MarkerView alpha --- .../annotations/BaseMarkerViewOptions.java | 23 +++++++++++++++++++++- .../mapboxsdk/annotations/MarkerViewOptions.java | 3 +++ .../activity/annotation/MarkerViewActivity.java | 1 + .../annotations/CountryMarkerViewOptions.java | 8 ++++++-- .../model/annotations/TextMarkerViewOptions.java | 5 +++++ 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java index 2a41fad234..a5c6397b6f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java @@ -29,6 +29,7 @@ public abstract class BaseMarkerViewOptions { @@ -23,8 +24,10 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions { @@ -24,6 +25,8 @@ public class TextMarkerViewOptions extends BaseMarkerViewOptions Date: Mon, 13 Jun 2016 12:46:38 +0200 Subject: [android] #5276 - icon should be optional for MarkerView --- .../com/mapbox/mapboxsdk/annotations/IconFactory.java | 8 ++++++++ .../main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 8 +++++++- .../src/main/res/drawable-hdpi/default_markerview.png | Bin 0 -> 1669 bytes .../src/main/res/drawable-mdpi/default_markerview.png | Bin 0 -> 1115 bytes .../src/main/res/drawable-xhdpi/default_markerview.png | Bin 0 -> 2163 bytes .../src/main/res/drawable-xxhdpi/default_markerview.png | Bin 0 -> 3163 bytes .../src/main/res/drawable-xxxhdpi/default_markerview.png | Bin 0 -> 4071 bytes 7 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java index d7d41b98be..93c6deddc9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java @@ -33,6 +33,7 @@ public final class IconFactory { private Context mContext; private static IconFactory sInstance; private Icon mDefaultMarker; + private Icon mDefaultMarkerView; private BitmapFactory.Options mOptions; private int mNextId = 0; @@ -121,6 +122,13 @@ public final class IconFactory { return mDefaultMarker; } + public Icon defaultMarkerView() { + if (mDefaultMarkerView == null) { + mDefaultMarkerView = fromResource(R.drawable.default_markerview); + } + return mDefaultMarkerView; + } + private Icon fromInputStream(@NonNull InputStream is) { Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions); return fromBitmap(bitmap); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 3fbdebe2b7..72eabf5794 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.InfoWindow; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; @@ -1208,7 +1209,12 @@ public class MapboxMap { private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) { MarkerView marker = markerViewOptions.getMarker(); - marker.setIcon(markerViewOptions.getIcon()); + + Icon icon = markerViewOptions.getIcon(); + if (icon == null) { + icon = IconFactory.getInstance(mMapView.getContext()).defaultMarkerView(); + } + marker.setIcon(icon); return marker; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png new file mode 100644 index 0000000000..651482f3ee Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png new file mode 100644 index 0000000000..63cb7b5f4b Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png new file mode 100644 index 0000000000..175f88ff88 Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png new file mode 100644 index 0000000000..be782e1d4b Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png new file mode 100644 index 0000000000..fe1c486518 Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png differ -- cgit v1.2.1 From dd221596ba6dfa3b8866b69a11d01e918df5af29 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 16 Jun 2016 10:58:17 +0200 Subject: [android] #5342 - initial marker animation --- .../mapbox/mapboxsdk/annotations/MarkerView.java | 85 ++++++++++++- .../mapboxsdk/annotations/MarkerViewManager.java | 135 +++++++++++++++++---- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 6 +- .../annotation/AnimatedMarkerActivity.java | 31 ++--- .../main/res/layout/activity_animated_marker.xml | 7 +- 5 files changed, 218 insertions(+), 46 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java index 49d7a061d0..580c3796da 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java @@ -1,12 +1,16 @@ package com.mapbox.mapboxsdk.annotations; +import android.animation.AnimatorSet; import android.graphics.Bitmap; +import android.graphics.PointF; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; +import android.view.animation.AnimationUtils; import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; /** @@ -26,8 +30,8 @@ public class MarkerView extends Marker { private float anchorU; private float anchorV; - private float offsetX; - private float offsetY; + private float offsetX = -1; + private float offsetY = -1; private float infoWindowAnchorU; private float infoWindowAnchorV; @@ -43,6 +47,15 @@ public class MarkerView extends Marker { private boolean selected; + private LatLng targetPosition; + private boolean shouldAnimate; + private boolean isAnimationRunning; + private AnimatorSet set; + + private long startTime; + private long duration; + private long remainingTime; + /** * Publicly hidden default constructor */ @@ -279,7 +292,7 @@ public class MarkerView extends Marker { * * @param alpha the alpha value to animate to */ - public void setAlpha(@FloatRange(from=0.0, to=255.0)float alpha) { + public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) { this.alpha = alpha; if (markerViewManager != null) { markerViewManager.animateAlpha(this, alpha); @@ -339,6 +352,72 @@ public class MarkerView extends Marker { markerViewManager = mapboxMap.getMarkerViewManager(); } + @Override + public void setPosition(LatLng position) { + setPosition(position, 0); + } + + public void setPosition(LatLng position, long duration) { + if (duration <= 0) { + // update position instantly + super.setPosition(position); + if (markerViewManager != null) { + markerViewManager.update(); + } + } else { + // animate using Android SDK animations + this.targetPosition = position; + if (markerViewManager != null) { + markerViewManager.animatePosition(this, duration); + } + } + } + + boolean shouldAnimate() { + return shouldAnimate; + } + + void setShouldAnimate(boolean animating) { + shouldAnimate = animating; + } + + boolean isAnimating() { + return isAnimationRunning; + } + + void setAnimating(boolean animationRunning) { + isAnimationRunning = animationRunning; + } + + LatLng getTargetPosition() { + return targetPosition; + } + + void setAnimation(AnimatorSet set) { + this.set = set; + } + + AnimatorSet getAnimation() { + return set; + } + + long getRemainingTime() { + long time = duration - (AnimationUtils.currentAnimationTimeMillis() - startTime); + return time > 0 ? time : 0; + } + + void setDuration(long duration) { + this.duration = duration; + } + + void setStartTime(long startTime) { + this.startTime = startTime; + } + + PointF getScreenLocation(@NonNull View convertView) { + return new PointF(convertView.getX() + offsetX, convertView.getY() + offsetY); + } + /** * Get the String representation of a MarkerView. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index f1794b808f..b438e28d96 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -1,14 +1,19 @@ package com.mapbox.mapboxsdk.annotations; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.PointF; +import android.os.CountDownTimer; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.util.Pools; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.AnimationUtils; import android.widget.ImageView; import com.mapbox.mapboxsdk.R; @@ -38,6 +43,7 @@ public class MarkerViewManager { private long viewMarkerBoundsUpdateTime; private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; private ImageMarkerViewAdapter defaultMarkerViewAdapter; + private CountDownTimer timer; /** * Creates an instance of MarkerViewManager. @@ -111,24 +117,60 @@ public class MarkerViewManager { *

*/ public void update() { - View convertView; - for (MarkerView marker : markerViewMap.keySet()) { - convertView = markerViewMap.get(marker); + for (final MarkerView marker : markerViewMap.keySet()) { + final View convertView = markerViewMap.get(marker); if (convertView != null) { - PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); - int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); + if (marker.isAnimating() || !marker.shouldAnimate()) { + if (marker.isAnimating()) { + // cancel ongoing animations + marker.setAnimating(false); + AnimatorSet set = marker.getAnimation(); + List animations = set.getChildAnimations(); + float x = (Float) ((ObjectAnimator) animations.get(0)).getAnimatedValue(); + float y = (Float) ((ObjectAnimator) animations.get(1)).getAnimatedValue(); + PointF pointF = new PointF(x + marker.getOffsetX(), y + marker.getOffsetY()); + marker.setPosition(mapboxMap.getProjection().fromScreenLocation(pointF)); + set.cancel(); + } + + // update position on map + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + if (marker.getOffsetX() == -1) { + int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); + int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); + marker.setOffsetX(x); + marker.setOffsetY(y); + } + + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); - marker.setOffsetX(x); - marker.setOffsetY(y); + // animate visibility + if (marker.isVisible() && convertView.getVisibility() == View.GONE) { + convertView.animate().cancel(); + convertView.setAlpha(0); + AnimatorUtils.alpha(convertView, 1); + } + } else { + if (timer == null) { + timer = new CountDownTimer(50, 560) { + @Override + public void onTick(long millisUntilFinished) { - convertView.setX(point.x - x); - convertView.setY(point.y - y); + } - if (marker.isVisible() && convertView.getVisibility() == View.GONE) { - convertView.animate().cancel(); - convertView.setAlpha(0); - AnimatorUtils.alpha(convertView, 1); + @Override + public void onFinish() { + animate(marker, convertView); + } + }; + } else { + timer.cancel(); + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); + } + timer.start(); } } } @@ -200,9 +242,10 @@ public class MarkerViewManager { *

* The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} will be called to execute an animation. *

- * @param marker the MarkerView object to select + * + * @param marker the MarkerView object to select * @param convertView the View presentation of the MarkerView - * @param adapter the adapter used to adapt the marker to the convertView + * @param adapter the adapter used to adapt the marker to the convertView */ public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) { if (convertView != null) { @@ -240,17 +283,23 @@ public class MarkerViewManager { * @param marker the MarkerView to remove */ public void removeMarkerView(MarkerView marker) { + boolean isAnimating = marker.isAnimating(); final View viewHolder = markerViewMap.get(marker); if (viewHolder != null && marker != null) { for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { if (adapter.getMarkerClass().equals(marker.getClass())) { - if (adapter.prepareViewForReuse(marker, viewHolder)) { - adapter.releaseView(viewHolder); + if (!isAnimating) { + if (adapter.prepareViewForReuse(marker, viewHolder)) { + adapter.releaseView(viewHolder); + } } } } } - markerViewMap.remove(marker); + + if (!isAnimating) { + markerViewMap.remove(marker); + } } /** @@ -324,7 +373,7 @@ public class MarkerViewManager { Iterator iterator = markerViewMap.keySet().iterator(); while (iterator.hasNext()) { MarkerView m = iterator.next(); - if (!markers.contains(m)) { + if (!m.shouldAnimate() && !markers.contains(m)) { // remove marker convertView = markerViewMap.get(m); for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { @@ -396,6 +445,50 @@ public class MarkerViewManager { } } + public void animatePosition(@NonNull MarkerView marker, long duration) { + marker.setDuration(duration); + marker.setStartTime(AnimationUtils.currentAnimationTimeMillis()); + marker.setShouldAnimate(true); + animate(marker, markerViewMap.get(marker)); + } + + private void animate(final MarkerView marker, @Nullable View convertView) { + if (convertView != null) { + marker.setAnimating(true); + PointF screenLocation = mapboxMap.getProjection().toScreenLocation(marker.getTargetPosition()); + PointF currentLocation = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + convertView.setX(currentLocation.x - marker.getOffsetX()); + convertView.setY(currentLocation.y - marker.getOffsetY()); + ObjectAnimator animatorX = ObjectAnimator.ofFloat(convertView, "x", screenLocation.x - marker.getOffsetX()); + ObjectAnimator animatorY = ObjectAnimator.ofFloat(convertView, "y", screenLocation.y - marker.getOffsetY()); + AnimatorSet set = new AnimatorSet(); + set.playTogether(animatorX, animatorY); + marker.setAnimation(set); + set.setDuration(marker.getRemainingTime()); + set.addListener(new AnimatorListenerAdapter() { + + private boolean canceled; + + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + canceled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (!canceled) { + marker.setShouldAnimate(false); + marker.setPosition(marker.getTargetPosition()); + } + } + }); + marker.setAnimation(set); + set.start(); + } + } + /** * Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to an ImageView */ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index ae71ee384a..8fe9568eaa 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -1398,8 +1398,12 @@ public class MapView extends FrameLayout { mCompassView.update(getDirection()); mMyLocationView.update(); - mMapboxMap.getMarkerViewManager().update(); + try { + mMapboxMap.getMarkerViewManager().update(); + }catch (NullPointerException e){ + + } for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) { infoWindow.update(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 1e15c9ea36..bbd7428ead 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -1,18 +1,17 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; -import android.view.animation.AccelerateDecelerateInterpolator; -import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.annotations.MarkerView; +import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -42,24 +41,18 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(@NonNull final MapboxMap mapboxMap) { + LatLng brussels = new LatLng(50.900446, 4.485251); - LatLng washington = new LatLng(38.897108, -77.036716); - - final Marker marker = mapboxMap.addMarker(new MarkerOptions().position(brussels)); - ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{brussels, washington}); - markerAnimator.setDuration(5000); - markerAnimator.setRepeatCount(ValueAnimator.INFINITE); - markerAnimator.setRepeatMode(ValueAnimator.REVERSE); - markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + final MarkerView marker = mapboxMap.addMarker(new MarkerViewOptions().position(brussels)); + + // FIXME workaround because view is not actually added at this time + final LatLng utrecht = new LatLng(52.086224, 5.122309); + new Handler().postDelayed(new Runnable() { @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (marker != null) { - marker.setPosition((LatLng) animation.getAnimatedValue()); - } + public void run() { + marker.setPosition(utrecht, 6500l /*animation duration*/); } - }); - markerAnimator.start(); + }, 1000); } }); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml index 8c025d999c..b9bfa701a8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml @@ -1,8 +1,8 @@ + app:zoom="6" /> -- cgit v1.2.1 From cc1e2610c777a5b572f20de30e489f43521eea9f Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 15 Jun 2016 17:55:24 -0400 Subject: [android] Create Wrappers for Cordova Fixes #4761 --- .../mapbox/mapboxsdk/annotations/BaseMarkerOptions.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java index fc2022f9e1..3adeb52ea7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java @@ -39,6 +39,22 @@ public abstract class BaseMarkerOptions Date: Thu, 16 Jun 2016 14:30:34 +0200 Subject: [android] Dynamic update of InfowWindow with InfoWindowAdapter example Fixes #5353 --- .../mapbox/mapboxsdk/annotations/InfoWindow.java | 11 +- .../com/mapbox/mapboxsdk/annotations/Marker.java | 5 + .../src/main/AndroidManifest.xml | 8 + .../DynamicInfoWindowAdapterActivity.java | 169 +++++++++++++++++++++ .../layout/activity_infowindow_adapter_dynamic.xml | 24 +++ .../src/main/res/values/strings.xml | 2 + 6 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index aaa5525b4d..9af459e8a0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -259,11 +259,20 @@ public class InfoWindow { View view = mView.get(); if (mapboxMap != null && marker != null && view != null) { mCoordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset); + + if (view instanceof InfoWindowView) { + view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset); + } else { + view.setX(mCoordinates.x - (view.getMeasuredWidth() / 2) - mMarkerWidthOffset); + } view.setY(mCoordinates.y + mMarkerHeightOffset); } } + public View getView() { + return mView != null ? mView.get() : null; + } + boolean isVisible() { return mIsVisible; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index 2d4ec4257e..d24f020a18 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -117,6 +117,11 @@ public class Marker extends Annotation { refreshInfoWindowContent(); } + @Nullable + public InfoWindow getInfoWindow() { + return infoWindow; + } + /** * Update only for default Marker's InfoWindow content for Title and Snippet */ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 7268b7d551..c3bd231d30 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -41,6 +41,14 @@ android:name="@string/category" android:value="@string/category_infowindow" /> + + + + + + + + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index b856e7579a..2ec1b0d25d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ Standard InfoWindow example Custom InfoWindow Adapter + Custom Dynamic InfoWindow Adapter Animation Types @@ -80,6 +81,7 @@ 2 maps in a view hierarchy Restart map view after temporarily leaving to another activity Use an Android SDK View as marker + Learn how to create a dynamic custom InfoWindow Concurrent Open InfoWindows Deselect Markers On Tap -- cgit v1.2.1 From a5476346bf8dd696c6b7108d61dcc4928f8304e7 Mon Sep 17 00:00:00 2001 From: Justas Medeisis Date: Mon, 13 Jun 2016 16:52:47 +0300 Subject: [android] Fix crash when MyBearingTracking mode is not NONE. Fixes #5331 --- .../src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index a1515b39c9..12240aee86 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -260,7 +260,7 @@ public class MyLocationView extends View { camera.getMatrix(matrix); // - if (myBearingTrackingMode != MyBearingTracking.NONE) { + if (myBearingTrackingMode != MyBearingTracking.NONE && directionAnimator != null) { matrix.postRotate((Float) directionAnimator.getAnimatedValue()); } -- cgit v1.2.1 From 2893f39249650bac8c5c4c4edf6600018e811642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Mon, 13 Jun 2016 14:47:13 -0700 Subject: [android] Rename OS X SDK to macOS SDK in Android 4.1 release branch Fixes #5382 Also renamed as many references to OS X as possible to macOS in documentation. --- .gitignore | 1 + .ycm_extra_conf.py | 4 +- ARCHITECTURE.md | 87 + CHANGELOG.md | 2 +- CONTRIBUTING.md | 4 +- INSTALL.md | 4 +- Makefile | 74 +- README.md | 8 +- bin/offline.sh | 2 +- configure | 4 + deps/ninja/ninja-macos | Bin 0 -> 171356 bytes deps/ninja/ninja-osx | Bin 171356 -> 0 bytes platform/android/CONTRIBUTING_MACOS.md | 67 + platform/android/CONTRIBUTING_OSX.md | 67 - platform/android/README.md | 2 +- platform/darwin/README.md | 6 +- platform/darwin/src/http_file_source.mm | 4 +- platform/ios/DEVELOPING.md | 10 +- platform/macos/CHANGELOG.md | 12 + platform/macos/DEVELOPING.md | 53 + platform/macos/INSTALL.md | 50 + platform/macos/README.md | 12 + platform/macos/WorkspaceSettings.xcsettings | 18 + platform/macos/app/AppDelegate.h | 24 + platform/macos/app/AppDelegate.m | 270 +++ .../AppIcon.appiconset/AppIcon128x128.png | Bin 0 -> 3668 bytes .../AppIcon.appiconset/AppIcon16x16.png | Bin 0 -> 713 bytes .../AppIcon.appiconset/AppIcon256x256-1.png | Bin 0 -> 8495 bytes .../AppIcon.appiconset/AppIcon256x256.png | Bin 0 -> 8495 bytes .../AppIcon.appiconset/AppIcon32x32-1.png | Bin 0 -> 1213 bytes .../AppIcon.appiconset/AppIcon32x32.png | Bin 0 -> 1213 bytes .../AppIcon.appiconset/AppIcon512x512-1.png | Bin 0 -> 20280 bytes .../AppIcon.appiconset/AppIcon512x512.png | Bin 0 -> 20280 bytes .../AppIcon.appiconset/Contents.json | 68 + .../Assets.xcassets/AppIcon.appiconset/icon-1.png | Bin 0 -> 2205 bytes .../Assets.xcassets/AppIcon.appiconset/icon.png | Bin 0 -> 9293 bytes platform/macos/app/Assets.xcassets/Contents.json | 6 + platform/macos/app/Base.lproj/MainMenu.xib | 845 +++++++ platform/macos/app/Base.lproj/MapDocument.xib | 136 ++ platform/macos/app/Credits.rtf | 9 + platform/macos/app/DroppedPinAnnotation.h | 10 + platform/macos/app/DroppedPinAnnotation.m | 68 + platform/macos/app/Info.plist | 56 + .../macos/app/LocationCoordinate2DTransformer.h | 5 + .../macos/app/LocationCoordinate2DTransformer.m | 31 + platform/macos/app/MapDocument.h | 14 + platform/macos/app/MapDocument.m | 721 ++++++ .../macos/app/OfflinePackNameValueTransformer.h | 5 + .../macos/app/OfflinePackNameValueTransformer.m | 33 + platform/macos/app/TimeIntervalTransformer.h | 5 + platform/macos/app/TimeIntervalTransformer.m | 53 + platform/macos/app/main.m | 5 + platform/macos/bitrise.yml | 54 + platform/macos/docs/doc-README.md | 9 + platform/macos/docs/pod-README.md | 43 + platform/macos/jazzy.yml | 71 + platform/macos/macos.xcodeproj/project.pbxproj | 1119 +++++++++ .../project.xcworkspace/contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/CI.xcscheme | 128 + .../xcshareddata/xcschemes/dynamic.xcscheme | 113 + .../xcshareddata/xcschemes/macosapp.xcscheme | 101 + .../macos.xcworkspace/contents.xcworkspacedata | 10 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 25 + .../xcshareddata/xcschemes/mbgl-offline.xcscheme | 92 + .../xcshareddata/xcschemes/mbgl-render.xcscheme | 92 + .../xcshareddata/xcschemes/test.xcscheme | 92 + platform/macos/platform.gyp | 90 + platform/macos/screenshot.png | Bin 0 -> 680704 bytes platform/macos/scripts/configure.sh | 15 + platform/macos/scripts/document.sh | 45 + platform/macos/scripts/macostest.xcscheme | 56 + platform/macos/scripts/package.sh | 57 + platform/macos/sdk/Base.lproj/Localizable.strings | 30 + .../macos/sdk/Base.lproj/MGLAnnotationCallout.xib | 69 + platform/macos/sdk/Info.plist | 24 + platform/macos/sdk/default_marker.pdf | Bin 0 -> 2601 bytes platform/macos/sdk/mapbox.pdf | Bin 0 -> 3762 bytes platform/macos/src/MGLAnnotationImage.h | 64 + platform/macos/src/MGLAnnotationImage.m | 26 + platform/macos/src/MGLAnnotationImage_Private.h | 8 + platform/macos/src/MGLAttributionButton.h | 15 + platform/macos/src/MGLAttributionButton.m | 50 + platform/macos/src/MGLCompassCell.h | 5 + platform/macos/src/MGLCompassCell.m | 34 + platform/macos/src/MGLMapView+IBAdditions.h | 68 + platform/macos/src/MGLMapView+IBAdditions.m | 118 + platform/macos/src/MGLMapView.h | 764 ++++++ platform/macos/src/MGLMapView.mm | 2467 ++++++++++++++++++++ platform/macos/src/MGLMapViewDelegate.h | 220 ++ platform/macos/src/MGLMapView_Private.h | 23 + platform/macos/src/MGLOpenGLLayer.h | 12 + platform/macos/src/MGLOpenGLLayer.mm | 49 + platform/macos/src/Mapbox.h | 32 + platform/macos/test/Info.plist | 24 + platform/node/README.md | 4 +- platform/node/bitrise.yml | 4 +- platform/osx/CHANGELOG.md | 11 - platform/osx/DEVELOPING.md | 53 - platform/osx/INSTALL.md | 50 - platform/osx/README.md | 12 - platform/osx/WorkspaceSettings.xcsettings | 18 - platform/osx/app/AppDelegate.h | 24 - platform/osx/app/AppDelegate.m | 270 --- .../AppIcon.appiconset/AppIcon128x128.png | Bin 3668 -> 0 bytes .../AppIcon.appiconset/AppIcon16x16.png | Bin 713 -> 0 bytes .../AppIcon.appiconset/AppIcon256x256-1.png | Bin 8495 -> 0 bytes .../AppIcon.appiconset/AppIcon256x256.png | Bin 8495 -> 0 bytes .../AppIcon.appiconset/AppIcon32x32-1.png | Bin 1213 -> 0 bytes .../AppIcon.appiconset/AppIcon32x32.png | Bin 1213 -> 0 bytes .../AppIcon.appiconset/AppIcon512x512-1.png | Bin 20280 -> 0 bytes .../AppIcon.appiconset/AppIcon512x512.png | Bin 20280 -> 0 bytes .../AppIcon.appiconset/Contents.json | 68 - .../Assets.xcassets/AppIcon.appiconset/icon-1.png | Bin 2205 -> 0 bytes .../Assets.xcassets/AppIcon.appiconset/icon.png | Bin 9293 -> 0 bytes platform/osx/app/Assets.xcassets/Contents.json | 6 - platform/osx/app/Base.lproj/MainMenu.xib | 845 ------- platform/osx/app/Base.lproj/MapDocument.xib | 136 -- platform/osx/app/Credits.rtf | 9 - platform/osx/app/DroppedPinAnnotation.h | 10 - platform/osx/app/DroppedPinAnnotation.m | 68 - platform/osx/app/Info.plist | 56 - platform/osx/app/LocationCoordinate2DTransformer.h | 5 - platform/osx/app/LocationCoordinate2DTransformer.m | 31 - platform/osx/app/MapDocument.h | 14 - platform/osx/app/MapDocument.m | 721 ------ platform/osx/app/OfflinePackNameValueTransformer.h | 5 - platform/osx/app/OfflinePackNameValueTransformer.m | 33 - platform/osx/app/TimeIntervalTransformer.h | 5 - platform/osx/app/TimeIntervalTransformer.m | 53 - platform/osx/app/main.m | 5 - platform/osx/bitrise.yml | 54 - platform/osx/docs/doc-README.md | 9 - platform/osx/docs/pod-README.md | 43 - platform/osx/jazzy.yml | 71 - platform/osx/osx.xcodeproj/project.pbxproj | 1119 --------- .../project.xcworkspace/contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/CI.xcscheme | 128 - .../xcshareddata/xcschemes/dynamic.xcscheme | 113 - .../xcshareddata/xcschemes/osxapp.xcscheme | 101 - .../osx/osx.xcworkspace/contents.xcworkspacedata | 10 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 25 - .../xcshareddata/xcschemes/mbgl-offline.xcscheme | 92 - .../xcshareddata/xcschemes/mbgl-render.xcscheme | 92 - .../xcshareddata/xcschemes/test.xcscheme | 92 - platform/osx/platform.gyp | 90 - platform/osx/screenshot.png | Bin 680704 -> 0 bytes platform/osx/scripts/configure.sh | 15 - platform/osx/scripts/document.sh | 45 - platform/osx/scripts/osxtest.xcscheme | 56 - platform/osx/scripts/package.sh | 57 - platform/osx/sdk/Base.lproj/Localizable.strings | 30 - .../osx/sdk/Base.lproj/MGLAnnotationCallout.xib | 69 - platform/osx/sdk/Info.plist | 24 - platform/osx/sdk/default_marker.pdf | Bin 2601 -> 0 bytes platform/osx/sdk/mapbox.pdf | Bin 3762 -> 0 bytes platform/osx/src/MGLAnnotationImage.h | 64 - platform/osx/src/MGLAnnotationImage.m | 26 - platform/osx/src/MGLAnnotationImage_Private.h | 8 - platform/osx/src/MGLAttributionButton.h | 15 - platform/osx/src/MGLAttributionButton.m | 50 - platform/osx/src/MGLCompassCell.h | 5 - platform/osx/src/MGLCompassCell.m | 34 - platform/osx/src/MGLMapView+IBAdditions.h | 68 - platform/osx/src/MGLMapView+IBAdditions.m | 118 - platform/osx/src/MGLMapView.h | 764 ------ platform/osx/src/MGLMapView.mm | 2467 -------------------- platform/osx/src/MGLMapViewDelegate.h | 220 -- platform/osx/src/MGLMapView_Private.h | 23 - platform/osx/src/MGLOpenGLLayer.h | 12 - platform/osx/src/MGLOpenGLLayer.mm | 49 - platform/osx/src/Mapbox.h | 32 - platform/osx/test/Info.plist | 24 - platform/qt/README.md | 6 +- platform/qt/bitrise-qt4.yml | 4 +- platform/qt/bitrise-qt5.yml | 4 +- scripts/collect-coverage.sh | 2 +- 176 files changed, 9067 insertions(+), 8962 deletions(-) create mode 100644 ARCHITECTURE.md create mode 100755 deps/ninja/ninja-macos delete mode 100755 deps/ninja/ninja-osx create mode 100644 platform/android/CONTRIBUTING_MACOS.md delete mode 100644 platform/android/CONTRIBUTING_OSX.md create mode 100644 platform/macos/CHANGELOG.md create mode 100644 platform/macos/DEVELOPING.md create mode 100644 platform/macos/INSTALL.md create mode 100644 platform/macos/README.md create mode 100644 platform/macos/WorkspaceSettings.xcsettings create mode 100644 platform/macos/app/AppDelegate.h create mode 100644 platform/macos/app/AppDelegate.m create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png create mode 100644 platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png create mode 100644 platform/macos/app/Assets.xcassets/Contents.json create mode 100644 platform/macos/app/Base.lproj/MainMenu.xib create mode 100644 platform/macos/app/Base.lproj/MapDocument.xib create mode 100644 platform/macos/app/Credits.rtf create mode 100644 platform/macos/app/DroppedPinAnnotation.h create mode 100644 platform/macos/app/DroppedPinAnnotation.m create mode 100644 platform/macos/app/Info.plist create mode 100644 platform/macos/app/LocationCoordinate2DTransformer.h create mode 100644 platform/macos/app/LocationCoordinate2DTransformer.m create mode 100644 platform/macos/app/MapDocument.h create mode 100644 platform/macos/app/MapDocument.m create mode 100644 platform/macos/app/OfflinePackNameValueTransformer.h create mode 100644 platform/macos/app/OfflinePackNameValueTransformer.m create mode 100644 platform/macos/app/TimeIntervalTransformer.h create mode 100644 platform/macos/app/TimeIntervalTransformer.m create mode 100644 platform/macos/app/main.m create mode 100644 platform/macos/bitrise.yml create mode 100644 platform/macos/docs/doc-README.md create mode 100644 platform/macos/docs/pod-README.md create mode 100644 platform/macos/jazzy.yml create mode 100644 platform/macos/macos.xcodeproj/project.pbxproj create mode 100644 platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme create mode 100644 platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme create mode 100644 platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme create mode 100644 platform/macos/macos.xcworkspace/contents.xcworkspacedata create mode 100644 platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme create mode 100644 platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme create mode 100644 platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme create mode 100644 platform/macos/platform.gyp create mode 100644 platform/macos/screenshot.png create mode 100644 platform/macos/scripts/configure.sh create mode 100755 platform/macos/scripts/document.sh create mode 100644 platform/macos/scripts/macostest.xcscheme create mode 100755 platform/macos/scripts/package.sh create mode 100644 platform/macos/sdk/Base.lproj/Localizable.strings create mode 100644 platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib create mode 100644 platform/macos/sdk/Info.plist create mode 100644 platform/macos/sdk/default_marker.pdf create mode 100644 platform/macos/sdk/mapbox.pdf create mode 100644 platform/macos/src/MGLAnnotationImage.h create mode 100644 platform/macos/src/MGLAnnotationImage.m create mode 100644 platform/macos/src/MGLAnnotationImage_Private.h create mode 100644 platform/macos/src/MGLAttributionButton.h create mode 100644 platform/macos/src/MGLAttributionButton.m create mode 100644 platform/macos/src/MGLCompassCell.h create mode 100644 platform/macos/src/MGLCompassCell.m create mode 100644 platform/macos/src/MGLMapView+IBAdditions.h create mode 100644 platform/macos/src/MGLMapView+IBAdditions.m create mode 100644 platform/macos/src/MGLMapView.h create mode 100644 platform/macos/src/MGLMapView.mm create mode 100644 platform/macos/src/MGLMapViewDelegate.h create mode 100644 platform/macos/src/MGLMapView_Private.h create mode 100644 platform/macos/src/MGLOpenGLLayer.h create mode 100644 platform/macos/src/MGLOpenGLLayer.mm create mode 100644 platform/macos/src/Mapbox.h create mode 100644 platform/macos/test/Info.plist delete mode 100644 platform/osx/CHANGELOG.md delete mode 100644 platform/osx/DEVELOPING.md delete mode 100644 platform/osx/INSTALL.md delete mode 100644 platform/osx/README.md delete mode 100644 platform/osx/WorkspaceSettings.xcsettings delete mode 100644 platform/osx/app/AppDelegate.h delete mode 100644 platform/osx/app/AppDelegate.m delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon-1.png delete mode 100644 platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon.png delete mode 100644 platform/osx/app/Assets.xcassets/Contents.json delete mode 100644 platform/osx/app/Base.lproj/MainMenu.xib delete mode 100644 platform/osx/app/Base.lproj/MapDocument.xib delete mode 100644 platform/osx/app/Credits.rtf delete mode 100644 platform/osx/app/DroppedPinAnnotation.h delete mode 100644 platform/osx/app/DroppedPinAnnotation.m delete mode 100644 platform/osx/app/Info.plist delete mode 100644 platform/osx/app/LocationCoordinate2DTransformer.h delete mode 100644 platform/osx/app/LocationCoordinate2DTransformer.m delete mode 100644 platform/osx/app/MapDocument.h delete mode 100644 platform/osx/app/MapDocument.m delete mode 100644 platform/osx/app/OfflinePackNameValueTransformer.h delete mode 100644 platform/osx/app/OfflinePackNameValueTransformer.m delete mode 100644 platform/osx/app/TimeIntervalTransformer.h delete mode 100644 platform/osx/app/TimeIntervalTransformer.m delete mode 100644 platform/osx/app/main.m delete mode 100644 platform/osx/bitrise.yml delete mode 100644 platform/osx/docs/doc-README.md delete mode 100644 platform/osx/docs/pod-README.md delete mode 100644 platform/osx/jazzy.yml delete mode 100644 platform/osx/osx.xcodeproj/project.pbxproj delete mode 100644 platform/osx/osx.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 platform/osx/osx.xcodeproj/xcshareddata/xcschemes/CI.xcscheme delete mode 100644 platform/osx/osx.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme delete mode 100644 platform/osx/osx.xcodeproj/xcshareddata/xcschemes/osxapp.xcscheme delete mode 100644 platform/osx/osx.xcworkspace/contents.xcworkspacedata delete mode 100644 platform/osx/osx.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme delete mode 100644 platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme delete mode 100644 platform/osx/osx.xcworkspace/xcshareddata/xcschemes/test.xcscheme delete mode 100644 platform/osx/platform.gyp delete mode 100644 platform/osx/screenshot.png delete mode 100644 platform/osx/scripts/configure.sh delete mode 100755 platform/osx/scripts/document.sh delete mode 100644 platform/osx/scripts/osxtest.xcscheme delete mode 100755 platform/osx/scripts/package.sh delete mode 100644 platform/osx/sdk/Base.lproj/Localizable.strings delete mode 100644 platform/osx/sdk/Base.lproj/MGLAnnotationCallout.xib delete mode 100644 platform/osx/sdk/Info.plist delete mode 100644 platform/osx/sdk/default_marker.pdf delete mode 100644 platform/osx/sdk/mapbox.pdf delete mode 100644 platform/osx/src/MGLAnnotationImage.h delete mode 100644 platform/osx/src/MGLAnnotationImage.m delete mode 100644 platform/osx/src/MGLAnnotationImage_Private.h delete mode 100644 platform/osx/src/MGLAttributionButton.h delete mode 100644 platform/osx/src/MGLAttributionButton.m delete mode 100644 platform/osx/src/MGLCompassCell.h delete mode 100644 platform/osx/src/MGLCompassCell.m delete mode 100644 platform/osx/src/MGLMapView+IBAdditions.h delete mode 100644 platform/osx/src/MGLMapView+IBAdditions.m delete mode 100644 platform/osx/src/MGLMapView.h delete mode 100644 platform/osx/src/MGLMapView.mm delete mode 100644 platform/osx/src/MGLMapViewDelegate.h delete mode 100644 platform/osx/src/MGLMapView_Private.h delete mode 100644 platform/osx/src/MGLOpenGLLayer.h delete mode 100644 platform/osx/src/MGLOpenGLLayer.mm delete mode 100644 platform/osx/src/Mapbox.h delete mode 100644 platform/osx/test/Info.plist diff --git a/.gitignore b/.gitignore index d887dd3f90..16fd245107 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ xcuserdata /platform/ios/benchmark/assets/glyphs/DIN* /platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6 **/token +/platform/macos/macos.xcworkspace/xcshareddata/macos.xcscmblueprint diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index 632686f3d6..d2008c9ddf 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -36,8 +36,8 @@ import subprocess import ycm_core compilation_database_folders = [ - 'build/linux-x86_64/Release', - 'build/osx/Release', + 'build/linux-x86_64/Debug', + 'build/macos/Debug', ] subprocess.call(['make compdb'], shell=True) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000000..590ea97722 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,87 @@ +This document aims to outline at a high level the various parts that make up mapbox-gl-native and how they work together. + +# Repository structure + +mapbox-gl-native uses a monolithic that houses both core C++ code and code that wraps the C++ core with SDKs for Android, iOS, macOS, Node.js, and Qt. A "monorepo" allows us to: + + * Make changes to the core API and SDKs simultaneously, ensuring no platform falls behind. + * Ensure that core changes do not inadvertently break SDK tests. + * Centralize discussions about features and defects that affect multiple platforms. + +In the repository, core C++ code is contained in the `include` and `src` directories. The former includes headers that are considered to make up the "public" core C++ API, while the latter includes `.cpp` implementation files and headers that are private to the implementation. Within both directories, files are nested under an `mbgl` directory, which has various subdirectories based on areas of functionality. Both public and private headers therefore can (and should) always be included with the form `#include `. + +Code and build scripts belonging to platform SDKs are contained in the `platform` directory, which has subdirectories for each platform. The `platform/darwin` and `platform/default` directories contain code shared by multiple platform SDKs. + +# Build system + +The mapbox-gl-native build system uses a variety of tools. + +## Make + +GNU Make and a master `Makefile` serves as the coordinating tool for all other build system tools. Most of your interaction with the build system will be via `make` commands. We aim to have a consistent pattern for make targets across platforms: for a given platform, e.g. `ios`, `make ios` builds a reasonable set of end products (though perhaps not all permutations of build options, which can be prohibitively expensive), and `make test-ios` runs a complete test suite for the platform. + +## Git submodules + +Git submodules are used to pull in several dependencies: mason (see below) and several iOS dependencies (though we have plans to phase these out). Initializing these submodules is handled automatically by the necessary `make` targets. + +## npm + +npm is a package manager for Node.js. mapbox-gl-native uses it to pull in several development dependencies that happen to be packaged as node modules -- mainly for testing needs. + +## Mason + +[Mason](https://github.com/mapbox/mason) is Mapbox's own cross platform C/C++ package manager. mapbox-gl-native uses mason packages as a source of precompiled binaries for third-party dependencies such as Boost, RapidJSON, and SQLite, and Mapbox's own C++ modules such as [earcut.hpp](https://github.com/mapbox/earcut.hpp) and [geojson-vt-cpp](https://github.com/mapbox/geojson-vt-cpp). It is also used to obtain a toolchain for Android platform cross-compiliation. + +We track mason dependencies for a given platform in the file `platform//scripts/configure.sh`. The `configure` script at the root handles sourcing this file during the build, running the appropriate mason commands, and writing configuration settings for the subsequent build to a `config.gypi` in the build output directory. + +## gyp + +[gyp](https://gyp.gsrc.io/) is a build system originally created for Chromium and since adopted by Node.js. In mapbox-gl-native it's used to build the core C++ static library, the Node.js platform module, and the shared JNI module for Android. + +## Platform-specific subsystems + +Outside of the core C++ static library, platform SDKs typically rely on platform-native build tooling to complete the job. + +* For iOS and macOS this means Xcode and the xcodebuild command line tool. +* For Android, Gradle and Android Studio. +* For Qt, `qmake`. + +See the relevant platform-specific `README.md` / `INSTALL.md` for details. + +# Major functional components + +## Map +## Style + +The "Style" component of mapbox-gl-native contains an implementation of the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), defining what data to draw, the order to draw it in, and how to style the data when drawing it. + +In addition to supporting styles loaded from a URL, mapbox-gl-native includes a runtime styling API, which allows users to dynamically modify the current style: add and remove layers, modify layer properties, and so on. As appropriate for a C++ API, the runtime styling API API is _strongly typed_: there are subclasses for each layer type, with correctly-typed accessors for each style property. This results in a large API surface area. Fortunately, this is automated, by generating the API – and the regular portion of the implementation – from the style specification. + +The layers API makes a distinction between public API and internal implementation using [the `Impl` idiom](https://github.com/mapbox/mapbox-gl-native/issues/3254) seen elsewhere in the codebase. Here, it takes the form of two parallel class hierarchies: + +* `Layer` and its subclasses form the public API. +* `Layer::Impl` and its subclasses form the internal API. + +As well as forming the boundary between public and internal, these two class hierarchies form the boundary between generated code and handwritten code. Except for `CustomLayer` and `CustomLayer::Impl`: + +* `Layer` subclasses are entirely generated. (`Layer` itself is handwritten.) +* `Layer::Impl` and its subclasses are entirely handwritten. + +## FileSource +## Layout +## Rendering +## Annotations + +# Threading + +At runtime, mapbox-gl-native uses the following threads: + +* The "main thread" (or other thread on which a `Map` object is created) handles direct `Map` API requests, owns the active `Style` and its associated objects, and renders the map. Since this thread is usually dispatching events triggered by user input, it's important that these duties not require significant computation or perform blocking I/O that would cause UI jank or hangs. +* Many of the tasks that require significant computation are associated with layout and styling of map features: parsing vector tiles, computing text layout, and generating data buffers to be consumed by OpenGL. This work happens on "worker threads" that are spawned by the main thread, four per `Style` object. The `Style` and its associated objects handle dispatching tasks to the workers, typically on a tile-by-tile basis. +* A "FileSource" thread handles network requests for styles, tiles, and other resources, and I/O on the SQLite database used for offline maps and caching. Requests originate from the main thread, are dispatched by a FileSource internally to its thread, and results are returned to the main thread via an asynchronous callback function. (This is implemented with platform-specific hooks into the native message pump for the requesting thread.) + +To minimize data races and invalid memory access, we aim for zero shared memory state between any two threads. Cross-thread communication occurs via one thread requesting the "invocation" of a task on another thread. The parameters for this task should be passed as value objects, so that they are copied, or as ownership-transferring values such as `std::unique_ptr`. (We're [not entirely there yet](https://github.com/mapbox/mapbox-gl-native/issues/667), but that's the goal.) The result (if any) is likewise passed as a value or ownership-transferring parameter to the callback function. + +Invoking a task on another thread itself creates an ownership obligation: the responsibility for the work happening on the other thread. This ownership is represented by the invocation method returning `std::unique_ptr`. Destroying this object indicates that the result of the task is no longer required: the callback is guaranteed not to be called, and the work on the other thread may be aborted (if doing so is convenient). + +All this is implemented by [Thread](https://github.com/mapbox/mapbox-gl-native/blob/master/src/mbgl/util/thread.hpp) and [RunLoop](https://github.com/mapbox/mapbox-gl-native/blob/master/include/mbgl/util/run_loop.hpp). diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad2d51ad8..5034146cae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,5 +4,5 @@ Each Mapbox GL Native SDK has a separate changelog that highlights changes relev * [Mapbox Android SDK](platform/android/CHANGELOG.md) * [Mapbox iOS SDK](platform/ios/CHANGELOG.md) -* [Mapbox OS X SDK](platform/osx/CHANGELOG.md) +* [Mapbox macOS SDK](platform/macos/CHANGELOG.md) * [node-mapbox-gl-native](platform/node/CHANGELOG.md) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0df51bd174..3bb6186890 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,10 +11,10 @@ If you want to contribute code: 1. Pull requests are gladly accepted. If there are any changes that developers using one of the GL SDKs should be aware of, please update the **master** section of the relevant changelog(s): * [Mapbox Android SDK](platform/android/CHANGELOG.md) * [Mapbox iOS SDK](platform/ios/CHANGELOG.md) - * [Mapbox OS X SDK](platform/osx/CHANGELOG.md) + * [Mapbox macOS SDK](platform/macos/CHANGELOG.md) * [node-mapbox-gl-native](platform/node/CHANGELOG.md) -1. Prefix your commit messages with the platform(s) your changes affect: `[core]`, `[android]`, `[ios]`, `[osx]`, `[node]`, or `[qt]`. +1. Prefix your commit messages with the platform(s) your changes affect: `[core]`, `[android]`, `[ios]`, `[macos]`, `[node]`, or `[qt]`. # Code of conduct Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/). diff --git a/INSTALL.md b/INSTALL.md index d0f063840d..d002e8df79 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -37,7 +37,7 @@ dependencies: - [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL) -### Additional Dependencies for OS X +### Additional Dependencies for macOS - Apple Command Line Tools (available at [Apple Developer](https://developer.apple.com/downloads)) - [Homebrew](http://brew.sh) @@ -50,7 +50,7 @@ See the relevant SDK documentation for next steps: * [Mapbox Android SDK](platform/android/) * [Mapbox iOS SDK](platform/ios/) -* [Mapbox OS X SDK](platform/osx/) +* [Mapbox macOS SDK](platform/macos/) * [Mapbox Qt SDK](platform/qt/) * [Mapbox GL Native on Linux](platform/linux/) * [node-mapbox-gl-native](platform/node/) diff --git a/Makefile b/Makefile index 26e9b58ec5..9abce1a37c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ export BUILDTYPE ?= Debug ifeq ($(shell uname -s), Darwin) - HOST_PLATFORM = osx + HOST_PLATFORM = macos export JOBS ?= $(shell sysctl -n hw.ncpu) else ifeq ($(shell uname -s), Linux) HOST_PLATFORM = linux @@ -36,54 +36,54 @@ CONFIG_DEPENDENCIES = .mason configure # files are added or removed. GYP_DEPENDENCIES = mbgl.gypi test/test.gypi bin/*.gypi $(shell find src include -type d) node_modules -#### OS X targets ############################################################## +#### macOS targets ############################################################## -OSX_OUTPUT_PATH = build/osx -OSX_PROJ_PATH = $(OSX_OUTPUT_PATH)/platform/osx/platform.xcodeproj -OSX_WORK_PATH = platform/osx/osx.xcworkspace -OSX_USER_DATA_PATH = $(OSX_WORK_PATH)/xcuserdata/$(USER).xcuserdatad +MACOS_OUTPUT_PATH = build/macos +MACOS_PROJ_PATH = $(MACOS_OUTPUT_PATH)/platform/macos/platform.xcodeproj +MACOS_WORK_PATH = platform/macos/macos.xcworkspace +MACOS_USER_DATA_PATH = $(MACOS_WORK_PATH)/xcuserdata/$(USER).xcuserdatad -$(OSX_OUTPUT_PATH)/config.gypi: platform/osx/scripts/configure.sh $(CONFIG_DEPENDENCIES) - ./configure $< $@ osx +$(MACOS_OUTPUT_PATH)/config.gypi: platform/macos/scripts/configure.sh $(CONFIG_DEPENDENCIES) + ./configure $< $@ macos -$(OSX_OUTPUT_PATH)/mbgl.xcconfig: $(OSX_OUTPUT_PATH)/config.gypi +$(MACOS_OUTPUT_PATH)/mbgl.xcconfig: $(MACOS_OUTPUT_PATH)/config.gypi ./scripts/export-xcconfig.py $< $@ -$(OSX_PROJ_PATH): platform/osx/platform.gyp $(OSX_OUTPUT_PATH)/config.gypi $(OSX_OUTPUT_PATH)/mbgl.xcconfig $(GYP_DEPENDENCIES) - $(GYP) -f xcode --generator-output=$(OSX_OUTPUT_PATH) $< +$(MACOS_PROJ_PATH): platform/macos/platform.gyp $(MACOS_OUTPUT_PATH)/config.gypi $(MACOS_OUTPUT_PATH)/mbgl.xcconfig $(GYP_DEPENDENCIES) + $(GYP) -f xcode --generator-output=$(MACOS_OUTPUT_PATH) $< -osx: $(OSX_PROJ_PATH) +macos: $(MACOS_PROJ_PATH) set -o pipefail && xcodebuild \ - -derivedDataPath $(OSX_OUTPUT_PATH) \ + -derivedDataPath $(MACOS_OUTPUT_PATH) \ -configuration $(BUILDTYPE) \ - -workspace $(OSX_WORK_PATH) -scheme CI build $(XCPRETTY) + -workspace $(MACOS_WORK_PATH) -scheme CI build $(XCPRETTY) -xproj: $(OSX_PROJ_PATH) $(OSX_WORK_PATH) - mkdir -p "$(OSX_USER_DATA_PATH)" - cp platform/osx/WorkspaceSettings.xcsettings "$(OSX_USER_DATA_PATH)/WorkspaceSettings.xcsettings" - open $(OSX_WORK_PATH) +xproj: $(MACOS_PROJ_PATH) $(MACOS_WORK_PATH) + mkdir -p "$(MACOS_USER_DATA_PATH)" + cp platform/macos/WorkspaceSettings.xcsettings "$(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings" + open $(MACOS_WORK_PATH) -test-osx: osx node_modules - ulimit -c unlimited && ($(OSX_OUTPUT_PATH)/Build/Products/$(BUILDTYPE)/test & pid=$$! && wait $$pid \ +test-macos: macos node_modules + ulimit -c unlimited && ($(MACOS_OUTPUT_PATH)/Build/Products/$(BUILDTYPE)/test & pid=$$! && wait $$pid \ || (lldb -c /cores/core.$$pid --batch --one-line 'thread backtrace all' --one-line 'quit' && exit 1)) set -o pipefail && xcodebuild \ - -derivedDataPath $(OSX_OUTPUT_PATH) \ + -derivedDataPath $(MACOS_OUTPUT_PATH) \ -configuration $(BUILDTYPE) \ - -workspace $(OSX_WORK_PATH) -scheme CI test $(XCPRETTY) + -workspace $(MACOS_WORK_PATH) -scheme CI test $(XCPRETTY) -xpackage: $(OSX_PROJ_PATH) - SYMBOLS=$(SYMBOLS) ./platform/osx/scripts/package.sh +xpackage: $(MACOS_PROJ_PATH) + SYMBOLS=$(SYMBOLS) ./platform/macos/scripts/package.sh xdocument: - OUTPUT=$(OUTPUT) ./platform/osx/scripts/document.sh + OUTPUT=$(OUTPUT) ./platform/macos/scripts/document.sh genstrings: - genstrings -u -o platform/osx/sdk/Base.lproj platform/darwin/src/*.{m,mm} - genstrings -u -o platform/osx/sdk/Base.lproj platform/osx/src/*.{m,mm} + genstrings -u -o platform/macos/sdk/Base.lproj platform/darwin/src/*.{m,mm} + genstrings -u -o platform/macos/sdk/Base.lproj platform/macos/src/*.{m,mm} genstrings -u -o platform/ios/resources/Base.lproj platform/ios/src/*.{m,mm} - -find platform/ios/resources platform/osx/sdk -path '*/Base.lproj/*.strings' -exec \ + -find platform/ios/resources platform/macos/sdk -path '*/Base.lproj/*.strings' -exec \ textutil -convert txt -extension strings -inputencoding UTF-16 -encoding UTF-8 {} \; - mv platform/osx/sdk/Base.lproj/Foundation.strings platform/darwin/resources/Base.lproj/ + mv platform/macos/sdk/Base.lproj/Foundation.strings platform/darwin/resources/Base.lproj/ #### iOS targets ############################################################## @@ -288,10 +288,22 @@ compdb: platform/linux/platform.gyp $(LINUX_OUTPUT_PATH)/config.gypi deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) \ -t compdb cc cc_s cxx objc objcxx > $(LINUX_OUTPUT_PATH)/$(BUILDTYPE)/compile_commands.json -tidy: compdb - deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) version shaders +compdb-macos: platform/macos/platform.gyp $(MACOS_OUTPUT_PATH)/config.gypi + $(GYP) -f ninja -I $(MACOS_OUTPUT_PATH)/config.gypi \ + --generator-output=$(MACOS_OUTPUT_PATH) $< + deps/ninja/ninja-macos -C $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) \ + -t compdb cc cc_s cxx objc objcxx > $(MACOS_OUTPUT_PATH)/$(BUILDTYPE)/compile_commands.json + +tidy: compdb tidy-$(HOST_PLATFORM) + +tidy-linux: + deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) headers scripts/clang-tidy.sh $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) +tidy-macos: + deps/ninja/ninja-macos -C $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) headers + scripts/clang-tidy.sh $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) + #### Miscellaneous targets ##################################################### clean: diff --git a/README.md b/README.md index 27802976e8..3808f31ded 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ A library for embedding interactive, customizable vector maps into native applic ## The Mapbox GL ecosystem -This repository hosts the cross-platform Mapbox GL Native library, plus convenient SDKs for several platforms. The cross-platform library comes with a [GLFW](https://github.com/glfw/glfw)-based demo application for Ubuntu Linux and OS X. The SDKs target the usual languages on their respective platforms: +This repository hosts the cross-platform Mapbox GL Native library, plus convenient SDKs for several platforms. The cross-platform library comes with a [GLFW](https://github.com/glfw/glfw)-based demo application for Ubuntu Linux and macOS. The SDKs target the usual languages on their respective platforms: SDK | Languages | Build status ----|-----------|------------- [Mapbox GL Native](INSTALL.md) | C++14 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![Coverage Status](https://coveralls.io/repos/github/mapbox/mapbox-gl-native/badge.svg?branch=master)](https://coveralls.io/github/mapbox/mapbox-gl-native?branch=master) [Mapbox Android SDK](platform/android/) | Java | [![Bitrise](https://www.bitrise.io/app/79cdcbdc42de4303.svg?token=_InPF8bII6W7J6kFr-L8QQ&branch=master)](https://www.bitrise.io/app/79cdcbdc42de4303) [Mapbox iOS SDK](platform/ios/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/7514e4cf3da2cc57.svg?token=OwqZE5rSBR9MVWNr_lf4sA&branch=master)](https://www.bitrise.io/app/7514e4cf3da2cc57) -[Mapbox OS X SDK](platform/osx/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) -[node-mapbox-gl-native](platform/node/) | Node.js | [![Linux](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) / [![OS X](https://www.bitrise.io/app/55e3a9bf71202106.svg?token=5qf5ZUcKVN3LDnHhW7rO0w)](https://www.bitrise.io/app/55e3a9bf71202106) -[Mapbox Qt SDK](platform/qt) | C++03 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) +[Mapbox macOS SDK](platform/macos/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) +[node-mapbox-gl-native](platform/node/) | Node.js | [![Linux](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![macOS](https://www.bitrise.io/app/55e3a9bf71202106.svg?token=5qf5ZUcKVN3LDnHhW7rO0w)](https://www.bitrise.io/app/55e3a9bf71202106) +[Mapbox Qt SDK](platform/qt) | C++03 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![Bitrise](https://www.bitrise.io/app/96cfbc97e0245c22.svg?token=GxsqIOGPXhn0F23sSVSsYA&branch=master)](https://www.bitrise.io/app/96cfbc97e0245c22) Additional Mapbox GL Native–based libraries are developed outside of this repository: diff --git a/bin/offline.sh b/bin/offline.sh index f85cb1194b..99ce2185e8 100755 --- a/bin/offline.sh +++ b/bin/offline.sh @@ -3,7 +3,7 @@ set -e set -o pipefail -OFFLINE=./build/osx/Release/mbgl-offline +OFFLINE=./build/macos/Release/mbgl-offline # Barcelona $OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona.db diff --git a/configure b/configure index 1d58a82443..26052aa4f8 100755 --- a/configure +++ b/configure @@ -7,6 +7,10 @@ OUTPUT_FILE=$2 export MASON_PLATFORM=$3 export MASON_PLATFORM_VERSION=${4:-} +if [ "${MASON_PLATFORM}" = "macos" ]; then + export MASON_PLATFORM=osx +fi + if [ -z ${INPUT_FILE} ]; then abort 'You need to specify an input path for the configure.sh file' fi diff --git a/deps/ninja/ninja-macos b/deps/ninja/ninja-macos new file mode 100755 index 0000000000..64fcacc550 Binary files /dev/null and b/deps/ninja/ninja-macos differ diff --git a/deps/ninja/ninja-osx b/deps/ninja/ninja-osx deleted file mode 100755 index 64fcacc550..0000000000 Binary files a/deps/ninja/ninja-osx and /dev/null differ diff --git a/platform/android/CONTRIBUTING_MACOS.md b/platform/android/CONTRIBUTING_MACOS.md new file mode 100644 index 0000000000..447e989d6f --- /dev/null +++ b/platform/android/CONTRIBUTING_MACOS.md @@ -0,0 +1,67 @@ +# Contributing to the Android SDK on macOS + +Install Oracle JDK 7+ and Android Studio: + + brew tap caskroom/cask + brew install brew-cask + brew cask install java + + brew cask install android-studio + +You can [download Android Studio instead of installing it with Homebrew, but you'll still need to `brew install java`](https://developer.android.com/sdk/index.html) +for it to work. + +Once Android Studio is installed, the [first time it's run it'll ask to install the Android SDK](http://developer.android.com/sdk/installing/index.html?pkg=studio) which you should do. While doing so in the Android SDK Manager make sure to also select and install the latest versions of "Android Support Repository" and "Android Support Library" from "Extras": + +![image](https://cloud.githubusercontent.com/assets/98601/9915837/289f398e-5c6e-11e5-9a84-ed4d08d52d1f.png) + +By default, the Android SDK will be installed to `/Users//Library/Android/sdk/`. For more information on how to [configure Android Studio](http://tools.android.com/tech-docs/configuration) and how to [set Project JDK vs IDE JDK](http://tools.android.com/tech-docs/configuration/osx-jdk) please see [Google's documentation](http://tools.android.com/overview). + +## Setting Mapbox Access Token + +_The test application (used for development purposes) uses Mapbox vector tiles, which require a Mapbox account and API access token. Obtain a free access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._ + +If you start Android Studio from your terminal, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise, +you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`. + +## Developing In Android Studio + +To work with the Mapbox Android SDK, you'll first need to get it set up as a Project in Android Studio. To do so Open Android Studio and select "Import project (Eclipse ADT, Gradle, etc.)" from the Welcome to Android Studio dialog. From there select the `platform/android` directory from the local file system where `mapbox-gl-native` was cloned. For example: + +```sh +/Users//development/mapbox-gl-native/platform/android +``` + +The Mapbox Android SDK is a multi-module Gradle based project. Specifically, the SDK itself is an [Android Library](http://developer.android.com/tools/projects/index.html#LibraryModules) module and it utilizes a companion [test module](http://developer.android.com/tools/projects/index.html#testing) (aka "the TestApp") for daily development. When Android Studio finishes importing the project both `MapboxGLAndroidSDK` and `MapboxGLAndroidSDKTestApp` modules should be visible. + +## Setting `ANDROID_HOME` + +For `build android` to work, you'll need to set the `ANDROID_HOME` environment +to point to your Android SDK installation: + +``` +export ANDROID_HOME=//android-sdk-macosx +``` + +This environment variable configuration should go into a file that's read on +your shell's startup, like `~/.profile`. + +## Running The TestApp + +In order to run the TestApp on an emulator or device the Core GL portion needs to built first. Core GL is the common C++ based OpenGL engine that powers the maps for iOS, Android, and Qt in the project. To build it, open Terminal and run the following commands from the root of the `mapbox-gl-native` source code + +Run: + + // From /Users//development/mapbox-gl-native + + // Makes arm7 ABI version of Core GL + // Can be run on most Android phones and arm emulator + make android + + // Make x86 version of Core GL + // Useful for running faster Anroid x86 emulator on Macs + make android-lib-x86 + +Once Core GL has been built, the TestApp can be run by selecting `MapboxGLAndroidSDKTestApp` from the Run menu or toolbar in Android Studio. + +**Next: get your app [running on a hardware Android Device](docs/ANDROID_DEVICE.md) or [simulator](docs/ANDROID_SIMULATOR.md)** diff --git a/platform/android/CONTRIBUTING_OSX.md b/platform/android/CONTRIBUTING_OSX.md deleted file mode 100644 index 3154ac1087..0000000000 --- a/platform/android/CONTRIBUTING_OSX.md +++ /dev/null @@ -1,67 +0,0 @@ -# Contributing to the Android SDK on OS X - -Install Oracle JDK 7+ and Android Studio: - - brew tap caskroom/cask - brew install brew-cask - brew cask install java - - brew cask install android-studio - -You can [download Android Studio instead of installing it with Homebrew, but you'll still need to `brew install java`](https://developer.android.com/sdk/index.html) -for it to work. - -Once Android Studio is installed, the [first time it's run it'll ask to install the Android SDK](http://developer.android.com/sdk/installing/index.html?pkg=studio) which you should do. While doing so in the Android SDK Manager make sure to also select and install the latest versions of "Android Support Repository" and "Android Support Library" from "Extras": - -![image](https://cloud.githubusercontent.com/assets/98601/9915837/289f398e-5c6e-11e5-9a84-ed4d08d52d1f.png) - -By default, the Android SDK will be installed to `/Users//Library/Android/sdk/`. For more information on how to [configure Android Studio](http://tools.android.com/tech-docs/configuration) and how to [set Project JDK vs IDE JDK](http://tools.android.com/tech-docs/configuration/osx-jdk) please see [Google's documentation](http://tools.android.com/overview). - -## Setting Mapbox Access Token - -_The test application (used for development purposes) uses Mapbox vector tiles, which require a Mapbox account and API access token. Obtain a free access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._ - -If you start Android Studio from your terminal, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise, -you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`. - -## Developing In Android Studio - -To work with the Mapbox Android SDK, you'll first need to get it set up as a Project in Android Studio. To do so Open Android Studio and select "Import project (Eclipse ADT, Gradle, etc.)" from the Welcome to Android Studio dialog. From there select the `platform/android` directory from the local file system where `mapbox-gl-native` was cloned. For example: - -```sh -/Users//development/mapbox-gl-native/platform/android -``` - -The Mapbox Android SDK is a multi-module Gradle based project. Specifically, the SDK itself is an [Android Library](http://developer.android.com/tools/projects/index.html#LibraryModules) module and it utilizes a companion [test module](http://developer.android.com/tools/projects/index.html#testing) (aka "the TestApp") for daily development. When Android Studio finishes importing the project both `MapboxGLAndroidSDK` and `MapboxGLAndroidSDKTestApp` modules should be visible. - -## Setting `ANDROID_HOME` - -For `build android` to work, you'll need to set the `ANDROID_HOME` environment -to point to your Android SDK installation: - -``` -export ANDROID_HOME=//android-sdk-macosx -``` - -This environment variable configuration should go into a file that's read on -your shell's startup, like `~/.profile`. - -## Running The TestApp - -In order to run the TestApp on an emulator or device the Core GL portion needs to built first. Core GL is the common C++ based OpenGL engine that powers the maps for iOS, Android, and Qt in the project. To build it, open Terminal and run the following commands from the root of the `mapbox-gl-native` source code - -Run: - - // From /Users//development/mapbox-gl-native - - // Makes arm7 ABI version of Core GL - // Can be run on most Android phones and arm emulator - make android - - // Make x86 version of Core GL - // Useful for running faster Anroid x86 emulator on Macs - make android-lib-x86 - -Once Core GL has been built, the TestApp can be run by selecting `MapboxGLAndroidSDKTestApp` from the Run menu or toolbar in Android Studio. - -**Next: get your app [running on a hardware Android Device](docs/ANDROID_DEVICE.md) or [simulator](docs/ANDROID_SIMULATOR.md)** diff --git a/platform/android/README.md b/platform/android/README.md index 895cf84688..3f58370097 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -15,7 +15,7 @@ A library based on [Mapbox GL Native](../../README.md) for embedding interactive Building the SDK yourself requires [a number of dependencies and steps](../../INSTALL.md) that are unnecessary for developing production applications. * [Contributing on Linux](CONTRIBUTING_LINUX.md) -* [Contributing on OS X](CONTRIBUTING_OSX.md) +* [Contributing on macOS](CONTRIBUTING_MACOS.md) ### Setting up the Android emulator diff --git a/platform/darwin/README.md b/platform/darwin/README.md index 43e229028c..349c9a00c0 100644 --- a/platform/darwin/README.md +++ b/platform/darwin/README.md @@ -1,10 +1,10 @@ # Darwin The code in the Darwin platform targets Apple platforms but is not specific -to iOS or OS X. This code is not distributed as an SDK in itself, but is required +to iOS or macOS. This code is not distributed as an SDK in itself, but is required by the [Mapbox iOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/ios) -and [Mapbox OS X SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/osx). +and [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos). These files depend on the Foundation and Core Foundation frameworks but do not -depend on iOS- or OS X–specific frameworks, such as UIKit or AppKit. Any +depend on iOS- or macOS–specific frameworks, such as UIKit or AppKit. Any non-cross-platform code is guarded by TargetConditionals.h macros. diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm index eb751258c8..a678b6e5cb 100644 --- a/platform/darwin/src/http_file_source.mm +++ b/platform/darwin/src/http_file_source.mm @@ -130,7 +130,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { } } - // Avoid %s here because it inserts hidden bidirectional markers on OS X when the system + // Avoid %s here because it inserts hidden bidirectional markers on macOS when the system // language is set to a right-to-left language. [userAgentComponents addObject:[NSString stringWithFormat:@"MapboxGL/%@ (%@)", CFSTR(MBGL_VERSION_STRING), CFSTR(MBGL_VERSION_REV)]]; @@ -139,7 +139,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { #if TARGET_OS_IPHONE systemName = @"iOS"; #elif TARGET_OS_MAC - systemName = @"OS X"; + systemName = @"macOS"; #elif TARGET_OS_WATCH systemName = @"watchOS"; #elif TARGET_OS_TV diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md index d1be5d703e..240c3796b4 100644 --- a/platform/ios/DEVELOPING.md +++ b/platform/ios/DEVELOPING.md @@ -4,7 +4,7 @@ This document explains how to build the Mapbox iOS SDK from source. It is intend ## Requirements -The Mapbox iOS SDK and iosapp demo application build against the iOS 7.0 SDK. The SDK is intended to run on iOS 7.0 and above, while iosapp is intended to run on iOS 8.0 and above due to the use of a dynamic framework. Both require Xcode on a computer running OS X. +The Mapbox iOS SDK and iosapp demo application build against the iOS 7.0 SDK. The SDK is intended to run on iOS 7.0 and above, while iosapp is intended to run on iOS 8.0 and above due to the use of a dynamic framework. Both require Xcode on a computer running macOS. ## Building the SDK @@ -54,14 +54,14 @@ To add an Objective-C header or implementation file to the iOS SDK: 1. Add the file to the Headers or Compile Sources build phase, as appropriate, of both the “dynamic” and “static” targets. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. 1. _(Optional.)_ If it’s a public header, change its visibility from Project to Public and import it in [the iOS SDK’s umbrella header](./src/Mapbox.h). -1. _(Optional.)_ If the file would also be used by the OS X SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion OS X document](../osx/DEVELOPING.md#adding-a-source-code-file) for further instructions. +1. _(Optional.)_ If the file would also be used by the macOS SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion macOS document](../macos/DEVELOPING.md#adding-a-source-code-file) for further instructions. ### Adding a resource To add a resource (such as an image, SSL certificate, property list, or strings table) to the iOS SDK: 1. Add the header to the Copy Bundle Resources build phase of both the “dynamic” and “bundle” targets. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. -1. _(Optional.)_ If the resource would also be used by the OS X SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion OS X document](../osx/DEVELOPING.md#adding-a-resource) for further instructions. +1. _(Optional.)_ If the resource would also be used by the macOS SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion macOS document](../macos/DEVELOPING.md#adding-a-resource) for further instructions. ### Adding user-facing text @@ -70,11 +70,11 @@ To add or update text that the user may see in the iOS SDK: 1. Make sure the implementation file imports [NSBundle+MGLAdditions.h](../darwin/src/NSBundle+MGLAdditions.h). 1. Use the `NSLocalizedStringWithDefaultValue()` macro: * `key` is a unique identifier that won’t change if the user-facing text ever needs to change. - * `tbl` is `Foundation` in code shared between the iOS and OS X SDKs, or `nil` otherwise. + * `tbl` is `Foundation` in code shared between the iOS and macOS SDKs, or `nil` otherwise. * `bundle` is `nil`; the redefined macro looks for the SDK bundle at runtime and ignores this argument. * `val` is the English string. 1. _(Optional.)_ When dealing with a number followed by a pluralized word, do not split the string. Instead, use a format string and make `val` ambiguous, like `%d file(s)`. Then pluralize for English in the appropriate [.stringsdict file](https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html). See [platform/darwin/resources/en.lproj/Foundation.stringsdict](../darwin/resources/en.lproj/Foundation.stringsdict) for an example. Localizers should do likewise for their languages. -1. Run `make genstrings` and commit any changes it makes to .strings files. The make rule also updates the OS X SDK’s strings tables. +1. Run `make genstrings` and commit any changes it makes to .strings files. The make rule also updates the macOS SDK’s strings tables. ## Testing diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md new file mode 100644 index 0000000000..ca32580cfe --- /dev/null +++ b/platform/macos/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog for Mapbox macOS SDK + +## master + +* Renamed the SDK to the Mapbox macOS SDK. +* Fixed an issue in which Mapbox.framework was nested inside another folder named Mapbox.framework. ([#4998](https://github.com/mapbox/mapbox-gl-native/pull/4998)) +* Fixed a crash passing a mixture of point and shape annotations into `-[MGLMapView addAnnotations:]`. ([#5097](https://github.com/mapbox/mapbox-gl-native/pull/5097)) +* Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359)) + +## 0.1.0 + +* This version of the Mapbox OS X SDK roughly corresponds to version 3.3.0-alpha.2 of the Mapbox iOS SDK. The two SDKs have very similar feature sets. The main difference is the lack of user location tracking. Some APIs have been adapted to OS X conventions, particularly the use of NSPopover for callout views. diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md new file mode 100644 index 0000000000..fc7b0330a3 --- /dev/null +++ b/platform/macos/DEVELOPING.md @@ -0,0 +1,53 @@ +# Contributing to the Mapbox macOS SDK + +This document explains how to build the Mapbox macOS SDK from source. It is intended for advanced developers who wish to contribute to Mapbox GL and the Mapbox iOS SDK. + +## Requirements + +The Mapbox macOS SDK and the macosapp demo application run on macOS 10.10.0 and above. + +## Building the SDK + +1. [Install core dependencies](../../INSTALL.md). +1. Run `make xproj`. +1. Switch to the “dynamic” or “macosapp” scheme. The former builds just the Cocoa framework, while the latter also builds a Cocoa demo application based on it. + +## Contributing + +### Adding a source code file + +To add an Objective-C header or implementation file to the macOS SDK: + +1. Add the file to the “dynamic” target’s Headers or Compile Sources build phase, as appropriate. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. +1. _(Optional.)_ If it’s a public header, change its visibility from Project to Public and import it in [the macOS SDK’s umbrella header](./src/Mapbox.h). +1. _(Optional.)_ If the file would also be used by the iOS SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion iOS document](../ios/DEVELOPING.md#adding-a-source-code-file) for further instructions. + +### Adding a resource + +To add a resource (such as an image, SSL certificate, property list, or strings table) to the macOS SDK: + +1. Add the header to the Copy Bundle Resources build phase of the “dynamic” target. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. +1. _(Optional.)_ If the resource would also be used by the iOS SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion iOS document](../ios/DEVELOPING.md#adding-a-resource) for further instructions. + +### Adding user-facing text + +To add or update text that the user may see in the macOS SDK: + +1. Make sure the implementation file imports [NSBundle+MGLAdditions.h](../darwin/src/NSBundle+MGLAdditions.h). +1. Use the `NSLocalizedStringWithDefaultValue()` macro: + * `key` is a unique identifier that won’t change if the user-facing text ever needs to change. + * `tbl` is `Foundation` in code shared between the iOS and macOS SDKs, or `nil` otherwise. + * `bundle` is `nil`; the redefined macro looks for the SDK bundle at runtime and ignores this argument. + * `val` is the English string. +1. _(Optional.)_ When dealing with a number followed by a pluralized word, do not split the string. Instead, use a format string and make `val` ambiguous, like `%d file(s)`. Then pluralize for English in the appropriate [.stringsdict file](https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html). See [platform/darwin/resources/en.lproj/Foundation.stringsdict](../darwin/resources/en.lproj/Foundation.stringsdict) for an example. Localizers should do likewise for their languages. +1. Run `make genstrings` and commit any changes it makes to .strings files. The make rule also updates the iOS SDK’s strings tables. + +## 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/). You will be prompted for this access token the first time you launch the demo application. + +## Using macosapp + +Through the macOS SDK, the demo application supports a variety of standard gestures and keyboard shortcuts. For more details, open Mapbox GL Help from the Help menu. + +You can also [integrate the Mapbox macOS SDK into your own Cocoa application](INSTALL.md). diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md new file mode 100644 index 0000000000..42896d380d --- /dev/null +++ b/platform/macos/INSTALL.md @@ -0,0 +1,50 @@ +# Integrating the Mapbox macOS SDK into your application + +This document explains how to build the Mapbox macOS SDK and integrate it into your own Cocoa application. + +### Requirements + +The Mapbox macOS SDK requires the macOS 10.10.0 SDK or above. + +### Building the SDK + +Grab a [prebuilt release](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “macos-” – or build the SDK from source: + +1. [Install core dependencies](../../INSTALL.md). +1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/macos/pkg/` folder. + +### Installation + +1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. + +1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom macOS Application Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). + +## Usage + +In a storyboard or XIB, add a view to your view controller. (Drag Custom View from the Object library to the View Controller scene on the Interface Builder canvas.) In the Identity inspector, set the view’s custom class to `MGLMapView`. If you need to manipulate the map view programmatically: + +1. Switch to the Assistant Editor. +1. Import the `Mapbox` module. +1. Connect the map view to a new outlet in your view controller class. (Control-drag from the map view in Interface Builder to a valid location in your view controller implementation.) The resulting outlet declaration should look something like this: + +```objc +// ViewController.m +@import Mapbox; + +@interface ViewController : NSViewController + +@property (strong) IBOutlet MGLMapView *mapView; + +@end +``` + +```swift +// ViewController.swift +import Mapbox + +class ViewController: NSViewController { + @IBOutlet var mapView: MGLMapView! +} +``` + +Run `make xdocument` to generate complete API documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. diff --git a/platform/macos/README.md b/platform/macos/README.md new file mode 100644 index 0000000000..211b238d55 --- /dev/null +++ b/platform/macos/README.md @@ -0,0 +1,12 @@ +# Mapbox macOS SDK + +[![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) + +A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. + +This SDK is analogous to the Mapbox iOS SDK, and much of the iOS SDK documentation applies here. Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome. + +* [Integrating the Mapbox macOS SDK into your application](INSTALL.md) +* [Contributing to the Mapbox macOS SDK](DEVELOPING.md) + + diff --git a/platform/macos/WorkspaceSettings.xcsettings b/platform/macos/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..a2d959210c --- /dev/null +++ b/platform/macos/WorkspaceSettings.xcsettings @@ -0,0 +1,18 @@ + + + + + BuildLocationStyle + UseAppPreferences + CustomBuildLocationType + RelativeToDerivedData + DerivedDataCustomLocation + ../../build + DerivedDataLocationStyle + WorkspaceRelativePath + IssueFilterStyle + ShowActiveSchemeOnly + LiveSourceIssuesEnabled + + + diff --git a/platform/macos/app/AppDelegate.h b/platform/macos/app/AppDelegate.h new file mode 100644 index 0000000000..a1d9297b2f --- /dev/null +++ b/platform/macos/app/AppDelegate.h @@ -0,0 +1,24 @@ +#import + +extern NSString * const MGLMapboxAccessTokenDefaultsKey; + +@interface AppDelegate : NSObject + +@property (weak) IBOutlet NSWindow *preferencesWindow; + +// Normally, an application should respect the “Close windows when quitting an +// application” setting in the General pane of System Preferences. But the map +// would only be restored to its last opened location if the user quits the +// application using Quit and Keep Windows. An application that displays only a +// map should restore the last viewed map, like Maps.app does. These properties +// temporarily hold state for the next map window to be opened. + +@property (assign) double pendingZoomLevel; +@property (copy) MGLMapCamera *pendingCamera; +@property (assign) MGLCoordinateBounds pendingVisibleCoordinateBounds; +@property (assign) double pendingMinimumZoomLevel; +@property (assign) double pendingMaximumZoomLevel; +@property (copy) NSURL *pendingStyleURL; +@property (assign) MGLMapDebugMaskOptions pendingDebugMask; + +@end diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m new file mode 100644 index 0000000000..b7860cf130 --- /dev/null +++ b/platform/macos/app/AppDelegate.m @@ -0,0 +1,270 @@ +#import "AppDelegate.h" + +#import "MapDocument.h" + +NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken"; +NSString * const MGLLastMapCameraDefaultsKey = @"MGLLastMapCamera"; +NSString * const MGLLastMapStyleURLDefaultsKey = @"MGLLastMapStyleURL"; +NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask"; + +/** + Some convenience methods to make offline pack properties easier to bind to. + */ +@implementation MGLOfflinePack (Additions) + ++ (NSSet *)keyPathsForValuesAffectingStateImage { + return [NSSet setWithObjects:@"state", nil]; +} + +- (NSImage *)stateImage { + switch (self.state) { + case MGLOfflinePackStateComplete: + return [NSImage imageNamed:@"NSMenuOnStateTemplate"]; + + case MGLOfflinePackStateActive: + return [NSImage imageNamed:@"NSFollowLinkFreestandingTemplate"]; + + default: + return nil; + } +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesCompleted { + return [NSSet setWithObjects:@"progress", nil]; +} + +- (uint64_t)countOfResourcesCompleted { + return self.progress.countOfResourcesCompleted; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesExpected { + return [NSSet setWithObjects:@"progress", nil]; +} + +- (uint64_t)countOfResourcesExpected { + return self.progress.countOfResourcesExpected; +} + ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfBytesCompleted { + return [NSSet setWithObjects:@"progress", nil]; +} + +- (uint64_t)countOfBytesCompleted { + return self.progress.countOfBytesCompleted; +} + +@end + +@interface AppDelegate () + +@property (weak) IBOutlet NSArrayController *offlinePacksArrayController; +@property (weak) IBOutlet NSPanel *offlinePacksPanel; + +@end + +@implementation AppDelegate + +#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 { + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self + andSelector:@selector(handleGetURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; + + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) { + NSData *cameraData = [[NSUserDefaults standardUserDefaults] objectForKey:MGLLastMapCameraDefaultsKey]; + if (cameraData) { + NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingWithData:cameraData]; + self.pendingZoomLevel = -1; + self.pendingCamera = [[MGLMapCamera alloc] initWithCoder:coder]; + } + NSString *styleURLString = [[NSUserDefaults standardUserDefaults] objectForKey:MGLLastMapStyleURLDefaultsKey]; + if (styleURLString) { + self.pendingStyleURL = [NSURL URLWithString:styleURLString]; + } + self.pendingDebugMask = [[NSUserDefaults standardUserDefaults] integerForKey:MGLLastMapDebugMaskDefaultsKey]; + } +} + +- (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]; + } + + [self.offlinePacksArrayController bind:@"content" toObject:[MGLOfflineStorage sharedOfflineStorage] withKeyPath:@"packs" options:nil]; +} + +- (void)applicationWillTerminate:(NSNotification *)notification { + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) { + NSDocument *currentDocument = [NSDocumentController sharedDocumentController].currentDocument; + if ([currentDocument isKindOfClass:[MapDocument class]]) { + MGLMapView *mapView = [(MapDocument *)currentDocument mapView]; + NSMutableData *cameraData = [NSMutableData data]; + NSKeyedArchiver *coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:cameraData]; + [mapView.camera encodeWithCoder:coder]; + [coder finishEncoding]; + [[NSUserDefaults standardUserDefaults] setObject:cameraData forKey:MGLLastMapCameraDefaultsKey]; + [[NSUserDefaults standardUserDefaults] setObject:mapView.styleURL.absoluteString forKey:MGLLastMapStyleURLDefaultsKey]; + [[NSUserDefaults standardUserDefaults] setInteger:mapView.debugMask forKey:MGLLastMapDebugMaskDefaultsKey]; + } + } + + [self.offlinePacksArrayController unbind:@"content"]; +} + +#pragma mark Services + +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + // mapboxgl://?center=29.95,-90.066667&zoom=14&bearing=45&pitch=30 + 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]; + } + } + + MGLMapCamera *camera = [MGLMapCamera camera]; + NSString *zoomLevelString = params[@"zoom"]; + self.pendingZoomLevel = zoomLevelString.length ? zoomLevelString.doubleValue : -1; + + NSString *directionString = params[@"bearing"]; + if (directionString.length) { + camera.heading = directionString.doubleValue; + } + + NSString *centerString = params[@"center"]; + if (centerString) { + NSArray *coordinateValues = [centerString componentsSeparatedByString:@","]; + if (coordinateValues.count == 2) { + camera.centerCoordinate = CLLocationCoordinate2DMake([coordinateValues[0] doubleValue], + [coordinateValues[1] doubleValue]); + } + } + + NSString *pitchString = params[@"pitch"]; + if (pitchString.length) { + camera.pitch = pitchString.doubleValue; + } + + self.pendingCamera = camera; + [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:NULL]; +} + +#pragma mark Offline pack management + +- (IBAction)showOfflinePacksPanel:(id)sender { + [self.offlinePacksPanel makeKeyAndOrderFront:sender]; + + for (MGLOfflinePack *pack in self.offlinePacksArrayController.arrangedObjects) { + [pack requestProgress]; + } +} + +- (IBAction)delete:(id)sender { + for (MGLOfflinePack *pack in self.offlinePacksArrayController.selectedObjects) { + [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:^(NSError * _Nullable error) { + if (error) { + [[NSAlert alertWithError:error] runModal]; + } + }]; + } +} + +- (IBAction)chooseOfflinePack:(id)sender { + for (MGLOfflinePack *pack in self.offlinePacksArrayController.selectedObjects) { + switch (pack.state) { + case MGLOfflinePackStateComplete: + { + if ([pack.region isKindOfClass:[MGLTilePyramidOfflineRegion class]]) { + MGLTilePyramidOfflineRegion *region = (MGLTilePyramidOfflineRegion *)pack.region; + self.pendingVisibleCoordinateBounds = region.bounds; + self.pendingMinimumZoomLevel = region.minimumZoomLevel; + self.pendingMaximumZoomLevel = region.maximumZoomLevel; + [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:NULL]; + } + break; + } + + case MGLOfflinePackStateInactive: + [pack resume]; + break; + + case MGLOfflinePackStateActive: + [pack suspend]; + break; + + default: + break; + } + } +} + +#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 on a trackpad, or drag the cursor, or press the arrow keys.\n\ +• To zoom in, pinch two fingers apart on a trackpad, or double-click, or hold down Shift while dragging the cursor down, or hold down Option while pressing the up key.\n\ +• To zoom out, pinch two fingers together on a trackpad, or double-tap on a mouse, or hold down Shift while dragging the cursor up, or hold down Option while pressing the down key.\n\ +• To rotate, move two fingers opposite each other in a circle on a trackpad, 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.\n\ +• To drop a pin, click and hold.\ +"; + [alert runModal]; +} + +- (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 User interface validation + +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + if (menuItem.action == @selector(showShortcuts:)) { + return YES; + } + if (menuItem.action == @selector(showPreferences:)) { + return YES; + } + if (menuItem.action == @selector(showOfflinePacksPanel:)) { + return YES; + } + if (menuItem.action == @selector(delete:)) { + return self.offlinePacksArrayController.selectedObjects.count; + } + return NO; +} + +@end diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png new file mode 100644 index 0000000000..145d5a7d85 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png new file mode 100644 index 0000000000..fa2588dec3 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png new file mode 100644 index 0000000000..18fec77f84 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png new file mode 100644 index 0000000000..18fec77f84 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png new file mode 100644 index 0000000000..bf3acc1282 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png new file mode 100644 index 0000000000..bf3acc1282 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png new file mode 100644 index 0000000000..1ea7683696 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png new file mode 100644 index 0000000000..1ea7683696 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..58e739d056 --- /dev/null +++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "AppIcon16x16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "AppIcon32x32-1.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "AppIcon32x32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon-1.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "AppIcon128x128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "AppIcon256x256-1.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "AppIcon256x256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "AppIcon512x512-1.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "AppIcon512x512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png new file mode 100644 index 0000000000..36dd7acf90 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png differ diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png new file mode 100644 index 0000000000..fdee900aa4 Binary files /dev/null and b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png differ diff --git a/platform/macos/app/Assets.xcassets/Contents.json b/platform/macos/app/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/platform/macos/app/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000..4afb3b244e --- /dev/null +++ b/platform/macos/app/Base.lproj/MainMenu.xib @@ -0,0 +1,845 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OfflinePackNameValueTransformer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context + countOfResourcesCompleted + countOfResourcesExpected + countOfBytesCompleted + stateImage + + + + + + + + + diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib new file mode 100644 index 0000000000..9a3db47df6 --- /dev/null +++ b/platform/macos/app/Base.lproj/MapDocument.xib @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %{title1}@ + LocationCoordinate2DTransformer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/app/Credits.rtf b/platform/macos/app/Credits.rtf new file mode 100644 index 0000000000..6b17eb34b2 --- /dev/null +++ b/platform/macos/app/Credits.rtf @@ -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}}.} \ No newline at end of file diff --git a/platform/macos/app/DroppedPinAnnotation.h b/platform/macos/app/DroppedPinAnnotation.h new file mode 100644 index 0000000000..435a56738b --- /dev/null +++ b/platform/macos/app/DroppedPinAnnotation.h @@ -0,0 +1,10 @@ +#import + +@interface DroppedPinAnnotation : MGLPointAnnotation + +@property (nonatomic, readonly) NSTimeInterval elapsedShownTime; + +- (void)resume; +- (void)pause; + +@end diff --git a/platform/macos/app/DroppedPinAnnotation.m b/platform/macos/app/DroppedPinAnnotation.m new file mode 100644 index 0000000000..5b19fd7401 --- /dev/null +++ b/platform/macos/app/DroppedPinAnnotation.m @@ -0,0 +1,68 @@ +#import "DroppedPinAnnotation.h" + +#import "LocationCoordinate2DTransformer.h" +#import "TimeIntervalTransformer.h" + +#import + +static MGLCoordinateFormatter *DroppedPinCoordinateFormatter; + +@implementation DroppedPinAnnotation { + NSTimer *_timer; + NSTimeInterval _priorShownTimeInterval; + NSDate *_dateShown; + + NSValueTransformer *_timeIntervalTransformer; +} + ++ (void)initialize { + if (self == [DroppedPinAnnotation class]) { + DroppedPinCoordinateFormatter = [[MGLCoordinateFormatter alloc] init]; + } +} + +- (instancetype)init { + if (self = [super init]) { + _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 = [DroppedPinCoordinateFormatter stringFromCoordinate:self.coordinate]; + NSString *elapsedTime = [_timeIntervalTransformer transformedValue:@(self.elapsedShownTime)]; + self.subtitle = [NSString stringWithFormat:@"%@\nSelected for %@", coordinate, elapsedTime]; +} + +@end diff --git a/platform/macos/app/Info.plist b/platform/macos/app/Info.plist new file mode 100644 index 0000000000..cc7037f589 --- /dev/null +++ b/platform/macos/app/Info.plist @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + mbx + + CFBundleTypeName + Mapbox GL Map + CFBundleTypeRole + Editor + NSDocumentClass + MapDocument + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0 + CFBundleSignature + MBGL + CFBundleURLTypes + + + CFBundleURLName + ${PRODUCT_NAME} + CFBundleURLSchemes + + mapboxgl + + + + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/platform/macos/app/LocationCoordinate2DTransformer.h b/platform/macos/app/LocationCoordinate2DTransformer.h new file mode 100644 index 0000000000..162325fbad --- /dev/null +++ b/platform/macos/app/LocationCoordinate2DTransformer.h @@ -0,0 +1,5 @@ +#import + +@interface LocationCoordinate2DTransformer : NSValueTransformer + +@end diff --git a/platform/macos/app/LocationCoordinate2DTransformer.m b/platform/macos/app/LocationCoordinate2DTransformer.m new file mode 100644 index 0000000000..59654f1676 --- /dev/null +++ b/platform/macos/app/LocationCoordinate2DTransformer.m @@ -0,0 +1,31 @@ +#import "LocationCoordinate2DTransformer.h" + +#import + +@implementation LocationCoordinate2DTransformer { + MGLCoordinateFormatter *_coordinateFormatter; +} + ++ (Class)transformedValueClass { + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation { + return NO; +} + +- (instancetype)init { + if (self = [super init]) { + _coordinateFormatter = [[MGLCoordinateFormatter alloc] init]; + } + return self; +} + +- (id)transformedValue:(id)value { + if (![value isKindOfClass:[NSValue class]]) { + return nil; + } + return [_coordinateFormatter stringForObjectValue:value].capitalizedString; +} + +@end diff --git a/platform/macos/app/MapDocument.h b/platform/macos/app/MapDocument.h new file mode 100644 index 0000000000..86ad05e6e2 --- /dev/null +++ b/platform/macos/app/MapDocument.h @@ -0,0 +1,14 @@ +#import + +@class MGLMapView; + +@interface MapDocument : NSDocument + +@property (weak) IBOutlet MGLMapView *mapView; + +- (IBAction)setStyle:(id)sender; +- (IBAction)chooseCustomStyle:(id)sender; + +- (IBAction)reload:(id)sender; + +@end diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m new file mode 100644 index 0000000000..9bff4603e4 --- /dev/null +++ b/platform/macos/app/MapDocument.m @@ -0,0 +1,721 @@ +#import "MapDocument.h" + +#import "AppDelegate.h" +#import "DroppedPinAnnotation.h" + +#import + +static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped"; + +static const CLLocationCoordinate2D WorldTourDestinations[] = { + { .latitude = 38.9131982, .longitude = -77.0325453144239 }, + { .latitude = 37.7757368, .longitude = -122.4135302 }, + { .latitude = 12.9810816, .longitude = 77.6368034 }, + { .latitude = -13.15589555, .longitude = -74.2178961777998 }, +}; + +@interface MapDocument () + +@property (weak) IBOutlet NSMenu *mapViewContextMenu; + +@end + +@implementation MapDocument { + /// Style URL inherited from an existing document at the time this document + /// was created. + NSURL *_inheritedStyleURL; + + NSPoint _mouseLocationForMapViewContextMenu; + NSUInteger _droppedPinCounter; + NSNumberFormatter *_spellOutNumberFormatter; + + BOOL _showsToolTipsOnDroppedPins; + BOOL _randomizesCursorsOnDroppedPins; + BOOL _isTouringWorld; + BOOL _isShowingPolygonAndPolylineAnnotations; +} + +#pragma mark Lifecycle + +- (NSString *)windowNibName { + return @"MapDocument"; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)windowControllerWillLoadNib:(NSWindowController *)windowController { + NSDocument *currentDocument = [NSDocumentController sharedDocumentController].currentDocument; + if ([currentDocument isKindOfClass:[MapDocument class]]) { + _inheritedStyleURL = [(MapDocument *)currentDocument mapView].styleURL; + } +} + +- (void)windowControllerDidLoadNib:(NSWindowController *)controller { + [super windowControllerDidLoadNib:controller]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(userDefaultsDidChange:) + name:NSUserDefaultsDidChangeNotification + object:nil]; + + _spellOutNumberFormatter = [[NSNumberFormatter alloc] init]; + + NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)]; + [self.mapView addGestureRecognizer:pressGestureRecognizer]; + + [self applyPendingState]; +} + +- (NSWindow *)window { + return self.windowControllers.firstObject.window; +} + +- (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 NSWindowDelegate methods + +- (void)window:(NSWindow *)window willEncodeRestorableState:(NSCoder *)state { + [state encodeObject:self.mapView.styleURL forKey:@"MBXMapViewStyleURL"]; +} + +- (void)window:(NSWindow *)window didDecodeRestorableState:(NSCoder *)state { + self.mapView.styleURL = [state decodeObjectForKey:@"MBXMapViewStyleURL"]; +} + +#pragma mark Services + +- (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 streetsStyleURLWithVersion:MGLStyleDefaultVersion]; + break; + case 2: + styleURL = [MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion]; + break; + case 3: + styleURL = [MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion]; + break; + case 4: + styleURL = [MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion]; + break; + case 5: + styleURL = [MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion]; + break; + case 6: + styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion]; + 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, such as a style designed in Mapbox Studio:"; + NSTextField *textField = [[NSTextField alloc] initWithFrame:NSZeroRect]; + [textField sizeToFit]; + NSRect textFieldFrame = textField.frame; + textFieldFrame.size.width = 300; + textField.frame = textFieldFrame; + NSURL *savedURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"MBXCustomStyleURL"]; + if (savedURL) { + textField.stringValue = savedURL.absoluteString; + } + alert.accessoryView = textField; + [alert addButtonWithTitle:@"Apply"]; + [alert addButtonWithTitle:@"Cancel"]; + if ([alert runModal] == NSAlertFirstButtonReturn) { + self.mapView.styleURL = [NSURL URLWithString:textField.stringValue]; + [[NSUserDefaults standardUserDefaults] setURL:self.mapView.styleURL forKey:@"MBXCustomStyleURL"]; + [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]; +} + +- (void)applyPendingState { + if (_inheritedStyleURL) { + self.mapView.styleURL = _inheritedStyleURL; + _inheritedStyleURL = nil; + } + + AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate; + if (appDelegate.pendingStyleURL) { + self.mapView.styleURL = appDelegate.pendingStyleURL; + } + if (appDelegate.pendingCamera) { + if (appDelegate.pendingZoomLevel >= 0) { + self.mapView.zoomLevel = appDelegate.pendingZoomLevel; + appDelegate.pendingCamera.altitude = self.mapView.camera.altitude; + } + self.mapView.camera = appDelegate.pendingCamera; + appDelegate.pendingZoomLevel = -1; + appDelegate.pendingCamera = nil; + } + if (!MGLCoordinateBoundsIsEmpty(appDelegate.pendingVisibleCoordinateBounds)) { + self.mapView.visibleCoordinateBounds = appDelegate.pendingVisibleCoordinateBounds; + appDelegate.pendingVisibleCoordinateBounds = (MGLCoordinateBounds){ { 0, 0 }, { 0, 0 } }; + } + if (appDelegate.pendingDebugMask) { + self.mapView.debugMask = appDelegate.pendingDebugMask; + } + if (appDelegate.pendingMinimumZoomLevel >= 0) { + self.mapView.zoomLevel = MAX(appDelegate.pendingMinimumZoomLevel, self.mapView.zoomLevel); + appDelegate.pendingMaximumZoomLevel = -1; + } + if (appDelegate.pendingMaximumZoomLevel >= 0) { + self.mapView.zoomLevel = MIN(appDelegate.pendingMaximumZoomLevel, self.mapView.zoomLevel); + appDelegate.pendingMaximumZoomLevel = -1; + } + + // Temporarily set the display name to the default center coordinate instead + // of “Untitled” until the binding kicks in. + NSValue *coordinateValue = [NSValue valueWithMGLCoordinate:self.mapView.centerCoordinate]; + self.displayName = [[NSValueTransformer valueTransformerForName:@"LocationCoordinate2DTransformer"] + transformedValue:coordinateValue]; +} + +#pragma mark Debug methods + +- (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; +} + +- (IBAction)toggleWireframes:(id)sender { + self.mapView.debugMask ^= MGLMapDebugWireframesMask; +} + +- (IBAction)showColorBuffer:(id)sender { + self.mapView.debugMask &= ~MGLMapDebugStencilBufferMask; +} + +- (IBAction)showStencilBuffer:(id)sender { + self.mapView.debugMask |= MGLMapDebugStencilBufferMask; +} + +- (IBAction)toggleShowsToolTipsOnDroppedPins:(id)sender { + _showsToolTipsOnDroppedPins = !_showsToolTipsOnDroppedPins; +} + +- (IBAction)toggleRandomizesCursorsOnDroppedPins:(id)sender { + _randomizesCursorsOnDroppedPins = !_randomizesCursorsOnDroppedPins; +} + +- (IBAction)dropManyPins:(id)sender { + [self removeAllAnnotations:sender]; + + NSRect bounds = self.mapView.bounds; + NSMutableArray *annotations = [NSMutableArray array]; + for (CGFloat x = NSMinX(bounds); x < NSMaxX(bounds); x += arc4random_uniform(50)) { + for (CGFloat y = NSMaxY(bounds); y >= NSMinY(bounds); y -= arc4random_uniform(100)) { + [annotations addObject:[self pinAtPoint:NSMakePoint(x, y)]]; + } + } + + [NSTimer scheduledTimerWithTimeInterval:1/60 + target:self + selector:@selector(dropOneOfManyPins:) + userInfo:annotations + repeats:YES]; +} + +- (void)dropOneOfManyPins:(NSTimer *)timer { + NSMutableArray *annotations = timer.userInfo; + NSUInteger numberOfAnnotationsToAdd = 50; + if (annotations.count < numberOfAnnotationsToAdd) { + numberOfAnnotationsToAdd = annotations.count; + } + NSArray *annotationsToAdd = [annotations subarrayWithRange: + NSMakeRange(0, numberOfAnnotationsToAdd)]; + [self.mapView addAnnotations:annotationsToAdd]; + [annotations removeObjectsInRange:NSMakeRange(0, numberOfAnnotationsToAdd)]; + if (!annotations.count) { + [timer invalidate]; + } +} + +- (IBAction)removeAllAnnotations:(id)sender { + [self.mapView removeAnnotations:self.mapView.annotations]; + _isShowingPolygonAndPolylineAnnotations = NO; +} + +- (IBAction)startWorldTour:(id)sender { + _isTouringWorld = YES; + + [self removeAllAnnotations:sender]; + NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]); + NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations]; + for (NSUInteger i = 0; i < numberOfAnnotations; i++) { + MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init]; + annotation.coordinate = WorldTourDestinations[i]; + [annotations addObject:annotation]; + } + [self.mapView addAnnotations:annotations]; + [self continueWorldTourWithRemainingAnnotations:annotations]; +} + +- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations { + MGLPointAnnotation *nextAnnotation = annotations.firstObject; + if (!nextAnnotation || !_isTouringWorld) { + _isTouringWorld = NO; + return; + } + + [annotations removeObjectAtIndex:0]; + MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate + fromDistance:0 + pitch:arc4random_uniform(60) + heading:arc4random_uniform(360)]; + __weak MapDocument *weakSelf = self; + [self.mapView flyToCamera:camera completionHandler:^{ + MapDocument *strongSelf = weakSelf; + [strongSelf performSelector:@selector(continueWorldTourWithRemainingAnnotations:) + withObject:annotations + afterDelay:2]; + }]; +} + +- (IBAction)stopWorldTour:(id)sender { + _isTouringWorld = NO; + // Any programmatic viewpoint change cancels outstanding animations. + self.mapView.camera = self.mapView.camera; +} + +- (IBAction)drawPolygonAndPolyLineAnnotations:(id)sender { + + if (_isShowingPolygonAndPolylineAnnotations) { + [self removeAllAnnotations:sender]; + return; + } + + _isShowingPolygonAndPolylineAnnotations = YES; + + // Pacific Northwest triangle + CLLocationCoordinate2D triangleCoordinates[3] = { + CLLocationCoordinate2DMake(44, -122), + CLLocationCoordinate2DMake(46, -122), + CLLocationCoordinate2DMake(46, -121) + }; + MGLPolygon *triangle = [MGLPolygon polygonWithCoordinates:triangleCoordinates count:3]; + [self.mapView addAnnotation:triangle]; + + // West coast line + CLLocationCoordinate2D lineCoordinates[4] = { + CLLocationCoordinate2DMake(47.6025, -122.3327), + CLLocationCoordinate2DMake(45.5189, -122.6726), + CLLocationCoordinate2DMake(37.7790, -122.4177), + CLLocationCoordinate2DMake(34.0532, -118.2349) + }; + MGLPolyline *line = [MGLPolyline polylineWithCoordinates:lineCoordinates count:4]; + [self.mapView addAnnotation:line]; +} + +#pragma mark Offline packs + +- (IBAction)addOfflinePack:(id)sender { + NSAlert *namePrompt = [[NSAlert alloc] init]; + namePrompt.messageText = @"Add offline pack"; + namePrompt.informativeText = @"Choose a name for the pack:"; + NSTextField *nameTextField = [[NSTextField alloc] initWithFrame:NSZeroRect]; + nameTextField.placeholderString = MGLStringFromCoordinateBounds(self.mapView.visibleCoordinateBounds); + [nameTextField sizeToFit]; + NSRect textFieldFrame = nameTextField.frame; + textFieldFrame.size.width = 300; + nameTextField.frame = textFieldFrame; + namePrompt.accessoryView = nameTextField; + [namePrompt addButtonWithTitle:@"Add"]; + [namePrompt addButtonWithTitle:@"Cancel"]; + if ([namePrompt runModal] != NSAlertFirstButtonReturn) { + return; + } + + id region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:self.mapView.styleURL bounds:self.mapView.visibleCoordinateBounds fromZoomLevel:self.mapView.zoomLevel toZoomLevel:self.mapView.maximumZoomLevel]; + NSData *context = [[NSValueTransformer valueTransformerForName:@"OfflinePackNameValueTransformer"] reverseTransformedValue:nameTextField.stringValue]; + [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) { + if (error) { + [[NSAlert alertWithError:error] runModal]; + } else { + [pack resume]; + } + }]; +} + +#pragma mark Help methods + +- (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 + 1)]]; + [[NSWorkspace sharedWorkspace] openURL:feedbackURL]; +} + +#pragma mark Mouse events + +- (void)handlePressGesture:(NSPressGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == NSGestureRecognizerStateBegan) { + NSPoint location = [gestureRecognizer locationInView:self.mapView]; + if (!NSPointInRect([gestureRecognizer locationInView:self.mapView.compass], self.mapView.compass.bounds) + && !NSPointInRect([gestureRecognizer locationInView:self.mapView.zoomControls], self.mapView.zoomControls.bounds) + && !NSPointInRect([gestureRecognizer locationInView:self.mapView.attributionView], self.mapView.attributionView.bounds)) { + [self dropPinAtPoint:location]; + } + } +} + +- (IBAction)dropPin:(NSMenuItem *)sender { + [self dropPinAtPoint:_mouseLocationForMapViewContextMenu]; +} + +- (void)dropPinAtPoint:(NSPoint)point { + DroppedPinAnnotation *annotation = [self pinAtPoint:point]; + [self.mapView addAnnotation:annotation]; + [self.mapView selectAnnotation:annotation]; +} + +- (DroppedPinAnnotation *)pinAtPoint:(NSPoint)point { + DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init]; + annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; + annotation.title = @"Dropped Pin"; + _spellOutNumberFormatter.numberStyle = NSNumberFormatterSpellOutStyle; + if (_showsToolTipsOnDroppedPins) { + NSString *formattedNumber = [_spellOutNumberFormatter stringFromNumber:@(++_droppedPinCounter)]; + annotation.toolTip = formattedNumber; + } + return annotation; +} + +- (IBAction)removePin:(NSMenuItem *)sender { + [self removePinAtPoint:_mouseLocationForMapViewContextMenu]; +} + +- (void)removePinAtPoint:(NSPoint)point { + [self.mapView removeAnnotation:[self.mapView annotationAtPoint:point]]; +} + +#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 streetsStyleURLWithVersion:MGLStyleDefaultVersion]]; + break; + case 2: + state = [styleURL isEqual:[MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion]]; + break; + case 3: + state = [styleURL isEqual:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion]]; + break; + case 4: + state = [styleURL isEqual:[MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion]]; + break; + case 5: + state = [styleURL isEqual:[MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion]]; + break; + case 6: + state = [styleURL isEqual:[MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion]]; + 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:)) { + id annotationUnderCursor = [self.mapView annotationAtPoint:_mouseLocationForMapViewContextMenu]; + menuItem.hidden = annotationUnderCursor != nil; + return YES; + } + if (menuItem.action == @selector(removePin:)) { + id annotationUnderCursor = [self.mapView annotationAtPoint:_mouseLocationForMapViewContextMenu]; + menuItem.hidden = annotationUnderCursor == nil; + 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(toggleWireframes:)) { + BOOL isShown = self.mapView.debugMask & MGLMapDebugWireframesMask; + menuItem.title = isShown ? @"Hide Wireframes" : @"Show Wireframes"; + return YES; + } + if (menuItem.action == @selector(showColorBuffer:)) { + BOOL enabled = self.mapView.debugMask & MGLMapDebugStencilBufferMask; + menuItem.state = enabled ? NSOffState : NSOnState; + return YES; + } + if (menuItem.action == @selector(showStencilBuffer:)) { + BOOL enabled = self.mapView.debugMask & MGLMapDebugStencilBufferMask; + menuItem.state = enabled ? NSOnState : NSOffState; + return YES; + } + if (menuItem.action == @selector(toggleShowsToolTipsOnDroppedPins:)) { + BOOL isShown = _showsToolTipsOnDroppedPins; + menuItem.title = isShown ? @"Hide Tooltips on Dropped Pins" : @"Show Tooltips on Dropped Pins"; + return YES; + } + if (menuItem.action == @selector(toggleRandomizesCursorsOnDroppedPins:)) { + BOOL isRandom = _randomizesCursorsOnDroppedPins; + menuItem.title = isRandom ? @"Use Default Cursor for Dropped Pins" : @"Use Random Cursors for Dropped Pins"; + return _showsToolTipsOnDroppedPins; + } + if (menuItem.action == @selector(dropManyPins:)) { + return YES; + } + if (menuItem.action == @selector(removeAllAnnotations:)) { + return self.mapView.annotations.count > 0; + } + if (menuItem.action == @selector(startWorldTour:)) { + return !_isTouringWorld; + } + if (menuItem.action == @selector(stopWorldTour:)) { + return _isTouringWorld; + } + if (menuItem.action == @selector(drawPolygonAndPolyLineAnnotations:)) { + return !_isShowingPolygonAndPolylineAnnotations; + } + if (menuItem.action == @selector(addOfflinePack:)) { + NSURL *styleURL = self.mapView.styleURL; + return !styleURL.isFileURL; + } + if (menuItem.action == @selector(giveFeedback:)) { + return YES; + } + return NO; +} + +- (NSUInteger)indexOfStyleInToolbarItem { + if (![MGLAccountManager accessToken]) { + return NSNotFound; + } + + NSArray *styleURLs = @[ + [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion], + [MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion], + [MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion], + [MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion], + [MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion], + [MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion], + ]; + 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]; + if (![MGLAccountManager accessToken]) { + return NO; + } + NSURL *styleURL = self.mapView.styleURL; + return ([styleURL.scheme isEqualToString:@"mapbox"] + && [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 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.contentView convertPoint:self.window.mouseLocationOutsideOfEventStream + toView:self.mapView]; + } +} + +#pragma mark MGLMapViewDelegate methods + +- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id )annotation { + return YES; +} + +- (MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id )annotation { + MGLAnnotationImage *annotationImage = [self.mapView dequeueReusableAnnotationImageWithIdentifier:MGLDroppedPinAnnotationImageIdentifier]; + if (!annotationImage) { + NSString *imagePath = [[NSBundle bundleForClass:[MGLMapView class]] + pathForResource:@"default_marker" ofType:@"pdf"]; + NSImage *image = [[NSImage alloc] initWithContentsOfFile:imagePath]; + NSRect alignmentRect = image.alignmentRect; + alignmentRect.origin.y = NSMidY(alignmentRect); + alignmentRect.size.height /= 2; + image.alignmentRect = alignmentRect; + annotationImage = [MGLAnnotationImage annotationImageWithImage:image + reuseIdentifier:MGLDroppedPinAnnotationImageIdentifier]; + } + if (_randomizesCursorsOnDroppedPins) { + NSArray *cursors = @[ + [NSCursor IBeamCursor], + [NSCursor crosshairCursor], + [NSCursor pointingHandCursor], + [NSCursor disappearingItemCursor], + [NSCursor IBeamCursorForVerticalLayout], + [NSCursor operationNotAllowedCursor], + [NSCursor dragLinkCursor], + [NSCursor dragCopyCursor], + [NSCursor contextualMenuCursor], + ]; + annotationImage.cursor = cursors[arc4random_uniform((uint32_t)cursors.count) % cursors.count]; + } else { + annotationImage.cursor = nil; + } + return annotationImage; +} + +- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id )annotation { + if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) { + DroppedPinAnnotation *droppedPin = annotation; + [droppedPin resume]; + } +} + +- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id )annotation { + if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) { + DroppedPinAnnotation *droppedPin = annotation; + [droppedPin pause]; + } +} + +@end + +@interface ValidatedToolbarItem : NSToolbarItem + +@end + +@implementation ValidatedToolbarItem + +- (void)validate { + [(MapDocument *)self.toolbar.delegate validateToolbarItem:self]; +} + +@end diff --git a/platform/macos/app/OfflinePackNameValueTransformer.h b/platform/macos/app/OfflinePackNameValueTransformer.h new file mode 100644 index 0000000000..11fe3ff441 --- /dev/null +++ b/platform/macos/app/OfflinePackNameValueTransformer.h @@ -0,0 +1,5 @@ +#import + +@interface OfflinePackNameValueTransformer : NSValueTransformer + +@end diff --git a/platform/macos/app/OfflinePackNameValueTransformer.m b/platform/macos/app/OfflinePackNameValueTransformer.m new file mode 100644 index 0000000000..2825e48ed3 --- /dev/null +++ b/platform/macos/app/OfflinePackNameValueTransformer.m @@ -0,0 +1,33 @@ +#import "OfflinePackNameValueTransformer.h" + +static NSString * const MBXOfflinePackContextNameKey = @"Name"; + +@implementation OfflinePackNameValueTransformer + ++ (Class)transformedValueClass { + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation { + return YES; +} + +- (NSString *)transformedValue:(NSData *)context { + NSAssert([context isKindOfClass:[NSData class]], @"Context should be NSData."); + + NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:context]; + NSAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline pack isn’t a dictionary."); + NSString *name = userInfo[MBXOfflinePackContextNameKey]; + NSAssert([name isKindOfClass:[NSString class]], @"Name of offline pack isn’t a string."); + return name; +} + +- (NSData *)reverseTransformedValue:(NSString *)name { + NSAssert([name isKindOfClass:[NSString class]], @"Name should be a string."); + + return [NSKeyedArchiver archivedDataWithRootObject:@{ + MBXOfflinePackContextNameKey: name, + }]; +} + +@end diff --git a/platform/macos/app/TimeIntervalTransformer.h b/platform/macos/app/TimeIntervalTransformer.h new file mode 100644 index 0000000000..ca88ad2cd1 --- /dev/null +++ b/platform/macos/app/TimeIntervalTransformer.h @@ -0,0 +1,5 @@ +#import + +@interface TimeIntervalTransformer : NSValueTransformer + +@end diff --git a/platform/macos/app/TimeIntervalTransformer.m b/platform/macos/app/TimeIntervalTransformer.m new file mode 100644 index 0000000000..39177dc5bc --- /dev/null +++ b/platform/macos/app/TimeIntervalTransformer.m @@ -0,0 +1,53 @@ +#import "TimeIntervalTransformer.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 diff --git a/platform/macos/app/main.m b/platform/macos/app/main.m new file mode 100644 index 0000000000..8a6799b414 --- /dev/null +++ b/platform/macos/app/main.m @@ -0,0 +1,5 @@ +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/platform/macos/bitrise.yml b/platform/macos/bitrise.yml new file mode 100644 index 0000000000..ce622ef0f8 --- /dev/null +++ b/platform/macos/bitrise.yml @@ -0,0 +1,54 @@ +format_version: 1.1.0 +default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git + +trigger_map: +- pattern: "*" + is_pull_request_allowed: true + workflow: primary + +workflows: + primary: + steps: + - script: + title: Check for skipping CI + inputs: + - content: |- + #!/bin/bash + if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" || + -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" || + -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" || + -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then + envman add --key SKIPCI --value true + else + envman add --key SKIPCI --value false + fi + - script: + title: Run build script + run_if: '{{enveq "SKIPCI" "false"}}' + inputs: + - content: |- + #!/bin/bash + set -eu -o pipefail + gem install xcpretty --no-rdoc --no-ri + export BUILDTYPE=Debug + make macos + make test-macos + - is_debug: 'yes' + - slack: + title: Post to Slack + run_if: '{{enveq "SKIPCI" "false"}}' + inputs: + - webhook_url: "$SLACK_HOOK_URL" + - channel: "#gl-bots" + - from_username: 'Bitrise macOS' + - from_username_on_error: 'Bitrise macOS' + - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> + for + by ${GIT_CLONE_COMMIT_COMMITER_NAME} + passed' + - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> + for + by ${GIT_CLONE_COMMIT_COMMITER_NAME} + failed' + - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png + - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md new file mode 100644 index 0000000000..b037da19d4 --- /dev/null +++ b/platform/macos/docs/doc-README.md @@ -0,0 +1,9 @@ +# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/) + +The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. + + + +For setup information, consult the README.md that comes with this documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. A [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/macos/CHANGELOG.md) is also available. + +Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md new file mode 100644 index 0000000000..70d98ecdb9 --- /dev/null +++ b/platform/macos/docs/pod-README.md @@ -0,0 +1,43 @@ +# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/) + +The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. + + + +## Installation + +1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework from the `dynamic` folder into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. + +1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom macOS Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). + +## Usage + +In a storyboard or XIB, add a view to your view controller. (Drag Custom View from the Object library to the View Controller scene on the Interface Builder canvas.) In the Identity inspector, set the view’s custom class to `MGLMapView`. If you need to manipulate the map view programmatically: + +1. Switch to the Assistant Editor. +1. Import the `Mapbox` module. +1. Connect the map view to a new outlet in your view controller class. (Control-drag from the map view in Interface Builder to a valid location in your view controller implementation.) The resulting outlet declaration should look something like this: + +```objc +// ViewController.m +@import Mapbox; + +@interface ViewController : NSViewController + +@property (strong) IBOutlet MGLMapView *mapView; + +@end +``` + +```swift +// ViewController.swift +import Mapbox + +class ViewController: NSViewController { + @IBOutlet var mapView: MGLMapView! +} +``` + +Full API documentation is included in this package, within the `documentation` folder. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. + +Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml new file mode 100644 index 0000000000..b1aca9bb45 --- /dev/null +++ b/platform/macos/jazzy.yml @@ -0,0 +1,71 @@ +module: Mapbox +author: Mapbox +author_url: https://www.mapbox.com/ +github_url: https://github.com/mapbox/mapbox-gl-native +copyright: '© 2014–2016 [Mapbox](https://www.mapbox.com/). See [license](https://github.com/mapbox/mapbox-gl-native/blob/master/LICENSE.md) for more details.' + +head: | + + +objc: Yes +skip_undocumented: Yes +hide_documentation_coverage: Yes +umbrella_header: src/Mapbox.h +framework_root: ../darwin/src + +custom_categories: + - name: Maps + children: + - MGLAccountManager + - MGLMapCamera + - MGLMapDebugMaskOptions + - MGLMapView + - MGLMapViewDelegate + - MGLStyle + - MGLStyleDefaultVersion + - MGLUserTrackingMode + - name: Annotations + children: + - MGLAnnotation + - MGLAnnotationImage + - MGLMultiPoint + - MGLPointAnnotation + - MGLPolygon + - MGLPolyline + - MGLOverlay + - MGLShape + - name: Offline Maps + children: + - MGLOfflineRegion + - MGLOfflineStorage + - MGLOfflinePack + - MGLOfflinePackAdditionCompletionHandler + - MGLOfflinePackErrorNotification + - MGLOfflinePackErrorUserInfoKey + - MGLOfflinePackMaximumCountUserInfoKey + - MGLOfflinePackMaximumMapboxTilesReachedNotification + - MGLOfflinePackProgress + - MGLOfflinePackProgressChangedNotification + - MGLOfflinePackProgressUserInfoKey + - MGLOfflinePackRemovalCompletionHandler + - MGLOfflinePackState + - MGLOfflinePackStateUserInfoKey + - MGLTilePyramidOfflineRegion + - name: Geometry + children: + - MGLClockDirectionFormatter + - MGLCompassDirectionFormatter + - MGLCoordinateBounds + - MGLCoordinateBoundsEqualToCoordinateBounds + - MGLCoordinateBoundsGetCoordinateSpan + - MGLCoordinateBoundsIsEmpty + - MGLCoordinateBoundsMake + - MGLCoordinateBoundsOffset + - MGLCoordinateFormatter + - MGLCoordinateSpan + - MGLCoordinateSpanEqualToCoordinateSpan + - MGLCoordinateSpanMake + - MGLCoordinateSpanZero + - MGLDegreesFromRadians + - MGLRadiansFromDegrees + - MGLStringFromCoordinateBounds diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..be82bcc479 --- /dev/null +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -0,0 +1,1119 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */; }; + DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */; }; + DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */; }; + DA35A2AD1CCA091800E826B2 /* MGLCompassDirectionFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */; }; + DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */; }; + DA35A2BF1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA35A2C01CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */; }; + DA35A2C21CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */; }; + DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA35A2D01CCAAED300E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */; }; + DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E961CC2E3400062CAFB /* AppDelegate.m */; }; + DA839E9A1CC2E3400062CAFB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E991CC2E3400062CAFB /* main.m */; }; + DA839E9D1CC2E3400062CAFB /* MapDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E9C1CC2E3400062CAFB /* MapDocument.m */; }; + DA839EA01CC2E3400062CAFB /* MapDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA839E9E1CC2E3400062CAFB /* MapDocument.xib */; }; + DA839EA21CC2E3400062CAFB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA839EA11CC2E3400062CAFB /* Assets.xcassets */; }; + DA839EA51CC2E3400062CAFB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA839EA31CC2E3400062CAFB /* MainMenu.xib */; }; + DA8933A51CCD287300E68420 /* MGLAnnotationCallout.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA8933A71CCD287300E68420 /* MGLAnnotationCallout.xib */; }; + DA8933AE1CCD290700E68420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA8933AB1CCD290700E68420 /* Localizable.strings */; }; + DA8933B51CCD2C2500E68420 /* Foundation.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA8933B31CCD2C2500E68420 /* Foundation.strings */; }; + DA8933B81CCD2C2D00E68420 /* Foundation.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DA8933B61CCD2C2D00E68420 /* Foundation.stringsdict */; }; + DAB6924A1CC75A31005AAB54 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; + DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; }; + DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C2E11CC304F900DB3429 /* Credits.rtf */; }; + DAE6C2ED1CC3050F00DB3429 /* DroppedPinAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */; }; + DAE6C2EE1CC3050F00DB3429 /* LocationCoordinate2DTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E61CC3050F00DB3429 /* LocationCoordinate2DTransformer.m */; }; + DAE6C2F01CC3050F00DB3429 /* OfflinePackNameValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2EA1CC3050F00DB3429 /* OfflinePackNameValueTransformer.m */; }; + DAE6C2F11CC3050F00DB3429 /* TimeIntervalTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2EC1CC3050F00DB3429 /* TimeIntervalTransformer.m */; }; + DAE6C3321CC30DB200DB3429 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; }; + DAE6C33D1CC30DB200DB3429 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; }; + DAE6C33E1CC30DB200DB3429 /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + DAE6C3471CC31D1200DB3429 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; + DAE6C3481CC31D1200DB3429 /* libmbgl-platform-macos.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */; }; + DAE6C35A1CC31E0400DB3429 /* MGLAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C35C1CC31E0400DB3429 /* MGLGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C35D1CC31E0400DB3429 /* MGLMapCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C35F1CC31E0400DB3429 /* MGLOfflinePack.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3601CC31E0400DB3429 /* MGLOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3611CC31E0400DB3429 /* MGLOfflineStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3621CC31E0400DB3429 /* MGLOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3631CC31E0400DB3429 /* MGLPointAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3641CC31E0400DB3429 /* MGLPolygon.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3661CC31E0400DB3429 /* MGLShape.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3561CC31E0400DB3429 /* MGLShape.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3671CC31E0400DB3429 /* MGLStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3571CC31E0400DB3429 /* MGLStyle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3681CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3691CC31E0400DB3429 /* MGLTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3591CC31E0400DB3429 /* MGLTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3841CC31E2A00DB3429 /* MGLAccountManager_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C36A1CC31E2A00DB3429 /* MGLAccountManager_Private.h */; }; + DAE6C3851CC31E2A00DB3429 /* MGLAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */; }; + DAE6C3861CC31E2A00DB3429 /* MGLGeometry_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */; }; + DAE6C3871CC31E2A00DB3429 /* MGLGeometry.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */; }; + DAE6C3881CC31E2A00DB3429 /* MGLMapCamera.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */; }; + DAE6C3891CC31E2A00DB3429 /* MGLMultiPoint_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */; }; + DAE6C38A1CC31E2A00DB3429 /* MGLMultiPoint.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */; }; + DAE6C38B1CC31E2A00DB3429 /* MGLOfflinePack_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */; }; + DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */; }; + DAE6C38D1CC31E2A00DB3429 /* MGLOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */; }; + DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */; }; + DAE6C38F1CC31E2A00DB3429 /* MGLOfflineStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */; }; + DAE6C3901CC31E2A00DB3429 /* MGLPointAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */; }; + DAE6C3911CC31E2A00DB3429 /* MGLPolygon.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */; }; + DAE6C3921CC31E2A00DB3429 /* MGLPolyline.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */; }; + DAE6C3931CC31E2A00DB3429 /* MGLShape.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3791CC31E2A00DB3429 /* MGLShape.m */; }; + DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */; }; + DAE6C3951CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */; }; + DAE6C3961CC31E2A00DB3429 /* MGLTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */; }; + DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */; }; + DAE6C3981CC31E2A00DB3429 /* NSBundle+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */; }; + DAE6C3991CC31E2A00DB3429 /* NSException+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */; }; + DAE6C39A1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */; }; + DAE6C39B1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */; }; + DAE6C39C1CC31E2A00DB3429 /* NSString+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */; }; + DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */; }; + DAE6C3A31CC31E9400DB3429 /* MGLAnnotationImage.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C39F1CC31E9400DB3429 /* MGLAnnotationImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3A41CC31E9400DB3429 /* MGLMapView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A01CC31E9400DB3429 /* MGLMapView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3A51CC31E9400DB3429 /* MGLMapView+IBAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A11CC31E9400DB3429 /* MGLMapView+IBAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */; }; + DAE6C3B21CC31EF300DB3429 /* MGLAttributionButton.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */; }; + DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */; }; + DAE6C3B41CC31EF300DB3429 /* MGLCompassCell.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */; }; + DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */; }; + DAE6C3B61CC31EF300DB3429 /* MGLMapView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */; }; + DAE6C3B71CC31EF300DB3429 /* MGLMapView.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3AD1CC31EF300DB3429 /* MGLMapView.mm */; }; + DAE6C3B81CC31EF300DB3429 /* MGLMapView+IBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3AE1CC31EF300DB3429 /* MGLMapView+IBAdditions.m */; }; + DAE6C3B91CC31EF300DB3429 /* MGLOpenGLLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3AF1CC31EF300DB3429 /* MGLOpenGLLayer.h */; }; + DAE6C3BA1CC31EF300DB3429 /* MGLOpenGLLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3B01CC31EF300DB3429 /* MGLOpenGLLayer.mm */; }; + DAE6C3BE1CC31F2E00DB3429 /* default_marker.pdf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C3BB1CC31F2E00DB3429 /* default_marker.pdf */; }; + DAE6C3BF1CC31F2E00DB3429 /* mapbox.pdf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */; }; + DAE6C3C21CC31F4500DB3429 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3C11CC31F4500DB3429 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAE6C3C71CC3499100DB3429 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */; }; + DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */; }; + DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */; }; + DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */; }; + DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */; }; + DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + DAE6C3331CC30DB200DB3429 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DA839E8A1CC2E3400062CAFB /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAE6C3271CC30DB200DB3429; + remoteInfo = dynamic; + }; + DAE6C33B1CC30DB200DB3429 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DA839E8A1CC2E3400062CAFB /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAE6C3271CC30DB200DB3429; + remoteInfo = dynamic; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + DAE6C3221CC30B3C00DB3429 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + DAE6C33E1CC30DB200DB3429 /* Mapbox.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = ""; }; + DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = ""; }; + DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCoordinateFormatterTests.m; path = ../../darwin/test/MGLCoordinateFormatterTests.m; sourceTree = ""; }; + DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCompassDirectionFormatter.h; sourceTree = ""; }; + DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCompassDirectionFormatter.m; sourceTree = ""; }; + DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCompassDirectionFormatterTests.m; path = ../../darwin/test/MGLCompassDirectionFormatterTests.m; sourceTree = ""; }; + DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLClockDirectionFormatter.h; sourceTree = ""; }; + DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLClockDirectionFormatter.m; sourceTree = ""; }; + DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLClockDirectionFormatterTests.m; path = ../../darwin/test/MGLClockDirectionFormatterTests.m; sourceTree = ""; }; + DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLAdditions.h"; sourceTree = ""; }; + DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+MGLAdditions.m"; sourceTree = ""; }; + DA839E921CC2E3400062CAFB /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + DA839E951CC2E3400062CAFB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + DA839E961CC2E3400062CAFB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + DA839E991CC2E3400062CAFB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + DA839E9B1CC2E3400062CAFB /* MapDocument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MapDocument.h; sourceTree = ""; }; + DA839E9C1CC2E3400062CAFB /* MapDocument.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MapDocument.m; sourceTree = ""; }; + DA839E9F1CC2E3400062CAFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MapDocument.xib; sourceTree = ""; }; + DA839EA11CC2E3400062CAFB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + DA839EA41CC2E3400062CAFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + DA839EA61CC2E3400062CAFB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DA8933A61CCD287300E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MGLAnnotationCallout.xib; sourceTree = ""; }; + DA8933AC1CCD290700E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + DA8933B41CCD2C2500E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Foundation.strings; sourceTree = ""; }; + DA8933B71CCD2C2D00E68420 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Foundation.stringsdict; sourceTree = ""; }; + DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = ""; }; + DAE6C2E11CC304F900DB3429 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; }; + DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DroppedPinAnnotation.h; sourceTree = ""; }; + DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DroppedPinAnnotation.m; sourceTree = ""; }; + DAE6C2E51CC3050F00DB3429 /* LocationCoordinate2DTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationCoordinate2DTransformer.h; sourceTree = ""; }; + DAE6C2E61CC3050F00DB3429 /* LocationCoordinate2DTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocationCoordinate2DTransformer.m; sourceTree = ""; }; + DAE6C2E91CC3050F00DB3429 /* OfflinePackNameValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OfflinePackNameValueTransformer.h; sourceTree = ""; }; + DAE6C2EA1CC3050F00DB3429 /* OfflinePackNameValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OfflinePackNameValueTransformer.m; sourceTree = ""; }; + DAE6C2EB1CC3050F00DB3429 /* TimeIntervalTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeIntervalTransformer.h; sourceTree = ""; }; + DAE6C2EC1CC3050F00DB3429 /* TimeIntervalTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimeIntervalTransformer.m; sourceTree = ""; }; + DAE6C3281CC30DB200DB3429 /* Mapbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DAE6C32C1CC30DB200DB3429 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DAE6C3311CC30DB200DB3429 /* test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + DAE6C33A1CC30DB200DB3429 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libmbgl-core.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libmbgl-platform-macos.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAccountManager.h; sourceTree = ""; }; + DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotation.h; sourceTree = ""; }; + DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLGeometry.h; sourceTree = ""; }; + DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapCamera.h; sourceTree = ""; }; + DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMultiPoint.h; sourceTree = ""; }; + DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflinePack.h; sourceTree = ""; }; + DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflineRegion.h; sourceTree = ""; }; + DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflineStorage.h; sourceTree = ""; }; + DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOverlay.h; sourceTree = ""; }; + DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointAnnotation.h; sourceTree = ""; }; + DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon.h; sourceTree = ""; }; + DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline.h; sourceTree = ""; }; + DAE6C3561CC31E0400DB3429 /* MGLShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShape.h; sourceTree = ""; }; + DAE6C3571CC31E0400DB3429 /* MGLStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyle.h; sourceTree = ""; }; + DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTilePyramidOfflineRegion.h; sourceTree = ""; }; + DAE6C3591CC31E0400DB3429 /* MGLTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTypes.h; sourceTree = ""; }; + DAE6C36A1CC31E2A00DB3429 /* MGLAccountManager_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAccountManager_Private.h; sourceTree = ""; }; + DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAccountManager.m; sourceTree = ""; }; + DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLGeometry_Private.h; sourceTree = ""; }; + DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLGeometry.mm; sourceTree = ""; }; + DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapCamera.mm; sourceTree = ""; }; + DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMultiPoint_Private.h; sourceTree = ""; }; + DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMultiPoint.mm; sourceTree = ""; }; + DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflinePack_Private.h; sourceTree = ""; }; + DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOfflinePack.mm; sourceTree = ""; }; + DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflineRegion_Private.h; sourceTree = ""; }; + DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOfflineStorage_Private.h; sourceTree = ""; }; + DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOfflineStorage.mm; sourceTree = ""; }; + DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLPointAnnotation.m; sourceTree = ""; }; + DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPolygon.mm; sourceTree = ""; }; + DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPolyline.mm; sourceTree = ""; }; + DAE6C3791CC31E2A00DB3429 /* MGLShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShape.m; sourceTree = ""; }; + DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLStyle.mm; sourceTree = ""; }; + DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTilePyramidOfflineRegion.mm; sourceTree = ""; }; + DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTypes.m; sourceTree = ""; }; + DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+MGLAdditions.h"; sourceTree = ""; }; + DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+MGLAdditions.m"; sourceTree = ""; }; + DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSException+MGLAdditions.h"; sourceTree = ""; }; + DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSProcessInfo+MGLAdditions.h"; sourceTree = ""; }; + DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSProcessInfo+MGLAdditions.m"; sourceTree = ""; }; + DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MGLAdditions.h"; sourceTree = ""; }; + DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MGLAdditions.m"; sourceTree = ""; }; + DAE6C39F1CC31E9400DB3429 /* MGLAnnotationImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage.h; sourceTree = ""; }; + DAE6C3A01CC31E9400DB3429 /* MGLMapView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView.h; sourceTree = ""; }; + DAE6C3A11CC31E9400DB3429 /* MGLMapView+IBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLMapView+IBAdditions.h"; sourceTree = ""; }; + DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapViewDelegate.h; sourceTree = ""; }; + DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationImage.m; sourceTree = ""; }; + DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionButton.h; sourceTree = ""; }; + DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButton.m; sourceTree = ""; }; + DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCompassCell.h; sourceTree = ""; }; + DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCompassCell.m; sourceTree = ""; }; + DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Private.h; sourceTree = ""; }; + DAE6C3AD1CC31EF300DB3429 /* MGLMapView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapView.mm; sourceTree = ""; }; + DAE6C3AE1CC31EF300DB3429 /* MGLMapView+IBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLMapView+IBAdditions.m"; sourceTree = ""; }; + DAE6C3AF1CC31EF300DB3429 /* MGLOpenGLLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLLayer.h; sourceTree = ""; }; + DAE6C3B01CC31EF300DB3429 /* MGLOpenGLLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLLayer.mm; sourceTree = ""; }; + DAE6C3BB1CC31F2E00DB3429 /* default_marker.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = default_marker.pdf; sourceTree = ""; }; + DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = mapbox.pdf; sourceTree = ""; }; + DAE6C3C11CC31F4500DB3429 /* Mapbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mapbox.h; path = src/Mapbox.h; sourceTree = SOURCE_ROOT; }; + DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/macos/mbgl.xcconfig; sourceTree = ""; }; + DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = ""; }; + DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = ""; }; + DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = ""; }; + DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineStorageTests.m; path = ../../darwin/test/MGLOfflineStorageTests.m; sourceTree = ""; }; + DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + DA839E8F1CC2E3400062CAFB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DAE6C33D1CC30DB200DB3429 /* Mapbox.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C3241CC30DB200DB3429 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */, + DAE6C3471CC31D1200DB3429 /* libmbgl-core.a in Frameworks */, + DAE6C3481CC31D1200DB3429 /* libmbgl-platform-macos.a in Frameworks */, + DAE6C3C71CC3499100DB3429 /* libsqlite3.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C32E1CC30DB200DB3429 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DAB6924A1CC75A31005AAB54 /* libmbgl-core.a in Frameworks */, + DAE6C3321CC30DB200DB3429 /* Mapbox.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + DA839E891CC2E3400062CAFB = { + isa = PBXGroup; + children = ( + DA839E941CC2E3400062CAFB /* Demo App */, + DAE6C3291CC30DB200DB3429 /* SDK */, + DAE6C3371CC30DB200DB3429 /* SDK Tests */, + DAE6C31E1CC308BC00DB3429 /* Frameworks */, + DAE6C3C41CC31F7800DB3429 /* Configuration */, + DA839E931CC2E3400062CAFB /* Products */, + ); + sourceTree = ""; + }; + DA839E931CC2E3400062CAFB /* Products */ = { + isa = PBXGroup; + children = ( + DA839E921CC2E3400062CAFB /* Mapbox GL.app */, + DAE6C3281CC30DB200DB3429 /* Mapbox.framework */, + DAE6C3311CC30DB200DB3429 /* test.xctest */, + ); + name = Products; + sourceTree = ""; + }; + DA839E941CC2E3400062CAFB /* Demo App */ = { + isa = PBXGroup; + children = ( + DA839E951CC2E3400062CAFB /* AppDelegate.h */, + DA839E961CC2E3400062CAFB /* AppDelegate.m */, + DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */, + DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */, + DAE6C2E51CC3050F00DB3429 /* LocationCoordinate2DTransformer.h */, + DAE6C2E61CC3050F00DB3429 /* LocationCoordinate2DTransformer.m */, + DA839E9B1CC2E3400062CAFB /* MapDocument.h */, + DA839E9C1CC2E3400062CAFB /* MapDocument.m */, + DA839E9E1CC2E3400062CAFB /* MapDocument.xib */, + DAE6C2E91CC3050F00DB3429 /* OfflinePackNameValueTransformer.h */, + DAE6C2EA1CC3050F00DB3429 /* OfflinePackNameValueTransformer.m */, + DAE6C2EB1CC3050F00DB3429 /* TimeIntervalTransformer.h */, + DAE6C2EC1CC3050F00DB3429 /* TimeIntervalTransformer.m */, + DA839EA11CC2E3400062CAFB /* Assets.xcassets */, + DA839EA31CC2E3400062CAFB /* MainMenu.xib */, + DAE6C2E11CC304F900DB3429 /* Credits.rtf */, + DA839EA61CC2E3400062CAFB /* Info.plist */, + DA839E981CC2E3400062CAFB /* Supporting Files */, + ); + name = "Demo App"; + path = app; + sourceTree = ""; + }; + DA839E981CC2E3400062CAFB /* Supporting Files */ = { + isa = PBXGroup; + children = ( + DA839E991CC2E3400062CAFB /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + DA8933A81CCD28D100E68420 /* Kit Resources */ = { + isa = PBXGroup; + children = ( + DA8933AB1CCD290700E68420 /* Localizable.strings */, + DAE6C3BB1CC31F2E00DB3429 /* default_marker.pdf */, + DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */, + DA8933A71CCD287300E68420 /* MGLAnnotationCallout.xib */, + ); + name = "Kit Resources"; + sourceTree = ""; + }; + DA8933B21CCD2C0700E68420 /* Foundation Resources */ = { + isa = PBXGroup; + children = ( + DA8933B31CCD2C2500E68420 /* Foundation.strings */, + DA8933B61CCD2C2D00E68420 /* Foundation.stringsdict */, + ); + name = "Foundation Resources"; + path = ../../darwin/resources; + sourceTree = ""; + }; + DAE6C31E1CC308BC00DB3429 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */, + DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */, + DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */, + DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; + DAE6C3291CC30DB200DB3429 /* SDK */ = { + isa = PBXGroup; + children = ( + DAE6C3C11CC31F4500DB3429 /* Mapbox.h */, + DAE6C3491CC31DF500DB3429 /* Foundation */, + DA8933B21CCD2C0700E68420 /* Foundation Resources */, + DAE6C39E1CC31E7C00DB3429 /* Kit */, + DA8933A81CCD28D100E68420 /* Kit Resources */, + DAE6C32C1CC30DB200DB3429 /* Info.plist */, + ); + name = SDK; + path = sdk; + sourceTree = ""; + }; + DAE6C3371CC30DB200DB3429 /* SDK Tests */ = { + isa = PBXGroup; + children = ( + DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */, + DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */, + DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */, + DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */, + DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */, + DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */, + DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */, + DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */, + DAE6C33A1CC30DB200DB3429 /* Info.plist */, + ); + name = "SDK Tests"; + path = test; + sourceTree = ""; + }; + DAE6C3491CC31DF500DB3429 /* Foundation */ = { + isa = PBXGroup; + children = ( + DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */, + DAE6C36A1CC31E2A00DB3429 /* MGLAccountManager_Private.h */, + DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */, + DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */, + DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */, + DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */, + DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */, + DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */, + DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */, + DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */, + DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */, + DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */, + DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */, + DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */, + DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */, + DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */, + DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */, + DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */, + DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */, + DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */, + DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */, + DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */, + DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */, + DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */, + DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */, + DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */, + DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */, + DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */, + DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */, + DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */, + DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */, + DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */, + DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */, + DAE6C3561CC31E0400DB3429 /* MGLShape.h */, + DAE6C3791CC31E2A00DB3429 /* MGLShape.m */, + DAE6C3571CC31E0400DB3429 /* MGLStyle.h */, + DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */, + DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */, + DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */, + DAE6C3591CC31E0400DB3429 /* MGLTypes.h */, + DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */, + DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */, + DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */, + DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */, + DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */, + DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */, + DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */, + DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */, + DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */, + DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */, + ); + name = Foundation; + path = ../darwin/src; + sourceTree = SOURCE_ROOT; + }; + DAE6C39E1CC31E7C00DB3429 /* Kit */ = { + isa = PBXGroup; + children = ( + DAE6C39F1CC31E9400DB3429 /* MGLAnnotationImage.h */, + DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */, + DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */, + DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */, + DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */, + DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */, + DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */, + DAE6C3A01CC31E9400DB3429 /* MGLMapView.h */, + DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */, + DAE6C3AD1CC31EF300DB3429 /* MGLMapView.mm */, + DAE6C3A11CC31E9400DB3429 /* MGLMapView+IBAdditions.h */, + DAE6C3AE1CC31EF300DB3429 /* MGLMapView+IBAdditions.m */, + DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */, + DAE6C3AF1CC31EF300DB3429 /* MGLOpenGLLayer.h */, + DAE6C3B01CC31EF300DB3429 /* MGLOpenGLLayer.mm */, + ); + name = Kit; + path = src; + sourceTree = SOURCE_ROOT; + }; + DAE6C3C41CC31F7800DB3429 /* Configuration */ = { + isa = PBXGroup; + children = ( + DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */, + ); + name = Configuration; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + DAE6C3251CC30DB200DB3429 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DAE6C38D1CC31E2A00DB3429 /* MGLOfflineRegion_Private.h in Headers */, + DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */, + DAE6C3B61CC31EF300DB3429 /* MGLMapView_Private.h in Headers */, + DAE6C3B21CC31EF300DB3429 /* MGLAttributionButton.h in Headers */, + DAE6C3A31CC31E9400DB3429 /* MGLAnnotationImage.h in Headers */, + DAE6C3A41CC31E9400DB3429 /* MGLMapView.h in Headers */, + DAE6C3611CC31E0400DB3429 /* MGLOfflineStorage.h in Headers */, + DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */, + DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */, + DAE6C3631CC31E0400DB3429 /* MGLPointAnnotation.h in Headers */, + DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */, + DAE6C35F1CC31E0400DB3429 /* MGLOfflinePack.h in Headers */, + DAE6C39C1CC31E2A00DB3429 /* NSString+MGLAdditions.h in Headers */, + DAE6C3861CC31E2A00DB3429 /* MGLGeometry_Private.h in Headers */, + DAE6C3841CC31E2A00DB3429 /* MGLAccountManager_Private.h in Headers */, + DAE6C3691CC31E0400DB3429 /* MGLTypes.h in Headers */, + DAE6C3991CC31E2A00DB3429 /* NSException+MGLAdditions.h in Headers */, + DAE6C3661CC31E0400DB3429 /* MGLShape.h in Headers */, + DAE6C3C21CC31F4500DB3429 /* Mapbox.h in Headers */, + DAE6C3641CC31E0400DB3429 /* MGLPolygon.h in Headers */, + DA35A2BF1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h in Headers */, + DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */, + DAE6C3621CC31E0400DB3429 /* MGLOverlay.h in Headers */, + DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */, + DAE6C39A1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h in Headers */, + DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */, + DAE6C3601CC31E0400DB3429 /* MGLOfflineRegion.h in Headers */, + DAE6C3681CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h in Headers */, + DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */, + DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */, + DAE6C38B1CC31E2A00DB3429 /* MGLOfflinePack_Private.h in Headers */, + DAE6C35C1CC31E0400DB3429 /* MGLGeometry.h in Headers */, + DAE6C35A1CC31E0400DB3429 /* MGLAccountManager.h in Headers */, + DAE6C35D1CC31E0400DB3429 /* MGLMapCamera.h in Headers */, + DAE6C3B41CC31EF300DB3429 /* MGLCompassCell.h in Headers */, + DAE6C3B91CC31EF300DB3429 /* MGLOpenGLLayer.h in Headers */, + DAE6C3891CC31E2A00DB3429 /* MGLMultiPoint_Private.h in Headers */, + DAE6C3A51CC31E9400DB3429 /* MGLMapView+IBAdditions.h in Headers */, + DA35A2AD1CCA091800E826B2 /* MGLCompassDirectionFormatter.h in Headers */, + DAE6C3671CC31E0400DB3429 /* MGLStyle.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXLegacyTarget section */ + DAAA17961CE13BAE00731EFE /* docs */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "xdocument OUTPUT=build/macos/pkg/documentation"; + buildConfigurationList = DAAA17991CE13BAE00731EFE /* Build configuration list for PBXLegacyTarget "docs" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ../../; + dependencies = ( + ); + name = docs; + passBuildSettingsInEnvironment = 1; + productName = docs; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXNativeTarget section */ + DA839E911CC2E3400062CAFB /* macosapp */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "macosapp" */; + buildPhases = ( + DA839E8E1CC2E3400062CAFB /* Sources */, + DA839E8F1CC2E3400062CAFB /* Frameworks */, + DA839E901CC2E3400062CAFB /* Resources */, + DAE6C3221CC30B3C00DB3429 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + DAE6C33C1CC30DB200DB3429 /* PBXTargetDependency */, + ); + name = macosapp; + productName = macosapp; + productReference = DA839E921CC2E3400062CAFB /* Mapbox GL.app */; + productType = "com.apple.product-type.application"; + }; + DAE6C3271CC30DB200DB3429 /* dynamic */ = { + isa = PBXNativeTarget; + buildConfigurationList = DAE6C3431CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "dynamic" */; + buildPhases = ( + DAE6C3231CC30DB200DB3429 /* Sources */, + DAE6C3241CC30DB200DB3429 /* Frameworks */, + DAE6C3251CC30DB200DB3429 /* Headers */, + DAE6C3261CC30DB200DB3429 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dynamic; + productName = dynamic; + productReference = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; + productType = "com.apple.product-type.framework"; + }; + DAE6C3301CC30DB200DB3429 /* test */ = { + isa = PBXNativeTarget; + buildConfigurationList = DAE6C3441CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "test" */; + buildPhases = ( + DAE6C32D1CC30DB200DB3429 /* Sources */, + DAE6C32E1CC30DB200DB3429 /* Frameworks */, + DAE6C32F1CC30DB200DB3429 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + DAE6C3341CC30DB200DB3429 /* PBXTargetDependency */, + ); + name = test; + productName = dynamicTests; + productReference = DAE6C3311CC30DB200DB3429 /* test.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + DA839E8A1CC2E3400062CAFB /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = MBX; + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Mapbox; + TargetAttributes = { + DA839E911CC2E3400062CAFB = { + CreatedOnToolsVersion = 7.3; + }; + DAAA17961CE13BAE00731EFE = { + CreatedOnToolsVersion = 7.3.1; + }; + DAE6C3271CC30DB200DB3429 = { + CreatedOnToolsVersion = 7.3; + }; + DAE6C3301CC30DB200DB3429 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "macos" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = DA839E891CC2E3400062CAFB; + productRefGroup = DA839E931CC2E3400062CAFB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DA839E911CC2E3400062CAFB /* macosapp */, + DAE6C3271CC30DB200DB3429 /* dynamic */, + DAE6C3301CC30DB200DB3429 /* test */, + DAAA17961CE13BAE00731EFE /* docs */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + DA839E901CC2E3400062CAFB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA839EA21CC2E3400062CAFB /* Assets.xcassets in Resources */, + DA839EA01CC2E3400062CAFB /* MapDocument.xib in Resources */, + DA839EA51CC2E3400062CAFB /* MainMenu.xib in Resources */, + DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C3261CC30DB200DB3429 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA8933AE1CCD290700E68420 /* Localizable.strings in Resources */, + DAE6C3BE1CC31F2E00DB3429 /* default_marker.pdf in Resources */, + DAE6C3BF1CC31F2E00DB3429 /* mapbox.pdf in Resources */, + DA8933A51CCD287300E68420 /* MGLAnnotationCallout.xib in Resources */, + DA8933B51CCD2C2500E68420 /* Foundation.strings in Resources */, + DA8933B81CCD2C2D00E68420 /* Foundation.stringsdict in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C32F1CC30DB200DB3429 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + DA839E8E1CC2E3400062CAFB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA839E9D1CC2E3400062CAFB /* MapDocument.m in Sources */, + DAE6C2ED1CC3050F00DB3429 /* DroppedPinAnnotation.m in Sources */, + DAE6C2EE1CC3050F00DB3429 /* LocationCoordinate2DTransformer.m in Sources */, + DAE6C2F11CC3050F00DB3429 /* TimeIntervalTransformer.m in Sources */, + DA839E9A1CC2E3400062CAFB /* main.m in Sources */, + DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */, + DAE6C2F01CC3050F00DB3429 /* OfflinePackNameValueTransformer.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C3231CC30DB200DB3429 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DAE6C3901CC31E2A00DB3429 /* MGLPointAnnotation.m in Sources */, + DAE6C3981CC31E2A00DB3429 /* NSBundle+MGLAdditions.m in Sources */, + DAE6C3B71CC31EF300DB3429 /* MGLMapView.mm in Sources */, + DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */, + DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */, + DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */, + DAE6C3931CC31E2A00DB3429 /* MGLShape.m in Sources */, + DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */, + DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */, + DAE6C3871CC31E2A00DB3429 /* MGLGeometry.mm in Sources */, + DAE6C3B81CC31EF300DB3429 /* MGLMapView+IBAdditions.m in Sources */, + DA35A2D01CCAAED300E826B2 /* NSValue+MGLAdditions.m in Sources */, + DA35A2C01CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m in Sources */, + DAE6C3BA1CC31EF300DB3429 /* MGLOpenGLLayer.mm in Sources */, + DAE6C38A1CC31E2A00DB3429 /* MGLMultiPoint.mm in Sources */, + DAE6C3961CC31E2A00DB3429 /* MGLTypes.m in Sources */, + DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */, + DAE6C3881CC31E2A00DB3429 /* MGLMapCamera.mm in Sources */, + DAE6C3911CC31E2A00DB3429 /* MGLPolygon.mm in Sources */, + DAE6C39B1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m in Sources */, + DAE6C38F1CC31E2A00DB3429 /* MGLOfflineStorage.mm in Sources */, + DAE6C3951CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm in Sources */, + DAE6C3851CC31E2A00DB3429 /* MGLAccountManager.m in Sources */, + DAE6C3921CC31E2A00DB3429 /* MGLPolyline.mm in Sources */, + DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */, + DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAE6C32D1CC30DB200DB3429 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA35A2C21CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m in Sources */, + DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */, + DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */, + DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */, + DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */, + DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */, + DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */, + DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + DAE6C3341CC30DB200DB3429 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DAE6C3271CC30DB200DB3429 /* dynamic */; + targetProxy = DAE6C3331CC30DB200DB3429 /* PBXContainerItemProxy */; + }; + DAE6C33C1CC30DB200DB3429 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DAE6C3271CC30DB200DB3429 /* dynamic */; + targetProxy = DAE6C33B1CC30DB200DB3429 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + DA839E9E1CC2E3400062CAFB /* MapDocument.xib */ = { + isa = PBXVariantGroup; + children = ( + DA839E9F1CC2E3400062CAFB /* Base */, + ); + name = MapDocument.xib; + sourceTree = ""; + }; + DA839EA31CC2E3400062CAFB /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + DA839EA41CC2E3400062CAFB /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; + DA8933A71CCD287300E68420 /* MGLAnnotationCallout.xib */ = { + isa = PBXVariantGroup; + children = ( + DA8933A61CCD287300E68420 /* Base */, + ); + name = MGLAnnotationCallout.xib; + sourceTree = ""; + }; + DA8933AB1CCD290700E68420 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + DA8933AC1CCD290700E68420 /* Base */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + DA8933B31CCD2C2500E68420 /* Foundation.strings */ = { + isa = PBXVariantGroup; + children = ( + DA8933B41CCD2C2500E68420 /* Base */, + ); + name = Foundation.strings; + sourceTree = ""; + }; + DA8933B61CCD2C2D00E68420 /* Foundation.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + DA8933B71CCD2C2D00E68420 /* en */, + ); + name = Foundation.stringsdict; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + DA839EA71CC2E3400062CAFB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + DA839EA81CC2E3400062CAFB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + DA839EAA1CC2E3400062CAFB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; + PRODUCT_NAME = "Mapbox GL"; + }; + name = Debug; + }; + DA839EAB1CC2E3400062CAFB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; + PRODUCT_NAME = "Mapbox GL"; + }; + name = Release; + }; + DAAA17971CE13BAE00731EFE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + DEBUGGING_SYMBOLS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DAAA17981CE13BAE00731EFE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + DAE6C33F1CC30DB200DB3429 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = ( + ../default, + ../../include, + ../../src, + ); + INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "$(zlib_cflags)", + "$(rapidjson_cflags)", + "$(variant_cflags)", + "$(geometry_cflags)", + ); + OTHER_LDFLAGS = ( + "$(zlib_ldflags)", + "$(opengl_ldflags)", + "$(geojsonvt_static_libs)", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; + PRODUCT_NAME = Mapbox; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + DAE6C3401CC30DB200DB3429 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = ( + ../default, + ../../include, + ../../src, + ); + INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "$(zlib_cflags)", + "$(rapidjson_cflags)", + "$(variant_cflags)", + "$(geometry_cflags)", + ); + OTHER_LDFLAGS = ( + "$(zlib_ldflags)", + "$(opengl_ldflags)", + "$(geojsonvt_static_libs)", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; + PRODUCT_NAME = Mapbox; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + DAE6C3411CC30DB200DB3429 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ../../include; + INFOPLIST_FILE = test/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "$(geometry_cflags)", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DAE6C3421CC30DB200DB3429 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ../../include; + INFOPLIST_FILE = test/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "$(geometry_cflags)", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "macos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA839EA71CC2E3400062CAFB /* Debug */, + DA839EA81CC2E3400062CAFB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "macosapp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA839EAA1CC2E3400062CAFB /* Debug */, + DA839EAB1CC2E3400062CAFB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DAAA17991CE13BAE00731EFE /* Build configuration list for PBXLegacyTarget "docs" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAAA17971CE13BAE00731EFE /* Debug */, + DAAA17981CE13BAE00731EFE /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + DAE6C3431CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "dynamic" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAE6C33F1CC30DB200DB3429 /* Debug */, + DAE6C3401CC30DB200DB3429 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DAE6C3441CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAE6C3411CC30DB200DB3429 /* Debug */, + DAE6C3421CC30DB200DB3429 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = DA839E8A1CC2E3400062CAFB /* Project object */; +} diff --git a/platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..f2c779de46 --- /dev/null +++ b/platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme new file mode 100644 index 0000000000..476532377d --- /dev/null +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme new file mode 100644 index 0000000000..1d1c9de8c5 --- /dev/null +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme new file mode 100644 index 0000000000..3e3baa8325 --- /dev/null +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcworkspace/contents.xcworkspacedata b/platform/macos/macos.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..67a33490e9 --- /dev/null +++ b/platform/macos/macos.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist b/platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000000..cb6ecad738 --- /dev/null +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme new file mode 100644 index 0000000000..90ba9db153 --- /dev/null +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme new file mode 100644 index 0000000000..c176861999 --- /dev/null +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme new file mode 100644 index 0000000000..20394eb258 --- /dev/null +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/platform.gyp b/platform/macos/platform.gyp new file mode 100644 index 0000000000..f748708b2c --- /dev/null +++ b/platform/macos/platform.gyp @@ -0,0 +1,90 @@ +{ + 'variables': { + 'loop_lib': 'darwin', + 'headless_lib': 'cgl', + 'coverage': 0, + }, + 'includes': [ + '../../build/macos/config.gypi', + '../../mbgl.gypi', + '../../test/test.gypi', + '../../bin/glfw.gypi', + '../../bin/render.gypi', + '../../bin/offline.gypi', + ], + 'targets': [ + { + 'target_name': 'test', + 'type': 'executable', + + 'dependencies': [ + 'test-lib', + 'platform-lib', + ], + + 'sources': [ + '../../test/src/main.cpp', + ], + }, + { + 'target_name': 'platform-lib', + 'product_name': 'mbgl-platform-macos', + 'type': 'static_library', + 'standalone_static_library': 1, + 'hard_dependency': 1, + 'dependencies': [ + 'core', + ], + + 'include_dirs': [ + 'include', + '../darwin/include', + '../default', + '../../include', + '../../src', # TODO: eliminate + '<(SHARED_INTERMEDIATE_DIR)/include', + ], + + 'sources': [ + '../default/asset_file_source.cpp', + '../default/default_file_source.cpp', + '../default/online_file_source.cpp', + '../default/mbgl/storage/offline.hpp', + '../default/mbgl/storage/offline.cpp', + '../default/mbgl/storage/offline_database.hpp', + '../default/mbgl/storage/offline_database.cpp', + '../default/mbgl/storage/offline_download.hpp', + '../default/mbgl/storage/offline_download.cpp', + '../default/sqlite3.hpp', + '../default/sqlite3.cpp', + '../darwin/src/http_file_source.mm', + '../darwin/src/log_nslog.mm', + '../darwin/src/string_nsstring.mm', + '../darwin/src/image.mm', + '../darwin/src/nsthread.mm', + '../darwin/src/reachability.m', + ], + + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': [ + '<@(sqlite_cflags)', + '<@(zlib_cflags)', + '<@(rapidjson_cflags)', + ], + 'CLANG_ENABLE_OBJC_ARC': 'YES', + 'CLANG_ENABLE_MODULES': 'YES', + }, + + 'link_settings': { + 'libraries': [ + '<@(sqlite_static_libs)', + '<@(zlib_static_libs)', + '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework', + ], + 'xcode_settings': { + 'OTHER_LDFLAGS': [ '<@(zlib_ldflags)' ], + }, + }, + }, + ], +} diff --git a/platform/macos/screenshot.png b/platform/macos/screenshot.png new file mode 100644 index 0000000000..3bf0c46ab0 Binary files /dev/null and b/platform/macos/screenshot.png differ diff --git a/platform/macos/scripts/configure.sh b/platform/macos/scripts/configure.sh new file mode 100644 index 0000000000..f009bae4f6 --- /dev/null +++ b/platform/macos/scripts/configure.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +PROTOZERO_VERSION=1.3.0 +BOOST_VERSION=1.60.0 +BOOST_LIBPROGRAM_OPTIONS_VERSION=1.60.0 +GLFW_VERSION=3.1.2 +SQLITE_VERSION=3.9.1 +ZLIB_VERSION=system +NUNICODE_VERSION=1.6 +GEOMETRY_VERSION=0.5.0 +GEOJSONVT_VERSION=4.1.2 +VARIANT_VERSION=1.1.0 +RAPIDJSON_VERSION=1.0.2 +GTEST_VERSION=1.7.0 +PIXELMATCH_VERSION=0.9.0 diff --git a/platform/macos/scripts/document.sh b/platform/macos/scripts/document.sh new file mode 100755 index 0000000000..e62a1e1668 --- /dev/null +++ b/platform/macos/scripts/document.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +if [ -z `which jazzy` ]; then + echo "Installing jazzy…" + gem install jazzy + if [ -z `which jazzy` ]; then + echo "Unable to install jazzy. See https://github.com/mapbox/mapbox-gl-native/blob/master/platform/macos/INSTALL.md" + exit 1 + fi +fi + +OUTPUT=${OUTPUT:-documentation} + +BRANCH=$( git describe --tags --match=macos-v*.*.* --abbrev=0 ) +SHORT_VERSION=$( echo ${BRANCH} | sed 's/^macos-v//' ) +RELEASE_VERSION=$( echo ${SHORT_VERSION} | sed -e 's/^macos-v//' -e 's/-.*//' ) + +SWIFT_VERSION=$(xcrun swift -version | head -n 1 | sed -e 's/^Apple Swift version //' -e 's/ .*$//') + +rm -rf /tmp/mbgl +mkdir -p /tmp/mbgl/ +README=/tmp/mbgl/README.md +cp platform/macos/docs/doc-README.md "${README}" +# http://stackoverflow.com/a/4858011/4585461 +echo "## Changes in version ${RELEASE_VERSION}" >> "${README}" +sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^##/q' -e 'p' -e 'ba' -e '}' platform/macos/CHANGELOG.md >> "${README}" + +rm -rf ${OUTPUT} +mkdir -p ${OUTPUT} + +jazzy \ + --config platform/macos/jazzy.yml \ + --sdk macosx \ + --swift-version $SWIFT_VERSION \ + --github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \ + --module-version ${SHORT_VERSION} \ + --readme ${README} \ + --output ${OUTPUT} +# https://github.com/realm/jazzy/issues/411 +find ${OUTPUT} -name *.html -exec \ + perl -pi -e 's/Mapbox\s+(Docs|Reference)/Mapbox macOS SDK $1/' {} \; diff --git a/platform/macos/scripts/macostest.xcscheme b/platform/macos/scripts/macostest.xcscheme new file mode 100644 index 0000000000..ba6f6a6f4b --- /dev/null +++ b/platform/macos/scripts/macostest.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/scripts/package.sh b/platform/macos/scripts/package.sh new file mode 100755 index 0000000000..a6952e8ab2 --- /dev/null +++ b/platform/macos/scripts/package.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail +set -u + +NAME=Mapbox +OUTPUT=build/macos/pkg +DERIVED_DATA=build/macos +PRODUCTS=${DERIVED_DATA}/Build/Products + +BUILDTYPE=${BUILDTYPE:-Release} +GCC_GENERATE_DEBUGGING_SYMBOLS=${SYMBOLS:-YES} + +function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; } +function finish { >&2 echo -en "\033[0m"; } +trap finish EXIT + +rm -rf ${OUTPUT} + +HASH=`git log | head -1 | awk '{ print $2 }' | cut -c 1-10` && true +PROJ_VERSION=$(git rev-list --count HEAD) +SEM_VERSION=$( git describe --tags --match=macos-v*.*.* --abbrev=0 | sed 's/^macos-v//' ) +SHORT_VERSION=${SEM_VERSION%-*} + +step "Building targets (build ${PROJ_VERSION}, version ${SEM_VERSION})…" +xcodebuild \ + GCC_GENERATE_DEBUGGING_SYMBOLS=${GCC_GENERATE_DEBUGGING_SYMBOLS} \ + CURRENT_PROJECT_VERSION=${PROJ_VERSION} \ + CURRENT_SHORT_VERSION=${SHORT_VERSION} \ + CURRENT_SEMANTIC_VERSION=${SEM_VERSION} \ + CURRENT_COMMIT_HASH=${HASH} \ + -derivedDataPath ${DERIVED_DATA} \ + -workspace ./platform/macos/macos.xcworkspace \ + -scheme dynamic \ + -configuration ${BUILDTYPE} \ + -jobs ${JOBS} | xcpretty + +step "Copying dynamic framework into place" +mkdir -p "${OUTPUT}/${NAME}.framework" +cp -r ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework/* "${OUTPUT}/${NAME}.framework" +if [[ -e ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework.dSYM ]]; then + cp -r ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework.dSYM "${OUTPUT}" +fi + +if [[ "${GCC_GENERATE_DEBUGGING_SYMBOLS}" == false ]]; then + step "Stripping binaries…" + strip -Sx "${OUTPUT}/${NAME}.framework/${NAME}" +fi + +step "Copying library resources…" +cp -pv LICENSE.md "${OUTPUT}" +cp -pv platform/macos/docs/pod-README.md "${OUTPUT}/README.md" +sed -n -e '/^## /,$p' platform/macos/CHANGELOG.md > "${OUTPUT}/CHANGELOG.md" + +step "Generating API documentation…" +make xdocument OUTPUT="${OUTPUT}/documentation" diff --git a/platform/macos/sdk/Base.lproj/Localizable.strings b/platform/macos/sdk/Base.lproj/Localizable.strings new file mode 100644 index 0000000000..818c82b2ec --- /dev/null +++ b/platform/macos/sdk/Base.lproj/Localizable.strings @@ -0,0 +1,30 @@ +/* Linked part of copyright notice */ +"COPYRIGHT_MAPBOX" = "Mapbox"; + +/* Copyright notice link */ +"COPYRIGHT_MAPBOX_LINK" = "https://www.mapbox.com/about/maps/"; + +/* Linked part of copyright notice */ +"COPYRIGHT_OSM" = "OpenStreetMap"; + +/* Copyright notice link */ +"COPYRIGHT_OSM_LINK" = "http://www.openstreetmap.org/about/"; + +/* Copyright notice prefix */ +"COPYRIGHT_PREFIX" = "© "; + +/* Accessibility title */ +"MAP_A11Y_TITLE" = "Mapbox"; + +/* Label of Zoom In button */ +"ZOOM_IN_LABEL" = "+"; + +/* Tooltip of Zoom In button */ +"ZOOM_IN_TOOLTIP" = "Zoom In"; + +/* Label of Zoom Out button; U+2212 MINUS SIGN */ +"ZOOM_OUT_LABEL" = "−"; + +/* Tooltip of Zoom Out button */ +"ZOOM_OUT_TOOLTIP" = "Zoom Out"; + diff --git a/platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib b/platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib new file mode 100644 index 0000000000..c8e29bc29e --- /dev/null +++ b/platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/sdk/Info.plist b/platform/macos/sdk/Info.plist new file mode 100644 index 0000000000..3b2b38a58a --- /dev/null +++ b/platform/macos/sdk/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleShortVersionString + 1.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/platform/macos/sdk/default_marker.pdf b/platform/macos/sdk/default_marker.pdf new file mode 100644 index 0000000000..4e2e332301 Binary files /dev/null and b/platform/macos/sdk/default_marker.pdf differ diff --git a/platform/macos/sdk/mapbox.pdf b/platform/macos/sdk/mapbox.pdf new file mode 100644 index 0000000000..c08a0e3135 Binary files /dev/null and b/platform/macos/sdk/mapbox.pdf differ diff --git a/platform/macos/src/MGLAnnotationImage.h b/platform/macos/src/MGLAnnotationImage.h new file mode 100644 index 0000000000..ad44993ee1 --- /dev/null +++ b/platform/macos/src/MGLAnnotationImage.h @@ -0,0 +1,64 @@ +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + The `MGLAnnotationImage` class is responsible for presenting point-based + annotations visually on an `MGLMapView` instance. Annotation image objects pair + `NSImage` objects with annotation-related metadata. They may be recycled later + and put into a reuse queue that is maintained by the map view. + */ +@interface MGLAnnotationImage : NSObject + +#pragma mark Initializing and Preparing the Image Object + +/** + Initializes and returns a new annotation image object. + + @param image The image to display for the annotation. + @param reuseIdentifier The string that identifies this annotation image in the + reuse queue. + @return The initialized annotation image object or `nil` if there was a problem + initializing the object. + */ ++ (instancetype)annotationImageWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier; + +#pragma mark Getting and Setting Attributes + +/** The image to display for the annotation. */ +@property (nonatomic, readonly) NSImage *image; + +/** + The string that identifies this annotation image in the reuse queue. + (read-only) + + You specify the reuse identifier when you create the image object. You use this + type later to retrieve an annotation image object that was created previously + but which is currently unused because its annotation is not on-screen. + + If you define distinctly different types of annotations (with distinctly + different annotation images to go with them), you can differentiate between the + annotation types by specifying different reuse identifiers for each one. + */ +@property (nonatomic, readonly) NSString *reuseIdentifier; + +/** + A Boolean value indicating whether the annotation is selectable. + + The default value of this property is `YES`. If the value of this property is + `NO`, the annotation image ignores click events and cannot be selected. + */ +@property (nonatomic, getter=isSelectable) BOOL selectable; + +/** + The cursor that appears above any annotation using this annotation image. + + By default, this property is set to `nil`, representing the current cursor. + */ +@property (nonatomic, nullable) NSCursor *cursor; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/macos/src/MGLAnnotationImage.m b/platform/macos/src/MGLAnnotationImage.m new file mode 100644 index 0000000000..1b545651d2 --- /dev/null +++ b/platform/macos/src/MGLAnnotationImage.m @@ -0,0 +1,26 @@ +#import "MGLAnnotationImage_Private.h" + +@interface MGLAnnotationImage () + +@property (nonatomic) NSImage *image; +@property (nonatomic) NSString *reuseIdentifier; +@property (nonatomic, strong, nullable) NSString *styleIconIdentifier; + +@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 diff --git a/platform/macos/src/MGLAnnotationImage_Private.h b/platform/macos/src/MGLAnnotationImage_Private.h new file mode 100644 index 0000000000..21963a86a0 --- /dev/null +++ b/platform/macos/src/MGLAnnotationImage_Private.h @@ -0,0 +1,8 @@ +#import + +@interface MGLAnnotationImage (Private) + +/// Unique identifier of the sprite image used by the style to represent the receiver’s `image`. +@property (nonatomic, strong, nullable) NSString *styleIconIdentifier; + +@end diff --git a/platform/macos/src/MGLAttributionButton.h b/platform/macos/src/MGLAttributionButton.h new file mode 100644 index 0000000000..9ff3137849 --- /dev/null +++ b/platform/macos/src/MGLAttributionButton.h @@ -0,0 +1,15 @@ +#import + +/// Button that looks like a hyperlink and opens a URL. +@interface MGLAttributionButton : NSButton + +/// Returns an `MGLAttributionButton` instance with the given title and URL. +- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url; + +/// The URL to open and display as a tooltip. +@property (nonatomic) NSURL *URL; + +/// Opens the URL. +- (IBAction)openURL:(id)sender; + +@end diff --git a/platform/macos/src/MGLAttributionButton.m b/platform/macos/src/MGLAttributionButton.m new file mode 100644 index 0000000000..e21b860794 --- /dev/null +++ b/platform/macos/src/MGLAttributionButton.m @@ -0,0 +1,50 @@ +#import "MGLAttributionButton.h" + +#import "NSBundle+MGLAdditions.h" + +@implementation MGLAttributionButton { + NSTrackingRectTag _trackingAreaTag; +} + +- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url { + if (self = [super initWithFrame:NSZeroRect]) { + self.bordered = NO; + self.bezelStyle = NSRegularSquareBezelStyle; + + // Start with a copyright symbol. The whole string will be mini. + NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:NSLocalizedStringWithDefaultValue(@"COPYRIGHT_PREFIX", nil, nil, @"© ", @"Copyright notice prefix") attributes:@{ + NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]], + }]; + // Append the specified title, underlining it like a hyperlink. + [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 { + // The whole button gets a pointing hand cursor, just like a hyperlink. + [self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]]; +} + +- (IBAction)openURL:(__unused id)sender { + [[NSWorkspace sharedWorkspace] openURL:self.URL]; +} + +@end diff --git a/platform/macos/src/MGLCompassCell.h b/platform/macos/src/MGLCompassCell.h new file mode 100644 index 0000000000..5ed70dcb06 --- /dev/null +++ b/platform/macos/src/MGLCompassCell.h @@ -0,0 +1,5 @@ +#import + +/// Circular slider with an arrow pointing north. +@interface MGLCompassCell : NSSliderCell +@end diff --git a/platform/macos/src/MGLCompassCell.m b/platform/macos/src/MGLCompassCell.m new file mode 100644 index 0000000000..b3a4ad4544 --- /dev/null +++ b/platform/macos/src/MGLCompassCell.m @@ -0,0 +1,34 @@ +#import "MGLCompassCell.h" + +@implementation MGLCompassCell + +- (instancetype)init { + if (self = [super init]) { + self.sliderType = NSCircularSlider; + // A tick mark for each cardinal direction. + self.numberOfTickMarks = 4; + // This slider goes backwards! + self.minValue = -360; + self.maxValue = 0; + } + return self; +} + +- (void)drawKnob:(NSRect)knobRect { + // Draw a red triangle pointing whichever way the slider is facing. + 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 diff --git a/platform/macos/src/MGLMapView+IBAdditions.h b/platform/macos/src/MGLMapView+IBAdditions.h new file mode 100644 index 0000000000..81f4506a57 --- /dev/null +++ b/platform/macos/src/MGLMapView+IBAdditions.h @@ -0,0 +1,68 @@ +#import + +#import "MGLMapView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLMapView (IBAdditions) + +#if TARGET_INTERFACE_BUILDER + +// 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. + +// 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. + +/** URL of the style currently displayed in the receiver. + + The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s + map ID (`mapbox://styles//