summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2017-01-16 15:08:17 -0800
committerMinh Nguyễn <mxn@1ec5.org>2017-01-16 15:08:17 -0800
commitcf166717b8e616a3599038ffff440b50251ed7b8 (patch)
tree74d06c35bdf0d6f970c63c988baef26650515afb
parentbd71eb8681529ab70ff892b12128f8b7a5faa4c7 (diff)
parent7ef2843e6a62116667be6a2c12de085951fdd5ea (diff)
downloadqtlocation-mapboxgl-cf166717b8e616a3599038ffff440b50251ed7b8.tar.gz
Merge branch '1ec5-release-ios-v3.4.0-beta.7'
-rw-r--r--Makefile9
-rw-r--r--include/mbgl/style/filter.hpp60
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp2
-rw-r--r--include/mbgl/style/sources/raster_source.hpp3
-rw-r--r--include/mbgl/style/sources/vector_source.hpp3
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs321
-rw-r--r--platform/darwin/docs/guides/Working with GeoJSON Data.md99
-rw-r--r--platform/darwin/docs/theme/assets/css/jazzy.css.scss25
-rwxr-xr-xplatform/darwin/docs/theme/assets/js/jazzy.js5
-rw-r--r--platform/darwin/docs/theme/templates/nav.mustache2
-rw-r--r--platform/darwin/scripts/generate-style-code.js327
-rw-r--r--platform/darwin/scripts/style-spec-cocoa-conventions-v8.json26
-rw-r--r--platform/darwin/scripts/style-spec-overrides-v8.json27
-rw-r--r--platform/darwin/scripts/update-examples.js152
-rw-r--r--platform/darwin/src/MGLAttributionInfo.h2
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm13
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.h46
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.mm3
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h211
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm108
-rw-r--r--platform/darwin/src/MGLFeature.h138
-rw-r--r--platform/darwin/src/MGLFeature.mm31
-rw-r--r--platform/darwin/src/MGLFeature_Private.h28
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h165
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm67
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h265
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm87
-rw-r--r--platform/darwin/src/MGLMultiPoint.h19
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm38
-rw-r--r--platform/darwin/src/MGLNetworkConfiguration.m4
-rw-r--r--platform/darwin/src/MGLOfflinePack.h4
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h14
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm18
-rw-r--r--platform/darwin/src/MGLOverlay.h5
-rw-r--r--platform/darwin/src/MGLPointAnnotation.h32
-rw-r--r--platform/darwin/src/MGLPointAnnotation.mm36
-rw-r--r--platform/darwin/src/MGLPointCollection.h27
-rw-r--r--platform/darwin/src/MGLPointCollection.mm42
-rw-r--r--platform/darwin/src/MGLPolygon.h58
-rw-r--r--platform/darwin/src/MGLPolygon.mm55
-rw-r--r--platform/darwin/src/MGLPolyline.h58
-rw-r--r--platform/darwin/src/MGLPolyline.mm30
-rw-r--r--platform/darwin/src/MGLRasterSource.h14
-rw-r--r--platform/darwin/src/MGLRasterSource.mm8
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h81
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.mm28
-rw-r--r--platform/darwin/src/MGLShape.h55
-rw-r--r--platform/darwin/src/MGLShape.mm66
-rw-r--r--platform/darwin/src/MGLShapeCollection.h24
-rw-r--r--platform/darwin/src/MGLShapeCollection.mm30
-rw-r--r--platform/darwin/src/MGLShapeSource.h78
-rw-r--r--platform/darwin/src/MGLShapeSource.mm16
-rw-r--r--platform/darwin/src/MGLShape_Private.h3
-rw-r--r--platform/darwin/src/MGLSource.h2
-rw-r--r--platform/darwin/src/MGLStyle.h35
-rw-r--r--platform/darwin/src/MGLStyle.mm34
-rw-r--r--platform/darwin/src/MGLStyleLayer.h.ejs94
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs58
-rw-r--r--platform/darwin/src/MGLStyleValue.h44
-rw-r--r--platform/darwin/src/MGLStyleValue.mm24
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h9
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h978
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm284
-rw-r--r--platform/darwin/src/MGLTileSource.h123
-rw-r--r--platform/darwin/src/MGLTileSource.mm6
-rw-r--r--platform/darwin/src/MGLVectorSource.h13
-rw-r--r--platform/darwin/src/MGLVectorSource.mm6
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.h30
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.m4
-rw-r--r--platform/darwin/src/NSArray+MGLAdditions.h15
-rw-r--r--platform/darwin/src/NSArray+MGLAdditions.mm28
-rw-r--r--platform/darwin/src/NSCoder+MGLAdditions.h16
-rw-r--r--platform/darwin/src/NSCoder+MGLAdditions.mm26
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm212
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm53
-rw-r--r--platform/darwin/src/NSDictionary+MGLAdditions.mm2
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.h10
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm73
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.mm113
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h9
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m22
-rw-r--r--platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm8
-rw-r--r--platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h232
-rw-r--r--platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs66
-rw-r--r--platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm169
-rw-r--r--platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs46
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.m44
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.mm134
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.m85
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm413
-rw-r--r--platform/darwin/test/MGLCodingTests.m469
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift220
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm61
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm9
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.m69
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.mm306
-rw-r--r--platform/darwin/test/MGLFilterTests.mm194
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.m106
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm557
-rw-r--r--platform/darwin/test/MGLNSStringAdditionsTests.m42
-rw-r--r--platform/darwin/test/MGLPredicateTests.mm419
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.m68
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.mm277
-rw-r--r--platform/darwin/test/MGLRuntimeStylingHelper.h35
-rw-r--r--platform/darwin/test/MGLRuntimeStylingHelper.m122
-rw-r--r--platform/darwin/test/MGLShapeSourceTests.mm52
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.h11
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m59
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m.ejs72
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs114
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.xib39
-rw-r--r--platform/darwin/test/MGLStyleTests.mm139
-rw-r--r--platform/darwin/test/MGLStyleValueTests.swift8
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.m283
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm1797
-rw-r--r--platform/darwin/test/one-liner.json1
-rw-r--r--platform/ios/CHANGELOG.md16
-rw-r--r--platform/ios/DEVELOPING.md18
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec8
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec6
-rw-r--r--platform/ios/README.md2
-rw-r--r--platform/ios/app/MBXCustomCalloutView.h4
-rw-r--r--platform/ios/app/MBXCustomCalloutView.m7
-rw-r--r--platform/ios/app/MBXViewController.m71
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.mm2
-rw-r--r--platform/ios/docs/doc-README.md2
-rw-r--r--platform/ios/docs/guides/Adding Points to a Map.md83
-rw-r--r--platform/ios/docs/guides/For Style Authors.md306
-rw-r--r--platform/ios/docs/guides/Info.plist Keys.md (renamed from platform/ios/docs/Info.plist Keys.md)8
-rw-r--r--platform/ios/docs/guides/Runtime Styling.md53
-rw-r--r--platform/ios/docs/guides/Working with Mapbox Studio.md96
-rw-r--r--platform/ios/docs/img/runtime-styling/CustomAnnotations.gifbin0 -> 45604 bytes
-rw-r--r--platform/ios/docs/img/runtime-styling/DynamicStyles.gifbin0 -> 97235 bytes
-rw-r--r--platform/ios/docs/img/runtime-styling/Emoji.gifbin0 -> 177077 bytes
-rw-r--r--platform/ios/docs/img/runtime-styling/HexBins.gifbin0 -> 554029 bytes
-rw-r--r--platform/ios/docs/img/runtime-styling/Population.gifbin0 -> 247152 bytes
-rw-r--r--platform/ios/docs/img/runtime-styling/SnowLevels.gifbin0 -> 489450 bytes
-rw-r--r--platform/ios/docs/img/screenshot.png (renamed from platform/ios/screenshot.png)bin327733 -> 327733 bytes
-rw-r--r--platform/ios/docs/img/studio-workflow/add-properties.gifbin0 -> 239499 bytes
-rw-r--r--platform/ios/docs/img/studio-workflow/create-polygons.gifbin0 -> 1659146 bytes
-rw-r--r--platform/ios/docs/img/studio-workflow/property-values.pngbin0 -> 83518 bytes
-rw-r--r--platform/ios/docs/img/studio-workflow/stop-functions.pngbin0 -> 166947 bytes
-rw-r--r--platform/ios/docs/pod-README.md2
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj125
-rw-r--r--platform/ios/jazzy.yml76
-rwxr-xr-xplatform/ios/scripts/deploy-packages.sh2
-rwxr-xr-xplatform/ios/scripts/document.sh4
-rw-r--r--platform/ios/src/MGLAPIClient.h1
-rw-r--r--platform/ios/src/MGLAPIClient.m11
-rw-r--r--platform/ios/src/MGLAnnotationImage.h2
-rw-r--r--platform/ios/src/MGLAnnotationImage.m35
-rw-r--r--platform/ios/src/MGLAnnotationView.h2
-rw-r--r--platform/ios/src/MGLAnnotationView.mm28
-rw-r--r--platform/ios/src/MGLCalloutView.h18
-rw-r--r--platform/ios/src/MGLCompactCalloutView.m8
-rw-r--r--platform/ios/src/MGLMapView.h9
-rw-r--r--platform/ios/src/MGLMapView.mm89
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h17
-rw-r--r--platform/ios/src/MGLMapView_Private.h6
-rw-r--r--platform/ios/src/MGLMapboxEvents.m71
-rw-r--r--platform/ios/src/MGLUserLocation.h2
-rw-r--r--platform/ios/src/MGLUserLocation.m38
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/macos/CHANGELOG.md12
-rw-r--r--platform/macos/DEVELOPING.md26
-rw-r--r--platform/macos/INSTALL.md9
-rw-r--r--platform/macos/Mapbox-macOS-SDK-symbols.podspec30
-rw-r--r--platform/macos/Mapbox-macOS-SDK.podspec30
-rw-r--r--platform/macos/README.md22
-rw-r--r--platform/macos/app/Base.lproj/MapDocument.xib3
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.h7
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.m42
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.h15
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.m49
-rw-r--r--platform/macos/app/MapDocument.m96
-rw-r--r--platform/macos/docs/doc-README.md6
-rw-r--r--platform/macos/docs/guides/For Style Authors.md300
-rw-r--r--platform/macos/docs/guides/Info.plist Keys.md (renamed from platform/macos/docs/Info.plist Keys.md)8
-rw-r--r--platform/macos/docs/img/screenshot.jpgbin0 -> 445665 bytes
-rw-r--r--platform/macos/docs/pod-README.md31
-rw-r--r--platform/macos/jazzy.yml64
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj126
-rw-r--r--platform/macos/screenshot.pngbin680704 -> 0 bytes
-rwxr-xr-xplatform/macos/scripts/deploy-packages.sh98
-rwxr-xr-xplatform/macos/scripts/document.sh16
-rwxr-xr-xplatform/macos/scripts/package.sh13
-rw-r--r--platform/macos/src/MGLAnnotationImage.h2
-rw-r--r--platform/macos/src/MGLAnnotationImage.m37
-rw-r--r--platform/macos/src/MGLMapView.h9
-rw-r--r--platform/macos/src/MGLMapView.mm38
-rw-r--r--platform/macos/src/MGLMapViewDelegate.h19
-rw-r--r--platform/macos/src/MGLMapView_Private.h4
-rw-r--r--platform/macos/src/Mapbox.h1
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.mm2
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp2
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp21
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.hpp2
-rw-r--r--src/mbgl/style/sources/raster_source.cpp12
-rw-r--r--src/mbgl/style/sources/vector_source.cpp12
199 files changed, 11320 insertions, 3190 deletions
diff --git a/Makefile b/Makefile
index c6ed494f4d..c4e123d645 100644
--- a/Makefile
+++ b/Makefile
@@ -163,6 +163,10 @@ macos-test: $(MACOS_PROJ_PATH)
xpackage: $(MACOS_PROJ_PATH)
SYMBOLS=$(SYMBOLS) ./platform/macos/scripts/package.sh
+.PHONY: xdeploy
+xdeploy:
+ caffeinate -i ./platform/macos/scripts/deploy-packages.sh
+
.PHONY: xdocument
xdocument:
OUTPUT=$(OUTPUT) ./platform/macos/scripts/document.sh
@@ -276,8 +280,13 @@ idocument:
.PHONY: darwin-style-code
darwin-style-code:
node platform/darwin/scripts/generate-style-code.js
+ node platform/darwin/scripts/update-examples.js
style-code: darwin-style-code
+.PHONY: darwin-update-examples
+darwin-update-examples:
+ node platform/darwin/scripts/update-examples.js
+
.PHONY: check-public-symbols
check-public-symbols:
node platform/darwin/scripts/check-public-symbols.js macOS
diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp
index dd2b20cd0d..e5d8081d82 100644
--- a/include/mbgl/style/filter.hpp
+++ b/include/mbgl/style/filter.hpp
@@ -6,85 +6,143 @@
#include <string>
#include <vector>
+#include <tuple>
namespace mbgl {
namespace style {
class Filter;
-class NullFilter {};
+class NullFilter {
+public:
+ friend bool operator==(const NullFilter&, const NullFilter&) {
+ return true;
+ }
+};
class EqualsFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const EqualsFilter& lhs, const EqualsFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class NotEqualsFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const NotEqualsFilter& lhs, const NotEqualsFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class LessThanFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const LessThanFilter& lhs, const LessThanFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class LessThanEqualsFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const LessThanEqualsFilter& lhs, const LessThanEqualsFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class GreaterThanFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const GreaterThanFilter& lhs, const GreaterThanFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class GreaterThanEqualsFilter {
public:
std::string key;
Value value;
+
+ friend bool operator==(const GreaterThanEqualsFilter& lhs, const GreaterThanEqualsFilter& rhs) {
+ return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value);
+ }
};
class InFilter {
public:
std::string key;
std::vector<Value> values;
+
+ friend bool operator==(const InFilter& lhs, const InFilter& rhs) {
+ return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values);
+ }
};
class NotInFilter {
public:
std::string key;
std::vector<Value> values;
+
+ friend bool operator==(const NotInFilter& lhs, const NotInFilter& rhs) {
+ return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values);
+ }
};
class AnyFilter {
public:
std::vector<Filter> filters;
+
+ friend bool operator==(const AnyFilter& lhs, const AnyFilter& rhs) {
+ return lhs.filters == rhs.filters;
+ }
};
class AllFilter {
public:
std::vector<Filter> filters;
+
+ friend bool operator==(const AllFilter& lhs, const AllFilter& rhs) {
+ return lhs.filters == rhs.filters;
+ }
};
class NoneFilter {
public:
std::vector<Filter> filters;
+
+ friend bool operator==(const NoneFilter& lhs, const NoneFilter& rhs) {
+ return lhs.filters == rhs.filters;
+ }
};
class HasFilter {
public:
std::string key;
+
+ friend bool operator==(const HasFilter& lhs, const HasFilter& rhs) {
+ return lhs.key == rhs.key;
+ }
};
class NotHasFilter {
public:
std::string key;
+
+ friend bool operator==(const NotHasFilter& lhs, const NotHasFilter& rhs) {
+ return lhs.key == rhs.key;
+ }
};
using FilterBase = variant<
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
index e633e6efba..ede0301725 100644
--- a/include/mbgl/style/sources/geojson_source.hpp
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -43,7 +43,7 @@ public:
void setURL(const std::string& url);
void setGeoJSON(const GeoJSON&);
- optional<std::string> getURL();
+ optional<std::string> getURL() const;
// Private implementation
diff --git a/include/mbgl/style/sources/raster_source.hpp b/include/mbgl/style/sources/raster_source.hpp
index 9bb951992c..395f25e51d 100644
--- a/include/mbgl/style/sources/raster_source.hpp
+++ b/include/mbgl/style/sources/raster_source.hpp
@@ -11,9 +11,12 @@ class RasterSource : public Source {
public:
RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize);
+ optional<std::string> getURL() const;
+
// Private implementation
class Impl;
+ Impl* const impl;
};
template <>
diff --git a/include/mbgl/style/sources/vector_source.hpp b/include/mbgl/style/sources/vector_source.hpp
index e16a6a68af..8626ce160a 100644
--- a/include/mbgl/style/sources/vector_source.hpp
+++ b/include/mbgl/style/sources/vector_source.hpp
@@ -11,9 +11,12 @@ class VectorSource : public Source {
public:
VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset);
+ optional<std::string> getURL() const;
+
// Private implementation
class Impl;
+ Impl* const impl;
};
template <>
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
new file mode 100644
index 0000000000..3d775c8a89
--- /dev/null
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -0,0 +1,321 @@
+<%
+ const os = locals.os;
+ const iOS = os === 'iOS';
+ const macOS = os === 'macOS';
+ const cocoaPrefix = iOS ? 'UI' : 'NS';
+ const layers = locals.layers;
+ const renamedProperties = locals.renamedProperties;
+-%>
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+-->
+# Information for Style Authors
+
+A _style_ defines a map view’s content and appearance. If you’ve authored a
+style using
+[Mapbox Studio’s Styles editor](https://www.mapbox.com/studio/styles/) or as
+JSON in a text editor, you can use that style in this SDK and manipulate it
+afterwards in code. This document provides information you can use to ensure a
+seamless transition from Mapbox Studio to your application.
+
+<% if (iOS) { -%>
+## Designing for iOS
+<% } else { -%>
+## Designing for macOS
+<% } -%>
+
+When designing your style, consider the context in which your application shows
+the style. There are a number of considerations specific to <%- os %> that may
+not be obvious when designing your style in Mapbox Studio on the Web. A map view
+is essentially a graphical user interface element, so many of same issues in
+user interface design also apply when designing a map style.
+
+### Color
+
+Ensure sufficient contrast in your application’s user interface when your map
+style is present. Standard user interface elements such as toolbars, sidebars,
+and sheets often overlap the map view with a translucent, blurred background, so
+make sure the contents of these elements remain legible with the map view
+underneath.
+<% if (iOS) { -%>
+The user location annotation view, the attribution button, any buttons in
+callout views, and any items in the navigation bar are influenced by your
+application’s tint color, so choose a tint color that constrasts well with your
+map style. If you intend your style to be used in the dark, consider the impact
+that Night Shift may have on your style’s colors.
+<% } -%>
+
+### Typography and graphics
+
+<% if (iOS) { -%>
+Choose font and icon sizes appropriate to iOS devices. iPhones and iPads have
+smaller screens than the typical browser window in which you would use Mapbox
+Studio, especially when multitasking is enabled. Your user’s viewing distance
+may be shorter than on a desktop computer. Some of your users may use the Larger
+Dynamic Type and Accessibility Text features to increase the size of all text on
+the device. You can use the
+[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s
+font and icon sizes accordingly.
+<% } -%>
+
+Design sprite images and choose font weights that look crisp on both
+standard-resolution displays and Retina displays. This SDK supports the same
+resolutions as <%- os %>.
+<% if (iOS) { -%>
+Standard-resolution displays are limited to older devices that your application
+may or may not support, depending on its minimum deployment target.
+<% } else { -%>
+Standard-resolution displays are often found on external monitors. Even with
+built-in screens, some of your users may use the Larger Text option in Display
+Preferences, which is essentially standard resolution, to make text easier to
+read.
+<% } -%>
+
+Icon and text labels should be legible regardless of the map’s orientation.
+<% if (iOS) { -%>
+By default, this SDK makes it easy for your users to rotate or tilt the map
+using multitouch gestures.
+<% } else { -%>
+By default, this SDK makes it easy for your users to rotate or tilt the map
+using multitouch trackpad gestures or keyboard shortcuts.
+<% } -%>
+If you do not intend your design to accommodate rotation and tilting, disable
+these gestures using the `MGLMapView.rotateEnabled` and
+`MGLMapView.pitchEnabled` properties, respectively, or the corresponding
+inspectables in Interface Builder.
+
+### Interactivity
+
+Pay attention to whether elements of your style appear to be interactive.
+<% if (iOS) { -%>
+A text label may look like a tappable button merely due to matching your
+application’s tint color or the default blue tint color.
+<% } else { -%>
+An icon with a shadow or shading effect may appear to be clickable.
+<% } -%>
+You can make an icon or text label interactive by installing a gesture
+recognizer and performing feature querying (e.g.,
+`-[MGLMapView visibleFeaturesAtPoint:]`) to get details about the selected
+feature.
+<% if (macOS) { -%>
+You can install cursor or tooltip tracking rectangles to indicate interactive
+features as an alternative to prominent hover effects.
+<% } -%>
+
+<% if (iOS) { -%>
+Make sure your users can easily distinguish any interactive elements from the
+surrounding map, such as pins, the user location annotation view, or a route
+line. Avoid relying on hover effects to indicate interactive elements. Leave
+enough room between interactive elements to accommodate imprecise tapping
+gestures.
+<% } else { -%>
+Make sure your users can easily distinguish any interactive elements from the
+surrounding map, such as pins or a route line. If your application supports
+printing, consider using the
+[runtime styling API](#manipulating-the-style-at-runtime) to optimize your style
+for ink economy before printing the map view.
+<% } -%>
+
+<% if (iOS) { -%>
+For more information about user interface design, consult Apple’s
+[_iOS Human Interface Guidelines_](https://developer.apple.com/ios/human-interface-guidelines/).
+<% } else { -%>
+For more information about user interface design, consult Apple’s
+[_macOS Human Interface Guidelines_](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/OSXHIGuidelines/).
+<% } -%>
+
+## Applying your style
+
+You set an `MGLMapView` object’s style either in code, by setting the
+`MGLMapView.styleURL` property, or in Interface Builder, by setting the “Style
+URL” inspectable. The URL must point to a local or remote style JSON file. The
+style JSON file format is defined by the
+[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/). This
+SDK supports the functionality defined by version 8 of the specification unless
+otherwise noted in the
+[style specification documentation](https://www.mapbox.com/mapbox-gl-style-spec/).
+
+## Manipulating the style at runtime
+
+The _runtime styling API_ enables you to modify every aspect of a style
+dynamically as a user interacts with your application. The style itself is
+represented at runtime by an `MGLStyle` object, which provides access to various
+`MGLSource` and `MGLStyleLayer` objects that represent content sources and style
+layers, respectively.
+<% if (iOS) { -%>
+For more information about the capabilities exposed by the runtime styling API,
+see “[Runtime Styling](runtime-styling.html)”.
+<% } -%>
+
+The names of runtime styling classes and properties on <%- os %> are generally
+consistent with the style specification and Mapbox Studio’s Styles editor. Any
+exceptions are listed in this document.
+
+To avoid conflicts with Objective-C keywords or Cocoa terminology, this SDK uses
+the following terms for concepts defined in the style specification:
+
+In the style specification | In the SDK
+---------------------------|---------
+class | style class
+filter | predicate
+id | identifier
+image | style image
+layer | style layer
+property | attribute
+SDF icon | template image
+source | content source
+
+## Specifying the map’s content
+
+Each source defined by a style JSON file is represented at runtime by a content
+source object that you can use to initialize new style layers. The content
+source object is a member of one of the following subclasses of `MGLSource`:
+
+In style JSON | In the SDK
+--------------|-----------
+`geojson` | `MGLShapeSource`
+`raster` | `MGLRasterSource`
+`vector` | `MGLVectorSource`
+
+`image` and `video` sources are not supported.
+
+### Tile sources
+
+Raster and vector sources may be defined in TileJSON configuration files. This
+SDK supports the properties defined in the style specification, which are a
+subset of the keys defined in version 2.1.0 of the
+[TileJSON](https://github.com/mapbox/tilejson-spec/tree/master/2.1.0)
+specification. As an alternative to authoring a custom TileJSON file, you may
+supply various tile source options when creating a raster or vector source.
+These options are detailed in the `MGLTileSourceOption` documentation:
+
+In style JSON | In TileJSON | In the SDK
+--------------|---------------|-----------
+`url` | — | `configurationURL` parameter in `-[MGLTileSource initWithIdentifier:configurationURL:]`
+`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
+`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
+`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
+`tileSize` | — | `MGLTileSourceOptionTileSize`
+`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
+`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
+
+### Shape sources
+
+Shape sources also accept various options. These options are detailed in the
+`MGLShapeSourceOption` documentation:
+
+In style JSON | In the SDK
+-----------------|-----------
+`data` | `url` parameter in `-[MGLShapeSource initWithIdentifier:URL:options:]`
+`maxzoom` | `MGLShapeSourceOptionMaximumZoomLevel`
+`buffer` | `MGLShapeSourceOptionBuffer`
+`tolerance` | `MGLShapeSourceOptionSimplificationTolerance`
+`cluster` | `MGLShapeSourceOptionClustered`
+`clusterRadius` | `MGLShapeSourceOptionClusterRadius`
+`clusterMaxZoom` | `MGLShapeSourceOptionMaximumZoomLevelForClustering`
+
+To create a shape source from local GeoJSON data, first
+[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
+then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+
+## Configuring the map content’s appearance
+
+Each layer defined by the style JSON file is represented at runtime by a style
+layer object, which you can use to refine the map’s appearance. The style layer
+object is a member of one of the following subclasses of `MGLStyleLayer`:
+
+In style JSON | In the SDK
+--------------|-----------
+<% for (const layer of layers) { -%>
+`<%- layer.type %>` | `MGL<%- camelize(layer.type) %>StyleLayer`
+<% } -%>
+
+You configure layout and paint attributes by setting properties on these style
+layer objects. The property names generally correspond to the style JSON
+properties, except for the use of camelCase instead of kebab-case. Properties
+whose names differ from the style specification are listed below:
+<% for (const type in renamedProperties) { -%>
+<% if (renamedProperties.hasOwnProperty(type)) { -%>
+
+### <%- camelize(type) %> style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+<% for (const name in renamedProperties[type]) { -%>
+<% if (renamedProperties[type].hasOwnProperty(name)) { -%>
+`<%- originalPropertyName(renamedProperties[type][name]) %>` | `MGL<%- camelize(type) %>StyleLayer.<%- objCName(renamedProperties[type][name]) %>` | `MGL<%- camelize(type) %>StyleLayer.<%- objCGetter(renamedProperties[type][name]) %>`
+<% } -%>
+<% } -%>
+<% } -%>
+<% } -%>
+
+## Setting attribute values
+
+Each property representing a layout or paint attribute is set to an
+`MGLStyleValue` object, which is either an `MGLStyleConstantValue` object (for
+constant values) or an `MGLStyleFunction` object (for zoom level functions). The
+style value object is a container for the raw value or function parameters that
+you want the attribute to be set to.
+
+In contrast to the JSON type that the style specification defines for each
+layout or paint property, the style value object often contains a more specific
+Foundation or Cocoa type. General rules for attribute types are listed below.
+Pay close attention to the SDK documentation for the attribute you want to get
+or set.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+Color | `<%- cocoaPrefix %>Color` | `<%- cocoaPrefix %>Color`
+Enum | `NSValue` (see `NSValue(MGLAdditions)`) | `NSValue` (see `NSValue(MGLAdditions)`)
+String | `NSString` | `String`
+Boolean | `NSNumber.boolValue` | `Bool`
+Number | `NSNumber.floatValue` | `Float`
+Array (`-dasharray`) | `NSArray<NSNumber>` | `[Float]`
+Array (`-font`) | `NSArray<NSString>` | `[String]`
+<% if (iOS) { -%>
+Array (`-offset`, `-translate`) | `NSValue.CGVectorValue` | `NSValue.cgVectorValue`
+Array (`-padding`) | `NSValue.UIEdgeInsetsValue` | `NSValue.uiEdgeInsetsValue`
+<% } else { -%>
+Array (`-offset`, `-translate`) | `NSValue` containing `CGVector` | `NSValue` containing `CGVector`
+Array (`-padding`) | `NSValue.edgeInsetsValue` | `NSValue.edgeInsetsValue`
+<% } -%>
+
+For padding attributes, note that the arguments to
+`<%- cocoaPrefix %>EdgeInsetsMake()` in Objective-C and
+`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
+order, in contrast to the clockwise order defined by the style specification.
+
+<% if (macOS) { -%>
+Additionally, on macOS, a screen coordinate of (0, 0) is located at the
+lower-left corner of the screen. Therefore, a positive `CGVector.dy` means an
+offset or translation upward, while a negative `CGVector.dy` means an offset or
+translation downward. This is the reverse of how `CGVector` is interpreted on
+iOS.
+
+<% } -%>
+## Filtering sources
+
+You can filter a shape or vector source by setting the
+`MGLVectorStyleLayer.predicate` property to an `NSPredicate` object. Below is a
+table of style JSON operators and the corresponding operators used in the
+predicate format string:
+
+In style JSON | In the format string
+--------------------------|---------------------
+`["has", key]` | `key != nil`
+`["!has", key]` | `key == nil`
+`["==", key, value]` | `key == value`
+`["!=", key, value]` | `key != value`
+`[">", key, value]` | `key > value`
+`[">=", key, value]` | `key >= value`
+`["<", key, value]` | `key < value`
+`["<=", key, value]` | `key <= value`
+`["in", key, v0, …, vn]` | `key IN {v0, …, vn}`
+`["!in", key, v0, …, vn]` | `NOT key IN {v0, …, vn}`
+`["all", f0, …, fn]` | `p0 AND … AND pn`
+`["any", f0, …, fn]` | `p0 OR … OR pn`
+`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+
+See the `MGLVectorStyleLayer.predicate` documentation for a full description of
+the supported operators and operand types.
diff --git a/platform/darwin/docs/guides/Working with GeoJSON Data.md b/platform/darwin/docs/guides/Working with GeoJSON Data.md
new file mode 100644
index 0000000000..57aaa3855d
--- /dev/null
+++ b/platform/darwin/docs/guides/Working with GeoJSON Data.md
@@ -0,0 +1,99 @@
+# Working with GeoJSON Data
+
+This SDK offers several ways to work with [GeoJSON](http://geojson.org/) files.
+GeoJSON is a standard file format for representing geographic data.
+
+## Adding a GeoJSON file to the map
+
+You can use
+[Mapbox Studio’s Datasets editor](https://www.mapbox.com/studio/datasets/) to
+upload a GeoJSON file and include it in your custom map style. The GeoJSON data
+will be hosted on Mapbox servers. When a user loads your style, the SDK
+automatically loads the GeoJSON data for display.
+
+Alternatively, if you need to host the GeoJSON file elsewhere or bundle it with
+your application, you can use a GeoJSON file as the basis of an `MGLShapeSource`
+object. Pass the file’s URL into the
+`-[MGLShapeSource initWithIdentifier:URL:options:]` initializer and add the
+shape source to the map using the `-[MGLStyle addSource:]` method. The URL may
+be a local file URL, an HTTP URL, or an HTTPS URL.
+
+Once you’ve added the GeoJSON file to the map via an `MGLShapeSource` object,
+you can configure the appearance of its data and control what data is visible
+using `MGLStyleLayer` objects, you can
+[access the data programmatically](#extracting-geojson-data-from-the-map).
+
+## Converting GeoJSON data into shape objects
+
+If you have GeoJSON data in the form of source code (also known as “GeoJSON
+text”), you can convert it into an `MGLShape`, `MGLFeature`, or
+`MGLShapeCollectionFeature` object that the `MGLShapeSource` class understands
+natively. First, create an `NSData` object out of the source code string or file
+contents, then pass that data object into the
+`+[MGLShape shapeWithData:encoding:error:]` method. Finally, you can pass the
+resulting shape or feature object into the
+`-[MGLShapeSource initWithIdentifier:shape:options:]` initializer and add it to
+the map, or you can use the object and its properties to power non-map-related
+functionality in your application.
+
+To include multiple shapes in the source, create and pass an `MGLShapeCollection` or
+ `MGLShapeCollectionFeature` object to
+ `-[MGLShapeSource initWithIdentifier:shape:options:]`. Alternatively, use the
+ `-[MGLShapeSource initWithIdentifier:features:options:]` or
+ `-[MGLShapeSource initWithIdentifier:shapes:options:]` method to create a shape source
+ with an array. `-[MGLShapeSource initWithIdentifier:features:options:]` accepts only `MGLFeature`
+ instances, such as `MGLPointFeature` objects, whose attributes you can use when
+ applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
+ appearance.
+
+## Extracting GeoJSON data from the map
+
+Any `MGLShape`, `MGLFeature`, or `MGLShapeCollectionFeature` object has an
+`-[MGLShape geoJSONDataUsingEncoding:]` method that you can use to create a
+GeoJSON source code representation of the object. You can extract a feature
+object from the map using a method such as
+`-[MGLMapView visibleFeaturesAtPoint:]`.
+
+## About GeoJSON deserialization
+
+The process of converting GeoJSON text into `MGLShape`, `MGLFeature`, or
+`MGLShapeCollectionFeature` objects is known as “GeoJSON deserialization”.
+GeoJSON geometries, features, and feature collections are known in this SDK as
+shapes, features, and shape collection features, respectively.
+
+Each GeoJSON object type corresponds to a type provided by either this SDK or
+the Core Location framework:
+
+GeoJSON object type | SDK type
+--------------------|---------
+`Position` (longitude, latitude) | `CLLocationCoordinate2D` (latitude, longitude)
+`Point` | `MGLPointAnnotation`
+`MultiPoint` | `MGLPointCollection`
+`LineString` | `MGLPolyline`
+`MultiLineString` | `MGLMultiPolyline`
+`Polygon` | `MGLPolygon`
+Linear ring | `MGLPolygon.coordinates`, `MGLPolygon.interiorPolygons`
+`MultiPolygon` | `MGLMultiPolygon`
+`GeometryCollection` | `MGLShapeCollection`
+`Feature` | `MGLFeature`
+`FeatureCollection` | `MGLShapeCollectionFeature`
+
+A `Feature` object in GeoJSON corresponds to an instance of an `MGLShape`
+subclass conforming to the `MGLFeature` protocol. There is a distinct
+`MGLFeature`-conforming class for each type of geometry that a GeoJSON feature
+can contain. This allows features to be used as shapes where convenient. For
+example, some features can be added to a map view as annotations.
+
+In contrast to the GeoJSON standard, it is possible for `MGLShape` subclasses
+other than `MGLPointAnnotation` to straddle the antimeridian.
+
+The following GeoJSON data types correspond straightforwardly to Foundation data
+types when they occur as feature identifiers or property values:
+
+GeoJSON data type | Objective-C representation | Swift representation
+-------------------|----------------------------|---------------------
+`null` | `NSNull` | `NSNull`
+`true`, `false` | `NSNumber.boolValue` | `Bool`
+Integer | `NSNumber.unsignedLongLongValue`, `NSNumber.longLongValue` | `UInt64`, `Int64`
+Floating-point number | `NSNumber.doubleValue` | `Double`
+String | `NSString` | `String`
diff --git a/platform/darwin/docs/theme/assets/css/jazzy.css.scss b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
index 9c1f347142..6b4dffc879 100644
--- a/platform/darwin/docs/theme/assets/css/jazzy.css.scss
+++ b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
@@ -51,6 +51,7 @@ $navigation_bg_color: #fbfbfb;
$navigation_task_color: $link_color;
$section_name_color: $color_darkblue;
+$navigation_gloss_color: #999;
// ----- Content
@@ -367,6 +368,30 @@ pre code {
color: $navigation_task_color;
}
+%nav-group-task-gloss {
+ color: $navigation_gloss_color;
+ font-size: 90%;
+ margin-left: 0.5em;
+}
+
+.nav-group-task[data-url^="Protocols/"] > .nav-group-task-link::after {
+ @extend %nav-group-task-gloss;
+ content: "(Protocol)";
+}
+
+.nav-group-task[data-name="MGLForegroundStyleLayer"],
+.nav-group-task[data-name="MGLMultiPoint"],
+.nav-group-task[data-name="MGLShape"],
+.nav-group-task[data-name="MGLSource"],
+.nav-group-task[data-name="MGLStyleLayer"],
+.nav-group-task[data-name="MGLTileSource"],
+.nav-group-task[data-name="MGLVectorStyleLayer"] {
+ .nav-group-task-link::after {
+ @extend %nav-group-task-gloss;
+ content: "(Abstract Class)";
+ }
+}
+
.nav-group-name > .small-heading,
.nav-group-task-link {
display: block;
diff --git a/platform/darwin/docs/theme/assets/js/jazzy.js b/platform/darwin/docs/theme/assets/js/jazzy.js
index 2e42193e38..e07f181acc 100755
--- a/platform/darwin/docs/theme/assets/js/jazzy.js
+++ b/platform/darwin/docs/theme/assets/js/jazzy.js
@@ -40,3 +40,8 @@ $(".token").click(function(event) {
}
event.preventDefault();
});
+
+// Dumb down quotes within code blocks that delimit strings instead of quotations.
+$("code q").replaceWith(function () {
+ return ["\"", $(this).contents(), "\""];
+});
diff --git a/platform/darwin/docs/theme/templates/nav.mustache b/platform/darwin/docs/theme/templates/nav.mustache
index 7584f49652..bfbd8e7d78 100644
--- a/platform/darwin/docs/theme/templates/nav.mustache
+++ b/platform/darwin/docs/theme/templates/nav.mustache
@@ -5,7 +5,7 @@
<a class="small-heading" href="{{path_to_root}}{{section}}.html">{{section}}<span class="anchor-icon" /></a>
<ul class="nav-group-tasks">
{{#children}}
- <li class="nav-group-task" data-name="{{name}}">
+ <li class="nav-group-task" data-name="{{name}}" data-url="{{url}}">
<a title="{{name}}" class="nav-group-task-link" href="{{path_to_root}}{{url}}">{{name}}</a>
</li>
{{/children}}
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 6606c956f2..3998246580 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -55,17 +55,38 @@ _.forOwn(cocoaConventions, function (properties, kind) {
})
});
+String.prototype.wrap = function (cols, indent) {
+ let wrapRe = new RegExp(`(.{1,${cols - indent}})(?: +|\n|$)`, "gm");
+ return this.replace(wrapRe, "$1\n").replace(/\s+$/, "").indent(indent);
+};
+
+String.prototype.indent = function (cols) {
+ return this.replace(/^|\n/g, "$&" + " ".repeat(cols));
+};
+
+global.camelize = function (str) {
+ return str.replace(/(?:^|-)(.)/g, function (_, x) {
+ return x.toUpperCase();
+ });
+};
+
+global.camelizeWithLeadingLowercase = function (str) {
+ return str.replace(/-(.)/g, function (_, x) {
+ return x.toUpperCase();
+ });
+};
+
global.objCName = function (property) {
return camelizeWithLeadingLowercase(property.name);
-}
+};
global.objCGetter = function (property) {
return camelizeWithLeadingLowercase(property.getter || property.name);
-}
+};
global.objCType = function (layerType, propertyName) {
return `${prefix}${camelize(propertyName)}`;
-}
+};
global.arrayType = function (property) {
return property.type === 'array' ? originalPropertyName(property).split('-').pop() : false;
@@ -74,7 +95,87 @@ global.arrayType = function (property) {
global.testImplementation = function (property, layerType, isFunction) {
let helperMsg = testHelperMessage(property, layerType, isFunction);
return `layer.${objCName(property)} = [MGLRuntimeStylingHelper ${helperMsg}];`;
-}
+};
+
+global.objCTestValue = function (property, layerType, indent) {
+ let propertyName = originalPropertyName(property);
+ switch (property.type) {
+ case 'boolean':
+ return property.default ? '@NO' : '@YES';
+ case 'number':
+ return '@0xff';
+ case 'string':
+ return `@"${_.startCase(propertyName)}"`;
+ case 'enum':
+ let type = objCType(layerType, property.name);
+ let value = `${type}${camelize(_.last(_.keys(property.values)))}`;
+ return `[NSValue valueWith${type}:${value}]`;
+ case 'color':
+ return '[MGLColor redColor]';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'dasharray':
+ return '@[@1, @2]';
+ case 'font':
+ return `@[@"${_.startCase(propertyName)}", @"${_.startCase(_.reverse(propertyName.split('')).join(''))}"]`;
+ case 'padding': {
+ let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ }
+ case 'offset':
+ case 'translate':
+ let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
+ return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ default:
+ throw new Error(`unknown array type for ${property.name}`);
+ }
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+};
+
+global.mbglTestValue = function (property, layerType) {
+ let propertyName = originalPropertyName(property);
+ switch (property.type) {
+ case 'boolean':
+ return property.default ? 'false' : 'true';
+ case 'number':
+ return '0xff';
+ case 'string':
+ return `"${_.startCase(propertyName)}"`;
+ case 'enum': {
+ let type = camelize(originalPropertyName(property));
+ if (/-translate-anchor$/.test(originalPropertyName(property))) {
+ type = 'TranslateAnchor';
+ }
+ if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
+ type = 'Alignment';
+ }
+ let value = camelize(_.last(_.keys(property.values)));
+ return `mbgl::style::${type}Type::${value}`;
+ }
+ case 'color':
+ return '{ 1, 0, 0, 1 }';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'dasharray':
+ return '{1, 2}';
+ case 'font':
+ return `{ "${_.startCase(propertyName)}", "${_.startCase(_.reverse(propertyName.split('')).join(''))}" }`;
+ case 'padding':
+ return '{ 1, 1, 1, 1 }';
+ case 'offset':
+ case 'translate':
+ return '{ 1, 1 }';
+ default:
+ throw new Error(`unknown array type for ${property.name}`);
+ }
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+};
global.testGetterImplementation = function (property, layerType, isFunction) {
let helperMsg = testHelperMessage(property, layerType, isFunction);
@@ -87,7 +188,7 @@ global.testGetterImplementation = function (property, layerType, isFunction) {
XCTAssertEqualObjects(gLayer.${objCName(property)}, ${value});`;
}
return `XCTAssertEqualObjects(gLayer.${objCName(property)}, ${value});`;
-}
+};
global.testHelperMessage = function (property, layerType, isFunction) {
let fnSuffix = isFunction ? 'Function' : '';
@@ -123,7 +224,7 @@ global.testHelperMessage = function (property, layerType, isFunction) {
}
};
-global.propertyDoc = function (propertyName, property, layerType) {
+global.propertyDoc = function (propertyName, property, layerType, kind) {
// Match references to other property names & values.
// Requires the format 'When `foo` is set to `bar`,'.
let doc = property.doc.replace(/`([^`]+?)` is set to `([^`]+?)`/g, function (m, peerPropertyName, propertyValue, offset, str) {
@@ -141,7 +242,7 @@ global.propertyDoc = function (propertyName, property, layerType) {
// Requires symbols to be surrounded by backticks.
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) {
- let objCType = objCType(layerType, property.name);
+ let objCType = global.objCType(layerType, property.name);
return '`' + `${objCType}${camelize(symbol)}` + '`';
}
if (str.substr(offset - 4, 3) !== 'CSS') {
@@ -154,11 +255,33 @@ global.propertyDoc = function (propertyName, property, layerType) {
if (!property.units.match(/s$/)) {
property.units += 's';
}
- doc += `
-
- This property is measured in ${property.units}.`;
+ doc += `\n\nThis property is measured in ${property.units}.`;
+ }
+ doc = doc.replace(/(p)ixel/gi, '$1oint').replace(/(\d)px\b/g, '$1pt');
+ if (kind !== 'enum') {
+ if ('default' in property) {
+ doc += `\n\nThe default value of this property is ${propertyDefault(property, layerType)}.`;
+ if (!property.required) {
+ doc += ' Set this property to `nil` to reset it to the default value.';
+ }
+ }
+ if ('requires' in property) {
+ doc += '\n\n' + propertyReqs(property, spec[`${kind}_${layerType}`], layerType);
+ }
+ if ('original' in property) {
+ let anchor;
+ switch (kind) {
+ case 'layout':
+ anchor = `layout-${layerType}-${property.original}`;
+ break;
+ case 'paint':
+ anchor = `paint-${property.original}`;
+ break;
+ }
+ doc += `\n\nThis attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#${anchor}"><code>${property.original}</code></a> layout property in the Mapbox Style Specification.`;
+ }
}
- return doc.replace(/(p)ixel/gi, '$1oint').replace(/(\d)px\b/g, '$1pt');
+ return doc;
};
global.propertyReqs = function (property, propertiesByName, type) {
@@ -217,30 +340,32 @@ global.describeValue = function (value, property, layerType) {
throw new Error(`unrecognized color format in default value of ${property.name}`);
}
if (color.r === 0 && color.g === 0 && color.b === 0 && color.a === 0) {
- return '`MGLColor.clearColor`';
+ return '`UIColor.clearColor`';
}
if (color.r === 0 && color.g === 0 && color.b === 0 && color.a === 1) {
- return '`MGLColor.blackColor`';
+ return '`UIColor.blackColor`';
}
if (color.r === 1 && color.g === 1 && color.b === 1 && color.a === 1) {
- return '`MGLColor.whiteColor`';
+ return '`UIColor.whiteColor`';
}
- return 'an `MGLColor`' + ` object whose RGB value is ${color.r}, ${color.g}, ${color.b} and whose alpha value is ${color.a}`;
+ return 'a `UIColor`' + ` object whose RGB value is ${color.r}, ${color.g}, ${color.b} and whose alpha value is ${color.a}`;
case 'array':
let units = property.units || '';
if (units) {
units = ` ${units}`.replace(/pixel/, 'point');
}
- if (property.name.indexOf('padding') !== -1) {
- if (value[0] === 0 && value[1] === 0 && value[2] === 0 && value[3] === 0) {
- return 'an `NSValue` object containing `NSEdgeInsetsZero` or `UIEdgeInsetsZero`';
- }
- return 'an `NSValue` object containing an `NSEdgeInsets` or `UIEdgeInsets` struct set to' + ` ${value[0]}${units} on the top, ${value[3]}${units} on the left, ${value[2]}${units} on the bottom, and ${value[1]}${units} on the right`;
- }
- if (property.name.indexOf('offset') !== -1 || property.name.indexOf('translate') !== -1) {
- return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${value[0]}${units} from the left and ${value[1]}${units} from the top`;
+ switch (arrayType(property)) {
+ case 'padding':
+ if (value[0] === 0 && value[1] === 0 && value[2] === 0 && value[3] === 0) {
+ return 'an `NSValue` object containing `UIEdgeInsetsZero`';
+ }
+ return 'an `NSValue` object containing a `UIEdgeInsets` struct set to' + ` ${value[0]}${units} on the top, ${value[3]}${units} on the left, ${value[2]}${units} on the bottom, and ${value[1]}${units} on the right`;
+ case 'offset':
+ case 'translate':
+ return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${value[0]}${units} rightward and ${value[1]}${units} downward`;
+ default:
+ return 'the array `' + value.join('`, `') + '`';
}
- return 'the array `' + value.join('`, `') + '`';
default:
throw new Error(`unknown type for ${property.name}`);
}
@@ -252,7 +377,7 @@ global.propertyDefault = function (property, layerType) {
global.originalPropertyName = function (property) {
return property.original || property.name;
-}
+};
global.propertyType = function (property) {
switch (property.type) {
@@ -317,100 +442,144 @@ global.valueTransformerArguments = function (property) {
}
};
+global.mbglType = function(property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'bool';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'std::string';
+ case 'enum': {
+ let type = camelize(originalPropertyName(property));
+ if (/-translate-anchor$/.test(originalPropertyName(property))) {
+ type = 'TranslateAnchor';
+ }
+ if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
+ type = 'Alignment';
+ }
+ return `mbgl::style::${type}Type`;
+ }
+ case 'color':
+ return 'mbgl::Color';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'dasharray':
+ return 'std::vector<float>';
+ case 'font':
+ return 'std::vector<std::string>';
+ case 'padding':
+ return 'std::array<float, 4>';
+ case 'offset':
+ case 'translate':
+ return 'std::array<float, 2>';
+ default:
+ throw new Error(`unknown array type for ${property.name}`);
+ }
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+};
+
global.initLayer = function (layerType) {
if (layerType == "background") {
return `_layer = new mbgl::style::${camelize(layerType)}Layer(identifier.UTF8String);`
} else {
return `_layer = new mbgl::style::${camelize(layerType)}Layer(identifier.UTF8String, source.identifier.UTF8String);`
}
-}
+};
global.setSourceLayer = function() {
- return `_layer->setSourceLayer(sourceLayer.UTF8String);`
-}
-
-global.mbglType = function(property) {
- let mbglType = camelize(originalPropertyName(property)) + 'Type';
- if (/-translate-anchor$/.test(originalPropertyName(property))) {
- mbglType = 'TranslateAnchorType';
- }
- if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
- mbglType = 'AlignmentType';
- }
- return mbglType;
-}
+ return `_layer->setSourceLayer(sourceLayer.UTF8String);`
+};
const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.ejs', 'utf8'), { strict: true });
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
-const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.m.ejs', 'utf8'), { strict: true});
-const categoryH = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs', 'utf8'), { strict: true});
-const categoryM = ejs.compile(fs.readFileSync('platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs', 'utf8'), { strict: true});
+const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true});
+const guideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
-const layers = Object.keys(spec.layer.type.values).map((type) => {
- const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
+const layers = _(spec.layer.type.values).map((value, layerType) => {
+ const layoutProperties = Object.keys(spec[`layout_${layerType}`]).reduce((memo, name) => {
if (name !== 'visibility') {
- spec[`layout_${type}`][name].name = name;
- memo.push(spec[`layout_${type}`][name]);
+ spec[`layout_${layerType}`][name].name = name;
+ memo.push(spec[`layout_${layerType}`][name]);
}
return memo;
}, []);
- const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
- spec[`paint_${type}`][name].name = name;
- memo.push(spec[`paint_${type}`][name]);
+ const paintProperties = Object.keys(spec[`paint_${layerType}`]).reduce((memo, name) => {
+ spec[`paint_${layerType}`][name].name = name;
+ memo.push(spec[`paint_${layerType}`][name]);
return memo;
}, []);
return {
- type: type,
+ doc: spec.layer.type.values[layerType].doc,
+ type: layerType,
layoutProperties: _.sortBy(layoutProperties, ['name']),
paintProperties: _.sortBy(paintProperties, ['name']),
- layoutPropertiesByName: spec[`layout_${type}`],
- paintPropertiesByName: spec[`paint_${type}`],
};
-});
+}).sortBy(['type']).value();
function duplicatePlatformDecls(src) {
- // Look for a documentation comment that contains “MGLColor” and the
- // subsequent function, method, or property declaration. Try not to match
- // greedily.
- return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\bMGLColor\b[\s\S]*?\*\/)(\s*.+?;)/g,
+ // Look for a documentation comment that contains “MGLColor” or “UIColor”
+ // and the subsequent function, method, or property declaration. Try not to
+ // match greedily.
+ return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\*\/)(\s*[^;]+?\b(?:MGL|NS|UI)(?:Color|EdgeInsets(?:Zero)?)\b[^;]+?;)/g,
(match, comment, decl) => {
- let iosComment = comment.replace(/\bMGLColor\b/g, 'UIColor')
+ let macosComment = comment.replace(/\b(?:MGL|UI)(Color|EdgeInsets(?:Zero)?)\b/g, 'NS$1')
// Use the correct indefinite article.
- .replace(/\b(a)n(\s+`?UIColor)\b/gi, '$1$2');
- let macosComment = comment.replace(/\bMGLColor\b/g, 'NSColor');
+ .replace(/\ba(\s+`?NS(?:Color|EdgeInsets))\b/gi, 'an$1');
+ let iosDecl = decl.replace(/\bMGL(Color|EdgeInsets)\b/g, 'UI$1');
+ let macosDecl = decl.replace(/\b(?:MGL|UI)(Color|EdgeInsets)\b/g, 'NS$1');
return `\
#if TARGET_OS_IPHONE
-${iosComment}${decl}
+${comment}${iosDecl}
+#else
+${macosComment}${macosDecl}
+#endif`;
+ })
+ // Do the same for CGVector-typed properties.
+ .replace(/(\/\*\*(?:\*[^\/]|[^*])*?\b(?:CGVector|UIEdgeInsets(?:Zero)?)\b[\s\S]*?\*\/)(\s*.+?;)/g,
+ (match, comment, decl) => {
+ let macosComment = comment.replace(/\bdownward\b/g, 'upward')
+ .replace(/\bUI(EdgeInsets(?:Zero)?)\b/g, 'NS$1');
+ return `\
+#if TARGET_OS_IPHONE
+${comment}${decl}
#else
${macosComment}${decl}
#endif`;
});
}
-var allLayoutProperties = [];
-var allPaintProperties = [];
-var allTypes = [];
+var renamedPropertiesByLayerType = {};
for (var layer of layers) {
- allLayoutProperties.push(layer.layoutProperties);
- allPaintProperties.push(layer.paintProperties);
- allTypes.push(layer.type);
- const containsEnumerationProperties = _.filter(layer.layoutProperties, function(property){ return property["type"] === "enum"; }).length || _.filter(layer.paintProperties, function(property){ return property["type"] === "enum"; }).length;
- layer.containsEnumerationProperties = containsEnumerationProperties;
+ layer.properties = _.concat(layer.layoutProperties, layer.paintProperties);
+ let enumProperties = _.filter(layer.properties, prop => prop.type === 'enum');
+ if (enumProperties.length) {
+ layer.enumProperties = enumProperties;
+ }
+
+ let renamedProperties = {};
+ _.assign(renamedProperties, _.filter(layer.properties, prop => 'original' in prop || 'getter' in prop));
+ if (!_.isEmpty(renamedProperties)) {
+ renamedPropertiesByLayerType[layer.type] = renamedProperties;
+ }
- writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
- writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
- writeIfModified(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.m`, testLayers(layer));
+ fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
+ fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
+ fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
}
-fs.writeFileSync(`platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h`, categoryH({
- layoutProperties: _.flatten(allLayoutProperties),
- paintProperties: _.flatten(allPaintProperties),
- types: allTypes
+fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, guideMD({
+ os: 'iOS',
+ renamedProperties: renamedPropertiesByLayerType,
+ layers: layers,
}));
-fs.writeFileSync(`platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm`, categoryM({
- layoutProperties: _.flatten(allLayoutProperties),
- paintProperties: _.flatten(allPaintProperties)
+fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, guideMD({
+ os: 'macOS',
+ renamedProperties: renamedPropertiesByLayerType,
+ layers: layers,
}));
diff --git a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
index 49cf515e3e..9d80ff3896 100644
--- a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
+++ b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
@@ -9,13 +9,26 @@
"icon-size": "icon-scale",
"symbol-avoid-edges": "symbol-avoids-edges",
"text-allow-overlap": "text-allows-overlap",
+ "text-field": "text",
+ "text-font": "text-font-names",
"text-ignore-placement": "text-ignores-placement",
"text-justify": "text-justification",
"text-keep-upright": "keeps-text-upright",
"text-max-angle": "maximum-text-angle",
"text-max-width": "maximum-text-width",
"text-optional": "is-text-optional",
- "text-rotate": "text-rotation"
+ "text-rotate": "text-rotation",
+ "text-size": "text-font-size"
+ },
+ "paint_circle": {
+ "circle-pitch-scale": "circle-scale-alignment",
+ "circle-translate": "circle-translation",
+ "circle-translate-anchor": "circle-translation-anchor"
+ },
+ "paint_fill": {
+ "fill-antialias": "is-fill-antialiased",
+ "fill-translate": "fill-translation",
+ "fill-translate-anchor": "fill-translation-anchor"
},
"paint_raster": {
"raster-brightness-min": "minimum-raster-brightness",
@@ -23,9 +36,14 @@
"raster-hue-rotate": "raster-hue-rotation"
},
"paint_line": {
- "line-dasharray": "line-dash-pattern"
+ "line-dasharray": "line-dash-pattern",
+ "line-translate": "line-translation",
+ "line-translate-anchor": "line-translation-anchor"
},
- "paint_fill": {
- "fill-antialias": "is-fill-antialiased"
+ "paint_symbol": {
+ "icon-translate": "icon-translation",
+ "icon-translate-anchor": "icon-translation-anchor",
+ "text-translate": "text-translation",
+ "text-translate-anchor": "text-translation-anchor"
}
} \ No newline at end of file
diff --git a/platform/darwin/scripts/style-spec-overrides-v8.json b/platform/darwin/scripts/style-spec-overrides-v8.json
index cfda85b7fb..28740d458b 100644
--- a/platform/darwin/scripts/style-spec-overrides-v8.json
+++ b/platform/darwin/scripts/style-spec-overrides-v8.json
@@ -1,4 +1,28 @@
{
+ "layer": {
+ "type": {
+ "values": {
+ "fill": {
+ "doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse a fill style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object."
+ },
+ "line": {
+ "doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse a line style layer to configure the visual appearance of polyline or multipolyline features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object."
+ },
+ "symbol": {
+ "doc": "An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at points or along lines on the map.\n\nUse a symbol style layer to configure the visual appearance of labels for features in vector tiles loaded by an `MGLVectorSource` object or `MGLShape` or `MGLFeature` instances in an `MGLShapeSource` object."
+ },
+ "circle": {
+ "doc": "An `MGLCircleStyleLayer` is a style layer that renders one or more filled circles on the map.\n\nUse a circle style layer to configure the visual appearance of point or point collection features in vector tiles loaded by an `MGLVectorSource` object or `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature` instances in an `MGLShapeSource` object.\n\nA circle style layer renders circles whose radii are measured in screen units. To display circles on the map whose radii correspond to real-world distances, use many-sided regular polygons and configure their appearance using an `MGLFillStyleLayer` object."
+ },
+ "raster": {
+ "doc": "An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` object. For example, you could use a raster style layer to render <a href=\"https://www.mapbox.com/satellite/\">Mapbox Satellite</a> imagery, a <a href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic."
+ },
+ "background": {
+ "doc": "An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a background style layer to configure a color or pattern to show below all other map content. If the style’s other layers use the Mapbox Streets source, the background style layer is responsible for drawing land, whereas the oceans and other bodies of water are drawn by `MGLFillStyleLayer` objects.\n\nA background style layer is typically the bottommost layer in a style, because it covers the entire map and can occlude any layers below it. You can therefore access it by getting the last item in the `MGLStyle.layers` array.\n\nIf the background style layer is transparent or omitted from the style, any portion of the map view that does not show another style layer is transparent."
+ }
+ }
+ }
+ },
"layout_symbol": {
"icon-text-fit-padding": {
"doc": "Size of the additional area added to dimensions determined by `icon-text-fit`."
@@ -6,6 +30,9 @@
"icon-offset": {
"doc": "Offset distance of icon from its anchor."
},
+ "text-font": {
+ "doc": "An array of font face names used to display the text.\n\nEach font name must be included in the `{fontstack}` portion of the JSON stylesheet’s <a href=\"https://www.mapbox.com/mapbox-gl-style-spec/#glyphs\"><code>glyphs</code></a> property. You can register a custom font when designing the style in Mapbox Studio. Fonts installed on the system are not used.\n\nThe first font named in the array is applied to the text. For each character in the text, if the first font lacks a glyph for the character, the next font is applied as a fallback, and so on."
+ },
"text-offset": {
"doc": "Offset distance of text from its anchor."
},
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js
new file mode 100644
index 0000000000..6291326068
--- /dev/null
+++ b/platform/darwin/scripts/update-examples.js
@@ -0,0 +1,152 @@
+'use strict';
+
+const fs = require('fs');
+const execFileSync = require('child_process').execFileSync;
+const _ = require('lodash');
+
+const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampleTests.swift', 'utf8');
+
+// Regex extracts the following block
+// /** Front matter to describe the example. **/
+// func testMGLClass$member() {
+// ...
+// //#-example-code
+// let sampleCode: String?
+// //#-end-example-code
+// ...
+// }
+//
+// into the following regex groups:
+// 1 (test method name): "MGLClass" or "MGLClass$member" or "MGLClass$initWithArg_anotherArg_"
+// 2 (indentation): " "
+// 3 (sample code): "let sampleCode: String?"
+const exampleRegex = /func test([\w$]+)\s*\(\)\s*\{[^]*?\n([ \t]+)\/\/#-example-code\n([^]+?)\n\2\/\/#-end-example-code\n/gm;
+
+/**
+ * Returns the given source with example code inserted into the documentation
+ * comment for the symbol at the given one-based line.
+ *
+ * @param {String} src Source code to insert the example code into.
+ * @param {Number} line One-based line number of the symbol being documented.
+ * @param {String} exampleCode Example code to insert.
+ * @returns {String} `src` with `exampleCode` inserted just above `line`.
+ */
+function completeSymbolInSource(src, line, exampleCode) {
+ // Split the file contents right before the symbol declaration (but after its documentation comment).
+ let srcUpToSymbol = src.split('\n', line - 1).join('\n');
+ let srcFromSymbol = src.substr(srcUpToSymbol.length);
+
+ // Match the documentation comment block that is not followed by the beginning or end of a declaration.
+ let commentMatch = srcUpToSymbol.match(/\/\*\*\s*(?:[^*]|\*(?!\/))+?\s*\*\/[^;{}]*?$/);
+
+ // Replace the Swift code block with the test method’s contents.
+ let completedComment = commentMatch[0].replace(/^([ \t]*)```swift\n[^]*?```/m, function (m, indentation) {
+ // Apply the original indentation to each line.
+ return ('```swift\n' + exampleCode + '\n```').replace(/^/gm, indentation);
+ });
+
+ // Splice the modified comment into the overall file contents.
+ srcUpToSymbol = (srcUpToSymbol.substr(0, commentMatch.index) + completedComment +
+ srcUpToSymbol.substr(commentMatch.index + commentMatch[0].length));
+ return srcUpToSymbol + srcFromSymbol;
+}
+
+let examples = {};
+let match;
+while ((match = exampleRegex.exec(examplesSrc)) !== null) {
+ let testMethodName = match[1],
+ indentation = match[2],
+ exampleCode = match[3];
+
+ // Trim leading whitespace from the example code.
+ exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
+
+ examples[testMethodName] = exampleCode;
+}
+
+function completeExamples(os) {
+ console.log(`Installing ${os} SDK examples…`);
+
+ let sdk = os === 'iOS' ? 'iphonesimulator' : 'macosx';
+ let sysroot = execFileSync('xcrun', ['--show-sdk-path', '--sdk', sdk]).toString().trim();
+ let umbrellaPath = `platform/${os.toLowerCase()}/src/Mapbox.h`;
+ let docArgs = ['doc', '--objc', umbrellaPath, '--',
+ '-x', 'objective-c', '-I', 'platform/darwin/src/', '-isysroot', sysroot];
+ let docStr = execFileSync('sourcekitten', docArgs).toString().trim();
+ let docJson = JSON.parse(docStr);
+ _.forEach(docJson, function (result) {
+ _.forEach(result, function (structure, path) {
+ let src;
+ let newSrc;
+ // Recursively search for code blocks in documentation comments and populate
+ // them with example code from the test methods. Find and replace the code
+ // blocks in reverse to keep the SourceKitten line numbers accurate.
+ _.forEachRight(structure['key.substructure'], function completeSubstructure(substructure, idx, substructures, symbolPath) {
+ if (!symbolPath) {
+ symbolPath = [substructure['key.name']];
+ }
+ _.forEachRight(substructure['key.substructure'], function (substructure, idx, substructures) {
+ completeSubstructure(substructure, idx, substructures, _.concat(symbolPath, substructure['key.name']));
+ });
+
+ let comment = substructure['key.doc.comment'];
+ if (!comment || !comment.match(/^(?:\s*)```swift\n/m)) {
+ return;
+ }
+
+ // Lazily read in the existing file.
+ if (!src) {
+ newSrc = src = fs.readFileSync(path, 'utf8');
+ }
+
+ // Get the contents of the test method whose name matches the symbol path.
+ let testMethodName = symbolPath.join('$').replace(/\$[+-]/, '$').replace(/:/g, '_');
+ let example = examples[testMethodName];
+ if (!example) {
+ console.error(`MGLDocumentationExampleTests.${testMethodName}() not found.`);
+ process.exit(1);
+ }
+
+ // Resolve conditional compilation blocks.
+ example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\n/gm,
+ function (m, indentation, ifOs, ifCase, elseCase) {
+ return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
+ });
+
+ // Insert the test method contents into the documentation comment just
+ // above the substructure.
+ let startLine = substructure['key.parsed_scope.start'];
+ newSrc = completeSymbolInSource(newSrc, startLine, example);
+ });
+
+ if (!src) {
+ return;
+ }
+
+ // Write out the modified file contents.
+ if (src === newSrc) {
+ console.log('Skipping', path);
+ } else {
+ console.log('Updating', path);
+ if (['0', 'false'].indexOf(process.env.DRY_RUN || '0') !== -1) {
+ fs.writeFileSync(path, newSrc);
+ }
+ }
+ });
+ });
+}
+
+function ensureSourceKittenIsInstalled() {
+ try {
+ execFileSync('which', ['sourcekitten']);
+ } catch (e) {
+ console.log(`Installing SourceKitten via Homebrew…`);
+ execFileSync('brew', ['install', 'sourcekitten']);
+ }
+}
+
+ensureSourceKittenIsInstalled();
+
+// Where a particular comment is part of both SDKs, prefer the iOS example.
+completeExamples('macOS');
+completeExamples('iOS');
diff --git a/platform/darwin/src/MGLAttributionInfo.h b/platform/darwin/src/MGLAttributionInfo.h
index 28b4fe50e6..c4e037059e 100644
--- a/platform/darwin/src/MGLAttributionInfo.h
+++ b/platform/darwin/src/MGLAttributionInfo.h
@@ -51,7 +51,7 @@ MGL_EXPORT
coordinate and zoom level.
@param centerCoordinate The map’s center coordinate.
- @param zoomLevel The map’s zoom level. See `MGLMapView`’s `zoomLevel` property
+ @param zoomLevel The map’s zoom level. See the `MGLMapView.zoomLevel` property
for more information.
@return A modified URL containing a fragment that points to the specified
viewport. If the `feedbackLink` property is set to `NO`, this method returns
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index cf7b3cb22f..2546808b34 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -26,9 +26,20 @@
// Apply a bogus, easily detectable style rule to any feedback link, since
// NSAttributedString doesn’t preserve the class attribute.
NSMutableString *css = [NSMutableString stringWithString:
+ @"html { font-family: -apple-system, -apple-system-font, sans-serif; }"
@".mapbox-improve-map { -webkit-text-stroke-width: 1000px; }"];
if (fontSize) {
- [css appendFormat:@"html { font-size: %.1fpx; }", fontSize];
+ NSString *sizeRule = [NSString stringWithFormat:@"font-size: %.1fpx;", fontSize];
+#if !TARGET_OS_IPHONE
+ if (fontSize == [NSFont systemFontSizeForControlSize:NSMiniControlSize]) {
+ sizeRule = @"font: -webkit-mini-control";
+ } else if (fontSize == [NSFont systemFontSizeForControlSize:NSSmallControlSize]) {
+ sizeRule = @"font: -webkit-small-control";
+ } else if (fontSize == [NSFont systemFontSizeForControlSize:NSRegularControlSize]) {
+ sizeRule = @"font: -webkit-control";
+ }
+#endif
+ [css appendFormat:@"html { %@ }", sizeRule];
}
if (linkColor) {
CGFloat red;
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h
index e0773d14d9..06d7c9ee08 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.h
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.h
@@ -8,10 +8,18 @@
NS_ASSUME_NONNULL_BEGIN
/**
- A map style's background layer is the bottommost layer and is used to style a color
- or pattern to show below all other map features. You can query an `MGLMapView` for its
- `style` and obtain the background layer using the `-[MGLStyle layerWithIdentifier:]`
- method and passing `background` for the identifier.
+ An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a
+ background style layer to configure a color or pattern to show below all other
+ map content. If the style’s other layers use the Mapbox Streets source, the
+ background style layer is responsible for drawing land, whereas the oceans and
+ other bodies of water are drawn by `MGLFillStyleLayer` objects.
+
+ A background style layer is typically the bottommost layer in a style, because
+ it covers the entire map and can occlude any layers below it. You can therefore
+ access it by getting the last item in the `MGLStyle.layers` array.
+
+ If the background style layer is transparent or omitted from the style, any
+ portion of the map view that does not show another style layer is transparent.
*/
MGL_EXPORT
@interface MGLBackgroundStyleLayer : MGLStyleLayer
@@ -24,31 +32,41 @@ MGL_EXPORT
/**
The color with which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `backgroundPattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `backgroundPattern` is set to
+ `nil`. Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *backgroundColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *backgroundColor;
#else
/**
The color with which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `backgroundPattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `backgroundPattern` is set to
+ `nil`. Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *backgroundColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *backgroundColor;
#endif
/**
The opacity at which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *backgroundOpacity;
/**
- Name of image in style images to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ Name of image in style images to use for drawing an image background. For
+ seamless patterns, image width and height must be a factor of two (2, 4, 8,
+ ..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *backgroundPattern;
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm
index f6a00de941..caf8ca9681 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.mm
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,6 +8,7 @@
#import "MGLStyleValue_Private.h"
#import "MGLBackgroundStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/background_layer.hpp>
@interface MGLBackgroundStyleLayer ()
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 17ac3e5881..8d8c4588e7 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -10,40 +10,71 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the scaling behavior of the circle when the map is pitched.
- Values of this type are used in the `circlePitchScale` property of `MGLCircleStyleLayer`.
+ Values of this type are used in the `MGLCircleStyleLayer.circleScaleAlignment`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLCirclePitchScale) {
+typedef NS_ENUM(NSUInteger, MGLCircleScaleAlignment) {
/**
Circles are scaled according to their apparent distance to the camera.
*/
- MGLCirclePitchScaleMap,
+ MGLCircleScaleAlignmentMap,
/**
Circles are not scaled.
*/
- MGLCirclePitchScaleViewport,
+ MGLCircleScaleAlignmentViewport,
};
/**
Controls the translation reference point.
- Values of this type are used in the `circleTranslateAnchor` property of `MGLCircleStyleLayer`.
+ Values of this type are used in the `MGLCircleStyleLayer.circleTranslationAnchor`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLCircleTranslateAnchor) {
+typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
/**
The circle is translated relative to the map.
*/
- MGLCircleTranslateAnchorMap,
+ MGLCircleTranslationAnchorMap,
/**
The circle is translated relative to the viewport.
*/
- MGLCircleTranslateAnchorViewport,
+ MGLCircleTranslationAnchorViewport,
};
/**
- A circle layer which allows customization of styling properties at runtime. You may
- instantiate a new circle layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLCircleStyleLayer` is a style layer that renders one or more filled
+ circles on the map.
+
+ Use a circle style layer to configure the visual appearance of point or point
+ collection features in vector tiles loaded by an `MGLVectorSource` object or
+ `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or
+ `MGLPointCollectionFeature` instances in an `MGLShapeSource` object.
+
+ A circle style layer renders circles whose radii are measured in screen units.
+ To display circles on the map whose radii correspond to real-world distances,
+ use many-sided regular polygons and configure their appearance using an
+ `MGLFillStyleLayer` object.
+
+ You can access an existing circle style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new circle style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
+ layer.sourceLayerIdentifier = "population"
+ layer.circleColor = MGLStyleValue(rawValue: .green)
+ layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
+ 12: MGLStyleValue(rawValue: 2),
+ 22: MGLStyleValue(rawValue: 180)
+ ])
+ layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
+ layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
+ mapView.style?.addLayer(layer)
+ ```
*/
MGL_EXPORT
@interface MGLCircleStyleLayer : MGLVectorStyleLayer
@@ -51,9 +82,12 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
/**
- Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
+ Amount to blur the circle. 1 blurs the circle such that only the centerpoint is
+ full opacity.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleBlur;
@@ -61,90 +95,185 @@ MGL_EXPORT
/**
The fill color of the circle.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleColor;
#else
/**
The fill color of the circle.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleColor;
#endif
/**
The opacity at which the circle will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleOpacity;
/**
- Controls the scaling behavior of the circle when the map is pitched.
+ Circle radius.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLCirclePitchScaleMap`. Set this property to `nil` to reset it to the default value.
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `5`. Set this property to `nil` to reset
+ it to the default value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchScale;
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleRadius;
/**
- Circle radius.
-
- This property is measured in points.
+ Controls the scaling behavior of the circle when the map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `5`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLCircleScaleAlignmentMap`. Set this property to
+ `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-pitch-scale"><code>circle-pitch-scale</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleRadius;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleScaleAlignment;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchScale __attribute__((unavailable("Use circleScaleAlignment instead.")));
#if TARGET_OS_IPHONE
/**
The stroke color of the circle.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleStrokeColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleStrokeColor;
#else
/**
The stroke color of the circle.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *circleStrokeColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleStrokeColor;
#endif
/**
The opacity of the circle's stroke.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeOpacity;
/**
- The width of the circle's stroke. Strokes are placed outside of the `circleRadius`.
-
+ The width of the circle's stroke. Strokes are placed outside of the
+ "circle-radius".
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeWidth;
+#if TARGET_OS_IPHONE
/**
The geometry's offset.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslate;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
+#else
+/**
+ The geometry's offset.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
+#endif
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslate __attribute__((unavailable("Use circleTranslation instead.")));
/**
Controls the translation reference point.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLCircleTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLCircleTranslationAnchorMap`. Set this property
+ to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `circleTranslation` is non-`nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate-anchor"><code>circle-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslateAnchor __attribute__((unavailable("Use circleTranslationAnchor instead.")));
+
+@end
+
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLCircleStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLCircleStyleLayerAdditions)
- This property is only applied to the style if `circleTranslate` is non-`nil`. Otherwise, it is ignored.
+#pragma mark Working with Circle Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLCircleScaleAlignment` enumeration.
+
+ @param circleScaleAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment;
+
+/**
+ The `MGLCircleScaleAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLCircleScaleAlignment MGLCircleScaleAlignmentValue;
+
+/**
+ Creates a new value object containing the given `MGLCircleTranslationAnchor` enumeration.
+
+ @param circleTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLCircleTranslationAnchor:(MGLCircleTranslationAnchor)circleTranslationAnchor;
+
+/**
+ The `MGLCircleTranslationAnchor` enumeration representation of the value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslateAnchor;
+@property (readonly) MGLCircleTranslationAnchor MGLCircleTranslationAnchorValue;
@end
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index e8ee2bca7e..adc5ed8dd3 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,17 +8,19 @@
#import "MGLStyleValue_Private.h"
#import "MGLCircleStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
+
namespace mbgl {
- MBGL_DEFINE_ENUM(MGLCirclePitchScale, {
- { MGLCirclePitchScaleMap, "map" },
- { MGLCirclePitchScaleViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLCircleScaleAlignment, {
+ { MGLCircleScaleAlignmentMap, "map" },
+ { MGLCircleScaleAlignmentViewport, "viewport" },
});
- MBGL_DEFINE_ENUM(MGLCircleTranslateAnchor, {
- { MGLCircleTranslateAnchorMap, "map" },
- { MGLCircleTranslateAnchorViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLCircleTranslationAnchor, {
+ { MGLCircleTranslationAnchorMap, "map" },
+ { MGLCircleTranslationAnchorViewport, "viewport" },
});
}
@@ -54,6 +56,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -73,7 +82,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
- self.rawLayer->setFilter(predicate.mgl_filter);
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -166,32 +175,39 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-- (void)setCirclePitchScale:(MGLStyleValue<NSValue *> *)circlePitchScale {
+- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumPropertyValue(circlePitchScale);
- self.rawLayer->setCirclePitchScale(mbglValue);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleRadius);
+ self.rawLayer->setCircleRadius(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circlePitchScale {
+- (MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
- return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius();
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
+- (void)setCircleScaleAlignment:(MGLStyleValue<NSValue *> *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleRadius);
- self.rawLayer->setCircleRadius(mbglValue);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumPropertyValue(circleScaleAlignment);
+ self.rawLayer->setCirclePitchScale(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleRadius {
+- (MGLStyleValue<NSValue *> *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
+ return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setCirclePitchScale:(MGLStyleValue<NSValue *> *)circlePitchScale {
+}
+
+- (MGLStyleValue<NSValue *> *)circlePitchScale {
+ return self.circleScaleAlignment;
}
- (void)setCircleStrokeColor:(MGLStyleValue<MGLColor *> *)circleStrokeColor {
@@ -236,33 +252,71 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-- (void)setCircleTranslate:(MGLStyleValue<NSValue *> *)circleTranslate {
+- (void)setCircleTranslation:(MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslate);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslation);
self.rawLayer->setCircleTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circleTranslate {
+- (MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
-- (void)setCircleTranslateAnchor:(MGLStyleValue<NSValue *> *)circleTranslateAnchor {
+- (void)setCircleTranslate:(MGLStyleValue<NSValue *> *)circleTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)circleTranslate {
+ return self.circleTranslation;
+}
+
+- (void)setCircleTranslationAnchor:(MGLStyleValue<NSValue *> *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumPropertyValue(circleTranslateAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumPropertyValue(circleTranslationAnchor);
self.rawLayer->setCircleTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
+- (MGLStyleValue<NSValue *> *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor();
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setCircleTranslateAnchor:(MGLStyleValue<NSValue *> *)circleTranslateAnchor {
}
+- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
+ return self.circleTranslationAnchor;
+}
+
+
+@end
+
+@implementation NSValue (MGLCircleStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment {
+ return [NSValue value:&circleScaleAlignment withObjCType:@encode(MGLCircleScaleAlignment)];
+}
+
+- (MGLCircleScaleAlignment)MGLCircleScaleAlignmentValue {
+ MGLCircleScaleAlignment circleScaleAlignment;
+ [self getValue:&circleScaleAlignment];
+ return circleScaleAlignment;
+}
+
++ (NSValue *)valueWithMGLCircleTranslationAnchor:(MGLCircleTranslationAnchor)circleTranslationAnchor {
+ return [NSValue value:&circleTranslationAnchor withObjCType:@encode(MGLCircleTranslationAnchor)];
+}
+
+- (MGLCircleTranslationAnchor)MGLCircleTranslationAnchorValue {
+ MGLCircleTranslationAnchor circleTranslationAnchor;
+ [self getValue:&circleTranslationAnchor];
+ return circleTranslationAnchor;
+}
@end
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index b3a1868ed2..82dbb450cf 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -11,30 +11,41 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLFeature` protocol is used to provide details about geographic features
- contained in a map view’s
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
- Each concrete subclass of `MGLShape` in turn has a subclass that conforms to
- this protocol.
-
- Typically, you do not create feature objects yourself but rather obtain them
- using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature
- object associates a shape with an identifier and attributes as specified by the
- source. Like ordinary `MGLAnnotation` objects, some kinds of `MGLFeature`
- objects can also be added to a map view using an `MGLShapeSource` or
- `-[MGLMapView addAnnotations:]` and related methods.
+ contained in an `MGLShapeSource` or `MGLVectorSource` object. Each concrete
+ subclass of `MGLShape` in turn has a subclass that conforms to this protocol. A
+ feature object associates a shape with an optional identifier and attributes.
+
+ You can add custom data to display on the map by creating feature objects and
+ adding them to an `MGLShapeSource` using the
+ `-[MGLShapeSource initWithIdentifier:shape:options:]` method or
+ `MGLShapeSource.shape` property. Similarly, you can add `MGLPointFeature`,
+ `MGLPolylineFeature`, and `MGLPolygonFeature` objects to the map as annotations
+ using `-[MGLMapView addAnnotations:]` and related methods.
+
+ In addition to adding data to the map, you can also extract data from the map:
+ `-[MGLMapView visibleFeaturesAtPoint:]` and related methods return feature
+ objects that correspond to features in the source. This enables you to inspect
+ the properties of features in vector tiles loaded by `MGLVectorSource` objects.
+ You also reuse these feature objects as overlay annotations.
*/
@protocol MGLFeature <MGLAnnotation>
/**
- An object that uniquely identifies the feature in its containing
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An object that uniquely identifies the feature in its containing content
+ source.
- The identifier corresponds to the
+ You can configure an `MGLVectorStyleLayer` object to include or exclude a
+ specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
+ `MGLVectorStyleLayer.predicate` property, compare the special `$id` attribute
+ to the feature’s identifier.
+
+ In vector tiles loaded by `MGLVectorSource` objects, the identifier corresponds
+ to the
<a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
- (`id`) in the tile source. If the source does not specify the feature’s
- identifier, the value of this property is `nil`. If specified, the identifier
- may be an integer, floating-point number, or string. These data types are
- mapped to instances of the following Foundation classes:
+ (`id`). If the source does not specify the feature’s identifier, the value of
+ this property is `nil`. If specified, the identifier may be an integer,
+ floating-point number, or string. These data types are mapped to instances of
+ the following Foundation classes:
<table>
<thead>
@@ -50,22 +61,40 @@ NS_ASSUME_NONNULL_BEGIN
For details about the identifiers used in most Mapbox-provided styles, consult
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
- layer reference. Note that while it is possible to change this value on feature
- instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
- methods, there will be no effect on the map. Setting this value can be useful
- when the feature instance is used to initialize an `MGLShapeSource` and that
- source is added to the map and styled.
+ layer reference.
+
+ The identifier should be set before adding the feature to an `MGLShapeSource`
+ object; setting it afterwards has no effect on the map’s contents. While it is
+ possible to change this value on feature instances obtained from
+ `-[MGLMapView visibleFeaturesAtPoint:]` and related methods, doing so likewise
+ has no effect on the map’s contents.
*/
@property (nonatomic, copy, nullable) id identifier;
/**
- A dictionary of attributes for this feature specified by the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ A dictionary of attributes for this feature.
+
+ You can configure an `MGLVectorStyleLayer` object to include or exclude a
+ specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
+ `MGLVectorStyleLayer.predicate` property, compare a key of the attribute
+ dictionary to the value you want to include. For example, if you want an
+ `MGLLineStyleLayer` object to display only important features, you might assign
+ a value above 50 to the important features’ `importance` attribute, then set
+ `MGLVectorStyleLayer.predicate` to an `NSPredicate` with the format
+ `importance > 50`.
- The keys and values of this dictionary are determined by the tile source. In
- the tile source, each attribute name is a string, while each attribute value
- may be a null value, Boolean value, integer, floating-point number, or string.
- These data types are mapped to instances of the following Foundation classes:
+ You can also configure some attributes of an `MGLSymbolStyleLayer` object to
+ include the value of an attribute in this dictionary whenever it renders this
+ feature. For example, to label features in an `MGLShapeSource` object by their
+ names, you can assign a `name` attribute to each of the source’s features, then
+ set `MGLSymbolStyleLayer.textField` to an `MGLStyleValue` object containing the
+ string `{name}`.
+
+ In vector tiles loaded by `MGLVectorSource` objects, the keys and values of
+ each feature’s attribute dictionary are determined by the source. Each
+ attribute name is a string, while each attribute value may be a null value,
+ Boolean value, integer, floating-point number, or string. These data types are
+ mapped to instances of the following Foundation classes:
<table>
<thead>
@@ -85,7 +114,9 @@ NS_ASSUME_NONNULL_BEGIN
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
and
<a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>
- layer references. Note that while it is possible to change this value on feature
+ layer references.
+
+ Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
when the feature instance is used to initialize an `MGLShapeSource` and that
@@ -115,56 +146,75 @@ NS_ASSUME_NONNULL_BEGIN
@end
/**
- The `MGLPointFeature` class represents a point in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLPointFeature` object associates a point shape with an optional
+ identifier and attributes.
*/
MGL_EXPORT
@interface MGLPointFeature : MGLPointAnnotation <MGLFeature>
@end
/**
- The `MGLPolylineFeature` class represents a polyline in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLPolylineFeature` object associates a polyline shape with an optional
+ identifier and attributes.
+
+ A polyline feature is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
+ feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLPolylineFeature : MGLPolyline <MGLFeature>
@end
/**
- The `MGLPolygonFeature` class represents a polygon in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLPolygonFeature` object associates a polygon shape with an optional
+ identifier and attributes.
*/
MGL_EXPORT
@interface MGLPolygonFeature : MGLPolygon <MGLFeature>
@end
/**
- The `MGLPointCollectionFeature` class represents a multipoint in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLPointCollectionFeature` object associates a point collection with an
+ optional identifier and attributes.
+
+ A point collection feature is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
+ feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLPointCollectionFeature : MGLPointCollection <MGLFeature>
@end
+// https://github.com/mapbox/mapbox-gl-native/issues/7473
+@compatibility_alias MGLMultiPointFeature MGLPointCollectionFeature;
+
/**
- The `MGLMultiPolylineFeature` class represents a multipolyline in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLMultiPolylineFeature` object associates a multipolyline shape with an
+ optional identifier and attributes.
+
+ A multipolyline feature is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
+ feature in GeoJSON.
*/
MGL_EXPORT
@interface MGLMultiPolylineFeature : MGLMultiPolyline <MGLFeature>
@end
/**
- The `MGLMultiPolygonFeature` class represents a multipolygon in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLMultiPolygonFeature` object associates a multipolygon shape with an
+ optional identifier and attributes.
*/
MGL_EXPORT
@interface MGLMultiPolygonFeature : MGLMultiPolygon <MGLFeature>
@end
/**
- The `MGLShapeCollectionFeature` class represents a shape collection in a
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ An `MGLShapeCollectionFeature` object associates a shape collection with an
+ optional identifier and attributes.
+
+ A shape collection feature is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.3">feature collection</a>
+ in GeoJSON.
*/
MGL_EXPORT
@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index c1e0c312a0..3bd7eae535 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -10,6 +10,7 @@
#import "MGLPolyline+MGLAdditions.h"
#import "MGLPolygon+MGLAdditions.h"
#import "NSDictionary+MGLAdditions.h"
+#import "NSArray+MGLAdditions.h"
#import "NSExpression+MGLAdditions.h"
@@ -25,6 +26,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -47,6 +52,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -69,6 +78,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -91,6 +104,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -113,6 +130,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -135,6 +156,10 @@
@synthesize identifier;
@synthesize attributes;
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
@@ -159,10 +184,14 @@
@dynamic shapes;
-+ (instancetype)shapeCollectionWithShapes:(NSArray *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
+MGL_DEFINE_FEATURE_INIT_WITH_CODER();
+MGL_DEFINE_FEATURE_ENCODE();
+MGL_DEFINE_FEATURE_IS_EQUAL();
+
- (id)attributeForKey:(NSString *)key {
return self.attributes[key];
}
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
index 59c5ab8611..6751b3196a 100644
--- a/platform/darwin/src/MGLFeature_Private.h
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -39,3 +39,31 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
NS_ASSUME_NONNULL_END
+
+#define MGL_DEFINE_FEATURE_INIT_WITH_CODER() \
+ - (instancetype)initWithCoder:(NSCoder *)decoder { \
+ if (self = [super initWithCoder:decoder]) { \
+ NSSet<Class> *identifierClasses = [NSSet setWithArray:@[[NSString class], [NSNumber class]]]; \
+ identifier = [decoder decodeObjectOfClasses:identifierClasses forKey:@"identifier"]; \
+ attributes = [decoder decodeObjectOfClass:[NSDictionary class] forKey:@"attributes"]; \
+ } \
+ return self; \
+ }
+
+#define MGL_DEFINE_FEATURE_ENCODE() \
+ - (void)encodeWithCoder:(NSCoder *)coder { \
+ [super encodeWithCoder:coder]; \
+ [coder encodeObject:identifier forKey:@"identifier"]; \
+ [coder encodeObject:attributes forKey:@"attributes"]; \
+ }
+
+#define MGL_DEFINE_FEATURE_IS_EQUAL() \
+ - (BOOL)isEqual:(id)other { \
+ if (other == self) return YES; \
+ if (![other isKindOfClass:[self class]]) return NO; \
+ __typeof(self) otherFeature = other; \
+ return [super isEqual:other] && [self geoJSONObject] == [otherFeature geoJSONObject]; \
+ } \
+ - (NSUInteger)hash { \
+ return [super hash] + [[self geoJSONDictionary] hash]; \
+ }
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index c586ce413b..2ab02acf5a 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -10,24 +10,44 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the translation reference point.
- Values of this type are used in the `fillTranslateAnchor` property of `MGLFillStyleLayer`.
+ Values of this type are used in the `MGLFillStyleLayer.fillTranslationAnchor`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) {
+typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
/**
The fill is translated relative to the map.
*/
- MGLFillTranslateAnchorMap,
+ MGLFillTranslationAnchorMap,
/**
The fill is translated relative to the viewport.
*/
- MGLFillTranslateAnchorViewport,
+ MGLFillTranslationAnchorViewport,
};
/**
- A fill layer which allows customization of styling properties at runtime. You may
- instantiate a new fill layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLFillStyleLayer` is a style layer that renders one or more filled (and
+ optionally stroked) polygons on the map.
+
+ Use a fill style layer to configure the visual appearance of polygon or
+ multipolygon features in vector tiles loaded by an `MGLVectorSource` object or
+ `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
+ `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
+
+ You can access an existing fill style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new fill style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
+ layer.sourceLayerIdentifier = "parks"
+ layer.fillColor = MGLStyleValue(rawValue: .green)
+ layer.predicate = NSPredicate(format: "type == %@", "national-park")
+ mapView.style?.addLayer(layer)
+ ```
*/
MGL_EXPORT
@interface MGLFillStyleLayer : MGLVectorStyleLayer
@@ -37,71 +57,154 @@ MGL_EXPORT
/**
Whether or not the fill should be antialiased.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `YES`. Set this property to `nil` to reset it to
+ the default value.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a> paint property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased;
-
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
#if TARGET_OS_IPHONE
/**
The color of the filled part of this layer.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `fillPattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillColor;
#else
/**
The color of the filled part of this layer.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `fillPattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillColor;
#endif
/**
- The opacity of the entire fill layer. In contrast to the `fillColor`, this value will also affect the 1pt stroke around the fill, if the stroke is used.
+ The opacity of the entire fill layer. In contrast to the `fillColor`, this
+ value will also affect the 1pt stroke around the fill, if the stroke is used.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillOpacity;
+#if TARGET_OS_IPHONE
/**
The outline color of the fill. Matches the value of `fillColor` if unspecified.
-
- This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialiased` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`,
+ and `fillAntialiased` is set to an `MGLStyleValue` object containing an
+ `NSNumber` object containing `YES`. Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillOutlineColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillOutlineColor;
+#else
+/**
+ The outline color of the fill. Matches the value of `fillColor` if unspecified.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`,
+ and `fillAntialiased` is set to an `MGLStyleValue` object containing an
+ `NSNumber` object containing `YES`. Otherwise, it is ignored.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillOutlineColor;
+#endif
/**
- Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ Name of image in sprite to use for drawing image fills. For seamless patterns,
+ image width and height must be a factor of two (2, 4, 8, ..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillPattern;
+#if TARGET_OS_IPHONE
/**
The geometry's offset.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslate;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
+#else
+/**
+ The geometry's offset.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
+#endif
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslate __attribute__((unavailable("Use fillTranslation instead.")));
/**
Controls the translation reference point.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLFillTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLFillTranslationAnchorMap`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `fillTranslation` is non-`nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate-anchor"><code>fill-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslateAnchor __attribute__((unavailable("Use fillTranslationAnchor instead.")));
- This property is only applied to the style if `fillTranslate` is non-`nil`. Otherwise, it is ignored.
+@end
+
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLFillStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLFillStyleLayerAdditions)
+
+#pragma mark Working with Fill Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLFillTranslationAnchor` enumeration.
+
+ @param fillTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLFillTranslationAnchor:(MGLFillTranslationAnchor)fillTranslationAnchor;
+
+/**
+ The `MGLFillTranslationAnchor` enumeration representation of the value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslateAnchor;
+@property (readonly) MGLFillTranslationAnchor MGLFillTranslationAnchorValue;
@end
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index 891ab85d0b..63a482ac2e 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,12 +8,14 @@
#import "MGLStyleValue_Private.h"
#import "MGLFillStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
+
namespace mbgl {
- MBGL_DEFINE_ENUM(MGLFillTranslateAnchor, {
- { MGLFillTranslateAnchorMap, "map" },
- { MGLFillTranslateAnchorViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLFillTranslationAnchor, {
+ { MGLFillTranslationAnchorMap, "map" },
+ { MGLFillTranslationAnchorViewport, "viewport" },
});
}
@@ -49,6 +51,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -68,7 +77,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
- self.rawLayer->setFilter(predicate.mgl_filter);
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -133,9 +142,11 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias {
- NSAssert(NO, @"Use -setFillAntialiased: instead.");
+}
+
+- (MGLStyleValue<NSNumber *> *)fillAntialias {
+ return self.isFillAntialiased;
}
- (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor {
@@ -194,33 +205,61 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
-- (void)setFillTranslate:(MGLStyleValue<NSValue *> *)fillTranslate {
+- (void)setFillTranslation:(MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslate);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslation);
self.rawLayer->setFillTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillTranslate {
+- (MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
-- (void)setFillTranslateAnchor:(MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+- (void)setFillTranslate:(MGLStyleValue<NSValue *> *)fillTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)fillTranslate {
+ return self.fillTranslation;
+}
+
+- (void)setFillTranslationAnchor:(MGLStyleValue<NSValue *> *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumPropertyValue(fillTranslateAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumPropertyValue(fillTranslationAnchor);
self.rawLayer->setFillTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+- (MGLStyleValue<NSValue *> *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor();
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setFillTranslateAnchor:(MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+}
+
+- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+ return self.fillTranslationAnchor;
}
@end
+
+@implementation NSValue (MGLFillStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLFillTranslationAnchor:(MGLFillTranslationAnchor)fillTranslationAnchor {
+ return [NSValue value:&fillTranslationAnchor withObjCType:@encode(MGLFillTranslationAnchor)];
+}
+
+- (MGLFillTranslationAnchor)MGLFillTranslationAnchorValue {
+ MGLFillTranslationAnchor fillTranslationAnchor;
+ [self getValue:&fillTranslationAnchor];
+ return fillTranslationAnchor;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 6df0d38088..98f2778291 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -10,19 +10,24 @@ NS_ASSUME_NONNULL_BEGIN
/**
The display of line endings.
- Values of this type are used in the `lineCap` property of `MGLLineStyleLayer`.
+ Values of this type are used in the `MGLLineStyleLayer.lineCap`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLLineCap) {
/**
- A cap with a squared-off end which is drawn to the exact endpoint of the line.
+ A cap with a squared-off end which is drawn to the exact endpoint of the
+ line.
*/
MGLLineCapButt,
/**
- A cap with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
+ A cap with a rounded end which is drawn beyond the endpoint of the line at
+ a radius of one-half of the line's width and centered on the endpoint of
+ the line.
*/
MGLLineCapRound,
/**
- A cap with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
+ A cap with a squared-off end which is drawn beyond the endpoint of the line
+ at a distance of one-half of the line's width.
*/
MGLLineCapSquare,
};
@@ -30,19 +35,24 @@ typedef NS_ENUM(NSUInteger, MGLLineCap) {
/**
The display of lines when joining.
- Values of this type are used in the `lineJoin` property of `MGLLineStyleLayer`.
+ Values of this type are used in the `MGLLineStyleLayer.lineJoin`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLLineJoin) {
/**
- A join with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
+ A join with a squared-off end which is drawn beyond the endpoint of the
+ line at a distance of one-half of the line's width.
*/
MGLLineJoinBevel,
/**
- A join with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
+ A join with a rounded end which is drawn beyond the endpoint of the line at
+ a radius of one-half of the line's width and centered on the endpoint of
+ the line.
*/
MGLLineJoinRound,
/**
- A join with a sharp, angled corner which is drawn with the outer sides beyond the endpoint of the path until they meet.
+ A join with a sharp, angled corner which is drawn with the outer sides
+ beyond the endpoint of the path until they meet.
*/
MGLLineJoinMiter,
};
@@ -50,24 +60,49 @@ typedef NS_ENUM(NSUInteger, MGLLineJoin) {
/**
Controls the translation reference point.
- Values of this type are used in the `lineTranslateAnchor` property of `MGLLineStyleLayer`.
+ Values of this type are used in the `MGLLineStyleLayer.lineTranslationAnchor`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLLineTranslateAnchor) {
+typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
/**
The line is translated relative to the map.
*/
- MGLLineTranslateAnchorMap,
+ MGLLineTranslationAnchorMap,
/**
The line is translated relative to the viewport.
*/
- MGLLineTranslateAnchorViewport,
+ MGLLineTranslationAnchorViewport,
};
/**
- A line layer which allows customization of styling properties at runtime. You may
- instantiate a new line layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLLineStyleLayer` is a style layer that renders one or more stroked
+ polylines on the map.
+
+ Use a line style layer to configure the visual appearance of polyline or
+ multipolyline features in vector tiles loaded by an `MGLVectorSource` object or
+ `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or
+ `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object.
+
+ You can access an existing line style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new line style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
+ layer.sourceLayerIdentifier = "trails"
+ layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 20),
+ ])
+ layer.lineColor = MGLStyleValue(rawValue: .brown)
+ layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
+ layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
+ mapView.style?.addLayer(layer)
+ ```
*/
MGL_EXPORT
@interface MGLLineStyleLayer : MGLVectorStyleLayer
@@ -77,32 +112,44 @@ MGL_EXPORT
/**
The display of line endings.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to
+ reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineCap;
/**
The display of lines when joining.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to
+ reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineJoin;
/**
Used to automatically convert miter joins to bevel joins for sharp angles.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `2`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `lineJoin` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinMiter`. Otherwise, it is ignored.
+ This property is only applied to the style if `lineJoin` is set to an
+ `MGLStyleValue` object containing an `NSValue` object containing
+ `MGLLineJoinMiter`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineMiterLimit;
/**
Used to automatically convert round joins to miter joins for shallow angles.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1.05`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1.05`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `lineJoin` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineJoinRound`. Otherwise, it is ignored.
+ This property is only applied to the style if `lineJoin` is set to an
+ `MGLStyleValue` object containing an `NSValue` object containing
+ `MGLLineJoinRound`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineRoundLimit;
@@ -110,10 +157,12 @@ MGL_EXPORT
/**
Blur applied to the line, in points.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineBlur;
@@ -121,93 +170,199 @@ MGL_EXPORT
/**
The color with which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `linePattern` is set to `nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *lineColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *lineColor;
#else
/**
The color with which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `linePattern` is set to `nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *lineColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *lineColor;
#endif
/**
- Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to points, multiply the length by the current line width.
-
+ Specifies the lengths of the alternating dashes and gaps that form the dash
+ pattern. The lengths are later scaled by the line width. To convert a dash
+ length to points, multiply the length by the current line width.
+
This property is measured in line widths.
-
- This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a> paint property in the Mapbox Style Specification.
+ This property is only applied to the style if `linePattern` is set to `nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern;
-
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray __attribute__((unavailable("Use lineDashPattern instead.")));
/**
- Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
-
+ Draws a line casing outside of a line's actual path. Value indicates the width
+ of the inner gap.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineGapWidth;
/**
- The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
-
+ The line's offset. For linear features, a positive value offsets the line to
+ the right, relative to the direction of the line, and a negative value to the
+ left. For polygon features, a positive value results in an inset, and a
+ negative value results in an outset.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOffset;
/**
The opacity at which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOpacity;
/**
- Name of image in style images to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ Name of image in style images to use for drawing image lines. For seamless
+ patterns, image width must be a factor of two (2, 4, 8, ..., 512).
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *linePattern;
+#if TARGET_OS_IPHONE
/**
The geometry's offset.
-
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
+#else
+/**
+ The geometry's offset.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslate;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
+#endif
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslate __attribute__((unavailable("Use lineTranslation instead.")));
/**
Controls the translation reference point.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLLineTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `lineTranslate` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLLineTranslationAnchorMap`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `lineTranslation` is non-`nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate-anchor"><code>line-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslateAnchor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslateAnchor __attribute__((unavailable("Use lineTranslationAnchor instead.")));
/**
Stroke thickness.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineWidth;
@end
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLLineStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLLineStyleLayerAdditions)
+
+#pragma mark Working with Line Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLLineCap` enumeration.
+
+ @param lineCap The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLLineCap:(MGLLineCap)lineCap;
+
+/**
+ The `MGLLineCap` enumeration representation of the value.
+ */
+@property (readonly) MGLLineCap MGLLineCapValue;
+
+/**
+ Creates a new value object containing the given `MGLLineJoin` enumeration.
+
+ @param lineJoin The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLLineJoin:(MGLLineJoin)lineJoin;
+
+/**
+ The `MGLLineJoin` enumeration representation of the value.
+ */
+@property (readonly) MGLLineJoin MGLLineJoinValue;
+
+/**
+ Creates a new value object containing the given `MGLLineTranslationAnchor` enumeration.
+
+ @param lineTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLLineTranslationAnchor:(MGLLineTranslationAnchor)lineTranslationAnchor;
+
+/**
+ The `MGLLineTranslationAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLLineTranslationAnchor MGLLineTranslationAnchorValue;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 48164ed0c8..13408d426c 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,7 +8,9 @@
#import "MGLStyleValue_Private.h"
#import "MGLLineStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/line_layer.hpp>
+
namespace mbgl {
MBGL_DEFINE_ENUM(MGLLineCap, {
@@ -23,9 +25,9 @@ namespace mbgl {
{ MGLLineJoinMiter, "miter" },
});
- MBGL_DEFINE_ENUM(MGLLineTranslateAnchor, {
- { MGLLineTranslateAnchorMap, "map" },
- { MGLLineTranslateAnchorViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLLineTranslationAnchor, {
+ { MGLLineTranslationAnchorMap, "map" },
+ { MGLLineTranslationAnchorViewport, "viewport" },
});
}
@@ -61,6 +63,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -80,7 +89,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
- self.rawLayer->setFilter(predicate.mgl_filter);
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -231,9 +240,11 @@ namespace mbgl {
return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue);
}
-
- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
- NSAssert(NO, @"Use -setLineDashPattern: instead.");
+}
+
+- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
+ return self.lineDashPattern;
}
- (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth {
@@ -292,32 +303,46 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
-- (void)setLineTranslate:(MGLStyleValue<NSValue *> *)lineTranslate {
+- (void)setLineTranslation:(MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslate);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslation);
self.rawLayer->setLineTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineTranslate {
+- (MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
-- (void)setLineTranslateAnchor:(MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+- (void)setLineTranslate:(MGLStyleValue<NSValue *> *)lineTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)lineTranslate {
+ return self.lineTranslation;
+}
+
+- (void)setLineTranslationAnchor:(MGLStyleValue<NSValue *> *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumPropertyValue(lineTranslateAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumPropertyValue(lineTranslationAnchor);
self.rawLayer->setLineTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+- (MGLStyleValue<NSValue *> *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor();
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setLineTranslateAnchor:(MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+}
+
+- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+ return self.lineTranslationAnchor;
}
- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
@@ -336,3 +361,37 @@ namespace mbgl {
@end
+
+@implementation NSValue (MGLLineStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLLineCap:(MGLLineCap)lineCap {
+ return [NSValue value:&lineCap withObjCType:@encode(MGLLineCap)];
+}
+
+- (MGLLineCap)MGLLineCapValue {
+ MGLLineCap lineCap;
+ [self getValue:&lineCap];
+ return lineCap;
+}
+
++ (NSValue *)valueWithMGLLineJoin:(MGLLineJoin)lineJoin {
+ return [NSValue value:&lineJoin withObjCType:@encode(MGLLineJoin)];
+}
+
+- (MGLLineJoin)MGLLineJoinValue {
+ MGLLineJoin lineJoin;
+ [self getValue:&lineJoin];
+ return lineJoin;
+}
+
++ (NSValue *)valueWithMGLLineTranslationAnchor:(MGLLineTranslationAnchor)lineTranslationAnchor {
+ return [NSValue value:&lineTranslationAnchor withObjCType:@encode(MGLLineTranslationAnchor)];
+}
+
+- (MGLLineTranslationAnchor)MGLLineTranslationAnchorValue {
+ MGLLineTranslationAnchor lineTranslationAnchor;
+ [self getValue:&lineTranslationAnchor];
+ return lineTranslationAnchor;
+}
+
+@end
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index eaac50af46..31ab5744a3 100644
--- a/platform/darwin/src/MGLMultiPoint.h
+++ b/platform/darwin/src/MGLMultiPoint.h
@@ -8,10 +8,15 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLMultiPoint` class is an abstract superclass used to define shapes
- composed of multiple vertices. You should not create instances of this class
- directly. Instead, you should create instances of the `MGLPolyline` or
- `MGLPolygon` classes. However, you can use the method and properties of this
- class to access information about the vertices of the line or polygon.
+ composed of multiple vertices.
+
+ You do not create instances of this class directly. Instead, you create
+ instances of the `MGLPolyline` or `MGLPolygon` classes. However, you can use
+ the method and properties of this class to access information about the
+ vertices of the line or polygon.
+
+ Do not confuse `MGLMultiPoint` with `MGLPointCollection`, which represents a
+ collection of related but disconnected points.
*/
MGL_EXPORT
@interface MGLMultiPoint : MGLShape
@@ -57,7 +62,7 @@ MGL_EXPORT
the map, it is redrawn immediately.
@param coords The array of coordinates to insert into the shape. The data in
- this array is copied to the shape’s `coordinate` property.
+ this array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
@param index The zero-based index at which the first coordinate in `coords`
will appear in the `coordinates` property.
@@ -69,7 +74,7 @@ MGL_EXPORT
the map, it is redrawn immediately.
@param coords The array of coordinates to add to the shape. The data in this
- array is copied to the shape’s `coordinate` property.
+ array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
*/
- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
@@ -92,7 +97,7 @@ MGL_EXPORT
being the second vertex, and so on. The `length` field indicates the number
of vertices to replace.
@param coords The array of coordinates defining part of the shape. The data in
- this array is copied to the shape’s `coordinate` property.
+ this array is copied to the shape’s `coordinates` property.
*/
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index c49e970c6b..3b03b78ca6 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -1,10 +1,9 @@
#import "MGLMultiPoint_Private.h"
#import "MGLGeometry_Private.h"
+#import "MGLShape_Private.h"
+#import "NSCoder+MGLAdditions.h"
#import "MGLTypes.h"
-#include <mbgl/util/geo.hpp>
-#include <mbgl/util/optional.hpp>
-
@implementation MGLMultiPoint
{
mbgl::optional<mbgl::LatLngBounds> _bounds;
@@ -27,6 +26,39 @@
return self;
}
+- (instancetype)initWithCoder:(NSCoder *)decoder
+{
+ if (self = [super initWithCoder:decoder]) {
+ _coordinates = [decoder mgl_decodeLocationCoordinates2DForKey:@"coordinates"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+ [super encodeWithCoder:coder];
+ [coder mgl_encodeLocationCoordinates2D:_coordinates forKey:@"coordinates"];
+}
+
+- (BOOL)isEqual:(id)other
+{
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLMultiPoint class]]) return NO;
+
+ MGLMultiPoint *otherMultipoint = other;
+ return ([super isEqual:otherMultipoint]
+ && _coordinates == otherMultipoint->_coordinates);
+}
+
+- (NSUInteger)hash
+{
+ NSUInteger hash = [super hash];
+ for (auto coord : _coordinates) {
+ hash += @(coord.latitude+coord.longitude).hash;
+ }
+ return hash;
+}
+
- (CLLocationCoordinate2D)coordinate
{
NSAssert([self pointCount] > 0, @"A multipoint must have coordinates");
diff --git a/platform/darwin/src/MGLNetworkConfiguration.m b/platform/darwin/src/MGLNetworkConfiguration.m
index d661d9090e..82d333dc99 100644
--- a/platform/darwin/src/MGLNetworkConfiguration.m
+++ b/platform/darwin/src/MGLNetworkConfiguration.m
@@ -1,5 +1,4 @@
#import "MGLNetworkConfiguration.h"
-#import "NSProcessInfo+MGLAdditions.h"
@implementation MGLNetworkConfiguration
@@ -12,9 +11,6 @@
}
+ (instancetype)sharedManager {
- if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) {
- return nil;
- }
static dispatch_once_t onceToken;
static MGLNetworkConfiguration *_sharedManager;
void (^setupBlock)() = ^{
diff --git a/platform/darwin/src/MGLOfflinePack.h b/platform/darwin/src/MGLOfflinePack.h
index de76228ff0..8436434e68 100644
--- a/platform/darwin/src/MGLOfflinePack.h
+++ b/platform/darwin/src/MGLOfflinePack.h
@@ -26,8 +26,8 @@ typedef NS_ENUM (NSInteger, MGLOfflinePackState) {
The pack is incomplete and is not currently downloading.
This is the initial state of a pack that is created using the
- `-[MGLOfflinePack addPackForRegion:withContext:completionHandler:]` method,
- as well as after the `-[MGLOfflinePack suspend]` method is
+ `-[MGLOfflineStorage addPackForRegion:withContext:completionHandler:]`
+ method, as well as after the `-[MGLOfflinePack suspend]` method is
called.
*/
MGLOfflinePackStateInactive = 1,
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 9557258b41..9125c5341e 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -19,7 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
`userInfo` dictionary contains the pack’s current state in the
`MGLOfflinePackStateUserInfoKey` key and details about the pack’s current
progress in the `MGLOfflinePackProgressUserInfoKey` key. You may also consult
- the pack’s `state` and `progress` properties, which provide the same values.
+ the `MGLOfflinePack.state` and `MGLOfflinePack.progress` properties, which
+ provide the same values.
If you only need to observe changes in a particular pack’s progress, you can
alternatively observe KVO change notifications to the pack’s `progress` key
@@ -183,8 +184,8 @@ MGL_EXPORT
- (void)addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)context completionHandler:(nullable MGLOfflinePackAdditionCompletionHandler)completion;
/**
- Unregisters the given offline pack and frees any resources that are no longer
- required by any remaining packs.
+ Unregisters the given offline pack and allows resources that are no longer
+ required by any remaining packs to be potentially freed.
As soon as this method is called on a pack, the pack becomes invalid; any
attempt to send it a message will result in an exception being thrown. If an
@@ -196,6 +197,13 @@ MGL_EXPORT
KVO change notifications on the shared offline storage object’s `packs` key
path. Removals from that array result in an `NSKeyValueChangeRemoval` change.
+ When you remove an offline pack, any resources that are required by that pack,
+ but not other packs, become eligible for deletion from offline storage. Because
+ the backing store used for offline storage is also used as a general purpose
+ cache for map resources, such resources may not be immediately removed if the
+ implementation determines that they remain useful for general performance of
+ the map.
+
@param pack The offline pack to remove.
@param completion The completion handler to call once the pack has been
removed. This handler is executed asynchronously on the main queue.
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index 745eacbf4e..5d81eb85ea 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -4,6 +4,7 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
@@ -52,10 +53,19 @@ void MGLFinishCustomStyleLayer(void *context) {
}
/**
- An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code in
- Objective-C blocks or Swift closures that you specify. You may initialize a new
- OpenGL style layer to add to an `MGLStyle` or obtain one from an `MGLMapView`’s
- current style using the `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
+ you provide.
+
+ By default, this class does nothing. You can subclass this class to provide
+ custom OpenGL drawing code that is run on each frame of the map. Your subclass
+ should override the `-didMoveToMapView:`, `-willMoveFromMapView:`, and
+ `-drawInMapView:withContext:` methods.
+
+ You can access an existing OpenGL style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new OpenGL style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
@warning This API is undocumented and therefore unsupported. It may change at
any time without notice.
diff --git a/platform/darwin/src/MGLOverlay.h b/platform/darwin/src/MGLOverlay.h
index 1066a86d1e..cc32bad1e6 100644
--- a/platform/darwin/src/MGLOverlay.h
+++ b/platform/darwin/src/MGLOverlay.h
@@ -9,9 +9,8 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLOverlay` protocol defines a specific type of annotation that represents
both a point and an area on a map. Overlay objects are essentially data objects
- that contain the geographic data needed to represent the map area. For example,
- overlays can take the form of common shapes such as rectangles and circles.
- They can also describe polygons and other complex shapes.
+ that contain the geographic data needed to represent the map area. Overlays can
+ take the form of a polyline or polygon.
You use overlays to layer more sophisticated content on top of a map view. For
example, you could use an overlay to show the boundaries of a national park or
diff --git a/platform/darwin/src/MGLPointAnnotation.h b/platform/darwin/src/MGLPointAnnotation.h
index 6b2e1dd43a..aeac43bd39 100644
--- a/platform/darwin/src/MGLPointAnnotation.h
+++ b/platform/darwin/src/MGLPointAnnotation.h
@@ -7,16 +7,38 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The `MGLPointAnnotation` class defines a concrete annotation object located at
- a specified point. You can use this class, rather than define your own, in
- situations where all you want to do is associate a point on the map with a
- title.
+ An `MGLPointAnnotation` object represents a one-dimensional shape located at a
+ single geographical coordinate. Depending on how it is used, an
+ `MGLPointAnnotation` object is known as a point annotation or point shape. For
+ example, you could use a point shape to represent a city at low zoom levels, an
+ address at high zoom levels, or the location of a long press gesture.
+
+ You can add point shapes to the map by adding them to an `MGLShapeSource`
+ object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s point shapes collectively using an `MGLCircleStyleLayer` or
+ `MGLSymbolStyleLayer` object.
+
+ For more interactivity, add a selectable point annotation to a map view using
+ the `-[MGLMapView addAnnotation:]` method. Alternatively, define your own model
+ class that conforms to the `MGLAnnotation` protocol. Configure a point
+ annotation’s appearance using
+ `-[MGLMapViewDelegate mapView:imageForAnnotation:]` or
+ `-[MGLMapViewDelegate mapView:viewForAnnotation:]` (iOS only). A point
+ annotation’s `MGLShape.title` and `MGLShape.subtitle` properties define the
+ default content of the annotation’s callout (on iOS) or popover (on macOS).
+
+ To group multiple related points together in one shape, use an
+ `MGLPointCollection` or `MGLShapeCollection` object.
+
+ A point shape is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.2">Point</a> geometry
+ in GeoJSON.
*/
MGL_EXPORT
@interface MGLPointAnnotation : MGLShape
/**
- The coordinate point of the annotation, specified as a latitude and longitude.
+ The coordinate point of the shape, specified as a latitude and longitude.
*/
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
diff --git a/platform/darwin/src/MGLPointAnnotation.mm b/platform/darwin/src/MGLPointAnnotation.mm
index d2e87f07d1..a2108a9e3b 100644
--- a/platform/darwin/src/MGLPointAnnotation.mm
+++ b/platform/darwin/src/MGLPointAnnotation.mm
@@ -1,6 +1,7 @@
#import "MGLPointAnnotation.h"
#import "MGLShape_Private.h"
+#import "NSCoder+MGLAdditions.h"
#import <mbgl/util/geometry.hpp>
@@ -9,6 +10,41 @@
@synthesize coordinate;
++ (BOOL)supportsSecureCoding
+{
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+ if (self = [super initWithCoder:coder]) {
+ self.coordinate = [coder decodeMGLCoordinateForKey:@"coordinate"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+ [super encodeWithCoder:coder];
+ [coder encodeMGLCoordinate:coordinate forKey:@"coordinate"];
+}
+
+- (BOOL)isEqual:(id)other
+{
+ if (other == self) return YES;
+ if (![other isKindOfClass:[MGLPointAnnotation class]]) return NO;
+
+ MGLPointAnnotation *otherAnnotation = other;
+ return ([super isEqual:other]
+ && self.coordinate.latitude == otherAnnotation.coordinate.latitude
+ && self.coordinate.longitude == otherAnnotation.coordinate.longitude);
+}
+
+- (NSUInteger)hash
+{
+ return [super hash] + @(self.coordinate.latitude).hash + @(self.coordinate.longitude).hash;
+}
+
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; title = %@; subtitle = %@; coordinate = %f, %f>",
diff --git a/platform/darwin/src/MGLPointCollection.h b/platform/darwin/src/MGLPointCollection.h
index e090c60b10..c7054c6bbf 100644
--- a/platform/darwin/src/MGLPointCollection.h
+++ b/platform/darwin/src/MGLPointCollection.h
@@ -6,15 +6,26 @@
#import "MGLShape.h"
/**
- The `MGLPointCollection` class is used to define an array of disconnected
- coordinates. The points in the collection may be related but are not
- connected visually in any way.
+ An `MGLPointCollection` object represents a shape consisting of one or more
+ disconnected vertices, specified as `CLLocationCoordinate2D` instances. The
+ points in the collection may be related but are not connected spatially. For
+ example, you could use a point collection to represent all the trees in an
+ orchard.
- @note `MGLPointCollection` objects cannot be added to a map view using
- `-[MGLMapView addAnnotations:]` and related methods. However, when used in a
- `MGLPointCollectionFeature` to initialize a `MGLShapeSource` that is added
- to the map view's style, the point collection represents as a group of distinct
- annotations.
+ You can add point collections to the map by adding them to an `MGLShapeSource`
+ object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s point collections collectively using an
+ `MGLCircleStyleLayer` or `MGLSymbolStyleLayer` object.
+
+ You cannot add an `MGLPointCollection` object directly to a map view as an
+ annotation. However, you can create individual `MGLPointAnnotation` objects
+ from the `coordinates` array and add those annotation objects to the map view
+ using the `-[MGLMapView addAnnotations:]` method.
+
+ A point collection is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
+ geometry in GeoJSON. Do not confuse `MGLPointCollection` with `MGLMultiPoint`,
+ the abstract superclass of `MGLPolyline` and `MGLPolygon`.
*/
MGL_EXPORT
@interface MGLPointCollection : MGLShape <MGLOverlay>
diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm
index 387a575b2d..acd78b8b33 100644
--- a/platform/darwin/src/MGLPointCollection.mm
+++ b/platform/darwin/src/MGLPointCollection.mm
@@ -1,5 +1,6 @@
#import "MGLPointCollection_Private.h"
#import "MGLGeometry_Private.h"
+#import "NSArray+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
@@ -8,12 +9,10 @@ NS_ASSUME_NONNULL_BEGIN
@implementation MGLPointCollection
{
- MGLCoordinateBounds _overlayBounds;
+ mbgl::optional<mbgl::LatLngBounds> _bounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
-@synthesize overlayBounds = _overlayBounds;
-
+ (instancetype)pointCollectionWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
@@ -25,14 +24,41 @@ NS_ASSUME_NONNULL_BEGIN
if (self)
{
_coordinates = { coords, coords + count };
+ }
+ return self;
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ NSArray *coordinates = [decoder decodeObjectOfClass:[NSArray class] forKey:@"coordinates"];
+ _coordinates = [coordinates mgl_coordinates];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:[NSArray mgl_coordinatesFromCoordinates:_coordinates] forKey:@"coordinates"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLPointCollection class]]) return NO;
+
+ MGLPointCollection *otherCollection = (MGLPointCollection *)other;
+ return ([super isEqual:other]
+ && ((![self geoJSONDictionary] && ![otherCollection geoJSONDictionary]) || [[self geoJSONDictionary] isEqualToDictionary:[otherCollection geoJSONDictionary]]));
+}
+
+- (MGLCoordinateBounds)overlayBounds {
+ if (!_bounds) {
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
- for (auto coordinate : _coordinates)
- {
+ for (auto coordinate : _coordinates) {
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
- _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
+ _bounds = bounds;
}
- return self;
+ return MGLCoordinateBoundsFromLatLngBounds(*_bounds);
}
- (NSUInteger)pointCount
@@ -65,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
- return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
+ return MGLCoordinateBoundsIntersectsCoordinateBounds(self.overlayBounds, overlayBounds);
}
- (mbgl::Geometry<double>)geometryObject
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 57402326d5..560741a150 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -10,10 +10,39 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The `MGLPolygon` class represents a shape consisting of one or more points that
- define a closed polygon. The points are connected end-to-end in the order they
- are provided. The first and last points are connected to each other to create
- the closed shape.
+ An `MGLPolygon` object represents a closed shape consisting of four or more
+ vertices, specified as `CLLocationCoordinate2D` instances, and the edges that
+ connect them. For example, you could use a polygon shape to represent a
+ building, a lake, or an area you want to highlight.
+
+ You can add polygon shapes to the map by adding them to an `MGLShapeSource`
+ object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s polygons collectively using an `MGLFillStyleLayer` or
+ `MGLSymbolStyleLayer` object.
+
+ Alternatively, you can add a polygon overlay directly to a map view using the
+ `-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
+ a polygon overlay’s appearance using
+ `-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
+ `-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`.
+
+ The vertices are automatically connected in the order in which you provide
+ them. You should close the polygon by specifying the same
+ `CLLocationCoordinate2D` as the first and last vertices; otherwise, the
+ polygon’s fill may not cover the area you expect it to. To avoid filling the
+ space within the shape, give the polygon a transparent fill or use an
+ `MGLPolyline` object.
+
+ A polygon may have one or more interior polygons, or holes, that you specify as
+ `MGLPolygon` objects with the `+polygonWithCoordinates:count:interiorPolygons:`
+ method. For example, if a polygon represents a lake, it could exclude an island
+ within the lake using an interior polygon. Interior polygons may not themselves
+ have interior polygons. To represent a shape that includes a polygon within a
+ hole or, more generally, to group multiple polygons together in one shape, use
+ an `MGLMultiPolygon` or `MGLShapeCollection` object.
+
+ To make the polygon straddle the antimeridian, specify some longitudes less
+ than −180 degrees or greater than 180 degrees.
*/
MGL_EXPORT
@interface MGLPolygon : MGLMultiPoint <MGLOverlay>
@@ -57,14 +86,21 @@ MGL_EXPORT
@end
/**
- The `MGLMultiPolygon` class represents a shape consisting of one or more
- polygons that do not overlap. For example, you would use an `MGLMultiPolygon`
- object to represent an atoll together with an island in the atoll’s lagoon:
- the atoll itself would be one `MGLPolygon` object, while the inner island would
- be another.
+ An `MGLMultiPolygon` object represents a shape consisting of one or more
+ polygons that do not overlap. For example, you could use a multipolygon shape
+ to represent the body of land that consists of an island surrounded by an
+ atoll: the inner island would be one `MGLPolygon` object, while the surrounding
+ atoll would be another. You could also use a multipolygon shape to represent a
+ group of disconnected but related buildings.
+
+ You can add multipolygon shapes to the map by adding them to an
+ `MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s multipolygons collectively using an `MGLFillStyleLayer` or
+ `MGLSymbolStyleLayer` object.
- @note `MGLMultiPolygon` objects cannot be added to a map view using
- `-[MGLMapView addAnnotations:]` and related methods.
+ You cannot add an `MGLMultiPolygon` object directly to a map view using
+ `-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
+ add the `polygons` array’s items as overlays individually.
*/
MGL_EXPORT
@interface MGLMultiPolygon : MGLShape <MGLOverlay>
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 393bd31d0d..565de017cc 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -28,6 +28,32 @@
return self;
}
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ self = [super initWithCoder:decoder];
+ if (self) {
+ _interiorPolygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"interiorPolygons"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:self.interiorPolygons forKey:@"interiorPolygons"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLPolygon class]]) return NO;
+
+ MGLPolygon *otherPolygon = (MGLPolygon *)other;
+ return ([super isEqual:otherPolygon] &&
+ [[self geoJSONDictionary] isEqualToDictionary:[otherPolygon geoJSONDictionary]]);
+}
+
+- (NSUInteger)hash {
+ return [super hash] + [[self geoJSONDictionary] hash];
+}
+
- (mbgl::LinearRing<double>)ring {
NSUInteger count = self.pointCount;
CLLocationCoordinate2D *coordinates = self.coordinates;
@@ -100,6 +126,35 @@
return self;
}
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ _polygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"polygons"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:_polygons forKey:@"polygons"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLMultiPolygon class]]) return NO;
+
+ MGLMultiPolygon *otherMultiPolygon = other;
+ return [super isEqual:other]
+ && [self.polygons isEqualToArray:otherMultiPolygon.polygons];
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [super hash];
+ for (MGLPolygon *polygon in self.polygons) {
+ hash += [polygon hash];
+ }
+ return hash;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index dfc471bae9..ca1f8e36cc 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -10,10 +10,35 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The `MGLPolyline` class represents a shape consisting of one or more points
- that define connecting line segments. The points are connected end-to-end in
- the order they are provided. The first and last points are not connected to
- each other.
+ An `MGLPolyline` object represents a shape consisting of two or more vertices,
+ specified as `CLLocationCoordinate2D` instances, and the line segments that
+ connect them. For example, you could use an polyline to represent a road or the
+ path along which something moves.
+
+ You can add polyline shapes to the map by adding them to an `MGLShapeSource`
+ object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s polylines collectively using an `MGLLineStyleLayer` or
+ `MGLSymbolStyleLayer` object.
+
+ Alternatively, you can add a polyline overlay directly to a map view using the
+ `-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
+ a polyline overlay’s appearance using
+ `-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
+ `-[MGLMapViewDelegate mapView:lineWidthForPolylineAnnotation:]`.
+
+ The vertices are automatically connected in the order in which you provide
+ them. The first and last vertices are not connected to each other, but you can
+ specify the same `CLLocationCoordinate2D` as the first and last vertices in
+ order to close the polyline. To fill the space within the shape, use an
+ `MGLPolygon` object. To group multiple polylines together in one shape, use an
+ `MGLMultiPolyline` or `MGLShapeCollection` object.
+
+ To make the polyline straddle the antimeridian, specify some longitudes less
+ than −180 degrees or greater than 180 degrees.
+
+ A polyline is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
+ geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLPolyline : MGLMultiPoint <MGLOverlay>
@@ -32,14 +57,23 @@ MGL_EXPORT
@end
/**
- The `MGLMultiPolyline` class represents a shape consisting of one or more
- polylines. For example, you could use an `MGLMultiPolyline` object to represent
- both sides of a divided highway (dual carriageway), excluding the median
- (central reservation): each carriageway would be a distinct `MGLPolyline`
- object.
-
- @note `MGLMultiPolyline` objects cannot be added to a map view using
- `-[MGLMapView addAnnotations:]` and related methods.
+ An `MGLMultiPolyline` object represents a shape consisting of one or more
+ polylines. For example, you could use a multipolyline shape to represent both
+ sides of a divided highway (dual carriageway), excluding the median (central
+ reservation): each carriageway would be a distinct `MGLPolyline` object.
+
+ You can add multipolyline shapes to the map by adding them to an
+ `MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s multipolylines collectively using an `MGLLineStyleLayer` or
+ `MGLSymbolStyleLayer` object.
+
+ You cannot add an `MGLMultiPolyline` object directly to a map view using
+ `-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
+ add the `polylines` array’s items as overlays individually.
+
+ A multipolyline is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
+ geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLMultiPolyline : MGLShape <MGLOverlay>
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 0baeb68e1a..e6b1cdebf6 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -80,6 +80,36 @@
return self;
}
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ _polylines = [decoder decodeObjectOfClass:[NSArray class] forKey:@"polylines"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:_polylines forKey:@"polylines"];
+}
+
+- (BOOL)isEqual:(id)other
+{
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLMultiPolyline class]]) return NO;
+
+ MGLMultiPolyline *otherMultipoline = other;
+ return ([super isEqual:otherMultipoline]
+ && [self.polylines isEqualToArray:otherMultipoline.polylines]);
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [super hash];
+ for (MGLPolyline *polyline in self.polylines) {
+ hash += [polyline hash];
+ }
+ return hash;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index 80b740692c..ac5be60105 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -36,6 +36,20 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileSize;
`MGLRasterSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
+
+ ### Example
+
+ ```swift
+ let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .tileSize: 512,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+ ```
*/
MGL_EXPORT
@interface MGLRasterSource : MGLTileSource
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm
index edca8bced1..fd36413fe0 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterSource.mm
@@ -5,6 +5,7 @@
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/raster_source.hpp>
const MGLTileSourceOption MGLTileSourceOptionTileSize = @"MGLTileSourceOptionTileSize";
@@ -50,7 +51,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
- uint16_t tileSize;
+ uint16_t tileSize = MGLRasterSourceRetinaTileSize;
if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
@@ -95,6 +96,11 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
super.rawSource = rawSource;
}
+- (NSURL *)configurationURL {
+ auto url = self.rawSource->getURL();
+ return url ? [NSURL URLWithString:@(url->c_str())] : nil;
+}
+
- (NSString *)attributionHTMLString {
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index 1bdff12466..cd57a74f6a 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -8,10 +8,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
- A raster layer which allows customization of styling properties at runtime. You may
- instantiate a new raster layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.
+
+ Use a raster style layer to configure the color parameters of raster tiles
+ loaded by an `MGLRasterSource` object. For example, you could use a raster
+ style layer to render <a href="https://www.mapbox.com/satellite/">Mapbox
+ Satellite</a> imagery, a <a
+ href="https://www.mapbox.com/help/define-tileset/#raster-tilesets">raster tile
+ set</a> uploaded to Mapbox Studio, or a raster map authored in <a
+ href="https://tilemill-project.github.io/tilemill/">TileMill</a>, the classic
+ Mapbox Editor, or Mapbox Studio Classic.
+
+ You can access an existing raster style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new raster style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
+ layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
+ mapView.style?.addLayer(layer)
+ ```
*/
MGL_EXPORT
@interface MGLRasterStyleLayer : MGLForegroundStyleLayer
@@ -19,70 +39,89 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
/**
- Increase or reduce the brightness of the image. The value is the maximum brightness.
+ Increase or reduce the brightness of the image. The value is the maximum
+ brightness.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a> paint property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness;
-
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead.")));
/**
- Increase or reduce the brightness of the image. The value is the minimum brightness.
+ Increase or reduce the brightness of the image. The value is the minimum
+ brightness.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a> paint property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness;
-
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead.")));
/**
Increase or reduce the contrast of the image.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterContrast;
/**
Fade duration when a new tile is added.
-
+
This property is measured in milliseconds.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `300`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `300`. Set this property to `nil` to
+ reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterFadeDuration;
/**
Rotates hues around the color wheel.
-
+
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a> paint property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotation;
-
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead.")));
/**
The opacity at which the image will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterOpacity;
/**
Increase or reduce the saturation of the image.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterSaturation;
diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm
index e61532773c..87afb8da9d 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.mm
+++ b/platform/darwin/src/MGLRasterStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,6 +8,7 @@
#import "MGLStyleValue_Private.h"
#import "MGLRasterStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@interface MGLRasterStyleLayer ()
@@ -41,6 +42,13 @@
super.rawLayer = rawLayer;
}
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
@@ -96,9 +104,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setRasterBrightnessMax:(MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
- NSAssert(NO, @"Use -setMaximumRasterBrightness: instead.");
+}
+
+- (MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
+ return self.maximumRasterBrightness;
}
- (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
@@ -115,9 +125,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setRasterBrightnessMin:(MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
- NSAssert(NO, @"Use -setMinimumRasterBrightness: instead.");
+}
+
+- (MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
+ return self.minimumRasterBrightness;
}
- (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast {
@@ -162,9 +174,11 @@
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate {
- NSAssert(NO, @"Use -setRasterHueRotation: instead.");
+}
+
+- (MGLStyleValue<NSNumber *> *)rasterHueRotate {
+ return self.rasterHueRotation;
}
- (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity {
diff --git a/platform/darwin/src/MGLShape.h b/platform/darwin/src/MGLShape.h
index cc545d783f..d1c150d02e 100644
--- a/platform/darwin/src/MGLShape.h
+++ b/platform/darwin/src/MGLShape.h
@@ -6,14 +6,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The `MGLShape` class is an abstract class that defines the basic properties for
- all shape-based annotation objects. This class must be subclassed and cannot be
- used as is. Subclasses are responsible for defining the geometry of the shape
- and providing an appropriate value for the coordinate property inherited from
- the `MGLAnnotation` protocol.
+ `MGLShape` is an abstract class that represents a shape or annotation. Shapes
+ constitute the content of a map – not only the overlays atop the map, but also
+ the content that forms the base map.
+
+ You do not create instances of this class directly or create subclasses of this
+ class. Instead, you create instances of `MGLPointAnnotation`,
+ `MGLPointCollection`, `MGLPolyline`, `MGLMultiPolyline`, `MGLPolygon`,
+ `MGLMultiPolygon`, or `MGLShapeCollection`. The shape classes correspond to the
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1">Geometry</a> object
+ types in the GeoJSON standard, but some have nonstandard names for backwards
+ compatibility.
+
+ Although you do not create instances of this class directly, you can use its
+ `+[MGLShape shapeWithData:encoding:error:]` factory method to create one of the
+ concrete subclasses of `MGLShape` noted above from GeoJSON data.
+
+ You can add shapes to the map by adding them to an `MGLShapeSource` object.
+ Configure the appearance of an `MGLShapeSource`’s or `MGLVectorSource`’s shapes
+ collectively using a concrete instance of `MGLVectorStyleLayer`. Alternatively,
+ you can add some kinds of shapes directly to a map view as annotations or
+ overlays.
*/
MGL_EXPORT
-@interface MGLShape : NSObject <MGLAnnotation>
+@interface MGLShape : NSObject <MGLAnnotation, NSSecureCoding>
#pragma mark Creating a Shape
@@ -27,6 +43,14 @@ MGL_EXPORT
collection object, the returned value is an instance of
`MGLShapeCollectionFeature`.
+ ### Example
+
+ ```swift
+ let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")!
+ let data = try! Data(contentsOf: url)
+ let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
+ ```
+
@param data String data containing GeoJSON source code.
@param encoding The encoding used by `data`.
@param outError Upon return, if an error has occurred, a pointer to an
@@ -40,21 +64,34 @@ MGL_EXPORT
#pragma mark Accessing the Shape Attributes
/**
- The title of the shape annotation. The default value of this property is `nil`.
+ The title of the shape annotation.
+
+ The default value of this property is `nil`.
+
+ This property is ignored when the shape is used in an `MGLShapeSource`. To name
+ a shape used in a shape source, create an `MGLFeature` and add an attribute to
+ the `MGLFeature.attributes` property.
*/
@property (nonatomic, copy, nullable) NSString *title;
/**
The subtitle of the shape annotation. The default value of this property is
`nil`.
+
+ This property is ignored when the shape is used in an `MGLShapeSource`. To
+ provide additional information about a shape used in a shape source, create an
+ `MGLFeature` and add an attribute to the `MGLFeature.attributes` property.
*/
@property (nonatomic, copy, nullable) NSString *subtitle;
#if !TARGET_OS_IPHONE
/**
- The tooltip of the shape annotation. The default value of this property is
- `nil`.
+ The tooltip of the shape annotation.
+
+ The default value of this property is `nil`.
+
+ This property is ignored when the shape is used in an `MGLShapeSource`.
*/
@property (nonatomic, copy, nullable) NSString *toolTip;
diff --git a/platform/darwin/src/MGLShape.mm b/platform/darwin/src/MGLShape.mm
index 889ef8b3d7..984235fd97 100644
--- a/platform/darwin/src/MGLShape.mm
+++ b/platform/darwin/src/MGLShape.mm
@@ -2,6 +2,15 @@
#import "MGLFeature_Private.h"
+#import "NSString+MGLAdditions.h"
+#import "MGLTypes.h"
+
+#import <mbgl/util/geo.hpp>
+
+bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D rhs) {
+ return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude;
+}
+
@implementation MGLShape
+ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError {
@@ -42,10 +51,61 @@
return [string dataUsingEncoding:NSUTF8StringEncoding];
}
-- (CLLocationCoordinate2D)coordinate {
- [NSException raise:@"MGLAbstractClassException"
- format:@"MGLShape is an abstract class"];
++ (BOOL)supportsSecureCoding
+{
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+ if (self = [super init]) {
+ _title = [coder decodeObjectOfClass:[NSString class] forKey:@"title"];
+ _subtitle = [coder decodeObjectOfClass:[NSString class] forKey:@"subtitle"];
+#if !TARGET_OS_IPHONE
+ _toolTip = [coder decodeObjectOfClass:[NSString class] forKey:@"toolTip"];
+#endif
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+ [coder encodeObject:_title forKey:@"title"];
+ [coder encodeObject:_subtitle forKey:@"subtitle"];
+#if !TARGET_OS_IPHONE
+ [coder encodeObject:_toolTip forKey:@"toolTip"];
+#endif
+}
+
+- (BOOL)isEqual:(id)other
+{
+ if (other == self) { return YES; }
+ id <MGLAnnotation> annotation = other;
+
+#if TARGET_OS_IPHONE
+ return ((!_title && ![annotation title]) || [_title isEqualToString:[annotation title]])
+ && ((!_subtitle && ![annotation subtitle]) || [_subtitle isEqualToString:[annotation subtitle]]);
+#else
+ return ((!_title && ![annotation title]) || [_title isEqualToString:[annotation title]])
+ && ((!_subtitle && ![annotation subtitle]) || [_subtitle isEqualToString:[annotation subtitle]])
+ && ((!_toolTip && ![annotation toolTip]) || [_toolTip isEqualToString:[annotation toolTip]]);
+#endif
+}
+
+- (NSUInteger)hash
+{
+ NSUInteger hash = _title.hash + _subtitle.hash;
+#if !TARGET_OS_IPHONE
+ hash += _toolTip.hash;
+#endif
+ return hash;
+}
+- (CLLocationCoordinate2D)coordinate
+{
+ [[NSException exceptionWithName:@"MGLAbstractClassException"
+ reason:@"MGLShape is an abstract class"
+ userInfo:nil] raise];
return kCLLocationCoordinate2DInvalid;
}
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
index dfad080de2..5d2ce588c9 100644
--- a/platform/darwin/src/MGLShapeCollection.h
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -8,12 +8,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The `MGLShapeCollection` class represents a shape consisting of one or more
+ An `MGLShapeCollection` object represents a shape consisting of zero or more
distinct but related shapes that are instances of `MGLShape`. The constituent
shapes can be a mixture of different kinds of shapes.
- @note `MGLShapeCollection` objects cannot be added to a map view using
- `-[MGLMapView addAnnotations:]` and related methods.
+ `MGLShapeCollection` is most commonly used to add multiple shapes to a single
+ `MGLShapeSource`. Configure the appearance of an `MGLShapeSource`’s or
+ `MGLVectorSource`’s shape collection collectively using an
+ `MGLSymbolStyleLayer` object, or use multiple instances of
+ `MGLCircleStyleLayer`, `MGLFillStyleLayer`, and `MGLLineStyleLayer` to
+ configure the appearance of each kind of shape inside the collection.
+
+ You cannot add an `MGLShapeCollection` object directly to a map view as an
+ annotation. However, you can create individual `MGLPointAnnotation`,
+ `MGLPolyline`, and `MGLPolygon` objects from the `shapes` array and add those
+ annotation objects to the map view using the `-[MGLMapView addAnnotations:]`
+ method.
+
+ To represent a collection of point, polyline, or polygon shapes, it may be more
+ convenient to use an `MGLPointCollection`, `MGLMultiPolyline`, or
+ `MGLMultiPolygon` object, respectively.
+
+ A multipolyline is known as a
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1.8">GeometryCollection</a>
+ geometry in GeoJSON.
*/
MGL_EXPORT
@interface MGLShapeCollection : MGLShape
diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm
index e317a443fe..4b468a1cbb 100644
--- a/platform/darwin/src/MGLShapeCollection.mm
+++ b/platform/darwin/src/MGLShapeCollection.mm
@@ -12,12 +12,40 @@
- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
if (self = [super init]) {
- NSAssert(shapes.count, @"Cannot create an empty shape collection");
_shapes = shapes.copy;
}
return self;
}
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ _shapes = [decoder decodeObjectOfClass:[NSArray class] forKey:@"shapes"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:_shapes forKey:@"shapes"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLShapeCollection class]]) return NO;
+
+ MGLShapeCollection *otherShapeCollection = other;
+ return [super isEqual:otherShapeCollection]
+ && [_shapes isEqualToArray:otherShapeCollection.shapes];
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [super hash];
+ for (MGLShape *shape in _shapes) {
+ hash += [shape hash];
+ }
+ return hash;
+}
+
- (CLLocationCoordinate2D)coordinate {
return _shapes.firstObject.coordinate;
}
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 7bd85c8d1f..34806c548d 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -17,6 +17,10 @@ typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
An `NSNumber` object containing a Boolean enabling or disabling clustering.
If the `shape` property contains point shapes, setting this option to
`YES` clusters the points by radius into groups. The default value is `NO`.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a>
+ source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
@@ -32,6 +36,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
which to cluster points if clustering is enabled. Defaults to one zoom level
less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
maximum zoom level, the shapes are not clustered.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a>
+ source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
@@ -39,6 +47,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLeve
An `NSNumber` object containing an integer; specifies the maximum zoom level at
which to create vector tiles. A greater value produces greater detail at high
zoom levels. The default value is 18.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a>
+ source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
@@ -47,6 +59,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLeve
buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
buffer as wide as the tile itself. Larger values produce fewer rendering
artifacts near tile edges and slower performance. The default value is 128.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a>
+ source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
@@ -54,6 +70,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
An `NSNumber` object containing a double; specifies the Douglas-Peucker
simplification tolerance. A greater value produces simpler geometries and
improves performance. The default value is 0.375.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a>
+ source property in the Mapbox Style Specification.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
@@ -75,6 +95,18 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationT
Any vector style layer initialized with a shape source should have a `nil`
value in its `sourceLayerIdentifier` property.
+
+ ### Example
+
+ ```swift
+ var coordinates: [CLLocationCoordinate2D] = [
+ CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42),
+ CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
+ ]
+ let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
+ let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
+ mapView.style?.addSource(source)
+ ```
*/
MGL_EXPORT
@interface MGLShapeSource : MGLSource
@@ -100,7 +132,9 @@ MGL_EXPORT
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
To include multiple shapes in the source, use an `MGLShapeCollection` or
- `MGLShapeCollectionFeature` object.
+ `MGLShapeCollectionFeature` object, or use the
+ `-initWithIdentifier:features:options:` or
+ `-initWithIdentifier:shapes:options:` methods.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@@ -112,6 +146,45 @@ MGL_EXPORT
*/
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+/**
+ Returns a shape source with an identifier, an array of features, and a dictionary
+ of options for the source.
+
+ Unlike `-initWithIdentifier:shapes:options:`, this method accepts `MGLFeature`
+ instances, such as `MGLPointFeature` objects, whose attributes you can use when
+ applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
+ appearance.
+
+ To create a shape from GeoJSON source code, use the
+ `+[MGLShape shapeWithData:encoding:error:]` method.
+
+ @param identifier A string that uniquely identifies the source.
+ @param features An array of objects that conform to the MGLFeature protocol.
+ @param options An `NSDictionary` of options for this source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+
+/**
+ Returns a shape source with an identifier, an array of shapes, and a dictionary of
+ options for the source.
+
+ Any `MGLFeature` instance passed into this initializer is treated as an ordinary
+ shape, causing any attributes to be inaccessible to an `MGLVectorStyleLayer` when
+ evaluating a predicate or configuring certain layout or paint attributes. To
+ preserve the attributes associated with each feature, use the
+ `-initWithIdentifier:features:options:` method instead.
+
+ To create a shape from GeoJSON source code, use the
+ `+[MGLShape shapeWithData:encoding:error:]` method.
+
+ @param identifier A string that uniquely identifies the source.
+ @param shapes An array of shapes; each shape is a member of a concrete subclass of MGLShape.
+ @param options An `NSDictionary` of options for this source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+
#pragma mark Accessing a Source’s Content
/**
@@ -121,6 +194,9 @@ MGL_EXPORT
If the receiver was initialized using `-initWithIdentifier:URL:options:`, this
property is set to `nil`. This property is unavailable until the receiver is
passed into `-[MGLStyle addSource:]`.
+
+ You can get/set the shapes within a collection via this property. Actions must
+ be performed on the application's main thread.
*/
@property (nonatomic, copy, nullable) MGLShape *shape;
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index d062e656c2..245b7f2de2 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -7,6 +7,7 @@
#import "NSURL+MGLAdditions.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
@@ -55,6 +56,21 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return self;
}
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+ for (id <MGLFeature> feature in features) {
+ if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
+ [NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
+ }
+ }
+ MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:features];
+ return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
+}
+
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+ MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
+ return [self initWithIdentifier:identifier shape:shapeCollection options:options];
+}
+
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
return [super initWithRawSource:rawSource];
}
diff --git a/platform/darwin/src/MGLShape_Private.h b/platform/darwin/src/MGLShape_Private.h
index 15d1c1eb97..9821d49176 100644
--- a/platform/darwin/src/MGLShape_Private.h
+++ b/platform/darwin/src/MGLShape_Private.h
@@ -2,6 +2,9 @@
#import <mbgl/util/geojson.hpp>
#import <mbgl/util/geometry.hpp>
+#import <mbgl/util/geo.hpp>
+
+bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D rhs);
@interface MGLShape (Private)
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index 550996f51b..7b3242e3ae 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLShapeSource` and the
- concrete subclasses of `MGLTileSource`.
+ concrete subclasses of `MGLTileSource`, `MGLVectorSource` and `MGLRasterSource`.
*/
MGL_EXPORT
@interface MGLSource : NSObject
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 6192632e75..9bd35142c2 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -41,10 +41,10 @@ static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 9;
via `-[MGLMapView style]` by updating the style's data sources or layers.
@note Wait until the map style has finished loading before modifying a map's
- style via any of the MGLStyle instance methods below.
- You can use the `MGLMapViewDelegate` methods `-mapViewDidFinishLoadingMap:`
- or `-mapView:didFinishLoadingStyle:` as indicators that it's safe
- to modify the map's style.
+ style via any of the `MGLStyle` instance methods below. You can use the
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` methods as indicators
+ that it's safe to modify the map's style.
*/
MGL_EXPORT
@interface MGLStyle : NSObject
@@ -191,7 +191,7 @@ MGL_EXPORT
/**
A set containing the style’s sources.
*/
-@property (nonatomic, strong) NS_MUTABLE_SET_OF(MGLSource *) *sources;
+@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources;
/**
Returns a source with the given identifier in the current style.
@@ -215,8 +215,13 @@ MGL_EXPORT
@note Adding the same source instance more than once will result in a
`MGLRedundantSourceException`. Reusing the same source identifier, even with
different source instances, will result in a
- `MGLRedundantSourceIdentifierException`.
+ `MGLRedundantSourceIdentifierException`.
+ @note Sources should be added in
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ has loaded the style and is ready to accept a new source.
+
@param source The source to add to the current style.
*/
- (void)addSource:(MGLSource *)source;
@@ -239,10 +244,10 @@ MGL_EXPORT
#pragma mark Managing Style Layers
/**
- The layers included in the style, arranged according to their front-to-back
+ The layers included in the style, arranged according to their back-to-front
ordering on the screen.
*/
-@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *layers;
+@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *layers;
/**
Returns a style layer with the given identifier in the current style.
@@ -266,7 +271,12 @@ MGL_EXPORT
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
- different layer instances, will also result in an exception.
+ different layer instances, will also result in an exception.
+
+ @note Layers should be added in
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ has loaded the style and is ready to accept a new layer.
@param layer The layer object to add to the map view. This object must be an
instance of a concrete subclass of `MGLStyleLayer`.
@@ -278,7 +288,12 @@ MGL_EXPORT
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
- different layer instances, will also result in an exception.
+ different layer instances, will also result in an exception.
+
+ @note Layers should be added in
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ has loaded the style and is ready to accept a new layer.
@param layer The layer to insert.
@param index The index at which to insert the layer. An index of 0 would send
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 9ea9e760f5..7e96c08ccc 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -24,6 +24,7 @@
#import "MGLAttributionInfo_Private.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -130,9 +131,9 @@ static NSURL *MGLStyleURL_emerald;
#pragma mark Sources
-- (NS_MUTABLE_SET_OF(MGLSource *) *)sources {
+- (NS_SET_OF(__kindof MGLSource *) *)sources {
auto rawSources = self.mapView.mbglMap->getSources();
- NSMutableSet *sources = [NSMutableSet setWithCapacity:rawSources.size()];
+ NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
[sources addObject:source];
@@ -140,7 +141,7 @@ static NSURL *MGLStyleURL_emerald;
return sources;
}
-- (void)setSources:(NS_MUTABLE_SET_OF(MGLSource *) *)sources {
+- (void)setSources:(NS_SET_OF(__kindof MGLSource *) *)sources {
for (MGLSource *source in self.sources) {
[self removeSource:source];
}
@@ -225,22 +226,22 @@ static NSURL *MGLStyleURL_emerald;
#pragma mark Style layers
-- (NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers
+- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
{
auto layers = self.mapView.mbglMap->getLayers();
- NSMutableArray *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
- for (auto layer = layers.rbegin(); layer != layers.rend(); ++layer) {
- MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:*layer];
+ NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
+ for (auto layer : layers) {
+ MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayers addObject:styleLayer];
}
return styleLayers;
}
-- (void)setLayers:(NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers {
- for (MGLStyleLayer *layer in self.layers.reverseObjectEnumerator) {
+- (void)setLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers {
+ for (MGLStyleLayer *layer in self.layers) {
[self removeLayer:layer];
}
- for (MGLStyleLayer *layer in layers.reverseObjectEnumerator) {
+ for (MGLStyleLayer *layer in layers) {
[self addLayer:layer];
}
}
@@ -253,12 +254,12 @@ static NSURL *MGLStyleURL_emerald;
- (MGLStyleLayer *)objectInLayersAtIndex:(NSUInteger)index
{
auto layers = self.mapView.mbglMap->getLayers();
- if (index > layers.size() - 1) {
+ if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"No style layer at index %lu.", (unsigned long)index];
return nil;
}
- auto layer = layers.at(layers.size() - 1 - index);
+ auto layer = layers.at(index);
return [self layerFromMBGLLayer:layer];
}
@@ -290,13 +291,14 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index];
} else if (index == 0) {
try {
- [styleLayer addToMapView:self.mapView belowLayer:nil];
+ MGLStyleLayer *sibling = layers.size() ? [self layerFromMBGLLayer:layers.at(0)] : nil;
+ [styleLayer addToMapView:self.mapView belowLayer:sibling];
} catch (const std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
try {
- MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(layers.size() - index)];
+ MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index)];
[styleLayer addToMapView:self.mapView belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
@@ -307,11 +309,11 @@ static NSURL *MGLStyleURL_emerald;
- (void)removeObjectFromLayersAtIndex:(NSUInteger)index
{
auto layers = self.mapView.mbglMap->getLayers();
- if (index > layers.size() - 1) {
+ if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index];
}
- auto layer = layers.at(layers.size() - 1 - index);
+ auto layer = layers.at(index);
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayer removeFromMapView:self.mapView];
}
diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs
index 7d0f6922f4..8ffed66b54 100644
--- a/platform/darwin/src/MGLStyleLayer.h.ejs
+++ b/platform/darwin/src/MGLStyleLayer.h.ejs
@@ -1,9 +1,9 @@
<%
+ const doc = locals.doc;
const type = locals.type;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
- const layoutPropertiesByName = locals.layoutPropertiesByName;
- const paintPropertiesByName = locals.paintPropertiesByName;
+ const enumProperties = locals.enumProperties;
-%>
// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
@@ -21,14 +21,15 @@ NS_ASSUME_NONNULL_BEGIN
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
/**
- <%- propertyDoc(property.name, property, type) %>
+<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
- Values of this type are used in the `<%- camelizeWithLeadingLowercase(property.name) %>` property of `MGL<%- camelize(type) %>StyleLayer`.
+ Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const value in property.values) { -%>
/**
- <%- propertyDoc(property.name, property.values[value], type) %>
+<%- propertyDoc(property.name, property.values[value], type, 'enum').wrap(80, 4+1) %>
*/
MGL<%- camelize(property.name) %><%- camelize(value) %>,
<% } -%>
@@ -39,14 +40,15 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
/**
- <%- propertyDoc(property.name, property, type) %>
+<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
- Values of this type are used in the `<%- camelizeWithLeadingLowercase(property.name) %>` property of `MGL<%- camelize(type) %>StyleLayer`.
+ Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% for (const value in property.values) { -%>
/**
- <%- propertyDoc(property.name, property.values[value], type) %>
+<%- propertyDoc(property.name, property.values[value], type, 'enum').wrap(80, 4+1) %>
*/
MGL<%- camelize(property.name) %><%- camelize(value) %>,
<% } -%>
@@ -56,17 +58,22 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% } -%>
<% if (type == 'background') { -%>
/**
- A map style's background layer is the bottommost layer and is used to style a color
- or pattern to show below all other map features. You can query an `MGLMapView` for its
- `style` and obtain the background layer using the `-[MGLStyle layerWithIdentifier:]`
- method and passing `background` for the identifier.
+<%- doc.wrap(80, 1) %>
*/
<% } else { -%>
/**
- A <%- type %> layer which allows customization of styling properties at runtime. You may
- instantiate a new <%- type %> layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+<%- doc.wrap(80, 1) %>
+
+ You can access an existing <%- type %> style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new <%- type %> style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ ```
*/
<% } -%>
MGL_EXPORT
@@ -85,18 +92,7 @@ MGL_EXPORT
<% for (const property of layoutProperties) { -%>
/**
- <%- propertyDoc(property.name, property, type) %>
-<% if ('default' in property) { -%>
-
- The default value of this property is <%- propertyDefault(property, type) %>.<% if (!property.required) { %> Set this property to `nil` to reset it to the default value.<% } %>
-<% } if (property.requires) { -%>
-
- <%- propertyReqs(property, layoutPropertiesByName, type) %>
-<% } -%>
-<% if (property.original) { -%>
-
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-<%- type -%>-<%- property.original -%>"><code><%- property.original -%></code></a> layout property in the Mapbox Style Specification.
-<% } -%>
+<%- propertyDoc(property.name, property, type, 'layout').wrap(80, 1) %>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
@@ -111,22 +107,11 @@ MGL_EXPORT
<% for (const property of paintProperties) { -%>
/**
- <%- propertyDoc(property.name, property, type) %>
-<% if ('default' in property) { -%>
-
- The default value of this property is <%- propertyDefault(property, type) %>.<% if (!property.required) { %> Set this property to `nil` to reset it to the default value.<% } %>
-<% } if (property.requires) { -%>
-
- <%- propertyReqs(property, paintPropertiesByName, type) %>
-<% } -%>
-<% if (property.original) { -%>
-
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-<%- property.original -%>"><code><%- property.original -%></code></a> paint property in the Mapbox Style Specification.
-<% } -%>
+<%- propertyDoc(property.name, property, type, 'paint').wrap(80, 1) %>
*/
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
-<% if (property.original) { %>
+<% if (property.original) { -%>
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
@@ -134,4 +119,31 @@ MGL_EXPORT
<% } -%>
@end
+<% if (enumProperties) { -%>
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGL<%- camelize(type) %>StyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)
+
+#pragma mark Working with <%- camelize(type) %> Style Layer Attribute Values
+
+<% for (let property of enumProperties) { -%>
+/**
+ Creates a new value object containing the given `MGL<%- camelize(property.name) %>` enumeration.
+
+ @param <%- objCName(property) %> The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
+
+/**
+ The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
+ */
+@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
+
+<% } -%>
+@end
+
+<% } -%>
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index baeed3b882..9445c3cf21 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -2,10 +2,10 @@
const type = locals.type;
const layoutProperties = locals.layoutProperties;
const paintProperties = locals.paintProperties;
- const containsEnumerationProperties = locals.containsEnumerationProperties;
+ const enumProperties = locals.enumProperties;
-%>
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -14,8 +14,10 @@
#import "MGLStyleValue_Private.h"
#import "MGL<%- camelize(type) %>StyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
-<% if (containsEnumerationProperties) { -%>
+<% if (enumProperties) { -%>
+
namespace mbgl {
<% if (layoutProperties.length) { -%>
@@ -89,7 +91,15 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
-<% if (type !== 'background' && type !== 'raster') { -%>
+<% if (type !== 'background') { -%>
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
+<% if (type !== 'raster') { -%>
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -109,7 +119,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
- self.rawLayer->setFilter(predicate.mgl_filter);
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -119,7 +129,7 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
-<% } -%>
+<% }} -%>
#pragma mark - Adding to and removing from a map view
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
@@ -167,7 +177,7 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
+ auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
@@ -180,15 +190,14 @@ namespace mbgl {
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
- return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
-<% if (property.original) { %>
+<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
- self.<%- camelizeWithLeadingLowercase(property.name) %> = <%- camelizeWithLeadingLowercase(originalPropertyName(property)) %>;
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
@@ -206,7 +215,7 @@ namespace mbgl {
MGLAssertStyleLayerIsValid();
<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
+ auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
@@ -219,15 +228,18 @@ namespace mbgl {
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
- return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}
-<% if (property.original) { %>
+<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
- NSAssert(NO, @"Use -set<%- camelize(property.name) %>: instead.");
+}
+
+- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
+ return self.<%- objCGetter(property) %>;
}
<% } -%>
@@ -235,3 +247,21 @@ namespace mbgl {
<% } -%>
@end
+<% if (enumProperties) { -%>
+
+@implementation NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)
+
+<% for (let property of enumProperties) { -%>
++ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
+ return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
+}
+
+- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
+ MGL<%- camelize(property.name) %> <%- objCName(property) %>;
+ [self getValue:&<%- objCName(property) %>];
+ return <%- objCName(property) %>;
+}
+
+<% } -%>
+@end
+<% } -%>
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index 315d48b761..5b6528f6fd 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -18,13 +18,13 @@ NS_ASSUME_NONNULL_BEGIN
The `MGLStyleValue` class takes a generic parameter `T` that indicates the
Foundation class being wrapped by this class. Common values for `T` include:
-
+
<ul>
- <li>`NSNumber` (for Boolean values, floating-point numbers, and enumerations)</li>
- <li>`NSValue` (for `CGVector`, `NSEdgeInset`, and `UIEdgeInset`s)</li>
- <li>`NSString`</li>
- <li>`NSColor` or `UIColor`</li>
- <li>`NSArray`</li>
+ <li><code>NSNumber</code> (for Boolean values and floating-point numbers)</li>
+ <li><code>NSValue</code> (for <code>CGVector</code>, <code>NSEdgeInsets</code>, <code>UIEdgeInsets</code>, and enumerations)</li>
+ <li><code>NSString</code></li>
+ <li><code>NSColor</code> or <code>UIColor</code></li>
+ <li><code>NSArray</code></li>
</ul>
*/
MGL_EXPORT
@@ -52,13 +52,13 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleFunction` object representing a zoom level
- function with an exponential base and any number of stops.
+ function with an exponential interpolation base and any number of stops.
- @param base The exponential base of the interpolation curve.
+ @param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given base and stops.
+ @return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
-+ (instancetype)valueWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
@end
@@ -131,38 +131,38 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleFunction` object representing a zoom level
- function with an exponential base and any number of stops.
+ function with an exponential interpolation base and any number of stops.
- @param base The exponential base of the interpolation curve.
+ @param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given base and stops.
+ @return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
-+ (instancetype)functionWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
#pragma mark Initializing a Style Function
/**
Returns an `MGLStyleFunction` object representing a zoom level function with an
- exponential base and any number of stops.
+ exponential interpolation base and any number of stops.
- @param base The exponential base of the interpolation curve.
+ @param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given base and stops.
+ @return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
-- (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing the Parameters of a Function
/**
- The exponential base of the function’s interpolation curve.
+ The exponential interpolation base of the function’s interpolation curve.
- The exponential base controls the rate at which the function’s output values
+ The exponential interpolation base controls the rate at which the function’s output values
increase. A value of 1 causes the function to increase linearly by zoom level.
- A higher exponential base causes the function’s output values to vary
+ A higher exponential interpolation base causes the function’s output values to vary
exponentially, increasing more rapidly towards the high end of the function’s
range. The default value of this property is 1, for a linear curve.
*/
-@property (nonatomic) CGFloat base;
+@property (nonatomic) CGFloat interpolationBase;
/**
A dictionary associating zoom levels with style values.
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 6ced819cd1..9e77114378 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -6,8 +6,8 @@
return [MGLStyleConstantValue valueWithRawValue:rawValue];
}
-+ (instancetype)valueWithBase:(CGFloat)base stops:(NSDictionary *)stops {
- return [MGLStyleFunction functionWithBase:base stops:stops];
++ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [MGLStyleFunction functionWithInterpolationBase:interpolationBase stops:stops];
}
+ (instancetype)valueWithStops:(NSDictionary *)stops {
@@ -49,44 +49,44 @@
@implementation MGLStyleFunction
-+ (instancetype)functionWithBase:(CGFloat)base stops:(NSDictionary *)stops {
- return [[self alloc] initWithBase:base stops:stops];
++ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops];
}
+ (instancetype)functionWithStops:(NSDictionary *)stops {
- return [[self alloc] initWithBase:1 stops:stops];
+ return [[self alloc] initWithInterpolationBase:1 stops:stops];
}
- (instancetype)init {
- return [self initWithBase:1 stops:@{}];
+ return [self initWithInterpolationBase:1 stops:@{}];
}
-- (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary *)stops {
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
if (self = [super init]) {
if (!stops.count)
{
[NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self];
}
- _base = base;
+ _interpolationBase = interpolationBase;
_stops = stops;
}
return self;
}
- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, base = %f; stops = %@>",
+ return [NSString stringWithFormat:@"<%@: %p, interpolationBase = %f; stops = %@>",
NSStringFromClass([self class]), (void *)self,
- self.base,
+ self.interpolationBase,
self.stops];
}
- (BOOL)isEqual:(MGLStyleFunction *)other {
- return ([other isKindOfClass:[self class]] && other.base == self.base
+ return ([other isKindOfClass:[self class]] && other.interpolationBase == self.interpolationBase
&& [other.stops isEqualToDictionary:self.stops]);
}
- (NSUInteger)hash {
- return self.base + self.stops.hash;
+ return self.interpolationBase + self.stops.hash;
}
@end
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 492ce20f1a..2c3de3fb74 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -4,7 +4,6 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
#import "MGLTypes.h"
-#import "MGLLineStyleLayer.h"
#import <mbgl/util/enum.hpp>
#if TARGET_OS_IPHONE
@@ -42,7 +41,7 @@ public:
for (const auto &mbglStop : mbglStops) {
stops[@(mbglStop.first)] = toEnumStyleConstantValue<>(mbglStop.second);
}
- return [MGLStyleFunction<NSValue *> functionWithBase:mbglValue.asFunction().getBase() stops:stops];
+ return [MGLStyleFunction<NSValue *> functionWithInterpolationBase:mbglValue.asFunction().getBase() stops:stops];
} else {
return nil;
}
@@ -62,7 +61,7 @@ public:
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
}];
- return mbgl::style::Function<MBGLType>({{mbglStops}}, function.base);
+ return mbgl::style::Function<MBGLType>({{mbglStops}}, function.interpolationBase);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -92,7 +91,7 @@ public:
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
}];
- return mbgl::style::Function<MBGLEnum>({{mbglStops}}, function.base);
+ return mbgl::style::Function<MBGLEnum>({{mbglStops}}, function.interpolationBase);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -118,7 +117,7 @@ private:
auto rawValue = toMGLRawStyleValue(mbglStop.second);
stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue];
}
- return [MGLStyleFunction<ObjCType> functionWithBase:mbglFunction.getBase() stops:stops];
+ return [MGLStyleFunction<ObjCType> functionWithInterpolationBase:mbglFunction.getBase() stops:stops];
}
template <typename MBGLEnum = MBGLType,
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index 57a8f71827..23ddd59d0d 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -8,21 +8,29 @@
NS_ASSUME_NONNULL_BEGIN
/**
- In combination with `symbolPlacement`, determines the rotation behavior of icons.
+ In combination with `symbolPlacement`, determines the rotation behavior of
+ icons.
- Values of this type are used in the `iconRotationAlignment` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.iconRotationAlignment`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLIconRotationAlignment) {
/**
- When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, aligns icons east-west. When `symbolPlacement` is set to `MGLSymbolPlacementLine`, aligns icon x-axes with the line.
+ When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, aligns icons
+ east-west. When `symbolPlacement` is set to `MGLSymbolPlacementLine`,
+ aligns icon x-axes with the line.
*/
MGLIconRotationAlignmentMap,
/**
- Produces icons whose x-axes are aligned with the x-axis of the viewport, regardless of the value of `symbolPlacement`.
+ Produces icons whose x-axes are aligned with the x-axis of the viewport,
+ regardless of the value of `symbolPlacement`.
*/
MGLIconRotationAlignmentViewport,
/**
- When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, this is equivalent to `MGLIconRotationAlignmentViewport`. When `symbolPlacement` is set to `MGLSymbolPlacementLine`, this is equivalent to `MGLIconRotationAlignmentMap`.
+ When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, this is
+ equivalent to `MGLIconRotationAlignmentViewport`. When `symbolPlacement` is
+ set to `MGLSymbolPlacementLine`, this is equivalent to
+ `MGLIconRotationAlignmentMap`.
*/
MGLIconRotationAlignmentAuto,
};
@@ -30,7 +38,8 @@ typedef NS_ENUM(NSUInteger, MGLIconRotationAlignment) {
/**
Scales the icon to fit around the associated text.
- Values of this type are used in the `iconTextFit` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.iconTextFit`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLIconTextFit) {
/**
@@ -54,7 +63,8 @@ typedef NS_ENUM(NSUInteger, MGLIconTextFit) {
/**
Label placement relative to its geometry.
- Values of this type are used in the `symbolPlacement` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.symbolPlacement`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLSymbolPlacement) {
/**
@@ -62,7 +72,8 @@ typedef NS_ENUM(NSUInteger, MGLSymbolPlacement) {
*/
MGLSymbolPlacementPoint,
/**
- The label is placed along the line of the geometry. Can only be used on `LineString` and `Polygon` geometries.
+ The label is placed along the line of the geometry. Can only be used on
+ `LineString` and `Polygon` geometries.
*/
MGLSymbolPlacementLine,
};
@@ -70,7 +81,8 @@ typedef NS_ENUM(NSUInteger, MGLSymbolPlacement) {
/**
Part of the text placed closest to the anchor.
- Values of this type are used in the `textAnchor` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textAnchor`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLTextAnchor) {
/**
@@ -114,7 +126,8 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) {
/**
Text justification options.
- Values of this type are used in the `textJustification` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textJustification`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLTextJustification) {
/**
@@ -134,7 +147,8 @@ typedef NS_ENUM(NSUInteger, MGLTextJustification) {
/**
Orientation of text when map is pitched.
- Values of this type are used in the `textPitchAlignment` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textPitchAlignment`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLTextPitchAlignment) {
/**
@@ -152,21 +166,29 @@ typedef NS_ENUM(NSUInteger, MGLTextPitchAlignment) {
};
/**
- In combination with `symbolPlacement`, determines the rotation behavior of the individual glyphs forming the text.
+ In combination with `symbolPlacement`, determines the rotation behavior of the
+ individual glyphs forming the text.
- Values of this type are used in the `textRotationAlignment` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textRotationAlignment`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLTextRotationAlignment) {
/**
- When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, aligns text east-west. When `symbolPlacement` is set to `MGLSymbolPlacementLine`, aligns text x-axes with the line.
+ When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, aligns text
+ east-west. When `symbolPlacement` is set to `MGLSymbolPlacementLine`,
+ aligns text x-axes with the line.
*/
MGLTextRotationAlignmentMap,
/**
- Produces glyphs whose x-axes are aligned with the x-axis of the viewport, regardless of the value of `symbolPlacement`.
+ Produces glyphs whose x-axes are aligned with the x-axis of the viewport,
+ regardless of the value of `symbolPlacement`.
*/
MGLTextRotationAlignmentViewport,
/**
- When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, this is equivalent to `MGLTextRotationAlignmentViewport`. When `symbolPlacement` is set to `MGLSymbolPlacementLine`, this is equivalent to `MGLTextRotationAlignmentMap`.
+ When `symbolPlacement` is set to `MGLSymbolPlacementPoint`, this is
+ equivalent to `MGLTextRotationAlignmentViewport`. When `symbolPlacement` is
+ set to `MGLSymbolPlacementLine`, this is equivalent to
+ `MGLTextRotationAlignmentMap`.
*/
MGLTextRotationAlignmentAuto,
};
@@ -174,7 +196,8 @@ typedef NS_ENUM(NSUInteger, MGLTextRotationAlignment) {
/**
Specifies how to capitalize text.
- Values of this type are used in the `textTransform` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textTransform`
+ property.
*/
typedef NS_ENUM(NSUInteger, MGLTextTransform) {
/**
@@ -194,40 +217,65 @@ typedef NS_ENUM(NSUInteger, MGLTextTransform) {
/**
Controls the translation reference point.
- Values of this type are used in the `iconTranslateAnchor` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.iconTranslationAnchor`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLIconTranslateAnchor) {
+typedef NS_ENUM(NSUInteger, MGLIconTranslationAnchor) {
/**
Icons are translated relative to the map.
*/
- MGLIconTranslateAnchorMap,
+ MGLIconTranslationAnchorMap,
/**
Icons are translated relative to the viewport.
*/
- MGLIconTranslateAnchorViewport,
+ MGLIconTranslationAnchorViewport,
};
/**
Controls the translation reference point.
- Values of this type are used in the `textTranslateAnchor` property of `MGLSymbolStyleLayer`.
+ Values of this type are used in the `MGLSymbolStyleLayer.textTranslationAnchor`
+ property.
*/
-typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) {
+typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
/**
The text is translated relative to the map.
*/
- MGLTextTranslateAnchorMap,
+ MGLTextTranslationAnchorMap,
/**
The text is translated relative to the viewport.
*/
- MGLTextTranslateAnchorViewport,
+ MGLTextTranslationAnchorViewport,
};
/**
- A symbol layer which allows customization of styling properties at runtime. You may
- instantiate a new symbol layer to add to a map style or you may query an
- `MGLMapView` for its `style` and obtain existing layers using the
- `-[MGLStyle layerWithIdentifier:]` method.
+ An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at
+ points or along lines on the map.
+
+ Use a symbol style layer to configure the visual appearance of labels for
+ features in vector tiles loaded by an `MGLVectorSource` object or `MGLShape` or
+ `MGLFeature` instances in an `MGLShapeSource` object.
+
+ You can access an existing symbol style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new symbol style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
+ layer.sourceLayerIdentifier = "pois"
+ layer.iconImageName = MGLStyleValue(rawValue: "coffee")
+ layer.iconScale = MGLStyleValue(rawValue: 0.5)
+ layer.text = MGLStyleValue(rawValue: "{name}")
+ layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
+ layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
+ layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
+ layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
+ mapView.style?.addLayer(layer)
+ ```
*/
MGL_EXPORT
@interface MGLSymbolStyleLayer : MGLVectorStyleLayer
@@ -235,13 +283,19 @@ MGL_EXPORT
#pragma mark - Accessing the Layout Attributes
/**
- If true, the icon will be visible even if it collides with other previously drawn symbols.
+ If true, the icon will be visible even if it collides with other previously
+ drawn symbols.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowsOverlap;
@@ -251,11 +305,16 @@ MGL_EXPORT
/**
If true, other symbols can be visible even if they collide with the icon.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnoresPlacement;
@@ -265,52 +324,84 @@ MGL_EXPORT
/**
A string with {tokens} replaced, referencing the data property to pull from.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImageName;
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImage __attribute__((unavailable("Use iconImageName instead.")));
+#if TARGET_OS_IPHONE
+/**
+ Offset distance of icon from its anchor.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 rightward and 0
+ downward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
+#else
/**
Offset distance of icon from its anchor.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 from the left and 0 from the top. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 rightward and 0
+ upward. Set this property to `nil` to reset it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
+#endif
/**
- If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
+ If true, text will display without their corresponding icons when the icon
+ collides with other symbols and the text does not.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `text` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable, getter=isIconOptional) MGLStyleValue<NSNumber *> *iconOptional;
/**
- Size of the additional area around the icon bounding box used for detecting symbol collisions.
-
+ Size of the additional area around the icon bounding box used for detecting
+ symbol collisions.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `2`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding;
/**
Rotates the icon clockwise.
-
+
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotation;
@@ -318,22 +409,31 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate __attribute__((unavailable("Use iconRotation instead.")));
/**
- In combination with `symbolPlacement`, determines the rotation behavior of icons.
+ In combination with `symbolPlacement`, determines the rotation behavior of
+ icons.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentAuto`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconRotationAlignmentAuto`. Set this property
+ to `nil` to reset it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
/**
Scale factor for icon. 1 is original size, 3 triples the size.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale;
@@ -343,31 +443,65 @@ MGL_EXPORT
/**
Scales the icon to fit around the associated text.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitNone`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconTextFitNone`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `text` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFit;
+#if TARGET_OS_IPHONE
/**
Size of the additional area added to dimensions determined by `iconTextFit`.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `NSEdgeInsetsZero` or `UIEdgeInsetsZero`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `UIEdgeInsetsZero`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
+ containing an `NSValue` object containing `MGLIconTextFitBoth`,
+ `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
+#else
+/**
+ Size of the additional area added to dimensions determined by `iconTextFit`.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `NSEdgeInsetsZero`. Set this property to `nil` to
+ reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
+ containing an `NSValue` object containing `MGLIconTextFitBoth`,
+ `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
+#endif
/**
If true, the icon may be flipped to prevent it from being rendered upside-down.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `iconImageName` is non-`nil`, and `iconRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `iconRotationAlignment` is set to an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconRotationAlignmentMap`, and
+ `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
+ object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsIconUpright;
@@ -375,13 +509,22 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright __attribute__((unavailable("Use keepsIconUpright instead.")));
/**
- If true, the text may be flipped vertically to prevent it from being rendered upside-down.
-
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`, and `textRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
-
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a> layout property in the Mapbox Style Specification.
+ If true, the text may be flipped vertically to prevent it from being rendered
+ upside-down.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `YES`. Set this property to `nil` to reset it to
+ the default value.
+
+ This property is only applied to the style if `text` is non-`nil`, and
+ `textRotationAlignment` is set to an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextRotationAlignmentMap`, and
+ `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
+ object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsTextUpright;
@@ -390,14 +533,20 @@ MGL_EXPORT
/**
Maximum angle change between adjacent characters.
-
+
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `45`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `45`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`, and
+ `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
+ object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextAngle;
@@ -406,14 +555,19 @@ MGL_EXPORT
/**
The maximum line width for text wrapping.
-
+
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `10`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `10`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextWidth;
@@ -421,11 +575,18 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth __attribute__((unavailable("Use maximumTextWidth instead.")));
/**
- If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
-
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
-
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a> layout property in the Mapbox Style Specification.
+ If true, the symbols will not cross tile edges to avoid mutual collisions.
+ Recommended in layers that don't have enough padding in the vector tile to
+ prevent collisions, or if it is a point symbol layer placed after a line symbol
+ layer.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidsEdges;
@@ -435,29 +596,57 @@ MGL_EXPORT
/**
Label placement relative to its geometry.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementPoint`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLSymbolPlacementPoint`. Set this property to
+ `nil` to reset it to the default value.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *symbolPlacement;
/**
Distance between two symbol anchors.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `250`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `250`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ This property is only applied to the style if `symbolPlacement` is set to an
+ `MGLStyleValue` object containing an `NSValue` object containing
+ `MGLSymbolPlacementLine`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolSpacing;
/**
- If true, the text will be visible even if it collides with other previously drawn symbols.
+ Value to use for a text label. Feature properties are specified using tokens
+ like {field_name}.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing the
+ empty string. Set this property to `nil` to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-field"><code>text-field</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *text;
+
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *textField __attribute__((unavailable("Use text instead.")));
+
+/**
+ If true, the text will be visible even if it collides with other previously
+ drawn symbols.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a> layout property in the Mapbox Style Specification.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowsOverlap;
@@ -467,36 +656,78 @@ MGL_EXPORT
/**
Part of the text placed closest to the anchor.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextAnchorCenter`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextAnchorCenter`. Set this property to `nil`
+ to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textAnchor;
/**
- Value to use for a text label. Feature properties are specified using tokens like {field_name}.
+ An array of font face names used to display the text.
+
+ Each font name must be included in the `{fontstack}` portion of the JSON
+ stylesheet’s <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#glyphs"><code>glyphs</code></a>
+ property. You can register a custom font when designing the style in Mapbox
+ Studio. Fonts installed on the system are not used.
- The default value of this property is an `MGLStyleValue` object containing the empty string. Set this property to `nil` to reset it to the default value.
+ The first font named in the array is applied to the text. For each character in
+ the text, if the first font lacks a glyph for the character, the next font is
+ applied as a fallback, and so on.
+
+ The default value of this property is an `MGLStyleValue` object containing the
+ array `Open Sans Regular`, `Arial Unicode MS Regular`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-font"><code>text-font</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *textField;
+@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSString *> *> *textFontNames;
+
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSString *> *> *textFont __attribute__((unavailable("Use textFontNames instead.")));
/**
- Font stack to use for displaying text.
+ Font size.
+
+ This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing the array `Open Sans Regular`, `Arial Unicode MS Regular`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `16`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-size"><code>text-size</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSString *> *> *textFont;
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textFontSize;
+
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textSize __attribute__((unavailable("Use textFontSize instead.")));
/**
If true, other symbols can be visible even if they collide with the text.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnoresPlacement;
@@ -506,11 +737,16 @@ MGL_EXPORT
/**
Text justification options.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextJustificationCenter`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextJustificationCenter`. Set this property to
+ `nil` to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustification;
@@ -519,76 +755,117 @@ MGL_EXPORT
/**
Text tracking amount.
-
+
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLetterSpacing;
/**
Text leading value for multi-line text.
-
+
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1.2`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1.2`. Set this property to `nil` to
+ reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLineHeight;
+#if TARGET_OS_IPHONE
/**
Offset distance of text from its anchor.
-
+
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 ems from the left and 0 ems from the top. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
+ ems downward. Set this property to `nil` to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
+#else
+/**
+ Offset distance of text from its anchor.
+
+ This property is measured in ems.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
+ ems upward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
+#endif
/**
- If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
+ If true, icons will display without their corresponding text when the text
+ collides with other symbols and the icon does not.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
+ the default value.
- This property is only applied to the style if `textField` is non-`nil`, and `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`, and
+ `iconImageName` is non-`nil`. Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable, getter=isTextOptional) MGLStyleValue<NSNumber *> *textOptional;
/**
- Size of the additional area around the text bounding box used for detecting symbol collisions.
-
+ Size of the additional area around the text bounding box used for detecting
+ symbol collisions.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `2`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textPadding;
/**
Orientation of text when map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextPitchAlignmentAuto`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextPitchAlignmentAuto`. Set this property to
+ `nil` to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textPitchAlignment;
/**
Rotates the text clockwise.
-
+
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
- This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a> layout property in the Mapbox Style Specification.
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a>
+ layout property in the Mapbox Style Specification.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotation;
@@ -596,31 +873,27 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate __attribute__((unavailable("Use textRotation instead.")));
/**
- In combination with `symbolPlacement`, determines the rotation behavior of the individual glyphs forming the text.
+ In combination with `symbolPlacement`, determines the rotation behavior of the
+ individual glyphs forming the text.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentAuto`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextRotationAlignmentAuto`. Set this property
+ to `nil` to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textRotationAlignment;
/**
- Font size.
-
- This property is measured in points.
-
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `16`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textSize;
-
-/**
Specifies how to capitalize text.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextTransformNone`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextTransformNone`. Set this property to `nil`
+ to reset it to the default value.
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTransform;
@@ -628,123 +901,195 @@ MGL_EXPORT
#if TARGET_OS_IPHONE
/**
- The tint color to apply to the icon. The `iconImageName` property must be set to a template image.
+ The tint color to apply to the icon. The `iconImageName` property must be set
+ to a template image.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconColor;
#else
/**
- The tint color to apply to the icon. The `iconImageName` property must be set to a template image.
+ The tint color to apply to the icon. The `iconImageName` property must be set
+ to a template image.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconColor;
#endif
/**
Fade out the halo towards the outside.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloBlur;
#if TARGET_OS_IPHONE
/**
- The color of the icon’s halo. The `iconImageName` property must be set to a template image.
+ The color of the icon’s halo. The `iconImageName` property must be set to a
+ template image.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.clearColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.clearColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconHaloColor;
#else
/**
- The color of the icon’s halo. The `iconImageName` property must be set to a template image.
+ The color of the icon’s halo. The `iconImageName` property must be set to a
+ template image.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.clearColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.clearColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconHaloColor;
#endif
/**
Distance of halo to the icon outline.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloWidth;
/**
The opacity at which the icon will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOpacity;
+#if TARGET_OS_IPHONE
/**
Distance that the icon's anchor is moved from its original placement.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslation;
+#else
+/**
+ Distance that the icon's anchor is moved from its original placement.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslate;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslation;
+#endif
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslate __attribute__((unavailable("Use iconTranslation instead.")));
/**
Controls the translation reference point.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `iconImageName` is non-`nil`, and `iconTranslate` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconTranslationAnchorMap`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`, and
+ `iconTranslation` is non-`nil`. Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate-anchor"><code>icon-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslateAnchor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslateAnchor __attribute__((unavailable("Use iconTranslationAnchor instead.")));
#if TARGET_OS_IPHONE
/**
The color with which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *textColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textColor;
#else
/**
The color with which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *textColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textColor;
#endif
/**
The halo's fadeout distance towards the outside.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloBlur;
@@ -752,61 +1097,252 @@ MGL_EXPORT
/**
The color of the text's halo, which helps it stand out from backgrounds.
- The default value of this property is an `MGLStyleValue` object containing `UIColor.clearColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.clearColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *textHaloColor;
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textHaloColor;
#else
/**
The color of the text's halo, which helps it stand out from backgrounds.
- The default value of this property is an `MGLStyleValue` object containing `NSColor.clearColor`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.clearColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *textHaloColor;
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textHaloColor;
#endif
/**
- Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
-
+ Distance of halo to the font outline. Max text halo width is 1/4 of the
+ font-size.
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloWidth;
/**
The opacity at which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textOpacity;
+#if TARGET_OS_IPHONE
/**
Distance that the text's anchor is moved from its original placement.
-
+
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value.
-
- This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
+ layout property in the Mapbox Style Specification.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslate;
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslation;
+#else
+/**
+ Distance that the text's anchor is moved from its original placement.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslation;
+#endif
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslate __attribute__((unavailable("Use textTranslation instead.")));
/**
Controls the translation reference point.
- The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextTranslateAnchorMap`. Set this property to `nil` to reset it to the default value.
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLTextTranslationAnchorMap`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `text` is non-`nil`, and
+ `textTranslation` is non-`nil`. Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate-anchor"><code>text-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslateAnchor __attribute__((unavailable("Use textTranslationAnchor instead.")));
+
+@end
+
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLSymbolStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLSymbolStyleLayerAdditions)
+
+#pragma mark Working with Symbol Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLIconRotationAlignment` enumeration.
+
+ @param iconRotationAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment;
+
+/**
+ The `MGLIconRotationAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLIconRotationAlignment MGLIconRotationAlignmentValue;
+
+/**
+ Creates a new value object containing the given `MGLIconTextFit` enumeration.
- This property is only applied to the style if `textField` is non-`nil`, and `textTranslate` is non-`nil`. Otherwise, it is ignored.
+ @param iconTextFit The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit;
+
+/**
+ The `MGLIconTextFit` enumeration representation of the value.
+ */
+@property (readonly) MGLIconTextFit MGLIconTextFitValue;
+
+/**
+ Creates a new value object containing the given `MGLSymbolPlacement` enumeration.
+
+ @param symbolPlacement The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement;
+
+/**
+ The `MGLSymbolPlacement` enumeration representation of the value.
+ */
+@property (readonly) MGLSymbolPlacement MGLSymbolPlacementValue;
+
+/**
+ Creates a new value object containing the given `MGLTextAnchor` enumeration.
+
+ @param textAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor;
+
+/**
+ The `MGLTextAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLTextAnchor MGLTextAnchorValue;
+
+/**
+ Creates a new value object containing the given `MGLTextJustification` enumeration.
+
+ @param textJustification The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextJustification:(MGLTextJustification)textJustification;
+
+/**
+ The `MGLTextJustification` enumeration representation of the value.
+ */
+@property (readonly) MGLTextJustification MGLTextJustificationValue;
+
+/**
+ Creates a new value object containing the given `MGLTextPitchAlignment` enumeration.
+
+ @param textPitchAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment;
+
+/**
+ The `MGLTextPitchAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLTextPitchAlignment MGLTextPitchAlignmentValue;
+
+/**
+ Creates a new value object containing the given `MGLTextRotationAlignment` enumeration.
+
+ @param textRotationAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment;
+
+/**
+ The `MGLTextRotationAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLTextRotationAlignment MGLTextRotationAlignmentValue;
+
+/**
+ Creates a new value object containing the given `MGLTextTransform` enumeration.
+
+ @param textTransform The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextTransform:(MGLTextTransform)textTransform;
+
+/**
+ The `MGLTextTransform` enumeration representation of the value.
+ */
+@property (readonly) MGLTextTransform MGLTextTransformValue;
+
+/**
+ Creates a new value object containing the given `MGLIconTranslationAnchor` enumeration.
+
+ @param iconTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLIconTranslationAnchor:(MGLIconTranslationAnchor)iconTranslationAnchor;
+
+/**
+ The `MGLIconTranslationAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLIconTranslationAnchor MGLIconTranslationAnchorValue;
+
+/**
+ Creates a new value object containing the given `MGLTextTranslationAnchor` enumeration.
+
+ @param textTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLTextTranslationAnchor:(MGLTextTranslationAnchor)textTranslationAnchor;
+
+/**
+ The `MGLTextTranslationAnchor` enumeration representation of the value.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslateAnchor;
+@property (readonly) MGLTextTranslationAnchor MGLTextTranslationAnchorValue;
@end
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 31c584b473..493a8c5b6f 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -1,5 +1,5 @@
// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
#import "MGLMapView_Private.h"
@@ -8,7 +8,9 @@
#import "MGLStyleValue_Private.h"
#import "MGLSymbolStyleLayer.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
+
namespace mbgl {
MBGL_DEFINE_ENUM(MGLIconRotationAlignment, {
@@ -65,14 +67,14 @@ namespace mbgl {
{ MGLTextTransformLowercase, "lowercase" },
});
- MBGL_DEFINE_ENUM(MGLIconTranslateAnchor, {
- { MGLIconTranslateAnchorMap, "map" },
- { MGLIconTranslateAnchorViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLIconTranslationAnchor, {
+ { MGLIconTranslationAnchorMap, "map" },
+ { MGLIconTranslationAnchorViewport, "viewport" },
});
- MBGL_DEFINE_ENUM(MGLTextTranslateAnchor, {
- { MGLTextTranslateAnchorMap, "map" },
- { MGLTextTranslateAnchorViewport, "viewport" },
+ MBGL_DEFINE_ENUM(MGLTextTranslationAnchor, {
+ { MGLTextTranslationAnchorMap, "map" },
+ { MGLTextTranslationAnchorViewport, "viewport" },
});
}
@@ -108,6 +110,13 @@ namespace mbgl {
super.rawLayer = rawLayer;
}
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -127,7 +136,7 @@ namespace mbgl {
{
MGLAssertStyleLayerIsValid();
- self.rawLayer->setFilter(predicate.mgl_filter);
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}
- (NSPredicate *)predicate
@@ -192,9 +201,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setIconAllowOverlap:(MGLStyleValue<NSNumber *> *)iconAllowOverlap {
- self.iconAllowsOverlap = iconAllowOverlap;
}
- (MGLStyleValue<NSNumber *> *)iconAllowOverlap {
@@ -215,9 +222,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setIconIgnorePlacement:(MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
- self.iconIgnoresPlacement = iconIgnorePlacement;
}
- (MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
@@ -238,9 +243,7 @@ namespace mbgl {
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
-
- (void)setIconImage:(MGLStyleValue<NSString *> *)iconImage {
- self.iconImageName = iconImage;
}
- (MGLStyleValue<NSString *> *)iconImage {
@@ -303,9 +306,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate {
- self.iconRotation = iconRotate;
}
- (MGLStyleValue<NSNumber *> *)iconRotate {
@@ -340,9 +341,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize {
- self.iconScale = iconSize;
}
- (MGLStyleValue<NSNumber *> *)iconSize {
@@ -391,9 +390,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setIconKeepUpright:(MGLStyleValue<NSNumber *> *)iconKeepUpright {
- self.keepsIconUpright = iconKeepUpright;
}
- (MGLStyleValue<NSNumber *> *)iconKeepUpright {
@@ -414,9 +411,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextKeepUpright:(MGLStyleValue<NSNumber *> *)textKeepUpright {
- self.keepsTextUpright = textKeepUpright;
}
- (MGLStyleValue<NSNumber *> *)textKeepUpright {
@@ -437,9 +432,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextMaxAngle:(MGLStyleValue<NSNumber *> *)textMaxAngle {
- self.maximumTextAngle = textMaxAngle;
}
- (MGLStyleValue<NSNumber *> *)textMaxAngle {
@@ -460,9 +453,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth {
- self.maximumTextWidth = textMaxWidth;
}
- (MGLStyleValue<NSNumber *> *)textMaxWidth {
@@ -483,9 +474,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setSymbolAvoidEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
- self.symbolAvoidsEdges = symbolAvoidEdges;
}
- (MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
@@ -520,6 +509,27 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
+- (void)setText:(MGLStyleValue<NSString *> *)text {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(text);
+ self.rawLayer->setTextField(mbglValue);
+}
+
+- (MGLStyleValue<NSString *> *)text {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField();
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+}
+
+- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
+}
+
+- (MGLStyleValue<NSString *> *)textField {
+ return self.text;
+}
+
- (void)setTextAllowsOverlap:(MGLStyleValue<NSNumber *> *)textAllowsOverlap {
MGLAssertStyleLayerIsValid();
@@ -534,9 +544,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextAllowOverlap:(MGLStyleValue<NSNumber *> *)textAllowOverlap {
- self.textAllowsOverlap = textAllowOverlap;
}
- (MGLStyleValue<NSNumber *> *)textAllowOverlap {
@@ -557,32 +565,46 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(propertyValue);
}
-- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
+- (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(textField);
- self.rawLayer->setTextField(mbglValue);
+ auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFontNames);
+ self.rawLayer->setTextFont(mbglValue);
}
-- (MGLStyleValue<NSString *> *)textField {
+- (MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField();
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont();
+ return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue);
}
- (void)setTextFont:(MGLStyleValue<NSArray<NSString *> *> *)textFont {
+}
+
+- (MGLStyleValue<NSArray<NSString *> *> *)textFont {
+ return self.textFontNames;
+}
+
+- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFont);
- self.rawLayer->setTextFont(mbglValue);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textFontSize);
+ self.rawLayer->setTextSize(mbglValue);
}
-- (MGLStyleValue<NSArray<NSString *> *> *)textFont {
+- (MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont();
- return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize();
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+}
+
+- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
+}
+
+- (MGLStyleValue<NSNumber *> *)textSize {
+ return self.textFontSize;
}
- (void)setTextIgnoresPlacement:(MGLStyleValue<NSNumber *> *)textIgnoresPlacement {
@@ -599,9 +621,7 @@ namespace mbgl {
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextIgnorePlacement:(MGLStyleValue<NSNumber *> *)textIgnorePlacement {
- self.textIgnoresPlacement = textIgnorePlacement;
}
- (MGLStyleValue<NSNumber *> *)textIgnorePlacement {
@@ -622,9 +642,7 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(propertyValue);
}
-
- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify {
- self.textJustification = textJustify;
}
- (MGLStyleValue<NSValue *> *)textJustify {
@@ -729,9 +747,7 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-
- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate {
- self.textRotation = textRotate;
}
- (MGLStyleValue<NSNumber *> *)textRotate {
@@ -752,20 +768,6 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(propertyValue);
}
-- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
- MGLAssertStyleLayerIsValid();
-
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textSize);
- self.rawLayer->setTextSize(mbglValue);
-}
-
-- (MGLStyleValue<NSNumber *> *)textSize {
- MGLAssertStyleLayerIsValid();
-
- auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
-}
-
- (void)setTextTransform:(MGLStyleValue<NSValue *> *)textTransform {
MGLAssertStyleLayerIsValid();
@@ -852,32 +854,46 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-- (void)setIconTranslate:(MGLStyleValue<NSValue *> *)iconTranslate {
+- (void)setIconTranslation:(MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslate);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslation);
self.rawLayer->setIconTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTranslate {
+- (MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslate() ?: self.rawLayer->getDefaultIconTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
-- (void)setIconTranslateAnchor:(MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+- (void)setIconTranslate:(MGLStyleValue<NSValue *> *)iconTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)iconTranslate {
+ return self.iconTranslation;
+}
+
+- (void)setIconTranslationAnchor:(MGLStyleValue<NSValue *> *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumPropertyValue(iconTranslateAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumPropertyValue(iconTranslationAnchor);
self.rawLayer->setIconTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+- (MGLStyleValue<NSValue *> *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslateAnchor() ?: self.rawLayer->getDefaultIconTranslateAnchor();
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setIconTranslateAnchor:(MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+}
+
+- (MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+ return self.iconTranslationAnchor;
}
- (void)setTextColor:(MGLStyleValue<MGLColor *> *)textColor {
@@ -950,33 +966,151 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
-- (void)setTextTranslate:(MGLStyleValue<NSValue *> *)textTranslate {
+- (void)setTextTranslation:(MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslate);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslation);
self.rawLayer->setTextTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textTranslate {
+- (MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslate() ?: self.rawLayer->getDefaultTextTranslate();
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
-- (void)setTextTranslateAnchor:(MGLStyleValue<NSValue *> *)textTranslateAnchor {
+- (void)setTextTranslate:(MGLStyleValue<NSValue *> *)textTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)textTranslate {
+ return self.textTranslation;
+}
+
+- (void)setTextTranslationAnchor:(MGLStyleValue<NSValue *> *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumPropertyValue(textTranslateAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumPropertyValue(textTranslationAnchor);
self.rawLayer->setTextTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textTranslateAnchor {
+- (MGLStyleValue<NSValue *> *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslateAnchor() ?: self.rawLayer->getDefaultTextTranslateAnchor();
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setTextTranslateAnchor:(MGLStyleValue<NSValue *> *)textTranslateAnchor {
+}
+
+- (MGLStyleValue<NSValue *> *)textTranslateAnchor {
+ return self.textTranslationAnchor;
+}
+
+
+@end
+
+@implementation NSValue (MGLSymbolStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
+ return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
}
+- (MGLIconRotationAlignment)MGLIconRotationAlignmentValue {
+ MGLIconRotationAlignment iconRotationAlignment;
+ [self getValue:&iconRotationAlignment];
+ return iconRotationAlignment;
+}
+
++ (NSValue *)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit {
+ return [NSValue value:&iconTextFit withObjCType:@encode(MGLIconTextFit)];
+}
+
+- (MGLIconTextFit)MGLIconTextFitValue {
+ MGLIconTextFit iconTextFit;
+ [self getValue:&iconTextFit];
+ return iconTextFit;
+}
+
++ (NSValue *)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement {
+ return [NSValue value:&symbolPlacement withObjCType:@encode(MGLSymbolPlacement)];
+}
+
+- (MGLSymbolPlacement)MGLSymbolPlacementValue {
+ MGLSymbolPlacement symbolPlacement;
+ [self getValue:&symbolPlacement];
+ return symbolPlacement;
+}
+
++ (NSValue *)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor {
+ return [NSValue value:&textAnchor withObjCType:@encode(MGLTextAnchor)];
+}
+
+- (MGLTextAnchor)MGLTextAnchorValue {
+ MGLTextAnchor textAnchor;
+ [self getValue:&textAnchor];
+ return textAnchor;
+}
+
++ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification {
+ return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)];
+}
+
+- (MGLTextJustification)MGLTextJustificationValue {
+ MGLTextJustification textJustification;
+ [self getValue:&textJustification];
+ return textJustification;
+}
+
++ (NSValue *)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment {
+ return [NSValue value:&textPitchAlignment withObjCType:@encode(MGLTextPitchAlignment)];
+}
+
+- (MGLTextPitchAlignment)MGLTextPitchAlignmentValue {
+ MGLTextPitchAlignment textPitchAlignment;
+ [self getValue:&textPitchAlignment];
+ return textPitchAlignment;
+}
+
++ (NSValue *)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment {
+ return [NSValue value:&textRotationAlignment withObjCType:@encode(MGLTextRotationAlignment)];
+}
+
+- (MGLTextRotationAlignment)MGLTextRotationAlignmentValue {
+ MGLTextRotationAlignment textRotationAlignment;
+ [self getValue:&textRotationAlignment];
+ return textRotationAlignment;
+}
+
++ (NSValue *)valueWithMGLTextTransform:(MGLTextTransform)textTransform {
+ return [NSValue value:&textTransform withObjCType:@encode(MGLTextTransform)];
+}
+
+- (MGLTextTransform)MGLTextTransformValue {
+ MGLTextTransform textTransform;
+ [self getValue:&textTransform];
+ return textTransform;
+}
+
++ (NSValue *)valueWithMGLIconTranslationAnchor:(MGLIconTranslationAnchor)iconTranslationAnchor {
+ return [NSValue value:&iconTranslationAnchor withObjCType:@encode(MGLIconTranslationAnchor)];
+}
+
+- (MGLIconTranslationAnchor)MGLIconTranslationAnchorValue {
+ MGLIconTranslationAnchor iconTranslationAnchor;
+ [self getValue:&iconTranslationAnchor];
+ return iconTranslationAnchor;
+}
+
++ (NSValue *)valueWithMGLTextTranslationAnchor:(MGLTextTranslationAnchor)textTranslationAnchor {
+ return [NSValue value:&textTranslationAnchor withObjCType:@encode(MGLTextTranslationAnchor)];
+}
+
+- (MGLTextTranslationAnchor)MGLTextTranslationAnchorValue {
+ MGLTextTranslationAnchor textTranslationAnchor;
+ [self getValue:&textTranslationAnchor];
+ return textTranslationAnchor;
+}
@end
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index 7e1a8206a3..99d23f4add 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -20,6 +20,10 @@ typedef NSString *MGLTileSourceOption NS_STRING_ENUM;
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMaximumZoomLevel`, if specified. The default value for this
option is 0.
+
+ This option corresponds to the `minzoom` key in the
+ <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
+ specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
@@ -30,6 +34,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMinimumZoomLevel`, if specified. The default value for this
option is 22.
+
+ This option corresponds to the `maxzoom` key in the
+ <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
+ specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
@@ -42,6 +50,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
+
+ This option corresponds to the `attribution` key in the
+ <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
+ specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
@@ -61,6 +73,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
+
+ This option corresponds to the `attribution` key in the
+ <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
+ specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString;
@@ -80,6 +96,10 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
the constants described in `MGLTileCoordinateSystem`.
The default value for this option is `MGLTileCoordinateSystemXYZ`.
+
+ This option corresponds to the `scheme` key in the
+ <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">TileJSON</a>
+ specification.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
@@ -150,13 +170,101 @@ MGL_EXPORT
/**
Returns a tile source initialized an identifier, tile URL templates, and
options.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
+ #### Tile URL templates
+
+ Tile URL templates are strings that specify the URLs of the tile images to
+ load. Each template resembles an absolute URL, but with any number of
+ placeholder strings that the source evaluates based on the tile it needs to
+ load. For example:
+
+ <ul>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
+ </ul>
+
+ Tile sources support the following placeholder strings in tile URL templates,
+ all of which are optional:
+
+ <table>
+ <thead>
+ <tr><th>Placeholder string</th><th>Description</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+ </tr>
+ <tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+ </tr>
+ <tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the
+ <code>options</code> parameter.</td>
+ </tr>
+ <tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+ </tr>
+ <tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+ Retina displays, including displays for which
+ <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
+ is 3.</td>
+ </tr>
+ <tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+ </tr>
+ </tbody>
+ </table>
+
+ For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+ consult the
+ <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
- @param tileURLTemplates An array of tile URL template strings.
+ @param tileURLTemplates An array of tile URL template strings. Only the first
+ string is used; any additional strings are ignored.
@param options A dictionary containing configuration options. See
`MGLTileSourceOption` for available keys and values. Pass in `nil` to use
the default values.
@@ -164,6 +272,17 @@ MGL_EXPORT
*/
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options;
+#pragma mark Accessing a Source’s Content
+
+/**
+ The URL to the TileJSON configuration file that specifies the contents of the
+ source.
+
+ If the receiver was initialized using
+ `-initWithIdentifier:tileURLTemplates:options`, this property is set to `nil`.
+ */
+@property (nonatomic, copy, nullable, readonly) NSURL *configurationURL;
+
#pragma mark Accessing Attribution Strings
/**
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index 522675bc88..1aef81d53c 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -27,6 +27,12 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
return [super initWithIdentifier:identifier];
}
+- (NSURL *)configurationURL {
+ [NSException raise:@"MGLAbstractClassException"
+ format:@"MGLTileSource is an abstract class"];
+ return nil;
+}
+
- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index a5fd2584f8..bfa52f5b49 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -25,6 +25,19 @@ NS_ASSUME_NONNULL_BEGIN
(<var>extent</var>&nbsp;×&nbsp;2)&nbsp;−&nbsp;1, inclusive. Any vector style
layer initialized with a vector source must have a non-`nil` value in its
`sourceLayerIdentifier` property.
+
+ ### Example
+
+ ```swift
+ let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+ ```
*/
MGL_EXPORT
@interface MGLVectorSource : MGLTileSource
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index 0eea8dd18c..8fda528546 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -5,6 +5,7 @@
#import "MGLTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/vector_source.hpp>
@interface MGLVectorSource ()
@@ -69,6 +70,11 @@
super.rawSource = rawSource;
}
+- (NSURL *)configurationURL {
+ auto url = self.rawSource->getURL();
+ return url ? [NSURL URLWithString:@(url->c_str())] : nil;
+}
+
- (NSString *)attributionHTMLString {
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h
index f59ef4bf7f..ca09c11716 100644
--- a/platform/darwin/src/MGLVectorStyleLayer.h
+++ b/platform/darwin/src/MGLVectorStyleLayer.h
@@ -61,11 +61,15 @@ MGL_EXPORT
<li><code>NSContainsPredicateOperatorType</code> (<code>CONTAINS</code>)</li>
</ul>
- To test whether a feature has or lacks a specific attribute, compare the attribute to `NULL` or `NIL`. Predicates created using the `+[NSPredicate predicateWithValue:]` method are also supported. String operators and custom operators are not supported.
+ To test whether a feature has or lacks a specific attribute, compare the
+ attribute to `NULL` or `NIL`. Predicates created using the
+ `+[NSPredicate predicateWithValue:]` method are also supported. String
+ operators and custom operators are not supported.
For details about the predicate format string syntax, consult the “Predicate
- Format String Syntax” chapter of the “Predicate Programming Guide” in Apple
- developer documentation.
+ Format String Syntax” chapter of the
+ “<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/">Predicate Programming Guide</a>”
+ in Apple developer documentation.
The predicate's left-hand expression must be a string that identifies a feature
attribute or, alternatively, one of the following special attributes:
@@ -121,15 +125,29 @@ MGL_EXPORT
Automatic type casting is not performed. Therefore, a feature only matches this
predicate if its value for the attribute in question is of the same type as the
- value specified in the predicate. Also, operator modifiers `c`, `d`, and the
- combined `cd` for case and diacritic insensitivity are unsupported for
- comparison and aggregate operators that are used in the predicate.
+ value specified in the predicate. Also, operator modifiers such as `c` (for
+ case insensitivity), `d` (for diacritic insensitivity), and `l` (for locale
+ sensitivity) are unsupported for comparison and aggregate operators that are
+ used in the predicate.
It is possible to create expressions that contain special characters in the
predicate format syntax. This includes the `$` in the `$id` and `$type` special
style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
`%K` in the format string to represent these variables:
`@"%K == 'LineString'", @"$type"`.
+
+ ### Example
+
+ To filter the layer to include only the features whose `index` attribute is 5
+ or 10 and whose `ele` attribute is at least 1,500, you could create an
+ `NSCompoundPredicate` along these lines:
+
+ ```swift
+ let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
+ layer.sourceLayerIdentifier = "contours"
+ layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
+ mapView.style?.addLayer(layer)
+ ```
*/
@property (nonatomic, nullable) NSPredicate *predicate;
diff --git a/platform/darwin/src/MGLVectorStyleLayer.m b/platform/darwin/src/MGLVectorStyleLayer.m
index d8146f4246..da6da0ea7f 100644
--- a/platform/darwin/src/MGLVectorStyleLayer.m
+++ b/platform/darwin/src/MGLVectorStyleLayer.m
@@ -4,12 +4,12 @@
- (void)setPredicate:(NSPredicate *)predicate {
[NSException raise:@"MGLAbstractClassException"
- format:@"MGLVectorLayer is an abstract class"];
+ format:@"MGLVectorStyleLayer is an abstract class"];
}
- (NSPredicate *)predicate {
[NSException raise:@"MGLAbstractClassException"
- format:@"MGLVectorLayer is an abstract class"];
+ format:@"MGLVectorStyleLayer is an abstract class"];
return nil;
}
diff --git a/platform/darwin/src/NSArray+MGLAdditions.h b/platform/darwin/src/NSArray+MGLAdditions.h
index eb1cfb7c47..c4dfd8207b 100644
--- a/platform/darwin/src/NSArray+MGLAdditions.h
+++ b/platform/darwin/src/NSArray+MGLAdditions.h
@@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
#import <mbgl/util/feature.hpp>
@@ -9,4 +10,18 @@
/** Returns a string resulting from inserting a separator between each attributed string in the array */
- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator;
+/**
+ Converts std::vector<CLLocationCoordinate> into an NSArray containing dictionary
+ representations of coordinates with the following structure:
+ [{"latitude": lat, "longitude": lng}]
+ */
++ (NSArray *)mgl_coordinatesFromCoordinates:(std::vector<CLLocationCoordinate2D>)coords;
+
+/**
+ Converts the receiver into a std::vector<CLLocationCoordinate>.
+ Receiver must conform to the following structure:
+ [{"latitude": lat, "longitude": lng}]
+ */
+- (std::vector<CLLocationCoordinate2D>)mgl_coordinates;
+
@end
diff --git a/platform/darwin/src/NSArray+MGLAdditions.mm b/platform/darwin/src/NSArray+MGLAdditions.mm
index b2799c46e1..8ec344f580 100644
--- a/platform/darwin/src/NSArray+MGLAdditions.mm
+++ b/platform/darwin/src/NSArray+MGLAdditions.mm
@@ -17,9 +17,9 @@
vector.push_back(propertyMap);
} else {
NSExpression *expression = [NSExpression expressionForConstantValue:value];
- vector.push_back([expression mgl_filterValue]);
+ vector.push_back(expression.mgl_constantMBGLValue);
}
- }
+ }
return vector;
}
@@ -38,4 +38,28 @@
return attributedString;
}
++ (NSArray *)mgl_coordinatesFromCoordinates:(std::vector<CLLocationCoordinate2D>)coords {
+ NSMutableArray *coordinates = [NSMutableArray array];
+ for (auto coord : coords) {
+ [coordinates addObject:@{@"latitude": @(coord.latitude),
+ @"longitude": @(coord.longitude)}];
+ }
+ return coordinates;
+}
+
+- (std::vector<CLLocationCoordinate2D>)mgl_coordinates {
+ NSUInteger numberOfCoordinates = [self count];
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(numberOfCoordinates * sizeof(CLLocationCoordinate2D));
+
+ for (NSUInteger i = 0; i < numberOfCoordinates; i++) {
+ coords[i] = CLLocationCoordinate2DMake([self[i][@"latitude"] doubleValue],
+ [self[i][@"longitude"] doubleValue]);
+ }
+
+ std::vector<CLLocationCoordinate2D> coordinates = { coords, coords + numberOfCoordinates };
+ free(coords);
+
+ return coordinates;
+}
+
@end
diff --git a/platform/darwin/src/NSCoder+MGLAdditions.h b/platform/darwin/src/NSCoder+MGLAdditions.h
new file mode 100644
index 0000000000..036a99c5af
--- /dev/null
+++ b/platform/darwin/src/NSCoder+MGLAdditions.h
@@ -0,0 +1,16 @@
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+#import <mbgl/util/feature.hpp>
+
+@interface NSCoder (MGLAdditions)
+
+- (void)encodeMGLCoordinate:(CLLocationCoordinate2D)coordinate forKey:(NSString *)key;
+
+- (CLLocationCoordinate2D)decodeMGLCoordinateForKey:(NSString *)key;
+
+- (void)mgl_encodeLocationCoordinates2D:(std::vector<CLLocationCoordinate2D>)coordinates forKey:(NSString *)key;
+
+- (std::vector<CLLocationCoordinate2D>)mgl_decodeLocationCoordinates2DForKey:(NSString *)key;
+
+@end
diff --git a/platform/darwin/src/NSCoder+MGLAdditions.mm b/platform/darwin/src/NSCoder+MGLAdditions.mm
new file mode 100644
index 0000000000..4af6c7588b
--- /dev/null
+++ b/platform/darwin/src/NSCoder+MGLAdditions.mm
@@ -0,0 +1,26 @@
+#import "NSCoder+MGLAdditions.h"
+
+#import "NSArray+MGLAdditions.h"
+#import "NSValue+MGLAdditions.h"
+
+@implementation NSCoder (MGLAdditions)
+
+- (void)mgl_encodeLocationCoordinates2D:(std::vector<CLLocationCoordinate2D>)coordinates forKey:(NSString *)key {
+ [self encodeObject:[NSArray mgl_coordinatesFromCoordinates:coordinates] forKey:key];
+}
+
+- (std::vector<CLLocationCoordinate2D>)mgl_decodeLocationCoordinates2DForKey:(NSString *)key {
+ NSArray *coordinates = [self decodeObjectOfClass:[NSArray class] forKey:key];
+ return [coordinates mgl_coordinates];
+}
+
+- (void)encodeMGLCoordinate:(CLLocationCoordinate2D)coordinate forKey:(NSString *)key {
+ [self encodeObject:@{@"latitude": @(coordinate.latitude), @"longitude": @(coordinate.longitude)} forKey:key];
+}
+
+- (CLLocationCoordinate2D)decodeMGLCoordinateForKey:(NSString *)key {
+ NSDictionary *coordinate = [self decodeObjectForKey:key];
+ return CLLocationCoordinate2DMake([coordinate[@"latitude"] doubleValue], [coordinate[@"longitude"] doubleValue]);
+}
+
+@end
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index 19c264aa40..58b37fae0e 100644
--- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -7,95 +7,189 @@
- (mbgl::style::Filter)mgl_filter
{
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ BOOL isReversed = ((leftType == NSConstantValueExpressionType || leftType == NSAggregateExpressionType)
+ && rightType == NSKeyPathExpressionType);
switch (self.predicateOperatorType) {
case NSEqualToPredicateOperatorType: {
- if (self.rightExpression.constantValue)
- {
- auto filter = mbgl::style::EqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
- }
- else
- {
- auto filter = mbgl::style::NotHasFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- return filter;
+ mbgl::style::EqualsFilter eqFilter;
+ eqFilter.key = self.mgl_keyPath.UTF8String;
+ eqFilter.value = self.mgl_constantValue;
+
+ // Convert == nil to NotHasFilter.
+ if (eqFilter.value.is<mbgl::NullValue>()) {
+ mbgl::style::NotHasFilter notHasFilter;
+ notHasFilter.key = eqFilter.key;
+ return notHasFilter;
}
+
+ return eqFilter;
}
case NSNotEqualToPredicateOperatorType: {
- if (self.rightExpression.constantValue)
- {
- auto filter = mbgl::style::NotEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
- }
- else
- {
- auto filter = mbgl::style::HasFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- return filter;
+ mbgl::style::NotEqualsFilter neFilter;
+ neFilter.key = self.mgl_keyPath.UTF8String;
+ neFilter.value = self.mgl_constantValue;
+
+ // Convert != nil to HasFilter.
+ if (neFilter.value.is<mbgl::NullValue>()) {
+ mbgl::style::HasFilter hasFilter;
+ hasFilter.key = neFilter.key;
+ return hasFilter;
}
+
+ return neFilter;
}
case NSGreaterThanPredicateOperatorType: {
- auto filter = mbgl::style::GreaterThanFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ if (isReversed) {
+ mbgl::style::LessThanFilter ltFilter;
+ ltFilter.key = self.mgl_keyPath.UTF8String;
+ ltFilter.value = self.mgl_constantValue;
+ return ltFilter;
+ } else {
+ mbgl::style::GreaterThanFilter gtFilter;
+ gtFilter.key = self.mgl_keyPath.UTF8String;
+ gtFilter.value = self.mgl_constantValue;
+ return gtFilter;
+ }
}
case NSGreaterThanOrEqualToPredicateOperatorType: {
- auto filter = mbgl::style::GreaterThanEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ if (isReversed) {
+ mbgl::style::LessThanEqualsFilter lteFilter;
+ lteFilter.key = self.mgl_keyPath.UTF8String;
+ lteFilter.value = self.mgl_constantValue;
+ return lteFilter;
+ } else {
+ mbgl::style::GreaterThanEqualsFilter gteFilter;
+ gteFilter.key = self.mgl_keyPath.UTF8String;
+ gteFilter.value = self.mgl_constantValue;
+ return gteFilter;
+ }
}
case NSLessThanPredicateOperatorType: {
- auto filter = mbgl::style::LessThanFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ if (isReversed) {
+ mbgl::style::GreaterThanFilter gtFilter;
+ gtFilter.key = self.mgl_keyPath.UTF8String;
+ gtFilter.value = self.mgl_constantValue;
+ return gtFilter;
+ } else {
+ mbgl::style::LessThanFilter ltFilter;
+ ltFilter.key = self.mgl_keyPath.UTF8String;
+ ltFilter.value = self.mgl_constantValue;
+ return ltFilter;
+ }
}
case NSLessThanOrEqualToPredicateOperatorType: {
- auto filter = mbgl::style::LessThanEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ if (isReversed) {
+ mbgl::style::GreaterThanEqualsFilter gteFilter;
+ gteFilter.key = self.mgl_keyPath.UTF8String;
+ gteFilter.value = self.mgl_constantValue;
+ return gteFilter;
+ } else {
+ mbgl::style::LessThanEqualsFilter lteFilter;
+ lteFilter.key = self.mgl_keyPath.UTF8String;
+ lteFilter.value = self.mgl_constantValue;
+ return lteFilter;
+ }
}
case NSInPredicateOperatorType: {
- auto filter = mbgl::style::InFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.values = self.rightExpression.mgl_filterValues;
- return filter;
+ if (isReversed) {
+ if (leftType == NSConstantValueExpressionType && [leftExpression.constantValue isKindOfClass:[NSString class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"CONTAINS not supported for string comparison."];
+ }
+ [NSException raise:NSInvalidArgumentException
+ format:@"Predicate cannot compare values IN attribute."];
+ }
+ mbgl::style::InFilter inFilter;
+ inFilter.key = leftExpression.keyPath.UTF8String;
+ inFilter.values = rightExpression.mgl_aggregateMBGLValue;
+ return inFilter;
}
case NSContainsPredicateOperatorType: {
- auto filter = mbgl::style::InFilter();
- filter.key = [self.rightExpression.constantValue UTF8String];
- filter.values = self.leftExpression.mgl_filterValues;
- return filter;
+ if (!isReversed) {
+ if (rightType == NSConstantValueExpressionType && [rightExpression.constantValue isKindOfClass:[NSString class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"IN not supported for string comparison."];
+ }
+ [NSException raise:NSInvalidArgumentException
+ format:@"Predicate cannot compare attribute CONTAINS values."];
+ }
+ mbgl::style::InFilter inFilter;
+ inFilter.key = rightExpression.keyPath.UTF8String;
+ inFilter.values = leftExpression.mgl_aggregateMBGLValue;
+ return inFilter;
}
case NSBetweenPredicateOperatorType: {
- auto filter = mbgl::style::AllFilter();
- auto gteFilter = mbgl::style::GreaterThanEqualsFilter();
- gteFilter.key = self.leftExpression.keyPath.UTF8String;
- gteFilter.value = self.rightExpression.mgl_filterValues[0];
- filter.filters.push_back(gteFilter);
- auto lteFilter = mbgl::style::LessThanEqualsFilter();
- lteFilter.key = self.leftExpression.keyPath.UTF8String;
- lteFilter.value = self.rightExpression.mgl_filterValues[1];
- filter.filters.push_back(lteFilter);
- return filter;
+ if (isReversed) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Predicate cannot compare bounds BETWEEN attribute."];
+ }
+ if (![rightExpression.constantValue isKindOfClass:[NSArray class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Right side of BETWEEN predicate must be an array."]; // not NSSet
+ }
+ auto values = rightExpression.mgl_aggregateMBGLValue;
+ if (values.size() != 2) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Right side of BETWEEN predicate must have two items."];
+ }
+ mbgl::style::AllFilter allFilter;
+ mbgl::style::GreaterThanEqualsFilter gteFilter;
+ gteFilter.key = leftExpression.keyPath.UTF8String;
+ gteFilter.value = values[0];
+ allFilter.filters.push_back(gteFilter);
+ mbgl::style::LessThanEqualsFilter lteFilter;
+ lteFilter.key = leftExpression.keyPath.UTF8String;
+ lteFilter.value = values[1];
+ allFilter.filters.push_back(lteFilter);
+ return allFilter;
}
case NSMatchesPredicateOperatorType:
case NSLikePredicateOperatorType:
case NSBeginsWithPredicateOperatorType:
case NSEndsWithPredicateOperatorType:
case NSCustomSelectorPredicateOperatorType:
- [NSException raise:@"Unsupported operator type"
+ [NSException raise:NSInvalidArgumentException
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
}
return {};
}
+- (NSString *)mgl_keyPath {
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ return leftExpression.keyPath;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ return rightExpression.keyPath;
+ }
+
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ return nil;
+}
+
+- (mbgl::Value)mgl_constantValue {
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ mbgl::Value value;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ value = rightExpression.mgl_constantMBGLValue;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ value = leftExpression.mgl_constantMBGLValue;
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ }
+ return value;
+}
+
@end
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
index 07114308c9..2697467198 100644
--- a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
@@ -18,32 +18,49 @@
{
switch (self.compoundPredicateType) {
case NSNotPredicateType: {
+ NSAssert(self.subpredicates.count <= 1, @"NOT predicate cannot have multiple subpredicates.");
+ NSPredicate *subpredicate = self.subpredicates.firstObject;
+ mbgl::style::Filter subfilter = subpredicate.mgl_filter;
- // Translate a nested NSComparisonPredicate with operator type NSInPredicateOperatorType into a flat mbgl::NotIn filter.
- NSArray<NSComparisonPredicate *> *comparisonPredicates = [self.subpredicates filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"class == %@", [NSComparisonPredicate class]]];
- NSArray<NSComparisonPredicate *> *notInPredicates = [comparisonPredicates filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSComparisonPredicate *_Nonnull predicate, NSDictionary<NSString *,id> * _Nullable bindings) {
- return predicate.predicateOperatorType == NSInPredicateOperatorType;
- }]];
+ // Convert NOT(!= nil) to NotHasFilter.
+ if (subfilter.is<mbgl::style::HasFilter>()) {
+ auto hasFilter = subfilter.get<mbgl::style::HasFilter>();
+ return mbgl::style::NotHasFilter { .key = hasFilter.key };
+ }
+
+ // Convert NOT(== nil) to HasFilter.
+ if (subfilter.is<mbgl::style::NotHasFilter>()) {
+ auto hasFilter = subfilter.get<mbgl::style::NotHasFilter>();
+ return mbgl::style::HasFilter { .key = hasFilter.key };
+ }
+
+ // Convert NOT(IN) or NOT(CONTAINS) to NotInFilter.
+ if (subfilter.is<mbgl::style::InFilter>()) {
+ auto inFilter = subfilter.get<mbgl::style::InFilter>();
+ mbgl::style::NotInFilter notInFilter;
+ notInFilter.key = inFilter.key;
+ notInFilter.values = inFilter.values;
+ return notInFilter;
+ }
- if (notInPredicates.count) {
- auto filter = mbgl::style::NotInFilter();
- filter.key = notInPredicates.firstObject.leftExpression.keyPath.UTF8String;
- filter.values = notInPredicates.firstObject.rightExpression.mgl_filterValues;
- return filter;
- } else {
- auto filter = mbgl::style::NoneFilter();
- filter.filters = [self mgl_subfilters];
- return filter;
+ // Convert NOT(), NOT(AND), NOT(NOT), NOT(==), etc. into NoneFilter.
+ mbgl::style::NoneFilter noneFilter;
+ if (subfilter.is<mbgl::style::AnyFilter>()) {
+ // Flatten NOT(OR).
+ noneFilter.filters = subfilter.get<mbgl::style::AnyFilter>().filters;
+ } else if (subpredicate) {
+ noneFilter.filters = { subfilter };
}
+ return noneFilter;
}
case NSAndPredicateType: {
- auto filter = mbgl::style::AllFilter();
- filter.filters = [self mgl_subfilters];
+ mbgl::style::AllFilter filter;
+ filter.filters = self.mgl_subfilters;
return filter;
}
case NSOrPredicateType: {
- auto filter = mbgl::style::AnyFilter();
- filter.filters = [self mgl_subfilters];
+ mbgl::style::AnyFilter filter;
+ filter.filters = self.mgl_subfilters;
return filter;
}
}
diff --git a/platform/darwin/src/NSDictionary+MGLAdditions.mm b/platform/darwin/src/NSDictionary+MGLAdditions.mm
index 1023e91a48..aad7fd8810 100644
--- a/platform/darwin/src/NSDictionary+MGLAdditions.mm
+++ b/platform/darwin/src/NSDictionary+MGLAdditions.mm
@@ -15,7 +15,7 @@
propertyMap[[key UTF8String]] = [array mgl_vector];
} else {
NSExpression *expression = [NSExpression expressionForConstantValue:self[key]];
- propertyMap[[key UTF8String]] = [expression mgl_filterValue];
+ propertyMap[[key UTF8String]] = expression.mgl_constantMBGLValue;
}
}
return propertyMap;
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h
index 6d0fff5760..c60d6d78ba 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.h
+++ b/platform/darwin/src/NSExpression+MGLAdditions.h
@@ -2,10 +2,14 @@
#include <mbgl/style/filter.hpp>
+NS_ASSUME_NONNULL_BEGIN
+
@interface NSExpression (MGLAdditions)
-- (mbgl::Value)mgl_filterValue;
-- (std::vector<mbgl::Value>)mgl_filterValues;
-- (mbgl::FeatureIdentifier)mgl_featureIdentifier;
+@property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue;
+@property (nonatomic, readonly) std::vector<mbgl::Value> mgl_aggregateMBGLValue;
+@property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier;
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 25a2945cfb..b095091b17 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -2,27 +2,25 @@
@implementation NSExpression (MGLAdditions)
-- (std::vector<mbgl::Value>)mgl_filterValues
-{
- if ([self.constantValue isKindOfClass:NSArray.class]) {
- NSArray *values = self.constantValue;
- std::vector<mbgl::Value>convertedValues;
- for (id value in values) {
- convertedValues.push_back([self mgl_convertedValueWithValue:value]);
+- (std::vector<mbgl::Value>)mgl_aggregateMBGLValue {
+ if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
+ std::vector<mbgl::Value> convertedValues;
+ for (id value in self.constantValue) {
+ NSExpression *expression = value;
+ if (![expression isKindOfClass:[NSExpression class]]) {
+ expression = [NSExpression expressionForConstantValue:expression];
+ }
+ convertedValues.push_back(expression.mgl_constantMBGLValue);
}
return convertedValues;
}
- [NSException raise:@"Values not handled" format:@""];
- return { };
-}
-
-- (mbgl::Value)mgl_filterValue
-{
- return [self mgl_convertedValueWithValue:self.constantValue];
+ [NSException raise:NSInvalidArgumentException
+ format:@"Constant value expression must contain an array or set."];
+ return {};
}
-- (mbgl::Value)mgl_convertedValueWithValue:(id)value
-{
+- (mbgl::Value)mgl_constantMBGLValue {
+ id value = self.constantValue;
if ([value isKindOfClass:NSString.class]) {
return { std::string([(NSString *)value UTF8String]) };
} else if ([value isKindOfClass:NSNumber.class]) {
@@ -42,7 +40,10 @@
// We still do this conversion in order to provide a valid value.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
- NSLog(@"One-time warning: Float values are converted to double and can introduce imprecision; please use double values explicitly in predicate arguments.");
+ NSLog(@"Float value in expression will be converted to a double; some imprecision may result. "
+ @"Use double values explicitly when specifying constant expression values and "
+ @"when specifying arguments to predicate and expression format strings. "
+ @"This will be logged only once.");
});
return { (double)number.doubleValue };
} else if ([number compare:@(0)] == NSOrderedDescending ||
@@ -55,33 +56,27 @@
// We use long long here to avoid any truncation.
return { (int64_t)number.longLongValue };
}
+ } else if (value && value != [NSNull null]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
}
- [NSException raise:@"Value not handled"
- format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
- return { };
+ return {};
}
-- (mbgl::FeatureIdentifier)mgl_featureIdentifier
-{
- id value = self.constantValue;
- mbgl::Value mbglValue = [self mgl_filterValue];
+- (mbgl::FeatureIdentifier)mgl_featureIdentifier {
+ mbgl::Value mbglValue = self.mgl_constantMBGLValue;
- if ([value isKindOfClass:NSString.class]) {
+ if (mbglValue.is<std::string>()) {
return mbglValue.get<std::string>();
- } else if ([value isKindOfClass:NSNumber.class]) {
- NSNumber *number = (NSNumber *)value;
- if ((strcmp([number objCType], @encode(char)) == 0) ||
- (strcmp([number objCType], @encode(BOOL)) == 0)) {
- return uint64_t(mbglValue.get<bool>());
- } else if ( strcmp([number objCType], @encode(double)) == 0 ||
- strcmp([number objCType], @encode(float)) == 0) {
- return mbglValue.get<double>();
- } else if ([number compare:@(0)] == NSOrderedDescending ||
- [number compare:@(0)] == NSOrderedSame) {
- return mbglValue.get<uint64_t>();
- } else if ([number compare:@(0)] == NSOrderedAscending) {
- return mbglValue.get<int64_t>();
- }
+ }
+ if (mbglValue.is<double>()) {
+ return mbglValue.get<double>();
+ }
+ if (mbglValue.is<uint64_t>()) {
+ return mbglValue.get<uint64_t>();
+ }
+ if (mbglValue.is<int64_t>()) {
+ return mbglValue.get<int64_t>();
}
return {};
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm
index 64ad277e4d..0ac68095f9 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm
@@ -5,7 +5,7 @@
class FilterEvaluator {
public:
- NSArray* getPredicates(std::vector<mbgl::style::Filter> filters) {
+ NSArray *getPredicates(std::vector<mbgl::style::Filter> filters) {
NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:filters.size()];
for (auto filter : filters) {
[predicates addObject:mbgl::style::Filter::visit(filter, FilterEvaluator())];
@@ -13,73 +13,118 @@ public:
return predicates;
}
- NSArray* getValues(std::vector<mbgl::Value> values) {
+ NSExpression *getValues(std::vector<mbgl::Value> values) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()];
for (auto value : values) {
- [array addObject:mbgl::Value::visit(value, ValueEvaluator())];
+ id constantValue = mbgl::Value::visit(value, ValueEvaluator());
+ [array addObject:[NSExpression expressionForConstantValue:constantValue]];
}
- return array;
+ return [NSExpression expressionForAggregate:array];
}
- NSPredicate* operator()(mbgl::style::NullFilter filter) {
+ NSPredicate *operator()(mbgl::style::NullFilter filter) {
return nil;
}
- NSPredicate* operator()(mbgl::style::EqualsFilter filter) {
+ NSPredicate *operator()(mbgl::style::EqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::NotEqualsFilter filter) {
+ NSPredicate *operator()(mbgl::style::NotEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K != %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::GreaterThanFilter filter) {
+ NSPredicate *operator()(mbgl::style::GreaterThanFilter filter) {
return [NSPredicate predicateWithFormat:@"%K > %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::GreaterThanEqualsFilter filter) {
+ NSPredicate *operator()(mbgl::style::GreaterThanEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K >= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::LessThanFilter filter) {
+ NSPredicate *operator()(mbgl::style::LessThanFilter filter) {
return [NSPredicate predicateWithFormat:@"%K < %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::LessThanEqualsFilter filter) {
+ NSPredicate *operator()(mbgl::style::LessThanEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K <= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
- NSPredicate* operator()(mbgl::style::InFilter filter) {
+ NSPredicate *operator()(mbgl::style::InFilter filter) {
return [NSPredicate predicateWithFormat:@"%K IN %@", @(filter.key.c_str()), getValues(filter.values)];
}
- NSPredicate* operator()(mbgl::style::NotInFilter filter) {
+ NSPredicate *operator()(mbgl::style::NotInFilter filter) {
return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @(filter.key.c_str()), getValues(filter.values)];
}
- NSPredicate* operator()(mbgl::style::AnyFilter filter) {
- return [NSCompoundPredicate orPredicateWithSubpredicates:getPredicates(filter.filters)];
- }
-
- NSPredicate* operator()(mbgl::style::AllFilter filter) {
- return [NSCompoundPredicate andPredicateWithSubpredicates:getPredicates(filter.filters)];
+ NSPredicate *operator()(mbgl::style::AnyFilter filter) {
+ NSArray *subpredicates = getPredicates(filter.filters);
+ if (subpredicates.count) {
+ return [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
+ }
+ return [NSPredicate predicateWithValue:NO];
+ }
+
+ NSPredicate *operator()(mbgl::style::AllFilter filter) {
+ // Convert [all, [>=, key, lower], [<=, key, upper]] to key BETWEEN {lower, upper}
+ if (filter.filters.size() == 2) {
+ auto leftFilter = filter.filters[0];
+ auto rightFilter = filter.filters[1];
+
+ std::string lowerKey;
+ std::string upperKey;
+ mbgl::Value lowerBound;
+ mbgl::Value upperBound;
+ if (leftFilter.is<mbgl::style::GreaterThanEqualsFilter>()) {
+ lowerKey = leftFilter.get<mbgl::style::GreaterThanEqualsFilter>().key;
+ lowerBound = leftFilter.get<mbgl::style::GreaterThanEqualsFilter>().value;
+ } else if (rightFilter.is<mbgl::style::GreaterThanEqualsFilter>()) {
+ lowerKey = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().key;
+ lowerBound = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().value;
+ }
+
+ if (leftFilter.is<mbgl::style::LessThanEqualsFilter>()) {
+ upperKey = leftFilter.get<mbgl::style::LessThanEqualsFilter>().key;
+ upperBound = leftFilter.get<mbgl::style::LessThanEqualsFilter>().value;
+ } else if (rightFilter.is<mbgl::style::LessThanEqualsFilter>()) {
+ upperKey = rightFilter.get<mbgl::style::LessThanEqualsFilter>().key;
+ upperBound = rightFilter.get<mbgl::style::LessThanEqualsFilter>().value;
+ }
+
+ if (!lowerBound.is<mbgl::NullValue>() && !upperBound.is<mbgl::NullValue>()
+ && lowerKey == upperKey) {
+ return [NSPredicate predicateWithFormat:@"%K BETWEEN {%@, %@}",
+ @(lowerKey.c_str()),
+ mbgl::Value::visit(lowerBound, ValueEvaluator()),
+ mbgl::Value::visit(upperBound, ValueEvaluator())];
+ }
+ }
+
+ NSArray *subpredicates = getPredicates(filter.filters);
+ if (subpredicates.count) {
+ return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
+ }
+ return [NSPredicate predicateWithValue:YES];
}
- NSPredicate* operator()(mbgl::style::NoneFilter filter) {
- NSArray *predicates = getPredicates(filter.filters);
- if (predicates.count > 1) {
- NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
+ NSPredicate *operator()(mbgl::style::NoneFilter filter) {
+ NSArray *subpredicates = getPredicates(filter.filters);
+ if (subpredicates.count > 1) {
+ NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
return [NSCompoundPredicate notPredicateWithSubpredicate:predicate];
+ } else if (subpredicates.count) {
+ return [NSCompoundPredicate notPredicateWithSubpredicate:subpredicates.firstObject];
} else {
- return [NSCompoundPredicate notPredicateWithSubpredicate:predicates.firstObject];
+ return [NSPredicate predicateWithValue:YES];
}
}
- NSPredicate* operator()(mbgl::style::HasFilter filter) {
+ NSPredicate *operator()(mbgl::style::HasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K != nil", @(filter.key.c_str())];
}
- NSPredicate* operator()(mbgl::style::NotHasFilter filter) {
+ NSPredicate *operator()(mbgl::style::NotHasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == nil", @(filter.key.c_str())];
}
@@ -91,18 +136,22 @@ public:
{
if ([self isEqual:[NSPredicate predicateWithValue:YES]])
{
- auto filter = mbgl::style::AllFilter();
- return filter;
+ return mbgl::style::AllFilter();
}
if ([self isEqual:[NSPredicate predicateWithValue:NO]])
{
- auto filter = mbgl::style::AnyFilter();
- return filter;
+ return mbgl::style::AnyFilter();
+ }
+
+ if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("])
+ {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Block-based predicates are not supported."];
}
- [NSException raise:@"Not supported"
- format:@"Try with NSComparisonPredicate or NSCompoundPredicate instead."];
+ [NSException raise:NSInvalidArgumentException
+ format:@"Unrecognized predicate type."];
return {};
}
diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 45fea25588..246dc084f4 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -10,6 +10,15 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns the receiver if non-empty or nil if empty. */
- (nullable NSString *)mgl_stringOrNilIfEmpty;
+/**
+ Returns a title-cased representation of the receiver using the specified
+ locale.
+
+ @param The locale. For strings presented to users, pass in the current locale
+ (`+[NSLocale currentLocale]`). To use the system locale, pass in `nil`.
+ */
+- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale;
+
@end
@interface NSAttributedString (MGLAdditions)
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index 04a65dc5e2..5c32f4b789 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -10,6 +10,28 @@
return self.length ? self : nil;
}
+- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
+ NSMutableString *string = self.mutableCopy;
+ [string enumerateLinguisticTagsInRange:string.mgl_wholeRange scheme:NSLinguisticTagSchemeLexicalClass options:0 orthography:nil usingBlock:^(NSString * _Nonnull tag, NSRange tokenRange, NSRange sentenceRange, BOOL * _Nonnull stop) {
+ NSString *word = [string substringWithRange:tokenRange];
+ if (word.length > 3
+ || !([tag isEqualToString:NSLinguisticTagConjunction]
+ || [tag isEqualToString:NSLinguisticTagPreposition]
+ || [tag isEqualToString:NSLinguisticTagDeterminer]
+ || [tag isEqualToString:NSLinguisticTagParticle]
+ || [tag isEqualToString:NSLinguisticTagClassifier])) {
+ unichar firstLetter = [[word capitalizedStringWithLocale:locale] characterAtIndex:0];
+ NSString *suffix = [word substringFromIndex:1];
+ if (!([word hasPrefix:@"i"] && suffix.length
+ && [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[suffix characterAtIndex:0]])) {
+ word = [NSString stringWithFormat:@"%C%@", firstLetter, suffix];
+ }
+ }
+ [string replaceCharactersInRange:tokenRange withString:word];
+ }];
+ return string;
+}
+
@end
@implementation NSAttributedString (MGLAdditions)
diff --git a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
index 59afe559d7..e66145aec1 100644
--- a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
+++ b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
@@ -12,6 +12,11 @@
+ (instancetype)mgl_valueWithOffsetArray:(std::array<float, 2>)offsetArray
{
CGVector vector = CGVectorMake(offsetArray[0], offsetArray[1]);
+#if !TARGET_OS_IPHONE
+ // Style specification assumes an origin at the upper-left corner.
+ // macOS defines an origin at the lower-left corner.
+ vector.dy *= -1;
+#endif
return [NSValue value:&vector withObjCType:@encode(CGVector)];
}
@@ -33,6 +38,9 @@
NSAssert(strcmp(self.objCType, @encode(CGVector)) == 0, @"Value does not represent a CGVector");
CGVector vector;
[self getValue:&vector];
+#if !TARGET_OS_IPHONE
+ vector.dy *= -1;
+#endif
return {
static_cast<float>(vector.dx),
static_cast<float>(vector.dy),
diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h
deleted file mode 100644
index 3387ce8188..0000000000
--- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h
+++ /dev/null
@@ -1,232 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import <Foundation/Foundation.h>
-
-#import "MGLFillStyleLayer.h"
-#import "MGLLineStyleLayer.h"
-#import "MGLSymbolStyleLayer.h"
-#import "MGLCircleStyleLayer.h"
-#import "MGLRasterStyleLayer.h"
-#import "MGLBackgroundStyleLayer.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- Methods for round-tripping values for Mapbox style layer enumeration values.
-*/
-@interface NSValue (MGLStyleEnumAttributeAdditions)
-
-#pragma mark Working with Style Layer Enumeration Attribute Values
-
-/**
- Creates a new value object containing the given `MGLLineCap` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLLineCap:(MGLLineCap)lineCap;
-
-/**
- The `MGLLineCap` enumeration representation of the value.
-*/
-@property (readonly) MGLLineCap MGLLineCapValue;
-
-/**
- Creates a new value object containing the given `MGLLineJoin` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLLineJoin:(MGLLineJoin)lineJoin;
-
-/**
- The `MGLLineJoin` enumeration representation of the value.
-*/
-@property (readonly) MGLLineJoin MGLLineJoinValue;
-
-/**
- Creates a new value object containing the given `MGLIconRotationAlignment` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment;
-
-/**
- The `MGLIconRotationAlignment` enumeration representation of the value.
-*/
-@property (readonly) MGLIconRotationAlignment MGLIconRotationAlignmentValue;
-
-/**
- Creates a new value object containing the given `MGLIconTextFit` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit;
-
-/**
- The `MGLIconTextFit` enumeration representation of the value.
-*/
-@property (readonly) MGLIconTextFit MGLIconTextFitValue;
-
-/**
- Creates a new value object containing the given `MGLSymbolPlacement` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement;
-
-/**
- The `MGLSymbolPlacement` enumeration representation of the value.
-*/
-@property (readonly) MGLSymbolPlacement MGLSymbolPlacementValue;
-
-/**
- Creates a new value object containing the given `MGLTextAnchor` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor;
-
-/**
- The `MGLTextAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLTextAnchor MGLTextAnchorValue;
-
-/**
- Creates a new value object containing the given `MGLTextJustification` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextJustification:(MGLTextJustification)textJustification;
-
-/**
- The `MGLTextJustification` enumeration representation of the value.
-*/
-@property (readonly) MGLTextJustification MGLTextJustificationValue;
-
-/**
- Creates a new value object containing the given `MGLTextPitchAlignment` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment;
-
-/**
- The `MGLTextPitchAlignment` enumeration representation of the value.
-*/
-@property (readonly) MGLTextPitchAlignment MGLTextPitchAlignmentValue;
-
-/**
- Creates a new value object containing the given `MGLTextRotationAlignment` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment;
-
-/**
- The `MGLTextRotationAlignment` enumeration representation of the value.
-*/
-@property (readonly) MGLTextRotationAlignment MGLTextRotationAlignmentValue;
-
-/**
- Creates a new value object containing the given `MGLTextTransform` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextTransform:(MGLTextTransform)textTransform;
-
-/**
- The `MGLTextTransform` enumeration representation of the value.
-*/
-@property (readonly) MGLTextTransform MGLTextTransformValue;
-
-/**
- Creates a new value object containing the given `MGLFillTranslateAnchor` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLFillTranslateAnchor:(MGLFillTranslateAnchor)fillTranslateAnchor;
-
-/**
- The `MGLFillTranslateAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLFillTranslateAnchor MGLFillTranslateAnchorValue;
-
-/**
- Creates a new value object containing the given `MGLLineTranslateAnchor` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLLineTranslateAnchor:(MGLLineTranslateAnchor)lineTranslateAnchor;
-
-/**
- The `MGLLineTranslateAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLLineTranslateAnchor MGLLineTranslateAnchorValue;
-
-/**
- Creates a new value object containing the given `MGLIconTranslateAnchor` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLIconTranslateAnchor:(MGLIconTranslateAnchor)iconTranslateAnchor;
-
-/**
- The `MGLIconTranslateAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLIconTranslateAnchor MGLIconTranslateAnchorValue;
-
-/**
- Creates a new value object containing the given `MGLTextTranslateAnchor` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLTextTranslateAnchor:(MGLTextTranslateAnchor)textTranslateAnchor;
-
-/**
- The `MGLTextTranslateAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLTextTranslateAnchor MGLTextTranslateAnchorValue;
-
-/**
- Creates a new value object containing the given `MGLCirclePitchScale` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLCirclePitchScale:(MGLCirclePitchScale)circlePitchScale;
-
-/**
- The `MGLCirclePitchScale` enumeration representation of the value.
-*/
-@property (readonly) MGLCirclePitchScale MGLCirclePitchScaleValue;
-
-/**
- Creates a new value object containing the given `MGLCircleTranslateAnchor` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGLCircleTranslateAnchor:(MGLCircleTranslateAnchor)circleTranslateAnchor;
-
-/**
- The `MGLCircleTranslateAnchor` enumeration representation of the value.
-*/
-@property (readonly) MGLCircleTranslateAnchor MGLCircleTranslateAnchorValue;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs
deleted file mode 100644
index c078ac7d02..0000000000
--- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h.ejs
+++ /dev/null
@@ -1,66 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-<%
-const types = locals.types;
-const layoutProperties = locals.layoutProperties;
-const paintProperties = locals.paintProperties;
--%>
-#import <Foundation/Foundation.h>
-
-<% if (types) { -%>
-<% for (const type of types) { -%>
-#import "MGL<%- camelize(type) %>StyleLayer.h"
-<% } -%>
-<% } -%>
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- Methods for round-tripping values for Mapbox style layer enumeration values.
-*/
-@interface NSValue (MGLStyleEnumAttributeAdditions)
-
-#pragma mark Working with Style Layer Enumeration Attribute Values
-
-<% if (layoutProperties.length) { -%>
-<% for (const property of layoutProperties) { -%>
-<% if (property.type == "enum") { -%>
-/**
- Creates a new value object containing the given `MGL<%- camelize(property.name) %>` enumeration.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
-
-/**
- The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
-*/
-@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
-
-<% } -%>
-<% } -%>
-<% } -%>
-<% if (paintProperties.length) { -%>
-<% for (const property of paintProperties) { -%>
-<% if (property.type == "enum") { -%>
-/**
- Creates a new value object containing the given `MGL<%- camelize(property.name) %>` structure.
-
- @param type The value for the new object.
- @return A new value object that contains the style enumeration type.
-*/
-+ (instancetype)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %>;
-
-/**
- The `MGL<%- camelize(property.name) %>` enumeration representation of the value.
-*/
-@property (readonly) MGL<%- camelize(property.name) %> MGL<%- camelize(property.name) %>Value;
-
-<% } -%>
-<% } -%>
-<% } -%>
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm
deleted file mode 100644
index db91408c5a..0000000000
--- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm
+++ /dev/null
@@ -1,169 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "NSValue+MGLStyleEnumAttributeAdditions.h"
-
-@implementation NSValue (MGLStyleEnumAttributeAdditions)
-
-+ (NSValue *)valueWithMGLLineCap:(MGLLineCap)lineCap {
- return [NSValue value:&lineCap withObjCType:@encode(MGLLineCap)];
-}
-
-- (MGLLineCap)MGLLineCapValue {
- MGLLineCap value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLLineJoin:(MGLLineJoin)lineJoin {
- return [NSValue value:&lineJoin withObjCType:@encode(MGLLineJoin)];
-}
-
-- (MGLLineJoin)MGLLineJoinValue {
- MGLLineJoin value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
- return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
-}
-
-- (MGLIconRotationAlignment)MGLIconRotationAlignmentValue {
- MGLIconRotationAlignment value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLIconTextFit:(MGLIconTextFit)iconTextFit {
- return [NSValue value:&iconTextFit withObjCType:@encode(MGLIconTextFit)];
-}
-
-- (MGLIconTextFit)MGLIconTextFitValue {
- MGLIconTextFit value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLSymbolPlacement:(MGLSymbolPlacement)symbolPlacement {
- return [NSValue value:&symbolPlacement withObjCType:@encode(MGLSymbolPlacement)];
-}
-
-- (MGLSymbolPlacement)MGLSymbolPlacementValue {
- MGLSymbolPlacement value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextAnchor:(MGLTextAnchor)textAnchor {
- return [NSValue value:&textAnchor withObjCType:@encode(MGLTextAnchor)];
-}
-
-- (MGLTextAnchor)MGLTextAnchorValue {
- MGLTextAnchor value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification {
- return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)];
-}
-
-- (MGLTextJustification)MGLTextJustificationValue {
- MGLTextJustification value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextPitchAlignment:(MGLTextPitchAlignment)textPitchAlignment {
- return [NSValue value:&textPitchAlignment withObjCType:@encode(MGLTextPitchAlignment)];
-}
-
-- (MGLTextPitchAlignment)MGLTextPitchAlignmentValue {
- MGLTextPitchAlignment value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextRotationAlignment:(MGLTextRotationAlignment)textRotationAlignment {
- return [NSValue value:&textRotationAlignment withObjCType:@encode(MGLTextRotationAlignment)];
-}
-
-- (MGLTextRotationAlignment)MGLTextRotationAlignmentValue {
- MGLTextRotationAlignment value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextTransform:(MGLTextTransform)textTransform {
- return [NSValue value:&textTransform withObjCType:@encode(MGLTextTransform)];
-}
-
-- (MGLTextTransform)MGLTextTransformValue {
- MGLTextTransform value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLFillTranslateAnchor:(MGLFillTranslateAnchor)fillTranslateAnchor {
-return [NSValue value:&fillTranslateAnchor withObjCType:@encode(MGLFillTranslateAnchor)];
-}
-
-- (MGLFillTranslateAnchor)MGLFillTranslateAnchorValue {
- MGLFillTranslateAnchor value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLLineTranslateAnchor:(MGLLineTranslateAnchor)lineTranslateAnchor {
-return [NSValue value:&lineTranslateAnchor withObjCType:@encode(MGLLineTranslateAnchor)];
-}
-
-- (MGLLineTranslateAnchor)MGLLineTranslateAnchorValue {
- MGLLineTranslateAnchor value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLIconTranslateAnchor:(MGLIconTranslateAnchor)iconTranslateAnchor {
-return [NSValue value:&iconTranslateAnchor withObjCType:@encode(MGLIconTranslateAnchor)];
-}
-
-- (MGLIconTranslateAnchor)MGLIconTranslateAnchorValue {
- MGLIconTranslateAnchor value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLTextTranslateAnchor:(MGLTextTranslateAnchor)textTranslateAnchor {
-return [NSValue value:&textTranslateAnchor withObjCType:@encode(MGLTextTranslateAnchor)];
-}
-
-- (MGLTextTranslateAnchor)MGLTextTranslateAnchorValue {
- MGLTextTranslateAnchor value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLCirclePitchScale:(MGLCirclePitchScale)circlePitchScale {
-return [NSValue value:&circlePitchScale withObjCType:@encode(MGLCirclePitchScale)];
-}
-
-- (MGLCirclePitchScale)MGLCirclePitchScaleValue {
- MGLCirclePitchScale value;
- [self getValue:&value];
- return value;
-}
-
-+ (NSValue *)valueWithMGLCircleTranslateAnchor:(MGLCircleTranslateAnchor)circleTranslateAnchor {
-return [NSValue value:&circleTranslateAnchor withObjCType:@encode(MGLCircleTranslateAnchor)];
-}
-
-- (MGLCircleTranslateAnchor)MGLCircleTranslateAnchorValue {
- MGLCircleTranslateAnchor value;
- [self getValue:&value];
- return value;
-}
-
-
-@end
diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs
deleted file mode 100644
index fab278aac8..0000000000
--- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm.ejs
+++ /dev/null
@@ -1,46 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-<%
-const type = locals.type;
-const layoutProperties = locals.layoutProperties;
-const paintProperties = locals.paintProperties;
--%>
-
-#import "NSValue+MGLStyleEnumAttributeAdditions.h"
-
-@implementation NSValue (MGLStyleEnumAttributeAdditions)
-
-<% if (layoutProperties.length) { -%>
-<% for (const property of layoutProperties) { -%>
-<% if (property.type == "enum") { -%>
-+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
- return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
-}
-
-- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
- MGL<%- camelize(property.name) %> value;
- [self getValue:&value];
- return value;
-}
-
-<% } -%>
-<% } -%>
-<% } -%>
-<% if (paintProperties.length) { -%>
-<% for (const property of paintProperties) { -%>
-<% if (property.type == "enum") { -%>
-+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
-return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
-}
-
-- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
- MGL<%- camelize(property.name) %> value;
- [self getValue:&value];
- return value;
-}
-
-<% } -%>
-<% } -%>
-<% } -%>
-
-@end
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.m b/platform/darwin/test/MGLBackgroundStyleLayerTests.m
deleted file mode 100644
index 934021d6b8..0000000000
--- a/platform/darwin/test/MGLBackgroundStyleLayerTests.m
+++ /dev/null
@@ -1,44 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLBackgroundLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLBackgroundLayerTests
-
-+ (NSString *)layerType {
- return @"background";
-}
-
-- (void)testBackgroundLayer {
- MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"];
- [self.mapView.style addLayer:layer];
-
- layer.backgroundColor = [MGLRuntimeStylingHelper testColor];
- layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.backgroundPattern = [MGLRuntimeStylingHelper testString];
-
- MGLBackgroundStyleLayer *gLayer = (MGLBackgroundStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLBackgroundStyleLayer class]]);
- XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testString]);
-
- layer.backgroundColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.backgroundPattern = [MGLRuntimeStylingHelper testStringFunction];
-
- XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testStringFunction]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"background-color" isBoolean:NO];
- [self testPropertyName:@"background-opacity" isBoolean:NO];
- [self testPropertyName:@"background-pattern" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
new file mode 100644
index 0000000000..60a332a5e7
--- /dev/null
+++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
@@ -0,0 +1,134 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/background_layer.hpp>
+
+@interface MGLBackgroundLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLBackgroundLayerTests
+
++ (NSString *)layerType {
+ return @"background";
+}
+
+- (void)testProperties {
+ MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::BackgroundLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::BackgroundLayer>();
+
+ // background-color
+ {
+ XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
+ @"background-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.backgroundColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.backgroundColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
+ @"Setting backgroundColor to a constant value should update background-color.");
+ XCTAssertEqualObjects(layer.backgroundColor, styleValue,
+ @"backgroundColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.backgroundColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
+ @"Setting backgroundColor to a function should update background-color.");
+ XCTAssertEqualObjects(layer.backgroundColor, styleValue,
+ @"backgroundColor should round-trip functions.");
+
+ layer.backgroundColor = nil;
+ XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
+ @"Unsetting backgroundColor should return background-color to the default value.");
+ XCTAssertEqualObjects(layer.backgroundColor, defaultStyleValue,
+ @"backgroundColor should return the default value after being unset.");
+ }
+
+ // background-opacity
+ {
+ XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
+ @"background-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.backgroundOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.backgroundOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
+ @"Setting backgroundOpacity to a constant value should update background-opacity.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
+ @"backgroundOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.backgroundOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
+ @"Setting backgroundOpacity to a function should update background-opacity.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
+ @"backgroundOpacity should round-trip functions.");
+
+ layer.backgroundOpacity = nil;
+ XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
+ @"Unsetting backgroundOpacity should return background-opacity to the default value.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, defaultStyleValue,
+ @"backgroundOpacity should return the default value after being unset.");
+ }
+
+ // background-pattern
+ {
+ XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
+ @"background-pattern should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.backgroundPattern;
+
+ MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"];
+ layer.backgroundPattern = styleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Background Pattern" };
+ XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
+ @"Setting backgroundPattern to a constant value should update background-pattern.");
+ XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
+ @"backgroundPattern should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.backgroundPattern = styleValue;
+ propertyValue = { mbgl::style::Function<std::string> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
+ @"Setting backgroundPattern to a function should update background-pattern.");
+ XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
+ @"backgroundPattern should round-trip functions.");
+
+ layer.backgroundPattern = nil;
+ XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
+ @"Unsetting backgroundPattern should return background-pattern to the default value.");
+ XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue,
+ @"backgroundPattern should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"background-color" isBoolean:NO];
+ [self testPropertyName:@"background-opacity" isBoolean:NO];
+ [self testPropertyName:@"background-pattern" isBoolean:NO];
+}
+
+@end
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.m b/platform/darwin/test/MGLCircleStyleLayerTests.m
deleted file mode 100644
index ce17d93557..0000000000
--- a/platform/darwin/test/MGLCircleStyleLayerTests.m
+++ /dev/null
@@ -1,85 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLCircleLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLCircleLayerTests
-
-+ (NSString *)layerType {
- return @"circle";
-}
-
-- (void)testCircleLayer {
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
- [self.mapView.style addLayer:layer];
-
- layer.circleBlur = [MGLRuntimeStylingHelper testNumber];
- layer.circleColor = [MGLRuntimeStylingHelper testColor];
- layer.circleOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.circlePitchScale = [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)];
- layer.circleRadius = [MGLRuntimeStylingHelper testNumber];
- layer.circleStrokeColor = [MGLRuntimeStylingHelper testColor];
- layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumber];
- layer.circleTranslate = [MGLRuntimeStylingHelper testOffset];
- layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)];
-
- MGLCircleStyleLayer *gLayer = (MGLCircleStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLCircleStyleLayer class]]);
- XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.circlePitchScale isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]);
- XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffset]);
- XCTAssert([gLayer.circleTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]);
-
- layer.circleBlur = [MGLRuntimeStylingHelper testNumberFunction];
- layer.circleColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.circleOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.circlePitchScale = [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)];
- layer.circleRadius = [MGLRuntimeStylingHelper testNumberFunction];
- layer.circleStrokeColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumberFunction];
- layer.circleTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)];
-
- XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]);
- XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"circle-blur" isBoolean:NO];
- [self testPropertyName:@"circle-color" isBoolean:NO];
- [self testPropertyName:@"circle-opacity" isBoolean:NO];
- [self testPropertyName:@"circle-pitch-scale" isBoolean:NO];
- [self testPropertyName:@"circle-radius" isBoolean:NO];
- [self testPropertyName:@"circle-stroke-color" isBoolean:NO];
- [self testPropertyName:@"circle-stroke-opacity" isBoolean:NO];
- [self testPropertyName:@"circle-stroke-width" isBoolean:NO];
- [self testPropertyName:@"circle-translate" isBoolean:NO];
- [self testPropertyName:@"circle-translate-anchor" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
new file mode 100644
index 0000000000..35e29b31d5
--- /dev/null
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -0,0 +1,413 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/circle_layer.hpp>
+
+@interface MGLCircleLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLCircleLayerTests
+
++ (NSString *)layerType {
+ return @"circle";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::CircleLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::CircleLayer>();
+
+ // circle-blur
+ {
+ XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
+ @"circle-blur should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleBlur;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleBlur = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
+ @"Setting circleBlur to a constant value should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, styleValue,
+ @"circleBlur should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleBlur = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
+ @"Setting circleBlur to a function should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, styleValue,
+ @"circleBlur should round-trip functions.");
+
+ layer.circleBlur = nil;
+ XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
+ @"Unsetting circleBlur should return circle-blur to the default value.");
+ XCTAssertEqualObjects(layer.circleBlur, defaultStyleValue,
+ @"circleBlur should return the default value after being unset.");
+ }
+
+ // circle-color
+ {
+ XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
+ @"circle-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.circleColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
+ @"Setting circleColor to a constant value should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, styleValue,
+ @"circleColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
+ @"Setting circleColor to a function should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, styleValue,
+ @"circleColor should round-trip functions.");
+
+ layer.circleColor = nil;
+ XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
+ @"Unsetting circleColor should return circle-color to the default value.");
+ XCTAssertEqualObjects(layer.circleColor, defaultStyleValue,
+ @"circleColor should return the default value after being unset.");
+ }
+
+ // circle-opacity
+ {
+ XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
+ @"circle-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
+ @"Setting circleOpacity to a constant value should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, styleValue,
+ @"circleOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
+ @"Setting circleOpacity to a function should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, styleValue,
+ @"circleOpacity should round-trip functions.");
+
+ layer.circleOpacity = nil;
+ XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
+ @"Unsetting circleOpacity should return circle-opacity to the default value.");
+ XCTAssertEqualObjects(layer.circleOpacity, defaultStyleValue,
+ @"circleOpacity should return the default value after being unset.");
+ }
+
+ // circle-radius
+ {
+ XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
+ @"circle-radius should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleRadius;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleRadius = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
+ @"Setting circleRadius to a constant value should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, styleValue,
+ @"circleRadius should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleRadius = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
+ @"Setting circleRadius to a function should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, styleValue,
+ @"circleRadius should round-trip functions.");
+
+ layer.circleRadius = nil;
+ XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
+ @"Unsetting circleRadius should return circle-radius to the default value.");
+ XCTAssertEqualObjects(layer.circleRadius, defaultStyleValue,
+ @"circleRadius should return the default value after being unset.");
+ }
+
+ // circle-pitch-scale
+ {
+ XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
+ @"circle-pitch-scale should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleScaleAlignment;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]];
+ layer.circleScaleAlignment = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType> propertyValue = { mbgl::style::CirclePitchScaleType::Viewport };
+ XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
+ @"Setting circleScaleAlignment to a constant value should update circle-pitch-scale.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
+ @"circleScaleAlignment should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleScaleAlignment = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::CirclePitchScaleType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
+ @"Setting circleScaleAlignment to a function should update circle-pitch-scale.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
+ @"circleScaleAlignment should round-trip functions.");
+
+ layer.circleScaleAlignment = nil;
+ XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
+ @"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue,
+ @"circleScaleAlignment should return the default value after being unset.");
+ }
+
+ // circle-stroke-color
+ {
+ XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
+ @"circle-stroke-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleStrokeColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.circleStrokeColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
+ @"Setting circleStrokeColor to a constant value should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
+ @"circleStrokeColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleStrokeColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
+ @"Setting circleStrokeColor to a function should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
+ @"circleStrokeColor should round-trip functions.");
+
+ layer.circleStrokeColor = nil;
+ XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
+ @"Unsetting circleStrokeColor should return circle-stroke-color to the default value.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, defaultStyleValue,
+ @"circleStrokeColor should return the default value after being unset.");
+ }
+
+ // circle-stroke-opacity
+ {
+ XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
+ @"circle-stroke-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleStrokeOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
+ @"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
+ @"circleStrokeOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleStrokeOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
+ @"Setting circleStrokeOpacity to a function should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
+ @"circleStrokeOpacity should round-trip functions.");
+
+ layer.circleStrokeOpacity = nil;
+ XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
+ @"Unsetting circleStrokeOpacity should return circle-stroke-opacity to the default value.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultStyleValue,
+ @"circleStrokeOpacity should return the default value after being unset.");
+ }
+
+ // circle-stroke-width
+ {
+ XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
+ @"circle-stroke-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleStrokeWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
+ @"Setting circleStrokeWidth to a constant value should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
+ @"circleStrokeWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleStrokeWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
+ @"Setting circleStrokeWidth to a function should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
+ @"circleStrokeWidth should round-trip functions.");
+
+ layer.circleStrokeWidth = nil;
+ XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
+ @"Unsetting circleStrokeWidth should return circle-stroke-width to the default value.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, defaultStyleValue,
+ @"circleStrokeWidth should return the default value after being unset.");
+ }
+
+ // circle-translate
+ {
+ XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
+ @"circle-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslation;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.circleTranslation = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
+ @"Setting circleTranslation to a constant value should update circle-translate.");
+ XCTAssertEqualObjects(layer.circleTranslation, styleValue,
+ @"circleTranslation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleTranslation = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
+ @"Setting circleTranslation to a function should update circle-translate.");
+ XCTAssertEqualObjects(layer.circleTranslation, styleValue,
+ @"circleTranslation should round-trip functions.");
+
+ layer.circleTranslation = nil;
+ XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
+ @"Unsetting circleTranslation should return circle-translate to the default value.");
+ XCTAssertEqualObjects(layer.circleTranslation, defaultStyleValue,
+ @"circleTranslation should return the default value after being unset.");
+ }
+
+ // circle-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
+ @"circle-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]];
+ layer.circleTranslationAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
+ @"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
+ @"circleTranslationAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.circleTranslationAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
+ @"Setting circleTranslationAnchor to a function should update circle-translate-anchor.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
+ @"circleTranslationAnchor should round-trip functions.");
+
+ layer.circleTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
+ @"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue,
+ @"circleTranslationAnchor should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"circle-blur" isBoolean:NO];
+ [self testPropertyName:@"circle-color" isBoolean:NO];
+ [self testPropertyName:@"circle-opacity" isBoolean:NO];
+ [self testPropertyName:@"circle-radius" isBoolean:NO];
+ [self testPropertyName:@"circle-scale-alignment" isBoolean:NO];
+ [self testPropertyName:@"circle-stroke-color" isBoolean:NO];
+ [self testPropertyName:@"circle-stroke-opacity" isBoolean:NO];
+ [self testPropertyName:@"circle-stroke-width" isBoolean:NO];
+ [self testPropertyName:@"circle-translation" isBoolean:NO];
+ [self testPropertyName:@"circle-translation-anchor" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentMap].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentViewport);
+ XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorMap].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/MGLCodingTests.m b/platform/darwin/test/MGLCodingTests.m
new file mode 100644
index 0000000000..b9b299d50f
--- /dev/null
+++ b/platform/darwin/test/MGLCodingTests.m
@@ -0,0 +1,469 @@
+#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
+
+#if TARGET_OS_IPHONE
+#import "MGLUserLocation_Private.h"
+#endif
+
+@interface MGLCodingTests : XCTestCase
+@end
+
+@implementation MGLCodingTests
+
+- (NSString *)temporaryFilePathForClass:(Class)clazz {
+ return [NSTemporaryDirectory() stringByAppendingPathComponent:NSStringFromClass(clazz)];
+}
+
+- (void)testPointAnnotation {
+ MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
+ annotation.coordinate = CLLocationCoordinate2DMake(0.5, 0.5);
+ annotation.title = @"title";
+ annotation.subtitle = @"subtitle";
+
+ NSString *filePath = [self temporaryFilePathForClass:MGLPointAnnotation.class];
+ [NSKeyedArchiver archiveRootObject:annotation toFile:filePath];
+ MGLPointAnnotation *unarchivedAnnotation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(annotation, unarchivedAnnotation);
+}
+
+- (void)testPointFeature {
+ MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
+ pointFeature.title = @"title";
+ pointFeature.subtitle = @"subtitle";
+ pointFeature.identifier = @(123);
+ pointFeature.attributes = @{@"bbox": @[@1, @2, @3, @4]};
+
+ NSString *filePath = [self temporaryFilePathForClass:MGLPointFeature.class];
+ [NSKeyedArchiver archiveRootObject:pointFeature toFile:filePath];
+ MGLPointFeature *unarchivedPointFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(pointFeature, unarchivedPointFeature);
+}
+
+- (void)testPolyline {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0.129631234123, 1.7812739312551),
+ CLLocationCoordinate2DMake(2.532083092342, 3.5216418292392)
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ polyline.title = @"title";
+ polyline.subtitle = @"subtitle";
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPolyline class]];
+ [NSKeyedArchiver archiveRootObject:polyline toFile:filePath];
+ MGLPolyline *unarchivedPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(polyline, unarchivedPolyline);
+
+ CLLocationCoordinate2D otherCoordinates[] = {
+ CLLocationCoordinate2DMake(-1, -2)
+ };
+
+ [unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates];
+
+ XCTAssertNotEqualObjects(polyline, unarchivedPolyline);
+}
+
+- (void)testPolygon {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0.664482398, 1.8865675),
+ CLLocationCoordinate2DMake(2.13224687, 3.9984632)
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
+ polygon.title = nil;
+ polygon.subtitle = @"subtitle";
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
+ [NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
+
+ MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(polygon, unarchivedPolygon);
+}
+
+- (void)testPolygonWithInteriorPolygons {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 20)
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ CLLocationCoordinate2D interiorCoordinates[] = {
+ CLLocationCoordinate2DMake(4, 4),
+ CLLocationCoordinate2DMake(6, 6)
+ };
+
+ NSUInteger numberOfInteriorCoordinates = sizeof(interiorCoordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolygon *interiorPolygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:numberOfInteriorCoordinates];
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates interiorPolygons:@[interiorPolygon]];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
+ [NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
+
+ MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(polygon, unarchivedPolygon);
+}
+
+- (void)testPolylineFeature {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 20)
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ polylineFeature.attributes = @{@"bbox": @[@0, @1, @2, @3]};
+ polylineFeature.identifier = @"identifier";
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPolylineFeature class]];
+ [NSKeyedArchiver archiveRootObject:polylineFeature toFile:filePath];
+
+ MGLPolylineFeature *unarchivedPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(polylineFeature, unarchivedPolylineFeature);
+
+ unarchivedPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
+
+ XCTAssertNotEqualObjects(polylineFeature, unarchivedPolylineFeature);
+}
+
+- (void)testPolygonFeature {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 20)
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPolygonFeature class]];
+ [NSKeyedArchiver archiveRootObject:polygonFeature toFile:filePath];
+
+ MGLPolygonFeature *unarchivedPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(polygonFeature, unarchivedPolygonFeature);
+
+ unarchivedPolygonFeature.identifier = @"test";
+
+ XCTAssertNotEqualObjects(polygonFeature, unarchivedPolygonFeature);
+}
+
+- (void)testPointCollection {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 11),
+ CLLocationCoordinate2DMake(20, 21),
+ CLLocationCoordinate2DMake(30, 31),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]];
+ [NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath];
+
+ MGLPointCollection *unarchivedPointCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(pointCollection, unarchivedPointCollection);
+}
+
+- (void)testPointCollectionFeature {
+ NSMutableArray *features = [NSMutableArray array];
+ for (NSUInteger i = 0; i < 100; i++) {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ feature.coordinate = CLLocationCoordinate2DMake(arc4random() % 90, arc4random() % 180);
+ [features addObject:feature];
+ }
+
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 11),
+ CLLocationCoordinate2DMake(20, 21),
+ CLLocationCoordinate2DMake(30, 31),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPointCollectionFeature *collection = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
+ collection.identifier = @"identifier";
+ collection.attributes = @{@"bbox": @[@1, @2, @3, @4]};
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollectionFeature class]];
+ [NSKeyedArchiver archiveRootObject:collection toFile:filePath];
+
+ MGLPointCollectionFeature *unarchivedCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(collection, unarchivedCollection);
+
+ unarchivedCollection.identifier = @"newIdentifier";
+
+ XCTAssertNotEqualObjects(collection, unarchivedCollection);
+}
+
+- (void)testMultiPolyline {
+
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 11),
+ CLLocationCoordinate2DMake(20, 21),
+ CLLocationCoordinate2DMake(30, 31),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ NSMutableArray *polylines = [NSMutableArray array];
+
+ for (NSUInteger i = 0; i < 100; i++) {
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ [polylines addObject:polyline];
+ }
+
+ MGLMultiPolyline *multiPolyline = [MGLMultiPolyline multiPolylineWithPolylines:polylines];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolyline class]];
+ [NSKeyedArchiver archiveRootObject:multiPolyline toFile:filePath];
+
+ MGLMultiPolyline *unarchivedMultiPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ MGLMultiPolyline *anotherMultipolyline = [MGLMultiPolyline multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
+
+ XCTAssertEqualObjects(multiPolyline, unarchivedMultiPolyline);
+ XCTAssertNotEqualObjects(unarchivedMultiPolyline, anotherMultipolyline);
+}
+
+- (void)testMultiPolygon {
+
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(0, 1),
+ CLLocationCoordinate2DMake(10, 11),
+ CLLocationCoordinate2DMake(20, 21),
+ CLLocationCoordinate2DMake(30, 31),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ NSMutableArray *polygons = [NSMutableArray array];
+
+ for (NSUInteger i = 0; i < 100; i++) {
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
+ [polygons addObject:polygon];
+ }
+
+ MGLMultiPolygon *multiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:polygons];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolygon class]];
+ [NSKeyedArchiver archiveRootObject:multiPolygon toFile:filePath];
+
+ MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
+
+ XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon);
+ XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon);
+}
+
+- (void)testShapeCollection {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(10.12315786, 11.23451186),
+ CLLocationCoordinate2DMake(20.91836515, 21.93689215),
+ CLLocationCoordinate2DMake(30.55697246, 31.33988123),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
+
+ MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polyline, polygon]];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollection class]];
+ [NSKeyedArchiver archiveRootObject:shapeCollection toFile:filePath];
+
+ MGLShapeCollection *unarchivedShapeCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ MGLShapeCollection *anotherShapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polygon]];
+
+ XCTAssertEqualObjects(shapeCollection, unarchivedShapeCollection);
+ XCTAssertNotEqualObjects(shapeCollection, anotherShapeCollection);
+}
+
+- (void)testMultiPolylineFeature {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(10.12315786, 11.23451186),
+ CLLocationCoordinate2DMake(20.91836515, 21.93689215),
+ CLLocationCoordinate2DMake(30.55697246, 31.33988123),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ NSMutableArray *polylines = [NSMutableArray array];
+ for (NSUInteger i = 0; i < 100; i++) {
+ MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ polylineFeature.identifier = @(arc4random() % 100).stringValue;
+ [polylines addObject:polylineFeature];
+ }
+
+ MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
+ multiPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
+ [NSKeyedArchiver archiveRootObject:multiPolylineFeature toFile:filePath];
+
+ MGLMultiPolylineFeature *unarchivedMultiPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ MGLMultiPolylineFeature *anotherMultiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
+
+ XCTAssertEqualObjects(multiPolylineFeature, unarchivedMultiPolylineFeature);
+ XCTAssertNotEqualObjects(unarchivedMultiPolylineFeature, anotherMultiPolylineFeature);
+}
+
+- (void)testMultiPolygonFeature {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(10.12315786, 11.23451185),
+ CLLocationCoordinate2DMake(20.88471238, 21.93684215),
+ CLLocationCoordinate2DMake(30.15697236, 31.32988123),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ NSMutableArray *polygons = [NSMutableArray array];
+ for (NSUInteger i = 0; i < 100; i++ ) {
+ MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
+ polygonFeature.identifier = @(arc4random_uniform(100)).stringValue;
+ [polygons addObject:polygonFeature];
+ }
+
+ MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
+ multiPolygonFeature.attributes = @{@"bbox": @[@(arc4random_uniform(100)),
+ @(arc4random_uniform(100)),
+ @(arc4random_uniform(100)),
+ @(arc4random_uniform(100))]};
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
+ [NSKeyedArchiver archiveRootObject:multiPolygonFeature toFile:filePath];
+
+ MGLMultiPolygonFeature *unarchivedMultiPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ MGLMultiPolygonFeature *anotherMultiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
+
+ XCTAssertEqualObjects(multiPolygonFeature, unarchivedMultiPolygonFeature);
+ XCTAssertNotEqualObjects(anotherMultiPolygonFeature, unarchivedMultiPolygonFeature);
+}
+
+- (void)testShapeCollectionFeature {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(10.12315786, 11.23451186),
+ CLLocationCoordinate2DMake(20.91836515, 21.93689215),
+ CLLocationCoordinate2DMake(30.55697246, 31.33988123),
+ };
+
+ NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolylineFeature *polyline = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
+ MGLPolygonFeature *polygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
+
+ MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polyline, polygon]];
+ shapeCollectionFeature.identifier = @(arc4random_uniform(100)).stringValue;
+ shapeCollectionFeature.attributes = @{@"bbox":@[@(arc4random_uniform(100)),
+ @(arc4random_uniform(100)),
+ @(arc4random_uniform(100)),
+ @(arc4random_uniform(100))]};
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollectionFeature class]];
+ [NSKeyedArchiver archiveRootObject:shapeCollectionFeature toFile:filePath];
+
+ MGLShapeCollectionFeature *unarchivedShapeCollectionFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(shapeCollectionFeature, unarchivedShapeCollectionFeature);
+}
+
+- (void)testAnnotationImage {
+#if TARGET_OS_IPHONE
+ UIGraphicsBeginImageContext(CGSizeMake(10, 10));
+ [[UIColor redColor] setFill];
+ UIRectFill(CGRectMake(0, 0, 10, 10));
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+#else
+ NSImage *image = [[NSImage alloc] initWithSize:CGSizeMake(10, 10)];
+ [image lockFocus];
+ [[NSColor redColor] drawSwatchInRect:CGRectMake(0, 0, 10, 10)];
+ [image unlockFocus];
+#endif
+
+ MGLAnnotationImage *annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:@(arc4random_uniform(100)).stringValue];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationImage class]];
+ [NSKeyedArchiver archiveRootObject:annotationImage toFile:filePath];
+
+ MGLAnnotationImage *unarchivedAnnotationImage = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(annotationImage, unarchivedAnnotationImage);
+}
+
+#if TARGET_OS_IPHONE
+- (void)testAnnotationView {
+ MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithReuseIdentifier:@"id"];
+ annotationView.enabled = NO;
+ annotationView.selected = YES;
+ annotationView.draggable = YES;
+ annotationView.centerOffset = CGVectorMake(10, 10);
+ annotationView.scalesWithViewingDistance = NO;
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationView class]];
+ [NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
+
+ MGLAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
+ XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
+ XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
+ XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset));
+ XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance);
+}
+#endif
+
+#if TARGET_OS_IPHONE
+- (void)testUserLocation {
+ MGLUserLocation *userLocation = [[MGLUserLocation alloc] init];
+ userLocation.location = [[CLLocation alloc] initWithLatitude:1 longitude:1];
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocation class]];
+ [NSKeyedArchiver archiveRootObject:userLocation toFile:filePath];
+
+ MGLUserLocation *unarchivedUserLocation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqualObjects(userLocation, unarchivedUserLocation);
+ unarchivedUserLocation.location = [[CLLocation alloc] initWithLatitude:10 longitude:10];
+ XCTAssertNotEqualObjects(userLocation, unarchivedUserLocation);
+}
+#endif
+
+#if TARGET_OS_IPHONE
+- (void)testUserLocationAnnotationView {
+ MGLUserLocationAnnotationView *annotationView = [[MGLUserLocationAnnotationView alloc] init];
+ annotationView.enabled = NO;
+ annotationView.selected = YES;
+ annotationView.draggable = YES;
+ annotationView.centerOffset = CGVectorMake(10, 10);
+ annotationView.scalesWithViewingDistance = NO;
+
+ NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocationAnnotationView class]];
+ [NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
+
+ MGLUserLocationAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+
+ XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
+ XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
+ XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
+ XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset));
+ XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance);
+}
+#endif
+
+@end
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
new file mode 100644
index 0000000000..d796b4e708
--- /dev/null
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -0,0 +1,220 @@
+import XCTest
+import Mapbox
+#if os(iOS)
+ import UIKit
+#else
+ import Cocoa
+#endif
+
+/**
+ Test cases that ensure the inline examples in the project documentation
+ compile.
+
+ To add an example:
+ 1. Add a test case named in the form testMGLClass or testMGLClass$method.
+ 2. Wrap the code you'd like to appear in the documentation within the
+ following comment blocks:
+ ```
+ //#-example-code
+ ...
+ //#-end-example-code
+ ```
+ 3. Insert an empty Swift code block inside the header file where you'd like the
+ example code to be inserted.
+ 4. Run `make darwin-update-examples` to extract example code from the test
+ method below and insert it into the header.
+ */
+class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
+ var mapView: MGLMapView!
+ var styleLoadingExpectation: XCTestExpectation!
+
+ override func setUp() {
+ super.setUp()
+ let styleURL = Bundle(for: MGLDocumentationExampleTests.self).url(forResource: "one-liner", withExtension: "json")
+ mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: 256, height: 256), styleURL: styleURL)
+ mapView.delegate = self
+ styleLoadingExpectation = expectation(description: "Map view should finish loading style")
+ waitForExpectations(timeout: 1, handler: nil)
+ }
+
+ override func tearDown() {
+ mapView = nil
+ styleLoadingExpectation = nil
+ super.tearDown()
+ }
+
+ func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
+ styleLoadingExpectation.fulfill()
+ }
+
+ func testMGLShape$shapeWithData_encoding_error_() {
+ let mainBundle = Bundle(for: MGLDocumentationExampleTests.self)
+
+ //#-example-code
+ let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")!
+ let data = try! Data(contentsOf: url)
+ let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
+ //#-end-example-code
+
+ XCTAssertNotNil(feature.shapes.first as? MGLPolygonFeature)
+ }
+
+ func testMGLShapeSource() {
+ //#-example-code
+ var coordinates: [CLLocationCoordinate2D] = [
+ CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42),
+ CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
+ ]
+ let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
+ let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "lines"))
+ }
+
+ func testMGLRasterSource() {
+ //#-example-code
+ let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .tileSize: 512,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "clouds"))
+ }
+
+ func testMGLVectorSource() {
+ //#-example-code
+ let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
+ }
+
+ func testMGLCircleStyleLayer() {
+ let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(population)
+
+ //#-example-code
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
+ layer.sourceLayerIdentifier = "population"
+ layer.circleColor = MGLStyleValue(rawValue: .green)
+ layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
+ 12: MGLStyleValue(rawValue: 2),
+ 22: MGLStyleValue(rawValue: 180)
+ ])
+ layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
+ layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "circles"))
+ }
+
+ func testMGLLineStyleLayer() {
+ let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(trails)
+
+ //#-example-code
+ let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
+ layer.sourceLayerIdentifier = "trails"
+ layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 20),
+ ])
+ layer.lineColor = MGLStyleValue(rawValue: .brown)
+ layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
+ layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "trails-path"))
+ }
+
+ func testMGLFillStyleLayer() {
+ let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(parks)
+
+ //#-example-code
+ let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
+ layer.sourceLayerIdentifier = "parks"
+ layer.fillColor = MGLStyleValue(rawValue: .green)
+ layer.predicate = NSPredicate(format: "type == %@", "national-park")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks"))
+ }
+
+ func testMGLSymbolStyleLayer() {
+ let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(pois)
+
+ //#-example-code
+ let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
+ layer.sourceLayerIdentifier = "pois"
+ layer.iconImageName = MGLStyleValue(rawValue: "coffee")
+ layer.iconScale = MGLStyleValue(rawValue: 0.5)
+ layer.text = MGLStyleValue(rawValue: "{name}")
+ #if os(macOS)
+ var vector = CGVector(dx: 10, dy: 0)
+ layer.textTranslation = MGLStyleValue(rawValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}"))
+ #else
+ layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
+ #endif
+ layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
+ layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
+ layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "coffeeshops"))
+ }
+
+ func testMGLRasterStyleLayer() {
+ let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .tileSize: 512,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+
+ //#-example-code
+ let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
+ layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "clouds"))
+ }
+
+ func testMGLVectorStyleLayer$predicate() {
+ let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(terrain)
+
+ //#-example-code
+ let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
+ layer.sourceLayerIdentifier = "contours"
+ layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "contour"))
+ }
+}
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 971f7d0e54..00b57c15f0 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -28,27 +28,35 @@
- (void)testExpressionConversionString
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"bar"];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
- XCTAssert(convertedValue.is<std::string>() == true);
+ mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
+ XCTAssertTrue(convertedValue.is<std::string>());
XCTAssertEqualObjects(@(convertedValue.get<std::string>().c_str()), @"bar");
}
+- (void)testExpressionConversionStringWithUnicode
+{
+ NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"🆔🆗🇦🇶"];
+ mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
+ XCTAssertTrue(convertedValue.is<std::string>());
+ XCTAssertEqual(convertedValue.get<std::string>(), "🆔🆗🇦🇶");
+}
+
#pragma mark - Boolean Tests
- (void)testExpressionConversionBooleanTrue
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@YES];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
- XCTAssert(convertedValue.is<bool>() == true);
- XCTAssert(convertedValue.get<bool>() == true);
+ mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
+ XCTAssertTrue(convertedValue.is<bool>());
+ XCTAssertEqual(convertedValue.get<bool>(), true);
}
- (void)testExpressionConversionBooleanFalse
{
NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@NO];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue;
- XCTAssert(convertedValue.is<bool>() == true);
- XCTAssert(convertedValue.get<bool>() == false);
+ mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
+ XCTAssertTrue(convertedValue.is<bool>());
+ XCTAssertEqual(convertedValue.get<bool>(), false);
}
#pragma mark - Floating Point Tests
@@ -59,12 +67,12 @@
mbgl::Value convertedValue;
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MIN]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), DBL_MIN);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MAX]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), DBL_MAX);
}
@@ -72,7 +80,7 @@
- (void)testExpressionConversionFloat
{
// Because we can't guarantee precision when using float, and because
- // we warn the user to this effect in mgl_convertedValueWithValue:,
+ // we warn the user to this effect in -[NSExpression mgl_constantMBGLValue],
// we just check that things are in the ballpark here with integer values
// and some lower-precision checks.
@@ -80,26 +88,24 @@
mbgl::Value convertedValue;
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-1]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), -1);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:1]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
XCTAssertEqual(convertedValue.get<double>(), 1);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-23.232342]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
- XCTAssertLessThan(-23.24, convertedValue.get<double>());
- XCTAssertGreaterThan(-23.23, convertedValue.get<double>());
+ XCTAssertEqualWithAccuracy(convertedValue.get<double>(), -23.232342, 0.000001);
predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:23.232342]];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<double>());
- XCTAssertLessThan(23.23, convertedValue.get<double>());
- XCTAssertGreaterThan(23.24, convertedValue.get<double>());
+ XCTAssertEqualWithAccuracy(convertedValue.get<double>(), 23.232342, 0.000001);
}
#pragma mark - Integer Tests
@@ -132,7 +138,7 @@
for (NSNumber *min in minValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<int64_t>());
XCTAssertEqual(convertedValue.get<int64_t>(), min.longLongValue);
}
@@ -144,7 +150,7 @@
for (NSNumber *max in maxValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
}
@@ -179,7 +185,7 @@
for (NSNumber *min in minValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), min.unsignedLongLongValue);
}
@@ -191,10 +197,19 @@
for (NSNumber *max in maxValues)
{
predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
- convertedValue = predicate.rightExpression.mgl_filterValue;
+ convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
XCTAssertTrue(convertedValue.is<uint64_t>());
XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
}
}
+#pragma mark - Null Tests
+
+- (void)testExpressionConversionNull
+{
+ NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNull null]];
+ mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
+ XCTAssertTrue(convertedValue.is<mbgl::NullValue>());
+}
+
@end
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index efc30d307b..91ec9d429e 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -322,6 +322,15 @@
@[@(coord2.longitude), @(coord2.latitude)]]}
]};
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
+
+ // When the shape collection is created with an empty array of shapes
+ shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]];
+
+ // it has the correct (empty) geometry
+ geoJSONFeature = [shapeCollectionFeature geoJSONDictionary];
+ expectedGeometry = @{@"type": @"GeometryCollection",
+ @"geometries": @[]};
+ XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
}
@end
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.m b/platform/darwin/test/MGLFillStyleLayerTests.m
deleted file mode 100644
index 7d51c15cf4..0000000000
--- a/platform/darwin/test/MGLFillStyleLayerTests.m
+++ /dev/null
@@ -1,69 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLFillLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLFillLayerTests
-
-+ (NSString *)layerType {
- return @"fill";
-}
-
-- (void)testFillLayer {
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
- [self.mapView.style addLayer:layer];
-
- layer.fillAntialiased = [MGLRuntimeStylingHelper testBool];
- layer.fillColor = [MGLRuntimeStylingHelper testColor];
- layer.fillOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.fillOutlineColor = [MGLRuntimeStylingHelper testColor];
- layer.fillPattern = [MGLRuntimeStylingHelper testString];
- layer.fillTranslate = [MGLRuntimeStylingHelper testOffset];
- layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)];
-
- MGLFillStyleLayer *gLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLFillStyleLayer class]]);
- XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testString]);
- XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffset]);
- XCTAssert([gLayer.fillTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
-
- layer.fillAntialiased = [MGLRuntimeStylingHelper testBoolFunction];
- layer.fillColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.fillOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.fillOutlineColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.fillPattern = [MGLRuntimeStylingHelper testStringFunction];
- layer.fillTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)];
-
- XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testStringFunction]);
- XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"is-fill-antialiased" isBoolean:YES];
- [self testPropertyName:@"fill-color" isBoolean:NO];
- [self testPropertyName:@"fill-opacity" isBoolean:NO];
- [self testPropertyName:@"fill-outline-color" isBoolean:NO];
- [self testPropertyName:@"fill-pattern" isBoolean:NO];
- [self testPropertyName:@"fill-translate" isBoolean:NO];
- [self testPropertyName:@"fill-translate-anchor" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm
new file mode 100644
index 0000000000..fb50512afd
--- /dev/null
+++ b/platform/darwin/test/MGLFillStyleLayerTests.mm
@@ -0,0 +1,306 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/fill_layer.hpp>
+
+@interface MGLFillLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLFillLayerTests
+
++ (NSString *)layerType {
+ return @"fill";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::FillLayer>();
+
+ // fill-antialias
+ {
+ XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
+ @"fill-antialias should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillAntialiased;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
+ layer.fillAntialiased = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { false };
+ XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
+ @"Setting fillAntialiased to a constant value should update fill-antialias.");
+ XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
+ @"fillAntialiased should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillAntialiased = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
+ @"Setting fillAntialiased to a function should update fill-antialias.");
+ XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
+ @"fillAntialiased should round-trip functions.");
+
+ layer.fillAntialiased = nil;
+ XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
+ @"Unsetting fillAntialiased should return fill-antialias to the default value.");
+ XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue,
+ @"fillAntialiased should return the default value after being unset.");
+ }
+
+ // fill-color
+ {
+ XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
+ @"fill-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.fillColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
+ @"Setting fillColor to a constant value should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, styleValue,
+ @"fillColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
+ @"Setting fillColor to a function should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, styleValue,
+ @"fillColor should round-trip functions.");
+
+ layer.fillColor = nil;
+ XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
+ @"Unsetting fillColor should return fill-color to the default value.");
+ XCTAssertEqualObjects(layer.fillColor, defaultStyleValue,
+ @"fillColor should return the default value after being unset.");
+ }
+
+ // fill-opacity
+ {
+ XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
+ @"fill-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.fillOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
+ @"Setting fillOpacity to a constant value should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, styleValue,
+ @"fillOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
+ @"Setting fillOpacity to a function should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, styleValue,
+ @"fillOpacity should round-trip functions.");
+
+ layer.fillOpacity = nil;
+ XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
+ @"Unsetting fillOpacity should return fill-opacity to the default value.");
+ XCTAssertEqualObjects(layer.fillOpacity, defaultStyleValue,
+ @"fillOpacity should return the default value after being unset.");
+ }
+
+ // fill-outline-color
+ {
+ XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
+ @"fill-outline-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillOutlineColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.fillOutlineColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
+ @"Setting fillOutlineColor to a constant value should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
+ @"fillOutlineColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillOutlineColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
+ @"Setting fillOutlineColor to a function should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
+ @"fillOutlineColor should round-trip functions.");
+
+ layer.fillOutlineColor = nil;
+ XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
+ @"Unsetting fillOutlineColor should return fill-outline-color to the default value.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, defaultStyleValue,
+ @"fillOutlineColor should return the default value after being unset.");
+ }
+
+ // fill-pattern
+ {
+ XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
+ @"fill-pattern should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.fillPattern;
+
+ MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"];
+ layer.fillPattern = styleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Pattern" };
+ XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
+ @"Setting fillPattern to a constant value should update fill-pattern.");
+ XCTAssertEqualObjects(layer.fillPattern, styleValue,
+ @"fillPattern should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillPattern = styleValue;
+ propertyValue = { mbgl::style::Function<std::string> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
+ @"Setting fillPattern to a function should update fill-pattern.");
+ XCTAssertEqualObjects(layer.fillPattern, styleValue,
+ @"fillPattern should round-trip functions.");
+
+ layer.fillPattern = nil;
+ XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
+ @"Unsetting fillPattern should return fill-pattern to the default value.");
+ XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue,
+ @"fillPattern should return the default value after being unset.");
+ }
+
+ // fill-translate
+ {
+ XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
+ @"fill-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslation;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.fillTranslation = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
+ @"Setting fillTranslation to a constant value should update fill-translate.");
+ XCTAssertEqualObjects(layer.fillTranslation, styleValue,
+ @"fillTranslation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillTranslation = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
+ @"Setting fillTranslation to a function should update fill-translate.");
+ XCTAssertEqualObjects(layer.fillTranslation, styleValue,
+ @"fillTranslation should round-trip functions.");
+
+ layer.fillTranslation = nil;
+ XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
+ @"Unsetting fillTranslation should return fill-translate to the default value.");
+ XCTAssertEqualObjects(layer.fillTranslation, defaultStyleValue,
+ @"fillTranslation should return the default value after being unset.");
+ }
+
+ // fill-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
+ @"fill-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]];
+ layer.fillTranslationAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
+ @"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
+ @"fillTranslationAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.fillTranslationAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
+ @"Setting fillTranslationAnchor to a function should update fill-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
+ @"fillTranslationAnchor should round-trip functions.");
+
+ layer.fillTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
+ @"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue,
+ @"fillTranslationAnchor should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"is-fill-antialiased" isBoolean:YES];
+ [self testPropertyName:@"fill-color" isBoolean:NO];
+ [self testPropertyName:@"fill-opacity" isBoolean:NO];
+ [self testPropertyName:@"fill-outline-color" isBoolean:NO];
+ [self testPropertyName:@"fill-pattern" isBoolean:NO];
+ [self testPropertyName:@"fill-translation" isBoolean:NO];
+ [self testPropertyName:@"fill-translation-anchor" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorMap].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/MGLFilterTests.mm b/platform/darwin/test/MGLFilterTests.mm
deleted file mode 100644
index e688d50583..0000000000
--- a/platform/darwin/test/MGLFilterTests.mm
+++ /dev/null
@@ -1,194 +0,0 @@
-#import "MGLStyleLayerTests.h"
-
-#import "NSPredicate+MGLAdditions.h"
-#import "MGLValueEvaluator.h"
-
-
-@interface MGLFilterTests : MGLStyleLayerTests {
- MGLShapeSource *source;
- MGLLineStyleLayer *layer;
-}
-@end
-
-@implementation MGLFilterTests
-
-- (void)setUp
-{
- [super setUp];
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- NSData *geoJSONData = [NSData dataWithContentsOfURL:url];
- NSError *error;
- MGLShape *shape = [MGLShape shapeWithData:geoJSONData encoding:NSUTF8StringEncoding error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(shape);
- source = [[MGLShapeSource alloc] initWithIdentifier:@"test-source" shape:shape options:nil];
- [self.mapView.style addSource:source];
- layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"test-layer" source:source];
-}
-
-- (void)tearDown
-{
- [self.mapView.style removeLayer:layer];
- [self.mapView.style removeSource:source];
-}
-
-- (NSArray<NSPredicate *> *)predicates
-{
- NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"];
- NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"];
- NSPredicate *greaterThanPredicate = [NSPredicate predicateWithFormat:@"%K > %@", @"stroke-width", @2.1];
- NSPredicate *greaterThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K >= %@", @"stroke-width", @2.1];
- NSPredicate *lessThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K <= %@", @"stroke-width", @2.1];
- NSPredicate *lessThanPredicate = [NSPredicate predicateWithFormat:@"%K < %@", @"stroke-width", @2.1];
- NSPredicate *inPredicate = [NSPredicate predicateWithFormat:@"type IN %@", @[@"park", @"neighbourhood"]];
- NSPredicate *notInPredicate = [NSPredicate predicateWithFormat:@"NOT (type IN %@)", @[@"park", @"neighbourhood"]];
- NSPredicate *inNotInPredicate = [NSPredicate predicateWithFormat:@"type IN %@ AND NOT (type IN %@)", @[@"park"], @[@"neighbourhood", @"test"]];
- NSPredicate *typePredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$type", @"Feature"];
- NSPredicate *idPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$id", @"1234123"];
- NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"];
- NSPredicate *booleanPredicate = [NSPredicate predicateWithFormat:@"cluster != YES"];
- NSPredicate *nilEqualsPredicate = [NSPredicate predicateWithFormat:@"type == %@", nil];
- NSPredicate *nilNotEqualsPredicate = [NSPredicate predicateWithFormat:@"type != %@", nil];
- return @[
- equalPredicate,
- notEqualPredicate,
- greaterThanPredicate,
- greaterThanOrEqualToPredicate,
- lessThanOrEqualToPredicate,
- lessThanPredicate,
- inPredicate,
- notInPredicate,
- inNotInPredicate,
- typePredicate,
- idPredicate,
- specialCharsPredicate,
- booleanPredicate,
- nilEqualsPredicate,
- nilNotEqualsPredicate
- ];
-}
-
-- (void)testAllPredicates
-{
- for (NSPredicate *predicate in self.predicates) {
- layer.predicate = predicate;
- XCTAssertEqualObjects(layer.predicate, predicate);
- }
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testContainsPredicate
-{
- // core does not have a "contains" filter but we can achieve the equivalent by creating an `mbgl::style::InFilter`
- // and searching the value for the key
- NSPredicate *expectedPredicate = [NSPredicate predicateWithFormat:@"park IN %@", @[@"park", @"neighbourhood"]];
- NSPredicate *containsPredicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS %@", @[@"park", @"neighbourhood"], @"park"];
-
- layer.predicate = containsPredicate;
- XCTAssertEqualObjects(layer.predicate, expectedPredicate);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testBetweenPredicate
-{
- // core does not have a "between" filter but we can achieve the equivalent by creating a set of greater than or equal / less than or equal
- // filters for the lower and upper bounds (inclusive)
- NSPredicate *expectedPredicate = [NSCompoundPredicate predicateWithFormat:@"%K >= 2 AND %K <= 3", @"stroke-width", @"stroke-width"];
- NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat:@"%K BETWEEN %@", @"stroke-width", @[@2.0, @3.0]];
-
- layer.predicate = betweenPredicate;
- XCTAssertEqualObjects(layer.predicate, expectedPredicate);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testTruePredicate
-{
- // This comes out of the class cluster as an NSTruePredicate and it is equal to `[NSPredicate predicateWithValue:YES]`
- NSPredicate *truePredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
-
- layer.predicate = truePredicate;
- XCTAssertEqualObjects(layer.predicate.description, truePredicate.description);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testFalsePredicate
-{
- // This comes out of the class cluster as an NSFalsePredicate and it is equal to `[NSPredicate predicateWithValue:NO]`
- NSPredicate *falsePredicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"];
-
- layer.predicate = falsePredicate;
- XCTAssertEqualObjects(layer.predicate.description, falsePredicate.description);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testIntermittentEncoding
-{
- NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"];
- layer.predicate = specialCharsPredicate;
-
- NSComparisonPredicate *getPredicate = (NSComparisonPredicate *)layer.predicate;
- mbgl::style::EqualsFilter filter = layer.predicate.mgl_filter.get<mbgl::style::EqualsFilter>();
-
- id objcKey = getPredicate.leftExpression.keyPath;
- id cppKey = @(filter.key.c_str());
- id objcValue = mbgl::Value::visit(getPredicate.rightExpression.mgl_filterValue, ValueEvaluator());
- id cppValue = mbgl::Value::visit(filter.value, ValueEvaluator());
-
- XCTAssertEqualObjects(objcKey, cppKey);
- XCTAssertEqualObjects(objcValue, cppValue);
-
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testNestedFilters
-{
- NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"];
- NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"];
-
- NSPredicate *allPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]];
- NSPredicate *anyPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]];
-
- layer.predicate = allPredicate;
- XCTAssertEqualObjects(layer.predicate, allPredicate);
- layer.predicate = anyPredicate;
- XCTAssertEqualObjects(layer.predicate, anyPredicate);
-
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testAndPredicates
-{
- NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates];
- layer.predicate = predicate;
- XCTAssertEqualObjects(predicate, layer.predicate);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testOrPredicates
-{
- NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates];
- layer.predicate = predicate;
- XCTAssertEqualObjects(predicate, layer.predicate);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testNotAndPredicates
-{
- NSPredicate *predicates = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates];
- NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates];
- layer.predicate = predicate;
- XCTAssertEqualObjects(predicate, layer.predicate);
- [self.mapView.style addLayer:layer];
-}
-
-- (void)testNotOrPredicates
-{
- NSPredicate *predicates = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates];
- NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates];
- layer.predicate = predicate;
- XCTAssertEqualObjects(predicate, layer.predicate);
- [self.mapView.style addLayer:layer];
-}
-
-@end
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.m b/platform/darwin/test/MGLLineStyleLayerTests.m
deleted file mode 100644
index e877c1d57a..0000000000
--- a/platform/darwin/test/MGLLineStyleLayerTests.m
+++ /dev/null
@@ -1,106 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLLineLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLLineLayerTests
-
-+ (NSString *)layerType {
- return @"line";
-}
-
-- (void)testLineLayer {
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
- [self.mapView.style addLayer:layer];
-
- layer.lineCap = [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)];
- layer.lineJoin = [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)];
- layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumber];
- layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumber];
- layer.lineBlur = [MGLRuntimeStylingHelper testNumber];
- layer.lineColor = [MGLRuntimeStylingHelper testColor];
- layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArray];
- layer.lineGapWidth = [MGLRuntimeStylingHelper testNumber];
- layer.lineOffset = [MGLRuntimeStylingHelper testNumber];
- layer.lineOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.linePattern = [MGLRuntimeStylingHelper testString];
- layer.lineTranslate = [MGLRuntimeStylingHelper testOffset];
- layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)];
- layer.lineWidth = [MGLRuntimeStylingHelper testNumber];
-
- MGLLineStyleLayer *gLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLLineStyleLayer class]]);
- XCTAssert([gLayer.lineCap isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)]);
- XCTAssert([gLayer.lineJoin isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)]);
- XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArray]);
- XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testString]);
- XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffset]);
- XCTAssert([gLayer.lineTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]);
- XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumber]);
-
- layer.lineCap = [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)];
- layer.lineJoin = [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)];
- layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumberFunction];
- layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumberFunction];
- layer.lineBlur = [MGLRuntimeStylingHelper testNumberFunction];
- layer.lineColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArrayFunction];
- layer.lineGapWidth = [MGLRuntimeStylingHelper testNumberFunction];
- layer.lineOffset = [MGLRuntimeStylingHelper testNumberFunction];
- layer.lineOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.linePattern = [MGLRuntimeStylingHelper testStringFunction];
- layer.lineTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)];
- layer.lineWidth = [MGLRuntimeStylingHelper testNumberFunction];
-
- XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)]);
- XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)]);
- XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArrayFunction]);
- XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testStringFunction]);
- XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]);
- XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumberFunction]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"line-cap" isBoolean:NO];
- [self testPropertyName:@"line-join" isBoolean:NO];
- [self testPropertyName:@"line-miter-limit" isBoolean:NO];
- [self testPropertyName:@"line-round-limit" isBoolean:NO];
- [self testPropertyName:@"line-blur" isBoolean:NO];
- [self testPropertyName:@"line-color" isBoolean:NO];
- [self testPropertyName:@"line-dash-pattern" isBoolean:NO];
- [self testPropertyName:@"line-gap-width" isBoolean:NO];
- [self testPropertyName:@"line-offset" isBoolean:NO];
- [self testPropertyName:@"line-opacity" isBoolean:NO];
- [self testPropertyName:@"line-pattern" isBoolean:NO];
- [self testPropertyName:@"line-translate" isBoolean:NO];
- [self testPropertyName:@"line-translate-anchor" isBoolean:NO];
- [self testPropertyName:@"line-width" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
new file mode 100644
index 0000000000..24a9d7afea
--- /dev/null
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -0,0 +1,557 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/line_layer.hpp>
+
+@interface MGLLineLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLLineLayerTests
+
++ (NSString *)layerType {
+ return @"line";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::LineLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::LineLayer>();
+
+ // line-cap
+ {
+ XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
+ @"line-cap should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineCap;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]];
+ layer.lineCap = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::LineCapType> propertyValue = { mbgl::style::LineCapType::Square };
+ XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
+ @"Setting lineCap to a constant value should update line-cap.");
+ XCTAssertEqualObjects(layer.lineCap, styleValue,
+ @"lineCap should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineCap = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::LineCapType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
+ @"Setting lineCap to a function should update line-cap.");
+ XCTAssertEqualObjects(layer.lineCap, styleValue,
+ @"lineCap should round-trip functions.");
+
+ layer.lineCap = nil;
+ XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
+ @"Unsetting lineCap should return line-cap to the default value.");
+ XCTAssertEqualObjects(layer.lineCap, defaultStyleValue,
+ @"lineCap should return the default value after being unset.");
+ }
+
+ // line-join
+ {
+ XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
+ @"line-join should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineJoin;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
+ layer.lineJoin = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
+ XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
+ @"Setting lineJoin to a constant value should update line-join.");
+ XCTAssertEqualObjects(layer.lineJoin, styleValue,
+ @"lineJoin should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineJoin = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::LineJoinType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
+ @"Setting lineJoin to a function should update line-join.");
+ XCTAssertEqualObjects(layer.lineJoin, styleValue,
+ @"lineJoin should round-trip functions.");
+
+ layer.lineJoin = nil;
+ XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
+ @"Unsetting lineJoin should return line-join to the default value.");
+ XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue,
+ @"lineJoin should return the default value after being unset.");
+ }
+
+ // line-miter-limit
+ {
+ XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
+ @"line-miter-limit should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineMiterLimit;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineMiterLimit = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
+ @"Setting lineMiterLimit to a constant value should update line-miter-limit.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
+ @"lineMiterLimit should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineMiterLimit = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
+ @"Setting lineMiterLimit to a function should update line-miter-limit.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
+ @"lineMiterLimit should round-trip functions.");
+
+ layer.lineMiterLimit = nil;
+ XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
+ @"Unsetting lineMiterLimit should return line-miter-limit to the default value.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, defaultStyleValue,
+ @"lineMiterLimit should return the default value after being unset.");
+ }
+
+ // line-round-limit
+ {
+ XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
+ @"line-round-limit should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineRoundLimit;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineRoundLimit = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
+ @"Setting lineRoundLimit to a constant value should update line-round-limit.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
+ @"lineRoundLimit should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineRoundLimit = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
+ @"Setting lineRoundLimit to a function should update line-round-limit.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
+ @"lineRoundLimit should round-trip functions.");
+
+ layer.lineRoundLimit = nil;
+ XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
+ @"Unsetting lineRoundLimit should return line-round-limit to the default value.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, defaultStyleValue,
+ @"lineRoundLimit should return the default value after being unset.");
+ }
+
+ // line-blur
+ {
+ XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
+ @"line-blur should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineBlur;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineBlur = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
+ @"Setting lineBlur to a constant value should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, styleValue,
+ @"lineBlur should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineBlur = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
+ @"Setting lineBlur to a function should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, styleValue,
+ @"lineBlur should round-trip functions.");
+
+ layer.lineBlur = nil;
+ XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
+ @"Unsetting lineBlur should return line-blur to the default value.");
+ XCTAssertEqualObjects(layer.lineBlur, defaultStyleValue,
+ @"lineBlur should return the default value after being unset.");
+ }
+
+ // line-color
+ {
+ XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
+ @"line-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.lineColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.lineColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
+ @"Setting lineColor to a constant value should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, styleValue,
+ @"lineColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
+ @"Setting lineColor to a function should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, styleValue,
+ @"lineColor should round-trip functions.");
+
+ layer.lineColor = nil;
+ XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
+ @"Unsetting lineColor should return line-color to the default value.");
+ XCTAssertEqualObjects(layer.lineColor, defaultStyleValue,
+ @"lineColor should return the default value after being unset.");
+ }
+
+ // line-dasharray
+ {
+ XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
+ @"line-dasharray should be unset initially.");
+ MGLStyleValue<NSArray<NSNumber *> *> *defaultStyleValue = layer.lineDashPattern;
+
+ MGLStyleValue<NSArray<NSNumber *> *> *styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
+ layer.lineDashPattern = styleValue;
+ mbgl::style::PropertyValue<std::vector<float>> propertyValue = { {1, 2} };
+ XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
+ @"Setting lineDashPattern to a constant value should update line-dasharray.");
+ XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
+ @"lineDashPattern should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineDashPattern = styleValue;
+ propertyValue = { mbgl::style::Function<std::vector<float>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
+ @"Setting lineDashPattern to a function should update line-dasharray.");
+ XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
+ @"lineDashPattern should round-trip functions.");
+
+ layer.lineDashPattern = nil;
+ XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
+ @"Unsetting lineDashPattern should return line-dasharray to the default value.");
+ XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue,
+ @"lineDashPattern should return the default value after being unset.");
+ }
+
+ // line-gap-width
+ {
+ XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
+ @"line-gap-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineGapWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineGapWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
+ @"Setting lineGapWidth to a constant value should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
+ @"lineGapWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineGapWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
+ @"Setting lineGapWidth to a function should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
+ @"lineGapWidth should round-trip functions.");
+
+ layer.lineGapWidth = nil;
+ XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
+ @"Unsetting lineGapWidth should return line-gap-width to the default value.");
+ XCTAssertEqualObjects(layer.lineGapWidth, defaultStyleValue,
+ @"lineGapWidth should return the default value after being unset.");
+ }
+
+ // line-offset
+ {
+ XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
+ @"line-offset should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOffset;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineOffset = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
+ @"Setting lineOffset to a constant value should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, styleValue,
+ @"lineOffset should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineOffset = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
+ @"Setting lineOffset to a function should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, styleValue,
+ @"lineOffset should round-trip functions.");
+
+ layer.lineOffset = nil;
+ XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
+ @"Unsetting lineOffset should return line-offset to the default value.");
+ XCTAssertEqualObjects(layer.lineOffset, defaultStyleValue,
+ @"lineOffset should return the default value after being unset.");
+ }
+
+ // line-opacity
+ {
+ XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
+ @"line-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
+ @"Setting lineOpacity to a constant value should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, styleValue,
+ @"lineOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
+ @"Setting lineOpacity to a function should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, styleValue,
+ @"lineOpacity should round-trip functions.");
+
+ layer.lineOpacity = nil;
+ XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
+ @"Unsetting lineOpacity should return line-opacity to the default value.");
+ XCTAssertEqualObjects(layer.lineOpacity, defaultStyleValue,
+ @"lineOpacity should return the default value after being unset.");
+ }
+
+ // line-pattern
+ {
+ XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
+ @"line-pattern should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.linePattern;
+
+ MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"];
+ layer.linePattern = styleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Line Pattern" };
+ XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
+ @"Setting linePattern to a constant value should update line-pattern.");
+ XCTAssertEqualObjects(layer.linePattern, styleValue,
+ @"linePattern should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.linePattern = styleValue;
+ propertyValue = { mbgl::style::Function<std::string> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
+ @"Setting linePattern to a function should update line-pattern.");
+ XCTAssertEqualObjects(layer.linePattern, styleValue,
+ @"linePattern should round-trip functions.");
+
+ layer.linePattern = nil;
+ XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
+ @"Unsetting linePattern should return line-pattern to the default value.");
+ XCTAssertEqualObjects(layer.linePattern, defaultStyleValue,
+ @"linePattern should return the default value after being unset.");
+ }
+
+ // line-translate
+ {
+ XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
+ @"line-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslation;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.lineTranslation = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
+ @"Setting lineTranslation to a constant value should update line-translate.");
+ XCTAssertEqualObjects(layer.lineTranslation, styleValue,
+ @"lineTranslation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineTranslation = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
+ @"Setting lineTranslation to a function should update line-translate.");
+ XCTAssertEqualObjects(layer.lineTranslation, styleValue,
+ @"lineTranslation should round-trip functions.");
+
+ layer.lineTranslation = nil;
+ XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
+ @"Unsetting lineTranslation should return line-translate to the default value.");
+ XCTAssertEqualObjects(layer.lineTranslation, defaultStyleValue,
+ @"lineTranslation should return the default value after being unset.");
+ }
+
+ // line-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
+ @"line-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]];
+ layer.lineTranslationAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
+ @"Setting lineTranslationAnchor to a constant value should update line-translate-anchor.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
+ @"lineTranslationAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineTranslationAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
+ @"Setting lineTranslationAnchor to a function should update line-translate-anchor.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
+ @"lineTranslationAnchor should round-trip functions.");
+
+ layer.lineTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
+ @"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue,
+ @"lineTranslationAnchor should return the default value after being unset.");
+ }
+
+ // line-width
+ {
+ XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
+ @"line-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a constant value should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, styleValue,
+ @"lineWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.lineWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, styleValue,
+ @"lineWidth should round-trip functions.");
+
+ layer.lineWidth = nil;
+ XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
+ @"Unsetting lineWidth should return line-width to the default value.");
+ XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
+ @"lineWidth should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"line-cap" isBoolean:NO];
+ [self testPropertyName:@"line-join" isBoolean:NO];
+ [self testPropertyName:@"line-miter-limit" isBoolean:NO];
+ [self testPropertyName:@"line-round-limit" isBoolean:NO];
+ [self testPropertyName:@"line-blur" isBoolean:NO];
+ [self testPropertyName:@"line-color" isBoolean:NO];
+ [self testPropertyName:@"line-dash-pattern" isBoolean:NO];
+ [self testPropertyName:@"line-gap-width" isBoolean:NO];
+ [self testPropertyName:@"line-offset" isBoolean:NO];
+ [self testPropertyName:@"line-opacity" isBoolean:NO];
+ [self testPropertyName:@"line-pattern" isBoolean:NO];
+ [self testPropertyName:@"line-translation" isBoolean:NO];
+ [self testPropertyName:@"line-translation-anchor" isBoolean:NO];
+ [self testPropertyName:@"line-width" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapButt].MGLLineCapValue, MGLLineCapButt);
+ XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapRound].MGLLineCapValue, MGLLineCapRound);
+ XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapSquare].MGLLineCapValue, MGLLineCapSquare);
+ XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinBevel].MGLLineJoinValue, MGLLineJoinBevel);
+ XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinRound].MGLLineJoinValue, MGLLineJoinRound);
+ XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinMiter].MGLLineJoinValue, MGLLineJoinMiter);
+ XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorMap].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m
new file mode 100644
index 0000000000..0c8a9f8143
--- /dev/null
+++ b/platform/darwin/test/MGLNSStringAdditionsTests.m
@@ -0,0 +1,42 @@
+#import <XCTest/XCTest.h>
+
+#import "NSString+MGLAdditions.h"
+
+@interface MGLNSStringAdditionsTests : XCTestCase
+
+@end
+
+@implementation MGLNSStringAdditionsTests
+
+- (void)testTitleCasedString {
+ NSLocale *locale = [NSLocale currentLocale];
+
+ XCTAssertEqualObjects([@"© OpenStreetMap" mgl_titleCasedStringWithLocale:locale], @"© OpenStreetMap");
+ XCTAssertEqualObjects([@"© OSM" mgl_titleCasedStringWithLocale:locale], @"© OSM");
+
+ XCTAssertEqualObjects([@"Improve this map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
+ XCTAssertEqualObjects([@"Improve This Map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
+
+ XCTAssertEqualObjects([@"Improve the map" mgl_titleCasedStringWithLocale:locale], @"Improve the Map");
+ XCTAssertEqualObjects([@"Improve The Map" mgl_titleCasedStringWithLocale:locale], @"Improve The Map");
+
+ XCTAssertEqualObjects([@"Improve a map" mgl_titleCasedStringWithLocale:locale], @"Improve a Map");
+ XCTAssertEqualObjects([@"Improve A Map" mgl_titleCasedStringWithLocale:locale], @"Improve A Map");
+
+ XCTAssertEqualObjects([@"Improve for the map" mgl_titleCasedStringWithLocale:locale], @"Improve for the Map");
+ XCTAssertEqualObjects([@"Improve For The Map" mgl_titleCasedStringWithLocale:locale], @"Improve For The Map");
+
+ XCTAssertEqualObjects([@"Improve and map" mgl_titleCasedStringWithLocale:locale], @"Improve and Map");
+ XCTAssertEqualObjects([@"Improve And Map" mgl_titleCasedStringWithLocale:locale], @"Improve And Map");
+
+ XCTAssertEqualObjects([@"Improve while mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
+ XCTAssertEqualObjects([@"Improve While Mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
+
+ XCTAssertEqualObjects([@"Improve with the map" mgl_titleCasedStringWithLocale:locale], @"Improve With the Map");
+ XCTAssertEqualObjects([@"Improve With The Map" mgl_titleCasedStringWithLocale:locale], @"Improve With The Map");
+
+ XCTAssertEqualObjects([@"Improve this iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
+ XCTAssertEqualObjects([@"Improve This iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
+}
+
+@end
diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm
new file mode 100644
index 0000000000..fbd144d28a
--- /dev/null
+++ b/platform/darwin/test/MGLPredicateTests.mm
@@ -0,0 +1,419 @@
+#import <XCTest/XCTest.h>
+#import <Mapbox/Mapbox.h>
+
+#import "NSPredicate+MGLAdditions.h"
+#import "MGLValueEvaluator.h"
+
+namespace mbgl {
+ namespace style {
+ bool operator!=(const Filter &a, const Filter &b) {
+ return !(a == b);
+ }
+ }
+}
+
+#define MGLAssertEqualFilters(actual, expected, ...) \
+ XCTAssertTrue(actual.is<__typeof__(expected)>()); \
+ if (actual.is<__typeof__(expected)>()) { \
+ XCTAssertEqual(actual.get<__typeof__(expected)>(), expected, __VA_ARGS__); \
+ }
+
+@interface MGLPredicateTests : XCTestCase
+@end
+
+@implementation MGLPredicateTests
+
+- (void)testFilterization {
+ {
+ auto actual = [NSPredicate predicateWithValue:YES].mgl_filter;
+ mbgl::style::AllFilter expected;
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithValue:NO].mgl_filter;
+ mbgl::style::AnyFilter expected;
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a = 'b'"].mgl_filter;
+ mbgl::style::EqualsFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a = nil"].mgl_filter;
+ mbgl::style::NotHasFilter expected = { .key = "a" };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a != 'b'"].mgl_filter;
+ mbgl::style::NotEqualsFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a != nil"].mgl_filter;
+ mbgl::style::HasFilter expected = { .key = "a" };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a < 'b'"].mgl_filter;
+ mbgl::style::LessThanFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a <= 'b'"].mgl_filter;
+ mbgl::style::LessThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a > 'b'"].mgl_filter;
+ mbgl::style::GreaterThanFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a >= 'b'"].mgl_filter;
+ mbgl::style::GreaterThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"].mgl_filter;
+ mbgl::style::AllFilter expected = {
+ .filters = {
+ mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@"b", @"z"]].mgl_filter;
+ mbgl::style::AllFilter expected = {
+ .filters = {
+ mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].mgl_filter;
+ mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a IN %@", @[@"b", @"c"]].mgl_filter;
+ mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"{'b', 'c'} CONTAINS a"].mgl_filter;
+ mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
+ mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"].mgl_filter;
+ mbgl::style::AllFilter expected = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"].mgl_filter;
+ mbgl::style::AnyFilter expected = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' AND c == 'd')"].mgl_filter;
+ mbgl::style::NoneFilter expected = {
+ .filters = {
+ mbgl::style::AllFilter {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"].mgl_filter;
+ mbgl::style::NoneFilter expected = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT a == nil"].mgl_filter;
+ mbgl::style::HasFilter expected = { .key = "a" };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT a != nil"].mgl_filter;
+ mbgl::style::NotHasFilter expected = { .key = "a" };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].mgl_filter;
+ mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT a IN %@", @[@"b", @"c"]].mgl_filter;
+ mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT {'b', 'c'} CONTAINS a"].mgl_filter;
+ mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"NOT %@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
+ mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BEGINSWITH 'L'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a ENDSWITH 'itude'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a LIKE 'glob?trotter'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a MATCHES 'i\\w{18}n'"].mgl_filter, NSException, NSInvalidArgumentException);
+ NSPredicate *selectorPredicate = [NSPredicate predicateWithFormat:@"(SELF isKindOfClass: %@)", [MGLPolyline class]];
+ XCTAssertThrowsSpecificNamed(selectorPredicate.mgl_filter, NSException, NSInvalidArgumentException);
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings) {
+ XCTAssertTrue(NO, @"Predicate block should not be evaluated.");
+ return NO;
+ }].mgl_filter, NSException, NSInvalidArgumentException);
+}
+
+- (void)testPredication {
+ XCTAssertNil([NSPredicate mgl_predicateWithFilter:mbgl::style::NullFilter()]);
+
+ {
+ mbgl::style::EqualsFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = 'b'"]);
+ }
+
+ {
+ mbgl::style::NotHasFilter filter = { .key = "a" };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = nil"]);
+ }
+
+ {
+ mbgl::style::NotEqualsFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != 'b'"]);
+ }
+
+ {
+ mbgl::style::HasFilter filter = { .key = "a" };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != nil"]);
+ }
+
+ {
+ mbgl::style::LessThanFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a < 'b'"]);
+ }
+
+ {
+ mbgl::style::LessThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a <= 'b'"]);
+ }
+
+ {
+ mbgl::style::GreaterThanFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a > 'b'"]);
+ }
+
+ {
+ mbgl::style::GreaterThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a >= 'b'"]);
+ }
+
+ {
+ mbgl::style::AllFilter filter = {
+ .filters = {
+ mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
+ },
+ };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
+ }
+
+ {
+ mbgl::style::AllFilter filter = {
+ .filters = {
+ mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
+ mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
+ },
+ };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
+ }
+
+ {
+ mbgl::style::InFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].predicateFormat);
+ }
+
+ {
+ mbgl::style::NotInFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].predicateFormat);
+ }
+
+ {
+ mbgl::style::AllFilter filter;
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
+ }
+
+ {
+ mbgl::style::AllFilter filter = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"]);
+ }
+
+ {
+ mbgl::style::AnyFilter filter;
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:NO]);
+ }
+
+ {
+ mbgl::style::AnyFilter filter = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"]);
+ }
+
+ {
+ mbgl::style::NoneFilter filter;
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
+ }
+
+ {
+ mbgl::style::NoneFilter filter = {
+ .filters = {
+ mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
+ mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
+ },
+ };
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"]);
+ }
+}
+
+- (void)testSymmetry {
+ [self testSymmetryWithFormat:@"a = 1" reverseFormat:@"1 = a" mustRoundTrip:YES];
+ [self testSymmetryWithFormat:@"a != 1" reverseFormat:@"1 != a" mustRoundTrip:YES];
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = b"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 = 1"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ // In the predicate format language, $ is a special character denoting a
+ // variable. Use %K to escape the special feature attribute $id.
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"$id == 670861802"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = $id"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ [self testSymmetryWithFormat:@"a = nil" reverseFormat:@"nil = a" mustRoundTrip:YES];
+ [self testSymmetryWithFormat:@"a != nil" reverseFormat:@"nil != a" mustRoundTrip:YES];
+
+ [self testSymmetryWithFormat:@"a < 1" reverseFormat:@"1 > a" mustRoundTrip:YES];
+ [self testSymmetryWithFormat:@"a <= 1" reverseFormat:@"1 >= a" mustRoundTrip:YES];
+ [self testSymmetryWithFormat:@"a > 1" reverseFormat:@"1 < a" mustRoundTrip:YES];
+ [self testSymmetryWithFormat:@"a >= 1" reverseFormat:@"1 <= a" mustRoundTrip:YES];
+
+ [self testSymmetryWithFormat:@"a BETWEEN {1, 2}" reverseFormat:@"1 <= a && 2 >= a" mustRoundTrip:YES];
+ [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@1, @2]]
+ reversePredicate:[NSPredicate predicateWithFormat:@"1 <= a && 2 >= a"]
+ mustRoundTrip:YES];
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"{1, 2} BETWEEN a"].mgl_filter, NSException, NSInvalidArgumentException);
+ NSPredicate *betweenSetPredicate = [NSPredicate predicateWithFormat:@"a BETWEEN %@", [NSSet setWithObjects:@1, @2, nil]];
+ XCTAssertThrowsSpecificNamed(betweenSetPredicate.mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1}"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1, 2, 3}"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ [self testSymmetryWithFormat:@"a IN {1, 2}" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
+ [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a IN %@", @[@1, @2]]
+ reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
+ mustRoundTrip:YES];
+
+ // The reverse formats here are a bit backwards because we canonicalize
+ // a reverse CONTAINS to a forward IN.
+ [self testSymmetryWithFormat:@"{1, 2} CONTAINS a" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
+ [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
+ reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
+ mustRoundTrip:NO];
+}
+
+- (void)testSymmetryWithFormat:(NSString *)forwardFormat reverseFormat:(NSString *)reverseFormat mustRoundTrip:(BOOL)mustRoundTrip {
+ NSPredicate *forwardPredicate = [NSPredicate predicateWithFormat:forwardFormat];
+ NSPredicate *reversePredicate = reverseFormat ? [NSPredicate predicateWithFormat:reverseFormat] : nil;
+ [self testSymmetryWithPredicate:forwardPredicate reversePredicate:reversePredicate mustRoundTrip:mustRoundTrip];
+}
+
+- (void)testSymmetryWithPredicate:(NSPredicate *)forwardPredicate reversePredicate:(NSPredicate *)reversePredicate mustRoundTrip:(BOOL)mustRoundTrip {
+ auto forwardFilter = forwardPredicate.mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ if (mustRoundTrip) {
+ // A collection of ints may turn into an aggregate of longs, for
+ // example, so compare formats instead of the predicates themselves.
+ XCTAssertEqualObjects(forwardPredicate.predicateFormat, forwardPredicateAfter.predicateFormat);
+ }
+
+ if (reversePredicate) {
+ auto reverseFilter = reversePredicate.mgl_filter;
+ NSPredicate *reversePredicateAfter = [NSPredicate mgl_predicateWithFilter:reverseFilter];
+ XCTAssertNotEqualObjects(reversePredicate, reversePredicateAfter);
+
+ XCTAssertEqualObjects(forwardPredicateAfter, reversePredicateAfter);
+ }
+}
+
+@end
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.m b/platform/darwin/test/MGLRasterStyleLayerTests.m
deleted file mode 100644
index f8de191da0..0000000000
--- a/platform/darwin/test/MGLRasterStyleLayerTests.m
+++ /dev/null
@@ -1,68 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLRasterLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLRasterLayerTests
-
-+ (NSString *)layerType {
- return @"raster";
-}
-
-- (void)testRasterLayer {
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
- [self.mapView.style addLayer:layer];
-
- layer.maximumRasterBrightness = [MGLRuntimeStylingHelper testNumber];
- layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumber];
- layer.rasterContrast = [MGLRuntimeStylingHelper testNumber];
- layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumber];
- layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumber];
- layer.rasterOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.rasterSaturation = [MGLRuntimeStylingHelper testNumber];
-
- MGLRasterStyleLayer *gLayer = (MGLRasterStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLRasterStyleLayer class]]);
- XCTAssertEqualObjects(gLayer.maximumRasterBrightness, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumber]);
-
- layer.maximumRasterBrightness = [MGLRuntimeStylingHelper testNumberFunction];
- layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumberFunction];
- layer.rasterContrast = [MGLRuntimeStylingHelper testNumberFunction];
- layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumberFunction];
- layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumberFunction];
- layer.rasterOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.rasterSaturation = [MGLRuntimeStylingHelper testNumberFunction];
-
- XCTAssertEqualObjects(gLayer.maximumRasterBrightness, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumberFunction]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"maximum-raster-brightness" isBoolean:NO];
- [self testPropertyName:@"minimum-raster-brightness" isBoolean:NO];
- [self testPropertyName:@"raster-contrast" isBoolean:NO];
- [self testPropertyName:@"raster-fade-duration" isBoolean:NO];
- [self testPropertyName:@"raster-hue-rotation" isBoolean:NO];
- [self testPropertyName:@"raster-opacity" isBoolean:NO];
- [self testPropertyName:@"raster-saturation" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm
new file mode 100644
index 0000000000..28a201961c
--- /dev/null
+++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm
@@ -0,0 +1,277 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/raster_layer.hpp>
+
+@interface MGLRasterLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLRasterLayerTests
+
++ (NSString *)layerType {
+ return @"raster";
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::RasterLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::RasterLayer>();
+
+ // raster-brightness-max
+ {
+ XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
+ @"raster-brightness-max should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumRasterBrightness;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumRasterBrightness = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
+ @"Setting maximumRasterBrightness to a constant value should update raster-brightness-max.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue,
+ @"maximumRasterBrightness should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.maximumRasterBrightness = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
+ @"Setting maximumRasterBrightness to a function should update raster-brightness-max.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue,
+ @"maximumRasterBrightness should round-trip functions.");
+
+ layer.maximumRasterBrightness = nil;
+ XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
+ @"Unsetting maximumRasterBrightness should return raster-brightness-max to the default value.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, defaultStyleValue,
+ @"maximumRasterBrightness should return the default value after being unset.");
+ }
+
+ // raster-brightness-min
+ {
+ XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
+ @"raster-brightness-min should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.minimumRasterBrightness;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.minimumRasterBrightness = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
+ @"Setting minimumRasterBrightness to a constant value should update raster-brightness-min.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue,
+ @"minimumRasterBrightness should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.minimumRasterBrightness = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
+ @"Setting minimumRasterBrightness to a function should update raster-brightness-min.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue,
+ @"minimumRasterBrightness should round-trip functions.");
+
+ layer.minimumRasterBrightness = nil;
+ XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
+ @"Unsetting minimumRasterBrightness should return raster-brightness-min to the default value.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, defaultStyleValue,
+ @"minimumRasterBrightness should return the default value after being unset.");
+ }
+
+ // raster-contrast
+ {
+ XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
+ @"raster-contrast should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterContrast;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterContrast = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
+ @"Setting rasterContrast to a constant value should update raster-contrast.");
+ XCTAssertEqualObjects(layer.rasterContrast, styleValue,
+ @"rasterContrast should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.rasterContrast = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
+ @"Setting rasterContrast to a function should update raster-contrast.");
+ XCTAssertEqualObjects(layer.rasterContrast, styleValue,
+ @"rasterContrast should round-trip functions.");
+
+ layer.rasterContrast = nil;
+ XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
+ @"Unsetting rasterContrast should return raster-contrast to the default value.");
+ XCTAssertEqualObjects(layer.rasterContrast, defaultStyleValue,
+ @"rasterContrast should return the default value after being unset.");
+ }
+
+ // raster-fade-duration
+ {
+ XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
+ @"raster-fade-duration should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterFadeDuration;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterFadeDuration = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
+ @"Setting rasterFadeDuration to a constant value should update raster-fade-duration.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue,
+ @"rasterFadeDuration should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.rasterFadeDuration = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
+ @"Setting rasterFadeDuration to a function should update raster-fade-duration.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue,
+ @"rasterFadeDuration should round-trip functions.");
+
+ layer.rasterFadeDuration = nil;
+ XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
+ @"Unsetting rasterFadeDuration should return raster-fade-duration to the default value.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, defaultStyleValue,
+ @"rasterFadeDuration should return the default value after being unset.");
+ }
+
+ // raster-hue-rotate
+ {
+ XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
+ @"raster-hue-rotate should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterHueRotation;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterHueRotation = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
+ @"Setting rasterHueRotation to a constant value should update raster-hue-rotate.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, styleValue,
+ @"rasterHueRotation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.rasterHueRotation = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
+ @"Setting rasterHueRotation to a function should update raster-hue-rotate.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, styleValue,
+ @"rasterHueRotation should round-trip functions.");
+
+ layer.rasterHueRotation = nil;
+ XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
+ @"Unsetting rasterHueRotation should return raster-hue-rotate to the default value.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, defaultStyleValue,
+ @"rasterHueRotation should return the default value after being unset.");
+ }
+
+ // raster-opacity
+ {
+ XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
+ @"raster-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
+ @"Setting rasterOpacity to a constant value should update raster-opacity.");
+ XCTAssertEqualObjects(layer.rasterOpacity, styleValue,
+ @"rasterOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.rasterOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
+ @"Setting rasterOpacity to a function should update raster-opacity.");
+ XCTAssertEqualObjects(layer.rasterOpacity, styleValue,
+ @"rasterOpacity should round-trip functions.");
+
+ layer.rasterOpacity = nil;
+ XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
+ @"Unsetting rasterOpacity should return raster-opacity to the default value.");
+ XCTAssertEqualObjects(layer.rasterOpacity, defaultStyleValue,
+ @"rasterOpacity should return the default value after being unset.");
+ }
+
+ // raster-saturation
+ {
+ XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
+ @"raster-saturation should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterSaturation;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterSaturation = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
+ @"Setting rasterSaturation to a constant value should update raster-saturation.");
+ XCTAssertEqualObjects(layer.rasterSaturation, styleValue,
+ @"rasterSaturation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.rasterSaturation = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
+ @"Setting rasterSaturation to a function should update raster-saturation.");
+ XCTAssertEqualObjects(layer.rasterSaturation, styleValue,
+ @"rasterSaturation should round-trip functions.");
+
+ layer.rasterSaturation = nil;
+ XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
+ @"Unsetting rasterSaturation should return raster-saturation to the default value.");
+ XCTAssertEqualObjects(layer.rasterSaturation, defaultStyleValue,
+ @"rasterSaturation should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"maximum-raster-brightness" isBoolean:NO];
+ [self testPropertyName:@"minimum-raster-brightness" isBoolean:NO];
+ [self testPropertyName:@"raster-contrast" isBoolean:NO];
+ [self testPropertyName:@"raster-fade-duration" isBoolean:NO];
+ [self testPropertyName:@"raster-hue-rotation" isBoolean:NO];
+ [self testPropertyName:@"raster-opacity" isBoolean:NO];
+ [self testPropertyName:@"raster-saturation" isBoolean:NO];
+}
+
+@end
diff --git a/platform/darwin/test/MGLRuntimeStylingHelper.h b/platform/darwin/test/MGLRuntimeStylingHelper.h
deleted file mode 100644
index 8857dba9c5..0000000000
--- a/platform/darwin/test/MGLRuntimeStylingHelper.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#import <Foundation/Foundation.h>
-
-#import "MGLTypes.h"
-#import "MGLStyleValue.h"
-
-@interface MGLRuntimeStylingHelper : NSObject
-
-+ (MGLStyleConstantValue<NSValue *> *)testPadding;
-+ (MGLStyleFunction<NSValue *> *)testPaddingFunction;
-
-+ (MGLStyleConstantValue<NSValue *> *)testOffset;
-+ (MGLStyleFunction<NSValue *> *)testOffsetFunction;
-
-+ (MGLStyleConstantValue<NSArray<NSString *> *> *)testFont;
-+ (MGLStyleFunction<NSArray<NSString *> *> *)testFontFunction;
-
-+ (MGLStyleConstantValue<NSArray<NSNumber *> *> *)testDashArray;
-+ (MGLStyleFunction<NSArray<NSNumber *> *> *)testDashArrayFunction;
-
-+ (MGLStyleConstantValue<NSNumber *> *)testNumber;
-+ (MGLStyleFunction<NSNumber *> *)testNumberFunction;
-
-+ (MGLStyleConstantValue<NSNumber *> *)testBool;
-+ (MGLStyleFunction<NSNumber *> *)testBoolFunction;
-
-+ (MGLStyleConstantValue<NSString *> *)testString;
-+ (MGLStyleFunction<NSString *> *)testStringFunction;
-
-+ (MGLStyleConstantValue<MGLColor *> *)testColor;
-+ (MGLStyleFunction<MGLColor *> *)testColorFunction;
-
-+ (MGLStyleConstantValue<NSValue *> *)testEnum:(NSUInteger)value type:(const char *)type;
-+ (MGLStyleFunction<NSValue *> *)testEnumFunction:(NSUInteger)value type:(const char *)type;
-
-@end
diff --git a/platform/darwin/test/MGLRuntimeStylingHelper.m b/platform/darwin/test/MGLRuntimeStylingHelper.m
deleted file mode 100644
index 955c664f2c..0000000000
--- a/platform/darwin/test/MGLRuntimeStylingHelper.m
+++ /dev/null
@@ -1,122 +0,0 @@
-#import "MGLRuntimeStylingHelper.h"
-
-#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- #import <UIKit/UIKit.h>
- #define MGLEdgeInsets UIEdgeInsets
-#else
- #import <Cocoa/Cocoa.h>
- #define MGLEdgeInsets NSEdgeInsets
-#endif
-
-@implementation MGLRuntimeStylingHelper
-
-+ (MGLStyleConstantValue<NSValue *> *)testPadding
-{
- MGLEdgeInsets insets = {
- .top = 1,
- .left = 1,
- .bottom = 1,
- .right = 1,
- };
- return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&insets withObjCType:@encode(MGLEdgeInsets)]];
-}
-
-+ (MGLStyleFunction<NSValue *> *)testPaddingFunction
-{
- return [MGLStyleFunction<NSValue *> functionWithStops:@{@(18): self.testPadding}];
-}
-
-+ (MGLStyleConstantValue<NSValue *> *)testOffset
-{
- CGVector vector = CGVectorMake(1, 1);
- return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&vector withObjCType:@encode(CGVector)]];
-}
-
-+ (MGLStyleFunction<NSValue *> *)testOffsetFunction
-{
- return [MGLStyleFunction<NSValue *> valueWithStops:@{ @(18): self.testOffset }];
-}
-
-+ (MGLStyleConstantValue<NSArray<NSString *> *> *)testFont
-{
- return [MGLStyleConstantValue<NSArray<NSString *> *> valueWithRawValue:@[@"Open Sans Regular", @"Arial Unicode MS Regular"]];
-}
-
-+ (MGLStyleFunction<NSArray<NSString *> *> *)testFontFunction
-{
- return [MGLStyleFunction<NSArray<NSString *> *> valueWithStops:@{ @18: self.testFont }];
-}
-
-+ (MGLStyleConstantValue<NSArray<NSNumber *> *> *)testDashArray
-{
- return [MGLStyleConstantValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
-}
-
-+ (MGLStyleFunction<NSArray<NSNumber *> *> *)testDashArrayFunction
-{
- return [MGLStyleFunction<NSArray<NSNumber *> *> valueWithStops:@{
- @18: self.testDashArray,
- }];
-}
-
-+ (MGLStyleConstantValue<NSNumber *> *)testNumber
-{
- return [MGLStyleConstantValue<NSNumber *> valueWithRawValue:@1];
-}
-
-+ (MGLStyleFunction<NSNumber *> *)testNumberFunction
-{
- return [MGLStyleFunction<NSNumber *> valueWithStops:@{
- @18: self.testNumber,
- }];
-}
-
-+ (MGLStyleConstantValue<NSNumber *> *)testBool
-{
- return [MGLStyleConstantValue<NSNumber *> valueWithRawValue:@YES];
-}
-
-+ (MGLStyleFunction<NSNumber *> *)testBoolFunction
-{
- return [MGLStyleFunction<NSNumber *> valueWithStops:@{
- @18: self.testBool,
- }];
-}
-
-+ (MGLStyleConstantValue<NSString *> *)testString
-{
- return [MGLStyleConstantValue<NSString *> valueWithRawValue:@"test"];
-}
-
-+ (MGLStyleFunction<NSString *> *)testStringFunction
-{
- return [MGLStyleFunction<NSString *> valueWithStops:@{
- @18: self.testString,
- }];
-}
-
-+ (MGLStyleConstantValue<MGLColor *> *)testColor
-{
- return [MGLStyleConstantValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
-}
-
-+ (MGLStyleFunction<MGLColor *> *)testColorFunction
-{
- return [MGLStyleFunction<MGLColor *> valueWithStops:@{
- @18: self.testColor,
- }];
-}
-
-+ (MGLStyleConstantValue<NSValue *> *)testEnum:(NSUInteger)value type:(const char *)type
-{
- return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&value withObjCType:type]];
-}
-
-+ (MGLStyleFunction<NSValue *> *)testEnumFunction:(NSUInteger)value type:(const char *)type
-{
- return [MGLStyleFunction<NSValue *> valueWithStops:@{
- @18: [self testEnum:value type:type],
- }];
-}
-
-@end
diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm
index efff4b393e..cf32b5c821 100644
--- a/platform/darwin/test/MGLShapeSourceTests.mm
+++ b/platform/darwin/test/MGLShapeSourceTests.mm
@@ -37,6 +37,19 @@
XCTAssertNil(source.shape);
}
+- (void)testUnclusterableShape {
+ NSDictionary *options = @{
+ MGLShapeSourceOptionClustered: @YES,
+ };
+
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:[[MGLPointFeature alloc] init] options:options];
+ XCTAssertTrue([source.shape isKindOfClass:[MGLPointFeature class]]);
+
+ MGLShapeCollectionFeature *feature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]];
+ source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:feature options:options];
+ XCTAssertTrue([source.shape isKindOfClass:[MGLShapeCollectionFeature class]]);
+}
+
- (void)testMGLShapeSourceWithDataMultipleFeatures {
NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}";
@@ -265,4 +278,43 @@
XCTAssert(shape.shapes.count == 6, @"Shape collection should contain 6 shapes");
}
+- (void)testMGLShapeSourceWithFeaturesConvenienceInitializer {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 0.0)};
+
+ MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil];
+ MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
+
+ XCTAssertTrue([shape isKindOfClass:[MGLShapeCollectionFeature class]]);
+ XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape");
+
+ // when a shape is included in the features array
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ XCTAssertThrowsSpecificNamed([[MGLShapeSource alloc] initWithIdentifier:@"source-id-invalid" features:@[polygon] options:nil], NSException, NSInvalidArgumentException, @"Shape source should raise an exception if a shape is sent to the features initializer");
+}
+
+- (void)testMGLShapeSourceWithShapesConvenienceInitializer {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 0.0)};
+
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shapes:@[polygon] options:nil];
+ MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
+
+ XCTAssertTrue([shape isKindOfClass:[MGLShapeCollection class]]);
+ XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape");
+}
+
@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.h b/platform/darwin/test/MGLStyleLayerTests.h
index 74ce62e894..f0b889f022 100644
--- a/platform/darwin/test/MGLStyleLayerTests.h
+++ b/platform/darwin/test/MGLStyleLayerTests.h
@@ -1,11 +1,8 @@
#import <Mapbox/Mapbox.h>
-#import "MGLRuntimeStylingHelper.h"
#import <XCTest/XCTest.h>
@interface MGLStyleLayerTests : XCTestCase <MGLMapViewDelegate>
-@property (nonatomic) IBOutlet MGLMapView *mapView;
-@property (nonatomic) XCTestExpectation *expectation;
@property (nonatomic, copy, readonly, class) NSString *layerType;
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean;
@@ -18,3 +15,11 @@
@property (nonatomic, readonly, copy) NSString *lemma;
@end
+
+@interface NSValue (MGLStyleLayerTestAdditions)
+
++ (instancetype)valueWithMGLVector:(CGVector)vector;
+
+@property (readonly) CGVector MGLVectorValue;
+
+@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m
index 590d6eda7f..1dba9f4305 100644
--- a/platform/darwin/test/MGLStyleLayerTests.m
+++ b/platform/darwin/test/MGLStyleLayerTests.m
@@ -8,21 +8,28 @@
@dynamic layerType;
-- (void)setUp {
- [super setUp];
-#if TARGET_OS_IPHONE
- UIApplication *app = [UIApplication sharedApplication];
- UIViewController *vc = [[UIViewController alloc] init];
- app.keyWindow.rootViewController = vc;
- [vc view]; // Force load xib
- _mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 256, 256)];
- [vc.view addSubview:_mapView];
- _mapView.delegate = self;
-#else
- [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
- NSWindowController *windowController = [[NSWindowController alloc] initWithWindowNibName:@"MGLStyleLayerTests" owner:self];
- [windowController showWindow:nil];
-#endif
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertEqualObjects(layer.identifier, @"layerID");
+ XCTAssertEqualObjects(layer.sourceIdentifier, source.identifier);
+
+ XCTAssertTrue(layer.visible);
+ layer.visible = NO;
+ XCTAssertFalse(layer.visible);
+ layer.visible = YES;
+ XCTAssertTrue(layer.visible);
+
+ XCTAssertEqual(layer.minimumZoomLevel, -INFINITY);
+ layer.minimumZoomLevel = 22;
+ XCTAssertEqual(layer.minimumZoomLevel, 22);
+
+ XCTAssertEqual(layer.maximumZoomLevel, INFINITY);
+ layer.maximumZoomLevel = 0;
+ XCTAssertEqual(layer.maximumZoomLevel, 0);
}
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean {
@@ -87,3 +94,25 @@
}
@end
+
+@implementation NSValue (MGLStyleLayerTestAdditions)
+
++ (instancetype)valueWithMGLVector:(CGVector)vector {
+#if TARGET_OS_IPHONE
+ return [self valueWithCGVector:vector];
+#else
+ return [self value:&vector withObjCType:@encode(CGVector)];
+#endif
+}
+
+- (CGVector)MGLVectorValue {
+#if TARGET_OS_IPHONE
+ return self.CGVectorValue;
+#else
+ CGVector vector;
+ [self getValue:&vector];
+ return vector;
+#endif
+}
+
+@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.m.ejs b/platform/darwin/test/MGLStyleLayerTests.m.ejs
deleted file mode 100644
index 6b7bfe2f1c..0000000000
--- a/platform/darwin/test/MGLStyleLayerTests.m.ejs
+++ /dev/null
@@ -1,72 +0,0 @@
-<%
- const type = locals.type;
- const layoutProperties = locals.layoutProperties;
- const paintProperties = locals.paintProperties;
--%>
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGL<%- camelize(type) %>LayerTests
-
-+ (NSString *)layerType {
- return @"<%- type %>";
-}
-
-- (void)test<%- camelize(type) %>Layer {
-<% if (type === 'background') { -%>
- MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"];
-<% } else { -%>
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-<% } -%>
- [self.mapView.style addLayer:layer];
-
-<% for (const property of layoutProperties) { -%>
- <%- testImplementation(property, type) %>
-<% } -%>
-<% for (const property of paintProperties) { -%>
- <%- testImplementation(property, type) %>
-<% } -%>
-
- MGL<%- camelize(type) %>StyleLayer *gLayer = (MGL<%- camelize(type) %>StyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGL<%- camelize(type) %>StyleLayer class]]);
-<% for (const property of layoutProperties) { -%>
- <%- testGetterImplementation(property, type) %>
-<% } -%>
-<% for (const property of paintProperties) { -%>
- <%- testGetterImplementation(property, type) %>
-<% } -%>
-
-<% for (const property of layoutProperties) { -%>
- <%- testImplementation(property, type, true) %>
-<% } -%>
-<% for (const property of paintProperties) { -%>
- <%- testImplementation(property, type, true) %>
-<% } -%>
-
-<% for (const property of layoutProperties) { -%>
- <%- testGetterImplementation(property, type, true) %>
-<% } -%>
-<% for (const property of paintProperties) { -%>
- <%- testGetterImplementation(property, type, true) %>
-<% } -%>
-}
-
-- (void)testPropertyNames {
-<% for (const property of layoutProperties) { -%>
- [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
-<% } -%>
-<% for (const property of paintProperties) { -%>
- [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
-<% } -%>
-}
-
-@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
new file mode 100644
index 0000000000..00842a5b4e
--- /dev/null
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -0,0 +1,114 @@
+<%
+ const type = locals.type;
+ const properties = locals.properties;
+ const enumProperties = locals.enumProperties;
+-%>
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/<%- type %>_layer.hpp>
+
+@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGL<%- camelize(type) %>LayerTests
+
++ (NSString *)layerType {
+ return @"<%- type %>";
+}
+
+<% if (type !== 'background' && type !== 'raster') { -%>
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+<% } -%>
+- (void)testProperties {
+<% if (type === 'background') { -%>
+ MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"];
+<% } else { -%>
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+<% } -%>
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::<%- camelize(type) %>Layer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::<%- camelize(type) %>Layer>();
+<% for (const property of properties) { -%>
+
+ // <%- originalPropertyName(property) %>
+ {
+ XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
+ @"<%- originalPropertyName(property) %> should be unset initially.");
+ MGLStyleValue<<%- propertyType(property) %>> *defaultStyleValue = layer.<%- objCName(property) %>;
+
+ MGLStyleValue<<%- propertyType(property) %>> *styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>];
+ layer.<%- objCName(property) %> = styleValue;
+ mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
+ XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
+ @"Setting <%- objCName(property) %> to a constant value should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue,
+ @"<%- objCName(property) %> should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.<%- objCName(property) %> = styleValue;
+ propertyValue = { mbgl::style::Function<<%- mbglType(property) %>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
+ @"Setting <%- objCName(property) %> to a function should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue,
+ @"<%- objCName(property) %> should round-trip functions.");
+<% if (!property.required) { -%>
+
+ layer.<%- objCName(property) %> = nil;
+ XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
+ @"Unsetting <%- objCName(property) %> should return <%- originalPropertyName(property) %> to the default value.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultStyleValue,
+ @"<%- objCName(property) %> should return the default value after being unset.");
+<% } -%>
+ }
+<% } -%>
+}
+
+- (void)testPropertyNames {
+<% for (const property of properties) { -%>
+ [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
+<% } -%>
+}
+
+<% if (enumProperties) { -%>
+- (void)testValueAdditions {
+<% for (let property of enumProperties) { -%>
+<% for (let value in property.values) { -%>
+<% if (property.values.hasOwnProperty(value)) { -%>
+ XCTAssertEqual([NSValue valueWithMGL<%- camelize(property.name) %>:MGL<%- camelize(property.name) %><%- camelize(value) %>].MGL<%- camelize(property.name) %>Value, MGL<%- camelize(property.name) %><%- camelize(value) %>);
+<% } -%>
+<% } -%>
+<% } -%>
+}
+
+<% } -%>
+@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.xib b/platform/darwin/test/MGLStyleLayerTests.xib
deleted file mode 100644
index 23ad22e7e3..0000000000
--- a/platform/darwin/test/MGLStyleLayerTests.xib
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A304a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
- <dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
- </dependencies>
- <objects>
- <customObject id="-2" userLabel="File's Owner" customClass="MGLStyleLayerTests">
- <connections>
- <outlet property="mapView" destination="6RL-d9-juy" id="0ch-aR-Um6"/>
- </connections>
- </customObject>
- <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
- <customObject id="-3" userLabel="Application" customClass="NSObject"/>
- <window title="MGLStyleLayerTests" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
- <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="196" y="240" width="256" height="256"/>
- <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1058"/>
- <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
- <rect key="frame" x="0.0" y="0.0" width="256" height="256"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="6RL-d9-juy" customClass="MGLMapView">
- <rect key="frame" x="0.0" y="0.0" width="256" height="256"/>
- <connections>
- <outlet property="delegate" destination="-2" id="6kS-ct-JEg"/>
- </connections>
- </customView>
- </subviews>
- <constraints>
- <constraint firstItem="6RL-d9-juy" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="KEN-aL-UF0"/>
- <constraint firstAttribute="bottom" secondItem="6RL-d9-juy" secondAttribute="bottom" id="V27-f3-xHZ"/>
- <constraint firstAttribute="trailing" secondItem="6RL-d9-juy" secondAttribute="trailing" id="vjq-iM-OyA"/>
- <constraint firstItem="6RL-d9-juy" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="yWg-v4-wJB"/>
- </constraints>
- </view>
- </window>
- </objects>
-</document>
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index e9ba4a9afa..176217619d 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -1,17 +1,4 @@
-#import "MGLMapView.h"
-#import "MGLStyle_Private.h"
-
-#import "MGLShapeSource.h"
-#import "MGLRasterSource.h"
-#import "MGLVectorSource.h"
-
-#import "MGLBackgroundStyleLayer.h"
-#import "MGLCircleStyleLayer.h"
-#import "MGLFillStyleLayer.h"
-#import "MGLLineStyleLayer.h"
-#import "MGLOpenGLStyleLayer.h"
-#import "MGLRasterStyleLayer.h"
-#import "MGLSymbolStyleLayer.h"
+#import <Mapbox/Mapbox.h>
#import "NSBundle+MGLAdditions.h"
@@ -25,20 +12,46 @@
#endif
#import <objc/runtime.h>
-@interface MGLStyleTests : XCTestCase
+@interface MGLStyleTests : XCTestCase <MGLMapViewDelegate>
@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) MGLStyle *style;
@end
-@implementation MGLStyleTests
+@implementation MGLStyleTests {
+ XCTestExpectation *_styleLoadingExpectation;
+}
- (void)setUp {
[super setUp];
+
+ [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
+ NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
+ self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) styleURL:styleURL];
+ self.mapView.delegate = self;
+ if (!self.mapView.style) {
+ _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."];
+ [self waitForExpectationsWithTimeout:1 handler:nil];
+ }
+}
- self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- self.style = [[MGLStyle alloc] initWithMapView:self.mapView];
+- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
+ XCTAssertNotNil(mapView.style);
+ XCTAssertEqual(mapView.style, style);
+
+ [_styleLoadingExpectation fulfill];
+}
+
+- (void)tearDown {
+ _styleLoadingExpectation = nil;
+ self.mapView = nil;
+
+ [super tearDown];
+}
+
+- (MGLStyle *)style {
+ return self.mapView.style;
}
- (void)testUnversionedStyleURLs {
@@ -121,6 +134,24 @@
}];
}
+- (void)testName {
+ XCTAssertNil(self.style.name);
+}
+
+- (void)testSources {
+ NSSet<MGLSource *> *initialSources = self.style.sources;
+ if ([initialSources.anyObject.identifier isEqualToString:@"com.mapbox.annotations"]) {
+ XCTAssertEqual(self.style.sources.count, 1);
+ } else {
+ XCTAssertEqual(self.style.sources.count, 0);
+ }
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
+ [self.style addSource:shapeSource];
+ XCTAssertEqual(self.style.sources.count, initialSources.count + 1);
+ [self.style removeSource:shapeSource];
+ XCTAssertEqual(self.style.sources.count, initialSources.count);
+}
+
- (void)testAddingSourcesTwice {
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
[self.style addSource:shapeSource];
@@ -143,6 +174,22 @@
XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException");
}
+- (void)testLayers {
+ NSArray<MGLStyleLayer *> *initialLayers = self.style.layers;
+ if ([initialLayers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) {
+ XCTAssertEqual(self.style.layers.count, 1);
+ } else {
+ XCTAssertEqual(self.style.layers.count, 0);
+ }
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
+ [self.style addSource:shapeSource];
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:shapeSource];
+ [self.style addLayer:fillLayer];
+ XCTAssertEqual(self.style.layers.count, initialLayers.count + 1);
+ [self.style removeLayer:fillLayer];
+ XCTAssertEqual(self.style.layers.count, initialLayers.count);
+}
+
- (void)testAddingLayersTwice {
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
@@ -174,18 +221,18 @@
- (void)testAddingLayersWithDuplicateIdentifiers {
//Just some source
MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
- [self.mapView.style addSource: source];
+ [self.style addSource: source];
//Add initial layer
MGLFillStyleLayer *initial = [[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source];
- [self.mapView.style addLayer:initial];
+ [self.style addLayer:initial];
//Try to add the duplicate
- XCTAssertThrowsSpecificNamed([self.mapView.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException");
- XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException");
- XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException");
- XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
- XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
+ XCTAssertThrowsSpecificNamed([self.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException");
+ XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException");
+ XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException");
+ XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
+ XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
}
- (NSString *)stringWithContentsOfStyleHeader {
@@ -198,6 +245,10 @@
return styleHeader;
}
+- (void)testClasses {
+ XCTAssertEqual(self.style.styleClasses.count, 0);
+}
+
- (void)testImages {
NSString *imageName = @"TrackingLocationMask";
#if TARGET_OS_IPHONE
@@ -209,12 +260,46 @@
#endif
XCTAssertNotNil(image);
- [self.mapView.style setImage:image forName:imageName];
- MGLImage *styleImage = [self.mapView.style imageForName:imageName];
+ [self.style setImage:image forName:imageName];
+ MGLImage *styleImage = [self.style imageForName:imageName];
XCTAssertNotNil(styleImage);
XCTAssertEqual(image.size.width, styleImage.size.width);
XCTAssertEqual(image.size.height, styleImage.size.height);
}
+- (void)testLayersOrder {
+ NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
+ NSURL *url = [NSURL fileURLWithPath:filePath];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
+ [self.style addSource:source];
+
+ MGLCircleStyleLayer *layer1 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer1" source:source];
+ [self.style addLayer:layer1];
+
+ MGLCircleStyleLayer *layer3 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer3" source:source];
+ [self.style addLayer:layer3];
+
+ MGLCircleStyleLayer *layer2 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer2" source:source];
+ [self.style insertLayer:layer2 aboveLayer:layer1];
+
+ MGLCircleStyleLayer *layer4 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer4" source:source];
+ [self.style insertLayer:layer4 aboveLayer:layer3];
+
+ MGLCircleStyleLayer *layer0 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer0" source:source];
+ [self.style insertLayer:layer0 belowLayer:layer1];
+
+ NSArray<MGLStyleLayer *> *layers = [self.style layers];
+ NSUInteger startIndex = 0;
+ if ([layers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) {
+ startIndex++;
+ }
+
+ XCTAssertEqualObjects(layers[startIndex++].identifier, layer0.identifier);
+ XCTAssertEqualObjects(layers[startIndex++].identifier, layer1.identifier);
+ XCTAssertEqualObjects(layers[startIndex++].identifier, layer2.identifier);
+ XCTAssertEqualObjects(layers[startIndex++].identifier, layer3.identifier);
+ XCTAssertEqualObjects(layers[startIndex++].identifier, layer4.identifier);
+}
+
@end
diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift
index bf01435114..18b6a901de 100644
--- a/platform/darwin/test/MGLStyleValueTests.swift
+++ b/platform/darwin/test/MGLStyleValueTests.swift
@@ -17,8 +17,8 @@ extension MGLStyleValueTests {
XCTAssertEqual((symbolStyleLayer.iconHaloWidth as! MGLStyleConstantValue<NSNumber>).rawValue, 3)
// String
- symbolStyleLayer.textField = MGLStyleConstantValue(rawValue: "{name}")
- XCTAssertEqual((symbolStyleLayer.textField as! MGLStyleConstantValue<NSString>).rawValue, "{name}")
+ symbolStyleLayer.text = MGLStyleConstantValue(rawValue: "{name}")
+ XCTAssertEqual((symbolStyleLayer.text as! MGLStyleConstantValue<NSString>).rawValue, "{name}")
}
func testFunctions() {
@@ -32,7 +32,7 @@ extension MGLStyleValueTests {
3: MGLStyleValue(rawValue: true),
4: MGLStyleValue(rawValue: false),
]
- symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction<NSNumber>(base: 1, stops: stops)
- XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction<NSNumber>), MGLStyleFunction(base: 1, stops: stops))
+ symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction<NSNumber>(interpolationBase: 1, stops: stops)
+ XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction<NSNumber>), MGLStyleFunction(interpolationBase: 1, stops: stops))
}
}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.m b/platform/darwin/test/MGLSymbolStyleLayerTests.m
deleted file mode 100644
index 40250a8c72..0000000000
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.m
+++ /dev/null
@@ -1,283 +0,0 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
-
-#import "MGLStyleLayerTests.h"
-
-@interface MGLSymbolLayerTests : MGLStyleLayerTests
-@end
-
-@implementation MGLSymbolLayerTests
-
-+ (NSString *)layerType {
- return @"symbol";
-}
-
-- (void)testSymbolLayer {
- NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
- [self.mapView.style addSource:source];
- MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
- [self.mapView.style addLayer:layer];
-
- layer.iconAllowsOverlap = [MGLRuntimeStylingHelper testBool];
- layer.iconIgnoresPlacement = [MGLRuntimeStylingHelper testBool];
- layer.iconImageName = [MGLRuntimeStylingHelper testString];
- layer.iconOffset = [MGLRuntimeStylingHelper testOffset];
- layer.iconOptional = [MGLRuntimeStylingHelper testBool];
- layer.iconPadding = [MGLRuntimeStylingHelper testNumber];
- layer.iconRotation = [MGLRuntimeStylingHelper testNumber];
- layer.iconRotationAlignment = [MGLRuntimeStylingHelper testEnum:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)];
- layer.iconScale = [MGLRuntimeStylingHelper testNumber];
- layer.iconTextFit = [MGLRuntimeStylingHelper testEnum:MGLIconTextFitBoth type:@encode(MGLIconTextFit)];
- layer.iconTextFitPadding = [MGLRuntimeStylingHelper testPadding];
- layer.keepsIconUpright = [MGLRuntimeStylingHelper testBool];
- layer.keepsTextUpright = [MGLRuntimeStylingHelper testBool];
- layer.maximumTextAngle = [MGLRuntimeStylingHelper testNumber];
- layer.maximumTextWidth = [MGLRuntimeStylingHelper testNumber];
- layer.symbolAvoidsEdges = [MGLRuntimeStylingHelper testBool];
- layer.symbolPlacement = [MGLRuntimeStylingHelper testEnum:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)];
- layer.symbolSpacing = [MGLRuntimeStylingHelper testNumber];
- layer.textAllowsOverlap = [MGLRuntimeStylingHelper testBool];
- layer.textAnchor = [MGLRuntimeStylingHelper testEnum:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)];
- layer.textField = [MGLRuntimeStylingHelper testString];
- layer.textFont = [MGLRuntimeStylingHelper testFont];
- layer.textIgnoresPlacement = [MGLRuntimeStylingHelper testBool];
- layer.textJustification = [MGLRuntimeStylingHelper testEnum:MGLTextJustificationRight type:@encode(MGLTextJustification)];
- layer.textLetterSpacing = [MGLRuntimeStylingHelper testNumber];
- layer.textLineHeight = [MGLRuntimeStylingHelper testNumber];
- layer.textOffset = [MGLRuntimeStylingHelper testOffset];
- layer.textOptional = [MGLRuntimeStylingHelper testBool];
- layer.textPadding = [MGLRuntimeStylingHelper testNumber];
- layer.textPitchAlignment = [MGLRuntimeStylingHelper testEnum:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)];
- layer.textRotation = [MGLRuntimeStylingHelper testNumber];
- layer.textRotationAlignment = [MGLRuntimeStylingHelper testEnum:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)];
- layer.textSize = [MGLRuntimeStylingHelper testNumber];
- layer.textTransform = [MGLRuntimeStylingHelper testEnum:MGLTextTransformLowercase type:@encode(MGLTextTransform)];
- layer.iconColor = [MGLRuntimeStylingHelper testColor];
- layer.iconHaloBlur = [MGLRuntimeStylingHelper testNumber];
- layer.iconHaloColor = [MGLRuntimeStylingHelper testColor];
- layer.iconHaloWidth = [MGLRuntimeStylingHelper testNumber];
- layer.iconOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.iconTranslate = [MGLRuntimeStylingHelper testOffset];
- layer.iconTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)];
- layer.textColor = [MGLRuntimeStylingHelper testColor];
- layer.textHaloBlur = [MGLRuntimeStylingHelper testNumber];
- layer.textHaloColor = [MGLRuntimeStylingHelper testColor];
- layer.textHaloWidth = [MGLRuntimeStylingHelper testNumber];
- layer.textOpacity = [MGLRuntimeStylingHelper testNumber];
- layer.textTranslate = [MGLRuntimeStylingHelper testOffset];
- layer.textTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)];
-
- MGLSymbolStyleLayer *gLayer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"];
- XCTAssertTrue([gLayer isKindOfClass:[MGLSymbolStyleLayer class]]);
- XCTAssertEqualObjects(gLayer.iconAllowsOverlap, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.iconIgnoresPlacement, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.iconImageName, [MGLRuntimeStylingHelper testString]);
- XCTAssertEqualObjects(gLayer.iconOffset, [MGLRuntimeStylingHelper testOffset]);
- XCTAssertEqualObjects(gLayer.iconOptional, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.iconPadding, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.iconRotation, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.iconRotationAlignment isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.iconRotationAlignment, [MGLRuntimeStylingHelper testEnum:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]);
- XCTAssertEqualObjects(gLayer.iconScale, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.iconTextFit isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.iconTextFit, [MGLRuntimeStylingHelper testEnum:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]);
- XCTAssertEqualObjects(gLayer.iconTextFitPadding, [MGLRuntimeStylingHelper testPadding]);
- XCTAssertEqualObjects(gLayer.keepsIconUpright, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.keepsTextUpright, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.maximumTextAngle, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.maximumTextWidth, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.symbolAvoidsEdges, [MGLRuntimeStylingHelper testBool]);
- XCTAssert([gLayer.symbolPlacement isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.symbolPlacement, [MGLRuntimeStylingHelper testEnum:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]);
- XCTAssertEqualObjects(gLayer.symbolSpacing, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textAllowsOverlap, [MGLRuntimeStylingHelper testBool]);
- XCTAssert([gLayer.textAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textAnchor, [MGLRuntimeStylingHelper testEnum:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]);
- XCTAssertEqualObjects(gLayer.textField, [MGLRuntimeStylingHelper testString]);
- XCTAssertEqualObjects(gLayer.textFont, [MGLRuntimeStylingHelper testFont]);
- XCTAssertEqualObjects(gLayer.textIgnoresPlacement, [MGLRuntimeStylingHelper testBool]);
- XCTAssert([gLayer.textJustification isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textJustification, [MGLRuntimeStylingHelper testEnum:MGLTextJustificationRight type:@encode(MGLTextJustification)]);
- XCTAssertEqualObjects(gLayer.textLetterSpacing, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textLineHeight, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textOffset, [MGLRuntimeStylingHelper testOffset]);
- XCTAssertEqualObjects(gLayer.textOptional, [MGLRuntimeStylingHelper testBool]);
- XCTAssertEqualObjects(gLayer.textPadding, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.textPitchAlignment isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textPitchAlignment, [MGLRuntimeStylingHelper testEnum:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]);
- XCTAssertEqualObjects(gLayer.textRotation, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.textRotationAlignment isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textRotationAlignment, [MGLRuntimeStylingHelper testEnum:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]);
- XCTAssertEqualObjects(gLayer.textSize, [MGLRuntimeStylingHelper testNumber]);
- XCTAssert([gLayer.textTransform isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textTransform, [MGLRuntimeStylingHelper testEnum:MGLTextTransformLowercase type:@encode(MGLTextTransform)]);
- XCTAssertEqualObjects(gLayer.iconColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.iconHaloBlur, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.iconHaloColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.iconHaloWidth, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.iconOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.iconTranslate, [MGLRuntimeStylingHelper testOffset]);
- XCTAssert([gLayer.iconTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.iconTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]);
- XCTAssertEqualObjects(gLayer.textColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.textHaloBlur, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textHaloColor, [MGLRuntimeStylingHelper testColor]);
- XCTAssertEqualObjects(gLayer.textHaloWidth, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textOpacity, [MGLRuntimeStylingHelper testNumber]);
- XCTAssertEqualObjects(gLayer.textTranslate, [MGLRuntimeStylingHelper testOffset]);
- XCTAssert([gLayer.textTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]);
- XCTAssertEqualObjects(gLayer.textTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]);
-
- layer.iconAllowsOverlap = [MGLRuntimeStylingHelper testBoolFunction];
- layer.iconIgnoresPlacement = [MGLRuntimeStylingHelper testBoolFunction];
- layer.iconImageName = [MGLRuntimeStylingHelper testStringFunction];
- layer.iconOffset = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.iconOptional = [MGLRuntimeStylingHelper testBoolFunction];
- layer.iconPadding = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconRotation = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconRotationAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)];
- layer.iconScale = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconTextFit = [MGLRuntimeStylingHelper testEnumFunction:MGLIconTextFitBoth type:@encode(MGLIconTextFit)];
- layer.iconTextFitPadding = [MGLRuntimeStylingHelper testPaddingFunction];
- layer.keepsIconUpright = [MGLRuntimeStylingHelper testBoolFunction];
- layer.keepsTextUpright = [MGLRuntimeStylingHelper testBoolFunction];
- layer.maximumTextAngle = [MGLRuntimeStylingHelper testNumberFunction];
- layer.maximumTextWidth = [MGLRuntimeStylingHelper testNumberFunction];
- layer.symbolAvoidsEdges = [MGLRuntimeStylingHelper testBoolFunction];
- layer.symbolPlacement = [MGLRuntimeStylingHelper testEnumFunction:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)];
- layer.symbolSpacing = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textAllowsOverlap = [MGLRuntimeStylingHelper testBoolFunction];
- layer.textAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)];
- layer.textField = [MGLRuntimeStylingHelper testStringFunction];
- layer.textFont = [MGLRuntimeStylingHelper testFontFunction];
- layer.textIgnoresPlacement = [MGLRuntimeStylingHelper testBoolFunction];
- layer.textJustification = [MGLRuntimeStylingHelper testEnumFunction:MGLTextJustificationRight type:@encode(MGLTextJustification)];
- layer.textLetterSpacing = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textLineHeight = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textOffset = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.textOptional = [MGLRuntimeStylingHelper testBoolFunction];
- layer.textPadding = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textPitchAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)];
- layer.textRotation = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textRotationAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)];
- layer.textSize = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textTransform = [MGLRuntimeStylingHelper testEnumFunction:MGLTextTransformLowercase type:@encode(MGLTextTransform)];
- layer.iconColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.iconHaloBlur = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconHaloColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.iconHaloWidth = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.iconTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.iconTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)];
- layer.textColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.textHaloBlur = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textHaloColor = [MGLRuntimeStylingHelper testColorFunction];
- layer.textHaloWidth = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textOpacity = [MGLRuntimeStylingHelper testNumberFunction];
- layer.textTranslate = [MGLRuntimeStylingHelper testOffsetFunction];
- layer.textTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)];
-
- XCTAssertEqualObjects(gLayer.iconAllowsOverlap, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.iconIgnoresPlacement, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.iconImageName, [MGLRuntimeStylingHelper testStringFunction]);
- XCTAssertEqualObjects(gLayer.iconOffset, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.iconOptional, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.iconPadding, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconRotation, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconRotationAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]);
- XCTAssertEqualObjects(gLayer.iconScale, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconTextFit, [MGLRuntimeStylingHelper testEnumFunction:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]);
- XCTAssertEqualObjects(gLayer.iconTextFitPadding, [MGLRuntimeStylingHelper testPaddingFunction]);
- XCTAssertEqualObjects(gLayer.keepsIconUpright, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.keepsTextUpright, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.maximumTextAngle, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.maximumTextWidth, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.symbolAvoidsEdges, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.symbolPlacement, [MGLRuntimeStylingHelper testEnumFunction:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]);
- XCTAssertEqualObjects(gLayer.symbolSpacing, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textAllowsOverlap, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.textAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]);
- XCTAssertEqualObjects(gLayer.textField, [MGLRuntimeStylingHelper testStringFunction]);
- XCTAssertEqualObjects(gLayer.textFont, [MGLRuntimeStylingHelper testFontFunction]);
- XCTAssertEqualObjects(gLayer.textIgnoresPlacement, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.textJustification, [MGLRuntimeStylingHelper testEnumFunction:MGLTextJustificationRight type:@encode(MGLTextJustification)]);
- XCTAssertEqualObjects(gLayer.textLetterSpacing, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textLineHeight, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textOffset, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.textOptional, [MGLRuntimeStylingHelper testBoolFunction]);
- XCTAssertEqualObjects(gLayer.textPadding, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textPitchAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]);
- XCTAssertEqualObjects(gLayer.textRotation, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textRotationAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]);
- XCTAssertEqualObjects(gLayer.textSize, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textTransform, [MGLRuntimeStylingHelper testEnumFunction:MGLTextTransformLowercase type:@encode(MGLTextTransform)]);
- XCTAssertEqualObjects(gLayer.iconColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.iconHaloBlur, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconHaloColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.iconHaloWidth, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.iconTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.iconTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]);
- XCTAssertEqualObjects(gLayer.textColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.textHaloBlur, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textHaloColor, [MGLRuntimeStylingHelper testColorFunction]);
- XCTAssertEqualObjects(gLayer.textHaloWidth, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textOpacity, [MGLRuntimeStylingHelper testNumberFunction]);
- XCTAssertEqualObjects(gLayer.textTranslate, [MGLRuntimeStylingHelper testOffsetFunction]);
- XCTAssertEqualObjects(gLayer.textTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]);
-}
-
-- (void)testPropertyNames {
- [self testPropertyName:@"icon-allows-overlap" isBoolean:YES];
- [self testPropertyName:@"icon-ignores-placement" isBoolean:YES];
- [self testPropertyName:@"icon-image-name" isBoolean:NO];
- [self testPropertyName:@"icon-offset" isBoolean:NO];
- [self testPropertyName:@"is-icon-optional" isBoolean:YES];
- [self testPropertyName:@"icon-padding" isBoolean:NO];
- [self testPropertyName:@"icon-rotation" isBoolean:NO];
- [self testPropertyName:@"icon-rotation-alignment" isBoolean:NO];
- [self testPropertyName:@"icon-scale" isBoolean:NO];
- [self testPropertyName:@"icon-text-fit" isBoolean:NO];
- [self testPropertyName:@"icon-text-fit-padding" isBoolean:NO];
- [self testPropertyName:@"keeps-icon-upright" isBoolean:YES];
- [self testPropertyName:@"keeps-text-upright" isBoolean:YES];
- [self testPropertyName:@"maximum-text-angle" isBoolean:NO];
- [self testPropertyName:@"maximum-text-width" isBoolean:NO];
- [self testPropertyName:@"symbol-avoids-edges" isBoolean:YES];
- [self testPropertyName:@"symbol-placement" isBoolean:NO];
- [self testPropertyName:@"symbol-spacing" isBoolean:NO];
- [self testPropertyName:@"text-allows-overlap" isBoolean:YES];
- [self testPropertyName:@"text-anchor" isBoolean:NO];
- [self testPropertyName:@"text-field" isBoolean:NO];
- [self testPropertyName:@"text-font" isBoolean:NO];
- [self testPropertyName:@"text-ignores-placement" isBoolean:YES];
- [self testPropertyName:@"text-justification" isBoolean:NO];
- [self testPropertyName:@"text-letter-spacing" isBoolean:NO];
- [self testPropertyName:@"text-line-height" isBoolean:NO];
- [self testPropertyName:@"text-offset" isBoolean:NO];
- [self testPropertyName:@"is-text-optional" isBoolean:YES];
- [self testPropertyName:@"text-padding" isBoolean:NO];
- [self testPropertyName:@"text-pitch-alignment" isBoolean:NO];
- [self testPropertyName:@"text-rotation" isBoolean:NO];
- [self testPropertyName:@"text-rotation-alignment" isBoolean:NO];
- [self testPropertyName:@"text-size" isBoolean:NO];
- [self testPropertyName:@"text-transform" isBoolean:NO];
- [self testPropertyName:@"icon-color" isBoolean:NO];
- [self testPropertyName:@"icon-halo-blur" isBoolean:NO];
- [self testPropertyName:@"icon-halo-color" isBoolean:NO];
- [self testPropertyName:@"icon-halo-width" isBoolean:NO];
- [self testPropertyName:@"icon-opacity" isBoolean:NO];
- [self testPropertyName:@"icon-translate" isBoolean:NO];
- [self testPropertyName:@"icon-translate-anchor" isBoolean:NO];
- [self testPropertyName:@"text-color" isBoolean:NO];
- [self testPropertyName:@"text-halo-blur" isBoolean:NO];
- [self testPropertyName:@"text-halo-color" isBoolean:NO];
- [self testPropertyName:@"text-halo-width" isBoolean:NO];
- [self testPropertyName:@"text-opacity" isBoolean:NO];
- [self testPropertyName:@"text-translate" isBoolean:NO];
- [self testPropertyName:@"text-translate-anchor" isBoolean:NO];
-}
-
-@end
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
new file mode 100644
index 0000000000..80a9c9d3ec
--- /dev/null
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -0,0 +1,1797 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+
+#import "MGLStyleLayerTests.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/symbol_layer.hpp>
+
+@interface MGLSymbolLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLSymbolLayerTests
+
++ (NSString *)layerType {
+ return @"symbol";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::SymbolLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::SymbolLayer>();
+
+ // icon-allow-overlap
+ {
+ XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
+ @"icon-allow-overlap should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconAllowsOverlap;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconAllowsOverlap = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
+ @"Setting iconAllowsOverlap to a constant value should update icon-allow-overlap.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue,
+ @"iconAllowsOverlap should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconAllowsOverlap = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
+ @"Setting iconAllowsOverlap to a function should update icon-allow-overlap.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue,
+ @"iconAllowsOverlap should round-trip functions.");
+
+ layer.iconAllowsOverlap = nil;
+ XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
+ @"Unsetting iconAllowsOverlap should return icon-allow-overlap to the default value.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultStyleValue,
+ @"iconAllowsOverlap should return the default value after being unset.");
+ }
+
+ // icon-ignore-placement
+ {
+ XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
+ @"icon-ignore-placement should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconIgnoresPlacement;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconIgnoresPlacement = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
+ @"Setting iconIgnoresPlacement to a constant value should update icon-ignore-placement.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue,
+ @"iconIgnoresPlacement should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconIgnoresPlacement = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
+ @"Setting iconIgnoresPlacement to a function should update icon-ignore-placement.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue,
+ @"iconIgnoresPlacement should round-trip functions.");
+
+ layer.iconIgnoresPlacement = nil;
+ XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
+ @"Unsetting iconIgnoresPlacement should return icon-ignore-placement to the default value.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultStyleValue,
+ @"iconIgnoresPlacement should return the default value after being unset.");
+ }
+
+ // icon-image
+ {
+ XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
+ @"icon-image should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.iconImageName;
+
+ MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"];
+ layer.iconImageName = styleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Icon Image" };
+ XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
+ @"Setting iconImageName to a constant value should update icon-image.");
+ XCTAssertEqualObjects(layer.iconImageName, styleValue,
+ @"iconImageName should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconImageName = styleValue;
+ propertyValue = { mbgl::style::Function<std::string> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
+ @"Setting iconImageName to a function should update icon-image.");
+ XCTAssertEqualObjects(layer.iconImageName, styleValue,
+ @"iconImageName should round-trip functions.");
+
+ layer.iconImageName = nil;
+ XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
+ @"Unsetting iconImageName should return icon-image to the default value.");
+ XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue,
+ @"iconImageName should return the default value after being unset.");
+ }
+
+ // icon-offset
+ {
+ XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
+ @"icon-offset should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconOffset;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.iconOffset = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
+ @"Setting iconOffset to a constant value should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, styleValue,
+ @"iconOffset should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconOffset = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
+ @"Setting iconOffset to a function should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, styleValue,
+ @"iconOffset should round-trip functions.");
+
+ layer.iconOffset = nil;
+ XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
+ @"Unsetting iconOffset should return icon-offset to the default value.");
+ XCTAssertEqualObjects(layer.iconOffset, defaultStyleValue,
+ @"iconOffset should return the default value after being unset.");
+ }
+
+ // icon-optional
+ {
+ XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
+ @"icon-optional should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOptional;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconOptional = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
+ @"Setting iconOptional to a constant value should update icon-optional.");
+ XCTAssertEqualObjects(layer.iconOptional, styleValue,
+ @"iconOptional should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconOptional = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
+ @"Setting iconOptional to a function should update icon-optional.");
+ XCTAssertEqualObjects(layer.iconOptional, styleValue,
+ @"iconOptional should round-trip functions.");
+
+ layer.iconOptional = nil;
+ XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
+ @"Unsetting iconOptional should return icon-optional to the default value.");
+ XCTAssertEqualObjects(layer.iconOptional, defaultStyleValue,
+ @"iconOptional should return the default value after being unset.");
+ }
+
+ // icon-padding
+ {
+ XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
+ @"icon-padding should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconPadding;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconPadding = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
+ @"Setting iconPadding to a constant value should update icon-padding.");
+ XCTAssertEqualObjects(layer.iconPadding, styleValue,
+ @"iconPadding should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconPadding = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
+ @"Setting iconPadding to a function should update icon-padding.");
+ XCTAssertEqualObjects(layer.iconPadding, styleValue,
+ @"iconPadding should round-trip functions.");
+
+ layer.iconPadding = nil;
+ XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
+ @"Unsetting iconPadding should return icon-padding to the default value.");
+ XCTAssertEqualObjects(layer.iconPadding, defaultStyleValue,
+ @"iconPadding should return the default value after being unset.");
+ }
+
+ // icon-rotate
+ {
+ XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
+ @"icon-rotate should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconRotation;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconRotation = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
+ @"Setting iconRotation to a constant value should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, styleValue,
+ @"iconRotation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconRotation = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
+ @"Setting iconRotation to a function should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, styleValue,
+ @"iconRotation should round-trip functions.");
+
+ layer.iconRotation = nil;
+ XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
+ @"Unsetting iconRotation should return icon-rotate to the default value.");
+ XCTAssertEqualObjects(layer.iconRotation, defaultStyleValue,
+ @"iconRotation should return the default value after being unset.");
+ }
+
+ // icon-rotation-alignment
+ {
+ XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
+ @"icon-rotation-alignment should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconRotationAlignment;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]];
+ layer.iconRotationAlignment = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
+ XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
+ @"Setting iconRotationAlignment to a constant value should update icon-rotation-alignment.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue,
+ @"iconRotationAlignment should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconRotationAlignment = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
+ @"Setting iconRotationAlignment to a function should update icon-rotation-alignment.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue,
+ @"iconRotationAlignment should round-trip functions.");
+
+ layer.iconRotationAlignment = nil;
+ XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
+ @"Unsetting iconRotationAlignment should return icon-rotation-alignment to the default value.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, defaultStyleValue,
+ @"iconRotationAlignment should return the default value after being unset.");
+ }
+
+ // icon-size
+ {
+ XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
+ @"icon-size should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconScale;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconScale = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a constant value should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, styleValue,
+ @"iconScale should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconScale = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, styleValue,
+ @"iconScale should round-trip functions.");
+
+ layer.iconScale = nil;
+ XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
+ @"Unsetting iconScale should return icon-size to the default value.");
+ XCTAssertEqualObjects(layer.iconScale, defaultStyleValue,
+ @"iconScale should return the default value after being unset.");
+ }
+
+ // icon-text-fit
+ {
+ XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
+ @"icon-text-fit should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFit;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]];
+ layer.iconTextFit = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::IconTextFitType> propertyValue = { mbgl::style::IconTextFitType::Both };
+ XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
+ @"Setting iconTextFit to a constant value should update icon-text-fit.");
+ XCTAssertEqualObjects(layer.iconTextFit, styleValue,
+ @"iconTextFit should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconTextFit = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::IconTextFitType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
+ @"Setting iconTextFit to a function should update icon-text-fit.");
+ XCTAssertEqualObjects(layer.iconTextFit, styleValue,
+ @"iconTextFit should round-trip functions.");
+
+ layer.iconTextFit = nil;
+ XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
+ @"Unsetting iconTextFit should return icon-text-fit to the default value.");
+ XCTAssertEqualObjects(layer.iconTextFit, defaultStyleValue,
+ @"iconTextFit should return the default value after being unset.");
+ }
+
+ // icon-text-fit-padding
+ {
+ XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
+ @"icon-text-fit-padding should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFitPadding;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]
+#else
+ [NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]
+#endif
+ ];
+ layer.iconTextFitPadding = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 4>> propertyValue = { { 1, 1, 1, 1 } };
+ XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
+ @"Setting iconTextFitPadding to a constant value should update icon-text-fit-padding.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue,
+ @"iconTextFitPadding should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconTextFitPadding = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 4>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
+ @"Setting iconTextFitPadding to a function should update icon-text-fit-padding.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue,
+ @"iconTextFitPadding should round-trip functions.");
+
+ layer.iconTextFitPadding = nil;
+ XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
+ @"Unsetting iconTextFitPadding should return icon-text-fit-padding to the default value.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, defaultStyleValue,
+ @"iconTextFitPadding should return the default value after being unset.");
+ }
+
+ // icon-keep-upright
+ {
+ XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
+ @"icon-keep-upright should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsIconUpright;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.keepsIconUpright = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
+ @"Setting keepsIconUpright to a constant value should update icon-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, styleValue,
+ @"keepsIconUpright should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.keepsIconUpright = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
+ @"Setting keepsIconUpright to a function should update icon-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, styleValue,
+ @"keepsIconUpright should round-trip functions.");
+
+ layer.keepsIconUpright = nil;
+ XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
+ @"Unsetting keepsIconUpright should return icon-keep-upright to the default value.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, defaultStyleValue,
+ @"keepsIconUpright should return the default value after being unset.");
+ }
+
+ // text-keep-upright
+ {
+ XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
+ @"text-keep-upright should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsTextUpright;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
+ layer.keepsTextUpright = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { false };
+ XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
+ @"Setting keepsTextUpright to a constant value should update text-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, styleValue,
+ @"keepsTextUpright should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.keepsTextUpright = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
+ @"Setting keepsTextUpright to a function should update text-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, styleValue,
+ @"keepsTextUpright should round-trip functions.");
+
+ layer.keepsTextUpright = nil;
+ XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
+ @"Unsetting keepsTextUpright should return text-keep-upright to the default value.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, defaultStyleValue,
+ @"keepsTextUpright should return the default value after being unset.");
+ }
+
+ // text-max-angle
+ {
+ XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
+ @"text-max-angle should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextAngle;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumTextAngle = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
+ @"Setting maximumTextAngle to a constant value should update text-max-angle.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, styleValue,
+ @"maximumTextAngle should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.maximumTextAngle = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
+ @"Setting maximumTextAngle to a function should update text-max-angle.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, styleValue,
+ @"maximumTextAngle should round-trip functions.");
+
+ layer.maximumTextAngle = nil;
+ XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
+ @"Unsetting maximumTextAngle should return text-max-angle to the default value.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, defaultStyleValue,
+ @"maximumTextAngle should return the default value after being unset.");
+ }
+
+ // text-max-width
+ {
+ XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
+ @"text-max-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumTextWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
+ @"Setting maximumTextWidth to a constant value should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, styleValue,
+ @"maximumTextWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.maximumTextWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
+ @"Setting maximumTextWidth to a function should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, styleValue,
+ @"maximumTextWidth should round-trip functions.");
+
+ layer.maximumTextWidth = nil;
+ XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
+ @"Unsetting maximumTextWidth should return text-max-width to the default value.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, defaultStyleValue,
+ @"maximumTextWidth should return the default value after being unset.");
+ }
+
+ // symbol-avoid-edges
+ {
+ XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
+ @"symbol-avoid-edges should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolAvoidsEdges;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.symbolAvoidsEdges = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
+ @"Setting symbolAvoidsEdges to a constant value should update symbol-avoid-edges.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue,
+ @"symbolAvoidsEdges should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.symbolAvoidsEdges = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
+ @"Setting symbolAvoidsEdges to a function should update symbol-avoid-edges.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue,
+ @"symbolAvoidsEdges should round-trip functions.");
+
+ layer.symbolAvoidsEdges = nil;
+ XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
+ @"Unsetting symbolAvoidsEdges should return symbol-avoid-edges to the default value.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultStyleValue,
+ @"symbolAvoidsEdges should return the default value after being unset.");
+ }
+
+ // symbol-placement
+ {
+ XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
+ @"symbol-placement should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.symbolPlacement;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]];
+ layer.symbolPlacement = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::SymbolPlacementType> propertyValue = { mbgl::style::SymbolPlacementType::Line };
+ XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
+ @"Setting symbolPlacement to a constant value should update symbol-placement.");
+ XCTAssertEqualObjects(layer.symbolPlacement, styleValue,
+ @"symbolPlacement should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.symbolPlacement = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::SymbolPlacementType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
+ @"Setting symbolPlacement to a function should update symbol-placement.");
+ XCTAssertEqualObjects(layer.symbolPlacement, styleValue,
+ @"symbolPlacement should round-trip functions.");
+
+ layer.symbolPlacement = nil;
+ XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
+ @"Unsetting symbolPlacement should return symbol-placement to the default value.");
+ XCTAssertEqualObjects(layer.symbolPlacement, defaultStyleValue,
+ @"symbolPlacement should return the default value after being unset.");
+ }
+
+ // symbol-spacing
+ {
+ XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
+ @"symbol-spacing should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolSpacing;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.symbolSpacing = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
+ @"Setting symbolSpacing to a constant value should update symbol-spacing.");
+ XCTAssertEqualObjects(layer.symbolSpacing, styleValue,
+ @"symbolSpacing should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.symbolSpacing = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
+ @"Setting symbolSpacing to a function should update symbol-spacing.");
+ XCTAssertEqualObjects(layer.symbolSpacing, styleValue,
+ @"symbolSpacing should round-trip functions.");
+
+ layer.symbolSpacing = nil;
+ XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
+ @"Unsetting symbolSpacing should return symbol-spacing to the default value.");
+ XCTAssertEqualObjects(layer.symbolSpacing, defaultStyleValue,
+ @"symbolSpacing should return the default value after being unset.");
+ }
+
+ // text-field
+ {
+ XCTAssertTrue(rawLayer->getTextField().isUndefined(),
+ @"text-field should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.text;
+
+ MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Text Field"];
+ layer.text = styleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Text Field" };
+ XCTAssertEqual(rawLayer->getTextField(), propertyValue,
+ @"Setting text to a constant value should update text-field.");
+ XCTAssertEqualObjects(layer.text, styleValue,
+ @"text should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.text = styleValue;
+ propertyValue = { mbgl::style::Function<std::string> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextField(), propertyValue,
+ @"Setting text to a function should update text-field.");
+ XCTAssertEqualObjects(layer.text, styleValue,
+ @"text should round-trip functions.");
+
+ layer.text = nil;
+ XCTAssertTrue(rawLayer->getTextField().isUndefined(),
+ @"Unsetting text should return text-field to the default value.");
+ XCTAssertEqualObjects(layer.text, defaultStyleValue,
+ @"text should return the default value after being unset.");
+ }
+
+ // text-allow-overlap
+ {
+ XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
+ @"text-allow-overlap should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textAllowsOverlap;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textAllowsOverlap = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
+ @"Setting textAllowsOverlap to a constant value should update text-allow-overlap.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue,
+ @"textAllowsOverlap should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textAllowsOverlap = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
+ @"Setting textAllowsOverlap to a function should update text-allow-overlap.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue,
+ @"textAllowsOverlap should round-trip functions.");
+
+ layer.textAllowsOverlap = nil;
+ XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
+ @"Unsetting textAllowsOverlap should return text-allow-overlap to the default value.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, defaultStyleValue,
+ @"textAllowsOverlap should return the default value after being unset.");
+ }
+
+ // text-anchor
+ {
+ XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
+ @"text-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
+ layer.textAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight };
+ XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
+ @"Setting textAnchor to a constant value should update text-anchor.");
+ XCTAssertEqualObjects(layer.textAnchor, styleValue,
+ @"textAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TextAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
+ @"Setting textAnchor to a function should update text-anchor.");
+ XCTAssertEqualObjects(layer.textAnchor, styleValue,
+ @"textAnchor should round-trip functions.");
+
+ layer.textAnchor = nil;
+ XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
+ @"Unsetting textAnchor should return text-anchor to the default value.");
+ XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue,
+ @"textAnchor should return the default value after being unset.");
+ }
+
+ // text-font
+ {
+ XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
+ @"text-font should be unset initially.");
+ MGLStyleValue<NSArray<NSString *> *> *defaultStyleValue = layer.textFontNames;
+
+ MGLStyleValue<NSArray<NSString *> *> *styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]];
+ layer.textFontNames = styleValue;
+ mbgl::style::PropertyValue<std::vector<std::string>> propertyValue = { { "Text Font", "Tnof Txet" } };
+ XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
+ @"Setting textFontNames to a constant value should update text-font.");
+ XCTAssertEqualObjects(layer.textFontNames, styleValue,
+ @"textFontNames should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textFontNames = styleValue;
+ propertyValue = { mbgl::style::Function<std::vector<std::string>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
+ @"Setting textFontNames to a function should update text-font.");
+ XCTAssertEqualObjects(layer.textFontNames, styleValue,
+ @"textFontNames should round-trip functions.");
+
+ layer.textFontNames = nil;
+ XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
+ @"Unsetting textFontNames should return text-font to the default value.");
+ XCTAssertEqualObjects(layer.textFontNames, defaultStyleValue,
+ @"textFontNames should return the default value after being unset.");
+ }
+
+ // text-size
+ {
+ XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
+ @"text-size should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textFontSize;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textFontSize = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a constant value should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, styleValue,
+ @"textFontSize should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textFontSize = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, styleValue,
+ @"textFontSize should round-trip functions.");
+
+ layer.textFontSize = nil;
+ XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
+ @"Unsetting textFontSize should return text-size to the default value.");
+ XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue,
+ @"textFontSize should return the default value after being unset.");
+ }
+
+ // text-ignore-placement
+ {
+ XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
+ @"text-ignore-placement should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textIgnoresPlacement;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textIgnoresPlacement = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
+ @"Setting textIgnoresPlacement to a constant value should update text-ignore-placement.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue,
+ @"textIgnoresPlacement should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textIgnoresPlacement = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
+ @"Setting textIgnoresPlacement to a function should update text-ignore-placement.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue,
+ @"textIgnoresPlacement should round-trip functions.");
+
+ layer.textIgnoresPlacement = nil;
+ XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
+ @"Unsetting textIgnoresPlacement should return text-ignore-placement to the default value.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultStyleValue,
+ @"textIgnoresPlacement should return the default value after being unset.");
+ }
+
+ // text-justify
+ {
+ XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
+ @"text-justify should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textJustification;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]];
+ layer.textJustification = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right };
+ XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
+ @"Setting textJustification to a constant value should update text-justify.");
+ XCTAssertEqualObjects(layer.textJustification, styleValue,
+ @"textJustification should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textJustification = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TextJustifyType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
+ @"Setting textJustification to a function should update text-justify.");
+ XCTAssertEqualObjects(layer.textJustification, styleValue,
+ @"textJustification should round-trip functions.");
+
+ layer.textJustification = nil;
+ XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
+ @"Unsetting textJustification should return text-justify to the default value.");
+ XCTAssertEqualObjects(layer.textJustification, defaultStyleValue,
+ @"textJustification should return the default value after being unset.");
+ }
+
+ // text-letter-spacing
+ {
+ XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
+ @"text-letter-spacing should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLetterSpacing;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textLetterSpacing = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
+ @"Setting textLetterSpacing to a constant value should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, styleValue,
+ @"textLetterSpacing should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textLetterSpacing = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
+ @"Setting textLetterSpacing to a function should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, styleValue,
+ @"textLetterSpacing should round-trip functions.");
+
+ layer.textLetterSpacing = nil;
+ XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
+ @"Unsetting textLetterSpacing should return text-letter-spacing to the default value.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, defaultStyleValue,
+ @"textLetterSpacing should return the default value after being unset.");
+ }
+
+ // text-line-height
+ {
+ XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
+ @"text-line-height should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLineHeight;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textLineHeight = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
+ @"Setting textLineHeight to a constant value should update text-line-height.");
+ XCTAssertEqualObjects(layer.textLineHeight, styleValue,
+ @"textLineHeight should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textLineHeight = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
+ @"Setting textLineHeight to a function should update text-line-height.");
+ XCTAssertEqualObjects(layer.textLineHeight, styleValue,
+ @"textLineHeight should round-trip functions.");
+
+ layer.textLineHeight = nil;
+ XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
+ @"Unsetting textLineHeight should return text-line-height to the default value.");
+ XCTAssertEqualObjects(layer.textLineHeight, defaultStyleValue,
+ @"textLineHeight should return the default value after being unset.");
+ }
+
+ // text-offset
+ {
+ XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
+ @"text-offset should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textOffset;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.textOffset = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
+ @"Setting textOffset to a constant value should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, styleValue,
+ @"textOffset should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textOffset = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
+ @"Setting textOffset to a function should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, styleValue,
+ @"textOffset should round-trip functions.");
+
+ layer.textOffset = nil;
+ XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
+ @"Unsetting textOffset should return text-offset to the default value.");
+ XCTAssertEqualObjects(layer.textOffset, defaultStyleValue,
+ @"textOffset should return the default value after being unset.");
+ }
+
+ // text-optional
+ {
+ XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
+ @"text-optional should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOptional;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textOptional = styleValue;
+ mbgl::style::PropertyValue<bool> propertyValue = { true };
+ XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
+ @"Setting textOptional to a constant value should update text-optional.");
+ XCTAssertEqualObjects(layer.textOptional, styleValue,
+ @"textOptional should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textOptional = styleValue;
+ propertyValue = { mbgl::style::Function<bool> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
+ @"Setting textOptional to a function should update text-optional.");
+ XCTAssertEqualObjects(layer.textOptional, styleValue,
+ @"textOptional should round-trip functions.");
+
+ layer.textOptional = nil;
+ XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
+ @"Unsetting textOptional should return text-optional to the default value.");
+ XCTAssertEqualObjects(layer.textOptional, defaultStyleValue,
+ @"textOptional should return the default value after being unset.");
+ }
+
+ // text-padding
+ {
+ XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
+ @"text-padding should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textPadding;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textPadding = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
+ @"Setting textPadding to a constant value should update text-padding.");
+ XCTAssertEqualObjects(layer.textPadding, styleValue,
+ @"textPadding should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textPadding = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
+ @"Setting textPadding to a function should update text-padding.");
+ XCTAssertEqualObjects(layer.textPadding, styleValue,
+ @"textPadding should round-trip functions.");
+
+ layer.textPadding = nil;
+ XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
+ @"Unsetting textPadding should return text-padding to the default value.");
+ XCTAssertEqualObjects(layer.textPadding, defaultStyleValue,
+ @"textPadding should return the default value after being unset.");
+ }
+
+ // text-pitch-alignment
+ {
+ XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
+ @"text-pitch-alignment should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textPitchAlignment;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]];
+ layer.textPitchAlignment = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
+ XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
+ @"Setting textPitchAlignment to a constant value should update text-pitch-alignment.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, styleValue,
+ @"textPitchAlignment should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textPitchAlignment = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
+ @"Setting textPitchAlignment to a function should update text-pitch-alignment.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, styleValue,
+ @"textPitchAlignment should round-trip functions.");
+
+ layer.textPitchAlignment = nil;
+ XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
+ @"Unsetting textPitchAlignment should return text-pitch-alignment to the default value.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, defaultStyleValue,
+ @"textPitchAlignment should return the default value after being unset.");
+ }
+
+ // text-rotate
+ {
+ XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
+ @"text-rotate should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textRotation;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textRotation = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
+ @"Setting textRotation to a constant value should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, styleValue,
+ @"textRotation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textRotation = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
+ @"Setting textRotation to a function should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, styleValue,
+ @"textRotation should round-trip functions.");
+
+ layer.textRotation = nil;
+ XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
+ @"Unsetting textRotation should return text-rotate to the default value.");
+ XCTAssertEqualObjects(layer.textRotation, defaultStyleValue,
+ @"textRotation should return the default value after being unset.");
+ }
+
+ // text-rotation-alignment
+ {
+ XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
+ @"text-rotation-alignment should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textRotationAlignment;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]];
+ layer.textRotationAlignment = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
+ XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
+ @"Setting textRotationAlignment to a constant value should update text-rotation-alignment.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, styleValue,
+ @"textRotationAlignment should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textRotationAlignment = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
+ @"Setting textRotationAlignment to a function should update text-rotation-alignment.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, styleValue,
+ @"textRotationAlignment should round-trip functions.");
+
+ layer.textRotationAlignment = nil;
+ XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
+ @"Unsetting textRotationAlignment should return text-rotation-alignment to the default value.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, defaultStyleValue,
+ @"textRotationAlignment should return the default value after being unset.");
+ }
+
+ // text-transform
+ {
+ XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
+ @"text-transform should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTransform;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]];
+ layer.textTransform = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TextTransformType> propertyValue = { mbgl::style::TextTransformType::Lowercase };
+ XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
+ @"Setting textTransform to a constant value should update text-transform.");
+ XCTAssertEqualObjects(layer.textTransform, styleValue,
+ @"textTransform should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textTransform = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TextTransformType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
+ @"Setting textTransform to a function should update text-transform.");
+ XCTAssertEqualObjects(layer.textTransform, styleValue,
+ @"textTransform should round-trip functions.");
+
+ layer.textTransform = nil;
+ XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
+ @"Unsetting textTransform should return text-transform to the default value.");
+ XCTAssertEqualObjects(layer.textTransform, defaultStyleValue,
+ @"textTransform should return the default value after being unset.");
+ }
+
+ // icon-color
+ {
+ XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
+ @"icon-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.iconColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
+ @"Setting iconColor to a constant value should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, styleValue,
+ @"iconColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
+ @"Setting iconColor to a function should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, styleValue,
+ @"iconColor should round-trip functions.");
+
+ layer.iconColor = nil;
+ XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
+ @"Unsetting iconColor should return icon-color to the default value.");
+ XCTAssertEqualObjects(layer.iconColor, defaultStyleValue,
+ @"iconColor should return the default value after being unset.");
+ }
+
+ // icon-halo-blur
+ {
+ XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
+ @"icon-halo-blur should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloBlur;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconHaloBlur = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
+ @"Setting iconHaloBlur to a constant value should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, styleValue,
+ @"iconHaloBlur should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconHaloBlur = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
+ @"Setting iconHaloBlur to a function should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, styleValue,
+ @"iconHaloBlur should round-trip functions.");
+
+ layer.iconHaloBlur = nil;
+ XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
+ @"Unsetting iconHaloBlur should return icon-halo-blur to the default value.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, defaultStyleValue,
+ @"iconHaloBlur should return the default value after being unset.");
+ }
+
+ // icon-halo-color
+ {
+ XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
+ @"icon-halo-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconHaloColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.iconHaloColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
+ @"Setting iconHaloColor to a constant value should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, styleValue,
+ @"iconHaloColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconHaloColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
+ @"Setting iconHaloColor to a function should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, styleValue,
+ @"iconHaloColor should round-trip functions.");
+
+ layer.iconHaloColor = nil;
+ XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
+ @"Unsetting iconHaloColor should return icon-halo-color to the default value.");
+ XCTAssertEqualObjects(layer.iconHaloColor, defaultStyleValue,
+ @"iconHaloColor should return the default value after being unset.");
+ }
+
+ // icon-halo-width
+ {
+ XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
+ @"icon-halo-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconHaloWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
+ @"Setting iconHaloWidth to a constant value should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, styleValue,
+ @"iconHaloWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconHaloWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
+ @"Setting iconHaloWidth to a function should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, styleValue,
+ @"iconHaloWidth should round-trip functions.");
+
+ layer.iconHaloWidth = nil;
+ XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
+ @"Unsetting iconHaloWidth should return icon-halo-width to the default value.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, defaultStyleValue,
+ @"iconHaloWidth should return the default value after being unset.");
+ }
+
+ // icon-opacity
+ {
+ XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
+ @"icon-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
+ @"Setting iconOpacity to a constant value should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, styleValue,
+ @"iconOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
+ @"Setting iconOpacity to a function should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, styleValue,
+ @"iconOpacity should round-trip functions.");
+
+ layer.iconOpacity = nil;
+ XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
+ @"Unsetting iconOpacity should return icon-opacity to the default value.");
+ XCTAssertEqualObjects(layer.iconOpacity, defaultStyleValue,
+ @"iconOpacity should return the default value after being unset.");
+ }
+
+ // icon-translate
+ {
+ XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
+ @"icon-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslation;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.iconTranslation = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
+ @"Setting iconTranslation to a constant value should update icon-translate.");
+ XCTAssertEqualObjects(layer.iconTranslation, styleValue,
+ @"iconTranslation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconTranslation = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
+ @"Setting iconTranslation to a function should update icon-translate.");
+ XCTAssertEqualObjects(layer.iconTranslation, styleValue,
+ @"iconTranslation should round-trip functions.");
+
+ layer.iconTranslation = nil;
+ XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
+ @"Unsetting iconTranslation should return icon-translate to the default value.");
+ XCTAssertEqualObjects(layer.iconTranslation, defaultStyleValue,
+ @"iconTranslation should return the default value after being unset.");
+ }
+
+ // icon-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
+ @"icon-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]];
+ layer.iconTranslationAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
+ @"Setting iconTranslationAnchor to a constant value should update icon-translate-anchor.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue,
+ @"iconTranslationAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.iconTranslationAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
+ @"Setting iconTranslationAnchor to a function should update icon-translate-anchor.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue,
+ @"iconTranslationAnchor should round-trip functions.");
+
+ layer.iconTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
+ @"Unsetting iconTranslationAnchor should return icon-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultStyleValue,
+ @"iconTranslationAnchor should return the default value after being unset.");
+ }
+
+ // text-color
+ {
+ XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
+ @"text-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.textColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
+ @"Setting textColor to a constant value should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, styleValue,
+ @"textColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
+ @"Setting textColor to a function should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, styleValue,
+ @"textColor should round-trip functions.");
+
+ layer.textColor = nil;
+ XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
+ @"Unsetting textColor should return text-color to the default value.");
+ XCTAssertEqualObjects(layer.textColor, defaultStyleValue,
+ @"textColor should return the default value after being unset.");
+ }
+
+ // text-halo-blur
+ {
+ XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
+ @"text-halo-blur should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloBlur;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textHaloBlur = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
+ @"Setting textHaloBlur to a constant value should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, styleValue,
+ @"textHaloBlur should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textHaloBlur = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
+ @"Setting textHaloBlur to a function should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, styleValue,
+ @"textHaloBlur should round-trip functions.");
+
+ layer.textHaloBlur = nil;
+ XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
+ @"Unsetting textHaloBlur should return text-halo-blur to the default value.");
+ XCTAssertEqualObjects(layer.textHaloBlur, defaultStyleValue,
+ @"textHaloBlur should return the default value after being unset.");
+ }
+
+ // text-halo-color
+ {
+ XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
+ @"text-halo-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textHaloColor;
+
+ MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.textHaloColor = styleValue;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
+ @"Setting textHaloColor to a constant value should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, styleValue,
+ @"textHaloColor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textHaloColor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::Color> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
+ @"Setting textHaloColor to a function should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, styleValue,
+ @"textHaloColor should round-trip functions.");
+
+ layer.textHaloColor = nil;
+ XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
+ @"Unsetting textHaloColor should return text-halo-color to the default value.");
+ XCTAssertEqualObjects(layer.textHaloColor, defaultStyleValue,
+ @"textHaloColor should return the default value after being unset.");
+ }
+
+ // text-halo-width
+ {
+ XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
+ @"text-halo-width should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloWidth;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textHaloWidth = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
+ @"Setting textHaloWidth to a constant value should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, styleValue,
+ @"textHaloWidth should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textHaloWidth = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
+ @"Setting textHaloWidth to a function should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, styleValue,
+ @"textHaloWidth should round-trip functions.");
+
+ layer.textHaloWidth = nil;
+ XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
+ @"Unsetting textHaloWidth should return text-halo-width to the default value.");
+ XCTAssertEqualObjects(layer.textHaloWidth, defaultStyleValue,
+ @"textHaloWidth should return the default value after being unset.");
+ }
+
+ // text-opacity
+ {
+ XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
+ @"text-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOpacity;
+
+ MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textOpacity = styleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
+ @"Setting textOpacity to a constant value should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, styleValue,
+ @"textOpacity should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textOpacity = styleValue;
+ propertyValue = { mbgl::style::Function<float> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
+ @"Setting textOpacity to a function should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, styleValue,
+ @"textOpacity should round-trip functions.");
+
+ layer.textOpacity = nil;
+ XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
+ @"Unsetting textOpacity should return text-opacity to the default value.");
+ XCTAssertEqualObjects(layer.textOpacity, defaultStyleValue,
+ @"textOpacity should return the default value after being unset.");
+ }
+
+ // text-translate
+ {
+ XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
+ @"text-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslation;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.textTranslation = styleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
+ @"Setting textTranslation to a constant value should update text-translate.");
+ XCTAssertEqualObjects(layer.textTranslation, styleValue,
+ @"textTranslation should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textTranslation = styleValue;
+ propertyValue = { mbgl::style::Function<std::array<float, 2>> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
+ @"Setting textTranslation to a function should update text-translate.");
+ XCTAssertEqualObjects(layer.textTranslation, styleValue,
+ @"textTranslation should round-trip functions.");
+
+ layer.textTranslation = nil;
+ XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
+ @"Unsetting textTranslation should return text-translate to the default value.");
+ XCTAssertEqualObjects(layer.textTranslation, defaultStyleValue,
+ @"textTranslation should return the default value after being unset.");
+ }
+
+ // text-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
+ @"text-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]];
+ layer.textTranslationAnchor = styleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
+ @"Setting textTranslationAnchor to a constant value should update text-translate-anchor.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue,
+ @"textTranslationAnchor should round-trip constant values.");
+
+ styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
+ @18: styleValue,
+ }];
+ layer.textTranslationAnchor = styleValue;
+ propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
+ {{ 18, propertyValue.asConstant() }},
+ 1,
+ }};
+ XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
+ @"Setting textTranslationAnchor to a function should update text-translate-anchor.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue,
+ @"textTranslationAnchor should round-trip functions.");
+
+ layer.textTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
+ @"Unsetting textTranslationAnchor should return text-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, defaultStyleValue,
+ @"textTranslationAnchor should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"icon-allows-overlap" isBoolean:YES];
+ [self testPropertyName:@"icon-ignores-placement" isBoolean:YES];
+ [self testPropertyName:@"icon-image-name" isBoolean:NO];
+ [self testPropertyName:@"icon-offset" isBoolean:NO];
+ [self testPropertyName:@"is-icon-optional" isBoolean:YES];
+ [self testPropertyName:@"icon-padding" isBoolean:NO];
+ [self testPropertyName:@"icon-rotation" isBoolean:NO];
+ [self testPropertyName:@"icon-rotation-alignment" isBoolean:NO];
+ [self testPropertyName:@"icon-scale" isBoolean:NO];
+ [self testPropertyName:@"icon-text-fit" isBoolean:NO];
+ [self testPropertyName:@"icon-text-fit-padding" isBoolean:NO];
+ [self testPropertyName:@"keeps-icon-upright" isBoolean:YES];
+ [self testPropertyName:@"keeps-text-upright" isBoolean:YES];
+ [self testPropertyName:@"maximum-text-angle" isBoolean:NO];
+ [self testPropertyName:@"maximum-text-width" isBoolean:NO];
+ [self testPropertyName:@"symbol-avoids-edges" isBoolean:YES];
+ [self testPropertyName:@"symbol-placement" isBoolean:NO];
+ [self testPropertyName:@"symbol-spacing" isBoolean:NO];
+ [self testPropertyName:@"text" isBoolean:NO];
+ [self testPropertyName:@"text-allows-overlap" isBoolean:YES];
+ [self testPropertyName:@"text-anchor" isBoolean:NO];
+ [self testPropertyName:@"text-font-names" isBoolean:NO];
+ [self testPropertyName:@"text-font-size" isBoolean:NO];
+ [self testPropertyName:@"text-ignores-placement" isBoolean:YES];
+ [self testPropertyName:@"text-justification" isBoolean:NO];
+ [self testPropertyName:@"text-letter-spacing" isBoolean:NO];
+ [self testPropertyName:@"text-line-height" isBoolean:NO];
+ [self testPropertyName:@"text-offset" isBoolean:NO];
+ [self testPropertyName:@"is-text-optional" isBoolean:YES];
+ [self testPropertyName:@"text-padding" isBoolean:NO];
+ [self testPropertyName:@"text-pitch-alignment" isBoolean:NO];
+ [self testPropertyName:@"text-rotation" isBoolean:NO];
+ [self testPropertyName:@"text-rotation-alignment" isBoolean:NO];
+ [self testPropertyName:@"text-transform" isBoolean:NO];
+ [self testPropertyName:@"icon-color" isBoolean:NO];
+ [self testPropertyName:@"icon-halo-blur" isBoolean:NO];
+ [self testPropertyName:@"icon-halo-color" isBoolean:NO];
+ [self testPropertyName:@"icon-halo-width" isBoolean:NO];
+ [self testPropertyName:@"icon-opacity" isBoolean:NO];
+ [self testPropertyName:@"icon-translation" isBoolean:NO];
+ [self testPropertyName:@"icon-translation-anchor" isBoolean:NO];
+ [self testPropertyName:@"text-color" isBoolean:NO];
+ [self testPropertyName:@"text-halo-blur" isBoolean:NO];
+ [self testPropertyName:@"text-halo-color" isBoolean:NO];
+ [self testPropertyName:@"text-halo-width" isBoolean:NO];
+ [self testPropertyName:@"text-opacity" isBoolean:NO];
+ [self testPropertyName:@"text-translation" isBoolean:NO];
+ [self testPropertyName:@"text-translation-anchor" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentMap].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentViewport].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentViewport);
+ XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentAuto);
+ XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitNone].MGLIconTextFitValue, MGLIconTextFitNone);
+ XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitWidth].MGLIconTextFitValue, MGLIconTextFitWidth);
+ XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitHeight].MGLIconTextFitValue, MGLIconTextFitHeight);
+ XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth].MGLIconTextFitValue, MGLIconTextFitBoth);
+ XCTAssertEqual([NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementPoint].MGLSymbolPlacementValue, MGLSymbolPlacementPoint);
+ XCTAssertEqual([NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine].MGLSymbolPlacementValue, MGLSymbolPlacementLine);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorCenter].MGLTextAnchorValue, MGLTextAnchorCenter);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorLeft].MGLTextAnchorValue, MGLTextAnchorLeft);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorRight].MGLTextAnchorValue, MGLTextAnchorRight);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTop].MGLTextAnchorValue, MGLTextAnchorTop);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottom].MGLTextAnchorValue, MGLTextAnchorBottom);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopLeft].MGLTextAnchorValue, MGLTextAnchorTopLeft);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopRight].MGLTextAnchorValue, MGLTextAnchorTopRight);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomLeft].MGLTextAnchorValue, MGLTextAnchorBottomLeft);
+ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight].MGLTextAnchorValue, MGLTextAnchorBottomRight);
+ XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationLeft].MGLTextJustificationValue, MGLTextJustificationLeft);
+ XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationCenter].MGLTextJustificationValue, MGLTextJustificationCenter);
+ XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationRight].MGLTextJustificationValue, MGLTextJustificationRight);
+ XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentMap].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentViewport].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentViewport);
+ XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentAuto);
+ XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentMap].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentViewport].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentViewport);
+ XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentAuto);
+ XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformNone].MGLTextTransformValue, MGLTextTransformNone);
+ XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformUppercase].MGLTextTransformValue, MGLTextTransformUppercase);
+ XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformLowercase].MGLTextTransformValue, MGLTextTransformLowercase);
+ XCTAssertEqual([NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorMap].MGLIconTranslationAnchorValue, MGLIconTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport].MGLIconTranslationAnchorValue, MGLIconTranslationAnchorViewport);
+ XCTAssertEqual([NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorMap].MGLTextTranslationAnchorValue, MGLTextTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport].MGLTextTranslationAnchorValue, MGLTextTranslationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/one-liner.json b/platform/darwin/test/one-liner.json
new file mode 100644
index 0000000000..23c546181f
--- /dev/null
+++ b/platform/darwin/test/one-liner.json
@@ -0,0 +1 @@
+{"version":8,"sources":{},"layers":[]} \ No newline at end of file
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index fa224eafb6..00fdf9f2c1 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -15,24 +15,25 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Xcode 7.3 or above is required for using this SDK. ([#6059](https://github.com/mapbox/mapbox-gl-native/issues/6059))
* Clarified that the `-ObjC` linker flag is required for linking against the static framework distribution of this SDK. ([#6213](https://github.com/mapbox/mapbox-gl-native/pull/6213))
+* The API reference has a sharper look. ([#7422](https://github.com/mapbox/mapbox-gl-native/pull/7422))
* Added documentation for the Info.plist keys used by this SDK. ([#6833](https://github.com/mapbox/mapbox-gl-native/pull/6833))
### Styles and data
* A new runtime styling API allows you to adjust the style and content of the base map dynamically. All the options available in [Mapbox Studio](https://www.mapbox.com/studio/) are now exposed via MGLStyle and subclasses of MGLStyleLayer and MGLSource. ([#5727](https://github.com/mapbox/mapbox-gl-native/pull/5727))
* MGLMapView’s `styleURL` property can now be set to an absolute file URL. ([#6026](https://github.com/mapbox/mapbox-gl-native/pull/6026))
-* MGLShapeSource objects, as well as GeoJSON sources specified by the stylesheet at design time, now support `cluster`, `clusterMaxZoom`, and `clusterRadius` attributes for clustering point features on the base map. ([#5724](https://github.com/mapbox/mapbox-gl-native/pull/5724))
+* When creating an MGLShapeSource, you can now specify options for clustering point features within the shape source. Similarly, GeoJSON sources specified by the stylesheet at design time can specify the `cluster`, `clusterMaxZoom`, and `clusterRadius` attributes. ([#5724](https://github.com/mapbox/mapbox-gl-native/pull/5724))
* Added [quadkey](https://msdn.microsoft.com/en-us/library/bb259689.aspx) support and limited WMS support in raster tile URL templates. ([#5628](https://github.com/mapbox/mapbox-gl-native/pull/5628))
-* TileJSON manifests can now specify `"scheme": "tms"` to indicate the use of [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) coordinates. ([#2270](https://github.com/mapbox/mapbox-gl-native/pull/2270))
-* Fixed an issue causing abstract MGLMultiPointFeature objects to be returned in feature query results. Now concrete MGLPointCollectionFeature objects are returned. ([#6742](https://github.com/mapbox/mapbox-gl-native/pull/6742))
+* When creating an MGLTileSource, you can now specify that the tile URLs use [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) coordinates by setting `MGLTileSourceOptionTileCoordinateSystem` to `MGLTileCoordinateSystemTMS`. TileJSON files can specify `"scheme": "tms"`. ([#2270](https://github.com/mapbox/mapbox-gl-native/pull/2270))
+* Fixed an issue causing abstract MGLMultiPointFeature objects to be returned in feature query results. Now concrete MGLPointCollectionFeature objects are returned. MGLMultiPointFeature is now an alias of MGLPointCollectionFeature. ([#6742](https://github.com/mapbox/mapbox-gl-native/pull/6742))
* Fixed rendering artifacts and missing glyphs that occurred after viewing a large number of CJK characters on the map. ([#5908](https://github.com/mapbox/mapbox-gl-native/pull/5908))
* `-[MGLMapView resetPosition]` now resets to the current style’s default center coordinates, zoom level, direction, and pitch, if specified. ([#6127](https://github.com/mapbox/mapbox-gl-native/pull/6127))
* Fixed an issue where feature querying sometimes failed to return the expected features when the map was tilted. ([#6773](https://github.com/mapbox/mapbox-gl-native/pull/6773))
* MGLFeature’s `attributes` and `identifier` properties are now writable. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728))
* The action sheet that appears when tapping the information button in the bottom-right corner now lists the correct attribution for the current style. ([#5999](https://github.com/mapbox/mapbox-gl-native/pull/5999))
-* The `text-pitch-alignment` property is now supported in stylesheets for improved street label legibility on a tilted map. ([#5288](https://github.com/mapbox/mapbox-gl-native/pull/5288))
-* The `icon-text-fit` and `icon-text-fit-padding` properties are now supported in stylesheets, allowing the background of a shield to automatically resize to fit the shield’s text. ([#5334](https://github.com/mapbox/mapbox-gl-native/pull/5334))
-* The `circle-pitch-scale` property is now supported in stylesheets, allowing circle features in a tilted base map to scale or remain the same size as the viewing distance changes. ([#5576](https://github.com/mapbox/mapbox-gl-native/pull/5576))
+* Added support for MGLSymbolStyleLayer’s `textPitchAlignment` property and the corresponding style JSON property for improved street label legibility on a tilted map. ([#5288](https://github.com/mapbox/mapbox-gl-native/pull/5288))
+* Added support for MGLSymbolStyleLayer’s `iconTextFit` and `iconTextFitPadding` properties and the corresponding style JSON properties, allowing the background of a shield to automatically resize to fit the shield’s text. ([#5334](https://github.com/mapbox/mapbox-gl-native/pull/5334))
+* Added support for MGLSymbolStyleLayer’s `circlePitchScale` property and the corresponding style JSON property, allowing circle features in a tilted base map to scale or remain the same size as the viewing distance changes. ([#5576](https://github.com/mapbox/mapbox-gl-native/pull/5576))
* The `identifier` property of an MGLFeature may now be either a number or string. ([#5514](https://github.com/mapbox/mapbox-gl-native/pull/5514))
* If MGLMapView is unable to obtain or parse a style, it now calls its delegate’s `-mapViewDidFailLoadingMap:withError:` method. ([#6145](https://github.com/mapbox/mapbox-gl-native/pull/6145))
* Added the `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` delegate method, which offers the earliest opportunity to modify the layout or appearance of the current style before the map view is displayed to the user. ([#6636](https://github.com/mapbox/mapbox-gl-native/pull/6636))
@@ -56,6 +57,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
* Added new APIs to MGLMapView to query for visible annotations. Combined with `-[MGLMapView viewForAnnotation:]`, these APIs can be used to access all visible annotation views. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
+* Shape, feature, and annotation classes now conform to NSSecureCoding. ([#6559](https://github.com/mapbox/mapbox-gl-native/pull/6559))
* Fixed an issue causing offscreen annotation views to be updated even when they were in the reuse queue. ([#5987](https://github.com/mapbox/mapbox-gl-native/pull/5987))
* Fixed an issue preventing MGLAnnotationView from animating when its coordinate changes. ([#6215](https://github.com/mapbox/mapbox-gl-native/pull/6215))
* Fixed an issue causing the wrong annotation view to be selected when tapping an annotation view with a center offset applied. ([#5931](https://github.com/mapbox/mapbox-gl-native/pull/5931))
@@ -63,11 +65,11 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed an issue causing the callout view to be dismissed when panning around. ([#6676](https://github.com/mapbox/mapbox-gl-native/pull/6676))
* Per documentation, the first and last coordinates in an MGLPolygon must be identical in order for the polygon to draw correctly. The same is true for an MGLPolygon’s interior polygon. ([#5514](https://github.com/mapbox/mapbox-gl-native/pull/5514))
* To make an MGLPolyline or MGLPolygon span the antimeridian, specify coordinates with longitudes greater than 180° or less than −180°. ([#6088](https://github.com/mapbox/mapbox-gl-native/pull/6088))
-* Deprecated `-[MGLMapViewDelegate mapView:alphaForShapeAnnotation:]` in favor of specifying an alpha component via `-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` or `-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`. ([#6706](https://github.com/mapbox/mapbox-gl-native/pull/6706))
* Various method arguments that are represented as C arrays of `CLLocationCoordinate2D` instances have been marked `const` to streamline bridging to Swift. ([#7215](https://github.com/mapbox/mapbox-gl-native/pull/7215))
* Fixed an issue that caused an annotation view to disappear if it isn’t created using the annotation view reuse queue. ([#6485](https://github.com/mapbox/mapbox-gl-native/pull/6485))
* Fixed an issue that could reset user-added transformations on annotation views. ([#6166](https://github.com/mapbox/mapbox-gl-native/pull/6166))
* Improved the performance of relocating a non-view-backed point annotation by changing its `coordinate` property. ([#5385](https://github.com/mapbox/mapbox-gl-native/pull/5385))
+* Fixed an issue that caused an assertion failure if a `MGLShapeCollection` (a GeoJSON GeometryCollection) was created with an empty array of shapes. ([#7632](https://github.com/mapbox/mapbox-gl-native/pull/7632))
* Improved the precision of annotations at zoom levels greater than 18. ([#5517](https://github.com/mapbox/mapbox-gl-native/pull/5517))
### Networking and offline maps
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 22635be264..72ad84868e 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -6,7 +6,7 @@ This document explains how to build the Mapbox iOS SDK from source. It is intend
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.
-The Mapbox iOS SDK requires Xcode 7.3 or higher.
+The Mapbox iOS SDK requires Xcode 7.3 or above. The iosapp demo application requires Xcode 8.0 or above to build.
## Building the SDK
@@ -119,6 +119,22 @@ To add a localization to the iOS SDK:
1. In the Project navigator, expand each .strings and .stringsdict file in the project. An additional version for your localization should be listed; translate it. Translate everything on the right side of the equals sign. Leave the left side and any comments unmodified. See Apple’s documentation on the [.strings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html) and [.stringsdict](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) formats.
1. You’re already most of the way towards localizing the macOS SDK too – consider [completing that localization](../macos/DEVELOPING.md#adding-a-localization).
+### Adding a code example
+
+To add an example code listing to the documentation for a class or class member:
+
+1. Add a test method named in the form `testMGLClass` or `testMGLClass$method`
+ to [MGLDocumentationExampleTests](test/MGLDocumentationExampleTests.swift).
+ Wrap the code you’d like to appear in the documentation within
+ `//#-example-code` and `//#-end-example-code` comments.
+1. Insert the code listings into the headers:
+
+```bash
+make darwin-update-examples
+```
+
+[SourceKitten](https://github.com/jpsim/SourceKitten/) is required and will be installed automatically using Homebrew.
+
## Testing
`make ios-test` builds and runs unit tests of cross-platform code as well as the SDK.
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index 2cf3695af1..1098c5cd10 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -1,14 +1,16 @@
Pod::Spec.new do |m|
- m.name = 'Mapbox-iOS-SDK'
- m.version = '3.4.0-beta.5-symbols'
+ version = '3.4.0-beta.7'
+
+ m.name = 'Mapbox-iOS-SDK-symbols'
+ m.version = "#{version}-symbols"
m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.'
m.homepage = 'https://www.mapbox.com/ios-sdk/'
m.license = { :type => 'BSD', :file => 'LICENSE.md' }
m.author = { 'Mapbox' => 'mobile@mapbox.com' }
- m.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png'
+ m.screenshot = "https://www.mapbox.com/ios-sdk/api/#{version}/img/screenshot.png"
m.social_media_url = 'https://twitter.com/mapbox'
m.documentation_url = 'https://www.mapbox.com/ios-sdk/api/'
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 8bc963f910..cf3f3afa61 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,14 +1,16 @@
Pod::Spec.new do |m|
+ version = '3.4.0-beta.7'
+
m.name = 'Mapbox-iOS-SDK'
- m.version = '3.4.0-beta.5'
+ m.version = version
m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.'
m.homepage = 'https://www.mapbox.com/ios-sdk/'
m.license = { :type => 'BSD', :file => 'LICENSE.md' }
m.author = { 'Mapbox' => 'mobile@mapbox.com' }
- m.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png'
+ m.screenshot = "https://www.mapbox.com/ios-sdk/api/#{version}/img/screenshot.png"
m.social_media_url = 'https://twitter.com/mapbox'
m.documentation_url = 'https://www.mapbox.com/ios-sdk/api/'
diff --git a/platform/ios/README.md b/platform/ios/README.md
index 2350d1e527..3d4cc3ff2b 100644
--- a/platform/ios/README.md
+++ b/platform/ios/README.md
@@ -9,4 +9,4 @@ This repository is for day-to-day development of the SDK. Building the SDK yours
* [Integrating the Mapbox iOS SDK into your application](INSTALL.md)
* [Contributing to the Mapbox iOS SDK](DEVELOPING.md)
-![](screenshot.png)
+![](docs/img/screenshot.png)
diff --git a/platform/ios/app/MBXCustomCalloutView.h b/platform/ios/app/MBXCustomCalloutView.h
index a61619b79f..961f2d7f6a 100644
--- a/platform/ios/app/MBXCustomCalloutView.h
+++ b/platform/ios/app/MBXCustomCalloutView.h
@@ -7,4 +7,8 @@
* callout title for demonstration purpose.
*/
@interface MBXCustomCalloutView : UIView <MGLCalloutView>
+
+@property (nonatomic, assign, getter=isAnchoredToAnnotation) BOOL anchoredToAnnotation;
+@property (nonatomic, assign) BOOL dismissesAutomatically;
+
@end
diff --git a/platform/ios/app/MBXCustomCalloutView.m b/platform/ios/app/MBXCustomCalloutView.m
index 9edc00f6e9..e46b727d84 100644
--- a/platform/ios/app/MBXCustomCalloutView.m
+++ b/platform/ios/app/MBXCustomCalloutView.m
@@ -17,6 +17,8 @@ static CGFloat const tipWidth = 10.0;
}
@synthesize representedObject = _representedObject;
+@synthesize anchoredToAnnotation = _anchoredToAnnotation;
+@synthesize dismissesAutomatically = _dismissesAutomatically;
@synthesize leftAccessoryView = _leftAccessoryView;
@synthesize rightAccessoryView = _rightAccessoryView;
@synthesize delegate = _delegate;
@@ -66,6 +68,11 @@ static CGFloat const tipWidth = 10.0;
}
}
+- (void)setCenter:(CGPoint)center {
+ center.y = center.y - CGRectGetMidY(self.bounds);
+ [super setCenter:center];
+}
+
- (void)dismissCalloutAnimated:(BOOL)animated
{
if (self.superview)
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 05c2f91695..a14ad9350f 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -89,6 +89,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@end
@interface MBXCustomCalloutAnnotation : MGLPointAnnotation
+@property (nonatomic, assign) BOOL anchoredToAnnotation;
+@property (nonatomic, assign) BOOL dismissesAutomatically;
@end
@implementation MBXCustomCalloutAnnotation
@@ -624,6 +626,17 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView addAnnotation:triangle];
+ // West coast polyline
+ //
+ 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];
+
// Orcas Island, WA hike polyline
//
NSDictionary *hike = [NSJSONSerialization JSONObjectWithData:
@@ -699,12 +712,28 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
[self.mapView removeAnnotations:self.mapView.annotations];
- MBXCustomCalloutAnnotation *annotation = [[MBXCustomCalloutAnnotation alloc] init];
- annotation.coordinate = CLLocationCoordinate2DMake(48.8533940, 2.3775439);
- annotation.title = @"Custom Callout";
-
- [self.mapView addAnnotation:annotation];
- [self.mapView showAnnotations:@[annotation] animated:YES];
+ MBXCustomCalloutAnnotation *firstAnnotation = [[MBXCustomCalloutAnnotation alloc] init];
+ firstAnnotation.coordinate = CLLocationCoordinate2DMake(48.8533940, 2.3775439);
+ firstAnnotation.title = @"Open anchored to annotation";
+ firstAnnotation.anchoredToAnnotation = YES;
+ firstAnnotation.dismissesAutomatically = NO;
+
+ MBXCustomCalloutAnnotation *secondAnnotation = [[MBXCustomCalloutAnnotation alloc] init];
+ secondAnnotation.coordinate = CLLocationCoordinate2DMake(48.8543940, 2.3775439);
+ secondAnnotation.title = @"Open not anchored to annotation";
+ secondAnnotation.anchoredToAnnotation = NO;
+ secondAnnotation.dismissesAutomatically = NO;
+
+ MBXCustomCalloutAnnotation *thirdAnnotation = [[MBXCustomCalloutAnnotation alloc] init];
+ thirdAnnotation.coordinate = CLLocationCoordinate2DMake(48.8553940, 2.3775439);
+ thirdAnnotation.title = @"Dismisses automatically";
+ thirdAnnotation.anchoredToAnnotation = YES;
+ thirdAnnotation.dismissesAutomatically = YES;
+
+ NSArray *annotations = @[firstAnnotation, secondAnnotation, thirdAnnotation];
+ [self.mapView addAnnotations:annotations];
+
+ [self.mapView showAnnotations:annotations animated:YES];
}
- (void)styleWaterLayer
@@ -901,8 +930,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
}
dispatch_async(dispatch_get_main_queue(), ^{
- MGLShapeCollectionFeature *features = [MGLShapeCollectionFeature shapeCollectionWithShapes:visibleFeatures];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:querySourceID shape:features options:nil];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:querySourceID features:visibleFeatures options:nil];
[self.mapView.style addSource:source];
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:queryLayerID source:source];
@@ -1184,13 +1212,13 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MGLSymbolStyleLayer *layer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:layerName];
if ([layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
- if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) {
- MGLStyleConstantValue *label = (MGLStyleConstantValue<NSString *> *)layer.textField;
+ if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) {
+ MGLStyleConstantValue *label = (MGLStyleConstantValue<NSString *> *)layer.text;
if ([label.rawValue hasPrefix:@"{name"]) {
- layer.textField = [MGLStyleValue valueWithRawValue:language];
+ layer.text = [MGLStyleValue valueWithRawValue:language];
}
- } else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.textField;
+ } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) {
+ MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.text;
[function.stops enumerateKeysAndObjectsUsingBlock:^(id zoomLevel, id stop, BOOL *done) {
if ([stop isKindOfClass:[MGLStyleConstantValue class]]) {
MGLStyleConstantValue *label = (MGLStyleConstantValue<NSString *> *)stop;
@@ -1199,7 +1227,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
}
}
}];
- layer.textField = function;
+ layer.text = function;
}
} else {
NSLog(@"%@ is not a symbol style layer", layerName);
@@ -1537,9 +1565,15 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
return YES;
}
+- (CGFloat)mapView:(__unused MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation
+{
+ return ([annotation isKindOfClass:[MGLPolygon class]] ? 0.5 : 1.0);
+}
+
- (UIColor *)mapView:(__unused MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation
{
- return ([annotation isKindOfClass:[MGLPolyline class]] ? [UIColor purpleColor] : [UIColor blackColor]);
+ UIColor *color = [annotation isKindOfClass:[MGLPolyline class]] ? [UIColor greenColor] : [UIColor blackColor];
+ return [color colorWithAlphaComponent:0.9];
}
- (UIColor *)mapView:(__unused MGLMapView *)mapView fillColorForPolygonAnnotation:(__unused MGLPolygon *)annotation
@@ -1582,8 +1616,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
if ([annotation respondsToSelector:@selector(title)]
&& [annotation isKindOfClass:[MBXCustomCalloutAnnotation class]])
{
+ MBXCustomCalloutAnnotation *customAnnotation = (MBXCustomCalloutAnnotation *)annotation;
MBXCustomCalloutView *calloutView = [[MBXCustomCalloutView alloc] init];
calloutView.representedObject = annotation;
+ calloutView.anchoredToAnnotation = customAnnotation.anchoredToAnnotation;
+ calloutView.dismissesAutomatically = customAnnotation.dismissesAutomatically;
return calloutView;
}
return nil;
@@ -1613,8 +1650,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
return;
}
-
- MGLPointAnnotation *point = annotation;
+
+ MGLPointAnnotation *point = (MGLPointAnnotation *)annotation;
point.coordinate = [self.mapView convertPoint:self.mapView.center toCoordinateFromView:self.mapView];
}
diff --git a/platform/ios/benchmark/MBXBenchViewController.mm b/platform/ios/benchmark/MBXBenchViewController.mm
index 43e98d7ccd..4f26d0cb1d 100644
--- a/platform/ios/benchmark/MBXBenchViewController.mm
+++ b/platform/ios/benchmark/MBXBenchViewController.mm
@@ -3,7 +3,7 @@
#import "MBXBenchAppDelegate.h"
#import <Mapbox/Mapbox.h>
-#import "MGLMapView_Internal.h"
+#import "MGLMapView_Private.h"
#include "locations.hpp"
diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index 22493b1502..e91bc0b1cc 100644
--- a/platform/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
@@ -2,7 +2,7 @@
The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox 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.
-![Mapbox iOS SDK screenshots](screenshot.png)
+![Mapbox iOS SDK screenshots](img/screenshot.png)
For setup information, check out the [Mapbox iOS SDK homepage](https://www.mapbox.com/ios-sdk/). For detailed usage instructions, read “[First steps with the Mapbox iOS SDK](https://www.mapbox.com/help/first-steps-ios-sdk/)” and consult the [online examples](https://www.mapbox.com/ios-sdk/examples/). A [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/CHANGELOG.md) is also available.
diff --git a/platform/ios/docs/guides/Adding Points to a Map.md b/platform/ios/docs/guides/Adding Points to a Map.md
new file mode 100644
index 0000000000..17e8ad3592
--- /dev/null
+++ b/platform/ios/docs/guides/Adding Points to a Map.md
@@ -0,0 +1,83 @@
+# Adding Points to a Map
+
+Mapbox offers a few different ways to add points to a map, each with different tradeoffs.
+
+## MGLPointAnnotation
+
+It’s straightforward to add an annotation to a map. You can use `MGLPointAnnotation` as is, or you can subclass it to add annotations with richer data.
+
+```swift
+let annotation = MGLPointAnnotation()
+annotation.coordinate = CLLocationCoordinate2D(latitude: 45.5076, longitude: -122.6736)
+annotation.title = "Bobby's Coffee"
+annotation.subtitle = "Coffeeshop"
+mapView.addAnnotation(annotation)
+```
+
+See the `MGLMapViewDelegate` method `-mapView:annotationCanShowCallout:` and similar methods for allowing interaction with a callout ([example](https://www.mapbox.com/ios-sdk/examples/callout-delegate/)).
+
+## Displaying annotations
+
+There are two basic ways to display the annotations you’ve added to a map, each with their own tradeoffs.
+
+### Annotation Images (`MGLAnnotationImage`)
+
+Annotation images are the quickest and most performant way to display annotations, but are also the most basic.
+
+By default, annotations added to the map are displayed with a red pin ([example](https://www.mapbox.com/ios-sdk/examples/marker/)). To use custom images, you can implement `MGLMapViewDelegate` `-mapView:imageForAnnotation:` ([example](https://www.mapbox.com/ios-sdk/examples/marker-image/)).
+
+**Pros**
+
+* The easiest way to display a marker on a map
+* Easily customizable with any `UIImage`
+* High performance, as the images are rendered directly in OpenGL
+
+**Cons**
+
+* Annotation images are purely static and cannot be animated
+* No control over z-ordering
+* Limits to the number and size of images you can add
+
+### Annotation Views (`MGLAnnotationView`)
+
+If you’re looking to add custom `UIView`s or have annotations that are dynamic or animatable, consider an `MGLAnnotationView` instead of an `MGLAnnotationImage` ([example](https://www.mapbox.com/ios-sdk/examples/annotation-views/)).
+
+Annotation views have significant advantages over annotation images when you need every annotation to be unique. For example, annotation views are ideal for showing user locations on a map using high-resolution profile pictures.
+
+To use annotation views, implement `MGLMapViewDelegate` `-mapView:viewForAnnotation` and provide a custom `MGLAnnotationView` (`UIView`) subclass.
+
+**Pros**
+
+* Custom, native UIViews
+* No limit on style or image size
+* Full support for animations
+* Relative control over z-ordering using the `zPosition` property on `CALayer`
+* [Familiar API for MapKit users](https://www.mapbox.com/help/switch-mapkit/#annotations-pins)
+
+**Cons**
+
+* Performance implications:
+ * `UIView`s are inherently slow to render compared to OpenGL, more apparent if you’re adding many views or moving the map rapidly
+ * In some cases, you might consider runtime styling
+
+## Advanced: Runtime Styling
+
+For absolute full control of how points are displayed on a map, consider [runtime styling](runtime-styling.html).
+
+You can use `MGLPointFeature` or any of the other [style feature subclasses](Style%20Features.html) to add points and shapes to an `MGLShapeSource`.
+
+From there, you can create one or many `MGLSymbolStyleLayer` or `MGLCircleStyleLayer` layers to filter and style points for display on the map ([example](https://www.mapbox.com/ios-sdk/examples/runtime-multiple-annotations)).
+
+**Pros**
+
+* Most powerful option
+* Highest performance (rendered in GL directly)
+* SDK-level support for labels rendered together with icons
+* Finer control of z-ordering
+ * Rendering respects ordering within the data source
+ * Otherwise layers are lightweight so you can create a new layer for each level you need
+
+**Cons**
+
+* Currently you must implement your own tap gesture recognizer together with `MGLMapView.visibleFeaturesAtPoint` to recognize taps and manually show callouts ([example](https://www.mapbox.com/ios-sdk/examples/select-feature)).
+* Currently no SDK support for animations. If you need animations, consider using an NSTimer and updating the layer properties accordingly.
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
new file mode 100644
index 0000000000..753eb7200c
--- /dev/null
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -0,0 +1,306 @@
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+-->
+# Information for Style Authors
+
+A _style_ defines a map view’s content and appearance. If you’ve authored a
+style using
+[Mapbox Studio’s Styles editor](https://www.mapbox.com/studio/styles/) or as
+JSON in a text editor, you can use that style in this SDK and manipulate it
+afterwards in code. This document provides information you can use to ensure a
+seamless transition from Mapbox Studio to your application.
+
+## Designing for iOS
+
+When designing your style, consider the context in which your application shows
+the style. There are a number of considerations specific to iOS that may
+not be obvious when designing your style in Mapbox Studio on the Web. A map view
+is essentially a graphical user interface element, so many of same issues in
+user interface design also apply when designing a map style.
+
+### Color
+
+Ensure sufficient contrast in your application’s user interface when your map
+style is present. Standard user interface elements such as toolbars, sidebars,
+and sheets often overlap the map view with a translucent, blurred background, so
+make sure the contents of these elements remain legible with the map view
+underneath.
+The user location annotation view, the attribution button, any buttons in
+callout views, and any items in the navigation bar are influenced by your
+application’s tint color, so choose a tint color that constrasts well with your
+map style. If you intend your style to be used in the dark, consider the impact
+that Night Shift may have on your style’s colors.
+
+### Typography and graphics
+
+Choose font and icon sizes appropriate to iOS devices. iPhones and iPads have
+smaller screens than the typical browser window in which you would use Mapbox
+Studio, especially when multitasking is enabled. Your user’s viewing distance
+may be shorter than on a desktop computer. Some of your users may use the Larger
+Dynamic Type and Accessibility Text features to increase the size of all text on
+the device. You can use the
+[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s
+font and icon sizes accordingly.
+
+Design sprite images and choose font weights that look crisp on both
+standard-resolution displays and Retina displays. This SDK supports the same
+resolutions as iOS.
+Standard-resolution displays are limited to older devices that your application
+may or may not support, depending on its minimum deployment target.
+
+Icon and text labels should be legible regardless of the map’s orientation.
+By default, this SDK makes it easy for your users to rotate or tilt the map
+using multitouch gestures.
+If you do not intend your design to accommodate rotation and tilting, disable
+these gestures using the `MGLMapView.rotateEnabled` and
+`MGLMapView.pitchEnabled` properties, respectively, or the corresponding
+inspectables in Interface Builder.
+
+### Interactivity
+
+Pay attention to whether elements of your style appear to be interactive.
+A text label may look like a tappable button merely due to matching your
+application’s tint color or the default blue tint color.
+You can make an icon or text label interactive by installing a gesture
+recognizer and performing feature querying (e.g.,
+`-[MGLMapView visibleFeaturesAtPoint:]`) to get details about the selected
+feature.
+
+Make sure your users can easily distinguish any interactive elements from the
+surrounding map, such as pins, the user location annotation view, or a route
+line. Avoid relying on hover effects to indicate interactive elements. Leave
+enough room between interactive elements to accommodate imprecise tapping
+gestures.
+
+For more information about user interface design, consult Apple’s
+[_iOS Human Interface Guidelines_](https://developer.apple.com/ios/human-interface-guidelines/).
+
+## Applying your style
+
+You set an `MGLMapView` object’s style either in code, by setting the
+`MGLMapView.styleURL` property, or in Interface Builder, by setting the “Style
+URL” inspectable. The URL must point to a local or remote style JSON file. The
+style JSON file format is defined by the
+[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/). This
+SDK supports the functionality defined by version 8 of the specification unless
+otherwise noted in the
+[style specification documentation](https://www.mapbox.com/mapbox-gl-style-spec/).
+
+## Manipulating the style at runtime
+
+The _runtime styling API_ enables you to modify every aspect of a style
+dynamically as a user interacts with your application. The style itself is
+represented at runtime by an `MGLStyle` object, which provides access to various
+`MGLSource` and `MGLStyleLayer` objects that represent content sources and style
+layers, respectively.
+For more information about the capabilities exposed by the runtime styling API,
+see “[Runtime Styling](runtime-styling.html)”.
+
+The names of runtime styling classes and properties on iOS are generally
+consistent with the style specification and Mapbox Studio’s Styles editor. Any
+exceptions are listed in this document.
+
+To avoid conflicts with Objective-C keywords or Cocoa terminology, this SDK uses
+the following terms for concepts defined in the style specification:
+
+In the style specification | In the SDK
+---------------------------|---------
+class | style class
+filter | predicate
+id | identifier
+image | style image
+layer | style layer
+property | attribute
+SDF icon | template image
+source | content source
+
+## Specifying the map’s content
+
+Each source defined by a style JSON file is represented at runtime by a content
+source object that you can use to initialize new style layers. The content
+source object is a member of one of the following subclasses of `MGLSource`:
+
+In style JSON | In the SDK
+--------------|-----------
+`geojson` | `MGLShapeSource`
+`raster` | `MGLRasterSource`
+`vector` | `MGLVectorSource`
+
+`image` and `video` sources are not supported.
+
+### Tile sources
+
+Raster and vector sources may be defined in TileJSON configuration files. This
+SDK supports the properties defined in the style specification, which are a
+subset of the keys defined in version 2.1.0 of the
+[TileJSON](https://github.com/mapbox/tilejson-spec/tree/master/2.1.0)
+specification. As an alternative to authoring a custom TileJSON file, you may
+supply various tile source options when creating a raster or vector source.
+These options are detailed in the `MGLTileSourceOption` documentation:
+
+In style JSON | In TileJSON | In the SDK
+--------------|---------------|-----------
+`url` | — | `configurationURL` parameter in `-[MGLTileSource initWithIdentifier:configurationURL:]`
+`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
+`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
+`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
+`tileSize` | — | `MGLTileSourceOptionTileSize`
+`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
+`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
+
+### Shape sources
+
+Shape sources also accept various options. These options are detailed in the
+`MGLShapeSourceOption` documentation:
+
+In style JSON | In the SDK
+-----------------|-----------
+`data` | `url` parameter in `-[MGLShapeSource initWithIdentifier:URL:options:]`
+`maxzoom` | `MGLShapeSourceOptionMaximumZoomLevel`
+`buffer` | `MGLShapeSourceOptionBuffer`
+`tolerance` | `MGLShapeSourceOptionSimplificationTolerance`
+`cluster` | `MGLShapeSourceOptionClustered`
+`clusterRadius` | `MGLShapeSourceOptionClusterRadius`
+`clusterMaxZoom` | `MGLShapeSourceOptionMaximumZoomLevelForClustering`
+
+To create a shape source from local GeoJSON data, first
+[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
+then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+
+## Configuring the map content’s appearance
+
+Each layer defined by the style JSON file is represented at runtime by a style
+layer object, which you can use to refine the map’s appearance. The style layer
+object is a member of one of the following subclasses of `MGLStyleLayer`:
+
+In style JSON | In the SDK
+--------------|-----------
+`background` | `MGLBackgroundStyleLayer`
+`circle` | `MGLCircleStyleLayer`
+`fill` | `MGLFillStyleLayer`
+`line` | `MGLLineStyleLayer`
+`raster` | `MGLRasterStyleLayer`
+`symbol` | `MGLSymbolStyleLayer`
+
+You configure layout and paint attributes by setting properties on these style
+layer objects. The property names generally correspond to the style JSON
+properties, except for the use of camelCase instead of kebab-case. Properties
+whose names differ from the style specification are listed below:
+
+### Circle style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`circle-pitch-scale` | `MGLCircleStyleLayer.circleScaleAlignment` | `MGLCircleStyleLayer.circleScaleAlignment`
+`circle-translate` | `MGLCircleStyleLayer.circleTranslation` | `MGLCircleStyleLayer.circleTranslation`
+`circle-translate-anchor` | `MGLCircleStyleLayer.circleTranslationAnchor` | `MGLCircleStyleLayer.circleTranslationAnchor`
+
+### Fill style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`fill-antialias` | `MGLFillStyleLayer.fillAntialiased` | `MGLFillStyleLayer.isFillAntialiased`
+`fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation`
+`fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor`
+
+### Line style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`line-dasharray` | `MGLLineStyleLayer.lineDashPattern` | `MGLLineStyleLayer.lineDashPattern`
+`line-translate` | `MGLLineStyleLayer.lineTranslation` | `MGLLineStyleLayer.lineTranslation`
+`line-translate-anchor` | `MGLLineStyleLayer.lineTranslationAnchor` | `MGLLineStyleLayer.lineTranslationAnchor`
+
+### Raster style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`raster-brightness-max` | `MGLRasterStyleLayer.maximumRasterBrightness` | `MGLRasterStyleLayer.maximumRasterBrightness`
+`raster-brightness-min` | `MGLRasterStyleLayer.minimumRasterBrightness` | `MGLRasterStyleLayer.minimumRasterBrightness`
+`raster-hue-rotate` | `MGLRasterStyleLayer.rasterHueRotation` | `MGLRasterStyleLayer.rasterHueRotation`
+
+### Symbol style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`icon-allow-overlap` | `MGLSymbolStyleLayer.iconAllowsOverlap` | `MGLSymbolStyleLayer.iconAllowsOverlap`
+`icon-ignore-placement` | `MGLSymbolStyleLayer.iconIgnoresPlacement` | `MGLSymbolStyleLayer.iconIgnoresPlacement`
+`icon-image` | `MGLSymbolStyleLayer.iconImageName` | `MGLSymbolStyleLayer.iconImageName`
+`icon-optional` | `MGLSymbolStyleLayer.iconOptional` | `MGLSymbolStyleLayer.isIconOptional`
+`icon-rotate` | `MGLSymbolStyleLayer.iconRotation` | `MGLSymbolStyleLayer.iconRotation`
+`icon-size` | `MGLSymbolStyleLayer.iconScale` | `MGLSymbolStyleLayer.iconScale`
+`icon-keep-upright` | `MGLSymbolStyleLayer.keepsIconUpright` | `MGLSymbolStyleLayer.keepsIconUpright`
+`text-keep-upright` | `MGLSymbolStyleLayer.keepsTextUpright` | `MGLSymbolStyleLayer.keepsTextUpright`
+`text-max-angle` | `MGLSymbolStyleLayer.maximumTextAngle` | `MGLSymbolStyleLayer.maximumTextAngle`
+`text-max-width` | `MGLSymbolStyleLayer.maximumTextWidth` | `MGLSymbolStyleLayer.maximumTextWidth`
+`symbol-avoid-edges` | `MGLSymbolStyleLayer.symbolAvoidsEdges` | `MGLSymbolStyleLayer.symbolAvoidsEdges`
+`text-field` | `MGLSymbolStyleLayer.text` | `MGLSymbolStyleLayer.text`
+`text-allow-overlap` | `MGLSymbolStyleLayer.textAllowsOverlap` | `MGLSymbolStyleLayer.textAllowsOverlap`
+`text-font` | `MGLSymbolStyleLayer.textFontNames` | `MGLSymbolStyleLayer.textFontNames`
+`text-size` | `MGLSymbolStyleLayer.textFontSize` | `MGLSymbolStyleLayer.textFontSize`
+`text-ignore-placement` | `MGLSymbolStyleLayer.textIgnoresPlacement` | `MGLSymbolStyleLayer.textIgnoresPlacement`
+`text-justify` | `MGLSymbolStyleLayer.textJustification` | `MGLSymbolStyleLayer.textJustification`
+`text-optional` | `MGLSymbolStyleLayer.textOptional` | `MGLSymbolStyleLayer.isTextOptional`
+`text-rotate` | `MGLSymbolStyleLayer.textRotation` | `MGLSymbolStyleLayer.textRotation`
+`icon-translate` | `MGLSymbolStyleLayer.iconTranslation` | `MGLSymbolStyleLayer.iconTranslation`
+`icon-translate-anchor` | `MGLSymbolStyleLayer.iconTranslationAnchor` | `MGLSymbolStyleLayer.iconTranslationAnchor`
+`text-translate` | `MGLSymbolStyleLayer.textTranslation` | `MGLSymbolStyleLayer.textTranslation`
+`text-translate-anchor` | `MGLSymbolStyleLayer.textTranslationAnchor` | `MGLSymbolStyleLayer.textTranslationAnchor`
+
+## Setting attribute values
+
+Each property representing a layout or paint attribute is set to an
+`MGLStyleValue` object, which is either an `MGLStyleConstantValue` object (for
+constant values) or an `MGLStyleFunction` object (for zoom level functions). The
+style value object is a container for the raw value or function parameters that
+you want the attribute to be set to.
+
+In contrast to the JSON type that the style specification defines for each
+layout or paint property, the style value object often contains a more specific
+Foundation or Cocoa type. General rules for attribute types are listed below.
+Pay close attention to the SDK documentation for the attribute you want to get
+or set.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+Color | `UIColor` | `UIColor`
+Enum | `NSValue` (see `NSValue(MGLAdditions)`) | `NSValue` (see `NSValue(MGLAdditions)`)
+String | `NSString` | `String`
+Boolean | `NSNumber.boolValue` | `Bool`
+Number | `NSNumber.floatValue` | `Float`
+Array (`-dasharray`) | `NSArray<NSNumber>` | `[Float]`
+Array (`-font`) | `NSArray<NSString>` | `[String]`
+Array (`-offset`, `-translate`) | `NSValue.CGVectorValue` | `NSValue.cgVectorValue`
+Array (`-padding`) | `NSValue.UIEdgeInsetsValue` | `NSValue.uiEdgeInsetsValue`
+
+For padding attributes, note that the arguments to
+`UIEdgeInsetsMake()` in Objective-C and
+`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
+order, in contrast to the clockwise order defined by the style specification.
+
+## Filtering sources
+
+You can filter a shape or vector source by setting the
+`MGLVectorStyleLayer.predicate` property to an `NSPredicate` object. Below is a
+table of style JSON operators and the corresponding operators used in the
+predicate format string:
+
+In style JSON | In the format string
+--------------------------|---------------------
+`["has", key]` | `key != nil`
+`["!has", key]` | `key == nil`
+`["==", key, value]` | `key == value`
+`["!=", key, value]` | `key != value`
+`[">", key, value]` | `key > value`
+`[">=", key, value]` | `key >= value`
+`["<", key, value]` | `key < value`
+`["<=", key, value]` | `key <= value`
+`["in", key, v0, …, vn]` | `key IN {v0, …, vn}`
+`["!in", key, v0, …, vn]` | `NOT key IN {v0, …, vn}`
+`["all", f0, …, fn]` | `p0 AND … AND pn`
+`["any", f0, …, fn]` | `p0 OR … OR pn`
+`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+
+See the `MGLVectorStyleLayer.predicate` documentation for a full description of
+the supported operators and operand types.
diff --git a/platform/ios/docs/Info.plist Keys.md b/platform/ios/docs/guides/Info.plist Keys.md
index 34d3da9e29..c5c7cf1d85 100644
--- a/platform/ios/docs/Info.plist Keys.md
+++ b/platform/ios/docs/guides/Info.plist Keys.md
@@ -1,6 +1,6 @@
# Info.plist Keys
-The Mapbox iOS SDK supports custom `Info.plist` keys in your application in order to configure various settings.
+The Mapbox iOS SDK supports custom `Info.plist` keys in your application in order to configure various settings.
## MGLMapboxAccessToken
@@ -8,13 +8,13 @@ Set the [Mapbox access token](https://www.mapbox.com/help/define-access-token/)
Mapbox-hosted vector tiles and styles require an API access token, which you can obtain from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). Access tokens associate requests to Mapbox’s vector tile and style APIs with your Mapbox account. They also deter other developers from using your styles without your permission.
-As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private.
+As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private.
## MGLMapboxAPIBaseURL
-Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used.
+Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used.
-The default value is `https://api.mapbox.com`.
+The default value is `https://api.mapbox.com`.
## MGLMapboxMetricsEnabledSettingShownInApp
diff --git a/platform/ios/docs/guides/Runtime Styling.md b/platform/ios/docs/guides/Runtime Styling.md
new file mode 100644
index 0000000000..e85b466c65
--- /dev/null
+++ b/platform/ios/docs/guides/Runtime Styling.md
@@ -0,0 +1,53 @@
+# Runtime Styling
+
+Mapbox’s runtime styling features allow you direct control over every layer in your maps with code. It’s now possible to create dynamic maps and visualizations that aren’t possible with other mobile maps SDKs.
+
+Runtime styling expands upon the design power of [Mapbox Studio](https://www.mapbox.com/mapbox-studio/) and exposes all of the same properties and attributes directly to mobile developers in our SDK.
+
+Beyond the custom styled maps that you can create with Mapbox Studio, you can now change the look and feel of your map on the fly having maps in your app visually respond to user interaction or or context. Or leverage the power of OpenGL for highly performant and complex data visualizations. Now it’s possible to mix in your own data and bring your map to life.
+
+## Example use cases
+
+As an example of what’s possible with runtime styling, consider some of the following use cases:
+
+### Styling maps on the fly
+
+At runtime, you can tailor the map specifically to your user interface. Tweak colors, text, and icons to match the style to your brand.
+
+![dynamic styles](img/runtime-styling/DynamicStyles.gif "an example showing dynamic styles")
+
+For maps that aren’t going to change in response to custom data or user interaction, consider creating a custom map style with [Mapbox Studio](https://www.mapbox.com/mapbox-studio/).
+
+### Map interactivity
+
+You can customize the map to the point of having it respond dynamically based on the actions your users are taking. Increase the text size of streets while a user is driving, emphasize points of interest tailored to a user’s preferences, or change your UI if users are at parks, trails, landmarks, or rivers.
+
+![emojis](img/runtime-styling/Emoji.gif "an example showing emoji interaction")
+
+### Powerful data visualization
+
+Mapbox maps are built on top of OpenGL and can support rendering data without the traditional overhead of `UIView`-based map annotations.
+
+Mapbox can support data visualizations that were slow or impossible with traditional map SDKs. Render heatmaps, visualize population density, or even go so far as updating the snow levels in the mountains to match recent snowfall.
+
+![hex bins](img/runtime-styling/HexBins.gif "an example using hex bins")
+![population](img/runtime-styling/Population.gif "an example showing population density")
+![snow levels](img/runtime-styling/SnowLevels.gif "an example visualizing snow levels in the mountains")
+
+### Powerful annotations
+
+The Mapbox SDK gives you access to all of the same tools we use to render our default map styles. Instead of using generic pin markers, enrich your place data or custom polygons with icons and labels that make your maps stand out.
+
+![custom annotations](img/runtime-styling/CustomAnnotations.gif "an example showing custom annotations")
+
+### Custom shapes
+
+Draw custom shapes on the map the same way you would a custom `UIView` or `CALayer`. These shapes keep their geographic scale and are perfect for visualizing everything from indoor floor plans to metro systems to hurricane tracks.
+
+## Resources
+
+* [Information for style authors](for-style-authors.html)
+* [Mapbox Streets source reference](https://www.mapbox.com/vector-tiles/mapbox-streets-v7/)
+* [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)
+* [Mapbox Studio](https://www.mapbox.com/mapbox-studio/)
+* [iOS code examples](https://www.mapbox.com/ios-sdk/examples/)
diff --git a/platform/ios/docs/guides/Working with Mapbox Studio.md b/platform/ios/docs/guides/Working with Mapbox Studio.md
new file mode 100644
index 0000000000..959731a3a7
--- /dev/null
+++ b/platform/ios/docs/guides/Working with Mapbox Studio.md
@@ -0,0 +1,96 @@
+# Working with Mapbox Studio
+
+[Mapbox Studio’s Styles editor](http://mapbox.com/studio) is Mapbox’s tool for creating custom map styles. It also serves as an excellent tool for rapidly prototyping dynamic maps and [runtime styling](runtime-styling.html) interactions for iOS.
+
+## Creating a base style
+
+Start by heading to [mapbox.com/studio](https://www.mapbox.com/studio) and creating a new style. Any style that’s close to what you’ll be using in your app is ideal.
+
+## Prototyping with data
+
+The goal in using Mapbox Studio for prototyping runtime styling implementations is to test data presentation assumptions as quickly as possible. With the Mapbox Studio tools, you can import a small subset of your own real data, fake data as a placeholder, or prototype with existing Mapbox data.
+
+### Prototyping with Mapbox data
+The default [Mapbox Streets tileset](https://www.mapbox.com/studio/tilesets/mapbox.mapbox-streets-v7/) might offer data similar to your own that you can use to style before you swap in your own data at runtime.
+
+For example, if you’re looking to prototype points of interest, consider the `poi_label` layer; if you want to style GPS traces, the `roads` layer might be a good proxy. Take a look at what’s available in [Mapbox Streets](https://www.mapbox.com/studio/tilesets/mapbox.mapbox-streets-v7/): there’s probably a layer that closely matches your data.
+
+### Importing real data
+If you can’t find a good approximation for your data in Mapbox Streets, consider uploading a small subset of your data into Mapbox Studio as a custom tileset.
+
+From the [Mapbox Studio Dashboard](https://www.mapbox.com/studio/), click `Tilesets` in the sidebar, then click `New Tileset` to get started with most common geo file formats including KML, GPX, GeoJSON, Shapefiles, and CSV.
+
+### Faking placeholder data
+If you don’t have any custom data on hand in a format that works easily with the Tileset importer, you can fake placeholder data with the Dataset Editor.
+
+From the [Mapbox Studio Dashboard](https://www.mapbox.com/studio/), click `Datasets` in the sidebar, then click on `New Dataset` to get started.
+
+Zoom into your desired location and use the draw tools on the left to start creating a set of sample data.
+
+![create shapes](img/studio-workflow/create-polygons.gif)
+
+Next, add data properties you’d like to use to drive your style. Consider categorical properties or numeric properties that you’d use to filter and group your data. Text properties can be used to display icons or labels.
+
+![add properties](img/studio-workflow/add-properties.gif)
+
+**General Guidelines:**
+
+* Text along a line: add line with a text property
+* Text at specific points on a line or polygon: in addition to the line, create points at the specific points you’d like with text properties
+* If you want circles where scale doesn’t matter relative to the geography (e.g. always 20 pixels), you can add as a point and style with a circle layer or a symbol
+* If you want circles or arcs where the scale matters (e.g. 10 mile radius), you’ll need to approximately freehand a polygon that you can create more precisely later in code.
+
+When you’re done, save your dataset and export as a tileset. When that’s complete, add your tileset to your style.
+
+### Import into your style
+
+1. Click `New Layer`
+2. Select your tileset
+3. Select your shape type:
+ * `Symbol`: best for text and icons
+ * `Line`: best for lines or adding strokes to polygons
+ * `Fill`: best for filling polygons
+ * `Circle`: for styling points or nodes along a line or polygon as circles. If you need circles of a fixed radius (e.g. 1 mile radius), you should model your data as a polygon.
+4. Add filters if necessary
+ * You can selectively filter your data by their properties to group and style separately
+5. Click on `Create Layer`
+
+## Styling with Mapbox Studio
+
+Mapbox Studio shines for styling your data and the process is much faster than attempting to style natively.
+
+There are some nuances to understand between the different layer types and how they work together. Don’t be afraid to use the layers sidebar to peek into the techniques used to style the stock Mapbox maps. You can duplicate these layers, re-point the source to your own data, and tweak as needed.
+
+**Best Practices:**
+
+* Layers are cheap, so duplicate and update filters liberally.
+* If you’d like to stroke polygons you’ll need to use two layers: one a fill and one a stroked line.
+* If you want to stroke a line, create two layers, one for the default stroke and one with a wider width for its casing
+* If you intend to animate properties or transition between values, consider creating separate layers for each state and toggling visibility to visualize the difference.
+
+## Implement on iOS with runtime styling
+
+Once you’re happy with the styles you’ve created, it’s time to [get setup with Mapbox in your app](https://www.mapbox.com/ios-sdk/).
+
+To implement your prototypes with runtime styling:
+
+1. Implement `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]`.
+2. Add your real data as a source:
+ * This can be done using vector data from tileset editor ([example](https://www.mapbox.com/ios-sdk/examples/runtime-circle-styles)), custom vector tiles, added as GeoJSON ([example](https://www.mapbox.com/ios-sdk/examples/runtime-add-line), or added manually through the app via `MGLShapeSource` ([example](https://www.mapbox.com/ios-sdk/examples/runtime-multiple-annotations))
+3. For each layer you’ve prototyped in Studio, add its corresponding `MGLStyleLayer` subclass. See [“Configuring the map content’s appearance”](for-style-authors.html#configuring-the-map-content-s-appearance) for the available style layer classes.
+
+**Translating style attributes from Studio**
+For each property you’ve edited in Studio, you can hover over the property name to find the corresponding property in the iOS SDK. It’ll generally be the camelCased version of the Property ID, but see [“Configuring the map content’s appearance”](for-style-authors.html#configuring-the-map-content-s-appearance) for a table of properties that differ between Mapbox Studio and the iOS SDK.
+
+![property values](img/studio-workflow/property-values.png)
+
+**Translating stop functions**
+It’s possible to use stop functions in Mapbox Studio to transition the style of a layer by its zoom level (e.g. a line that gets wider as you zoom in). These can be translated in the mobile SDKs using `+[MGLSyleValue valueWithInterpolationBase:stops:]`. The rate of change between stops in Studio is represented by `interpolationBase`.
+
+![Stop functions](img/studio-workflow/stop-functions.png)
+
+## Resources
+
+* [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)
+* [Mapbox Studio](https://www.mapbox.com/mapbox-studio/)
+* [iOS code examples](https://www.mapbox.com/ios-sdk/examples/)
diff --git a/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif b/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif
new file mode 100644
index 0000000000..dee99d01fd
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif
Binary files differ
diff --git a/platform/ios/docs/img/runtime-styling/DynamicStyles.gif b/platform/ios/docs/img/runtime-styling/DynamicStyles.gif
new file mode 100644
index 0000000000..b42d30c602
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/DynamicStyles.gif
Binary files differ
diff --git a/platform/ios/docs/img/runtime-styling/Emoji.gif b/platform/ios/docs/img/runtime-styling/Emoji.gif
new file mode 100644
index 0000000000..fc50b28972
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/Emoji.gif
Binary files differ
diff --git a/platform/ios/docs/img/runtime-styling/HexBins.gif b/platform/ios/docs/img/runtime-styling/HexBins.gif
new file mode 100644
index 0000000000..c810085f22
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/HexBins.gif
Binary files differ
diff --git a/platform/ios/docs/img/runtime-styling/Population.gif b/platform/ios/docs/img/runtime-styling/Population.gif
new file mode 100644
index 0000000000..81b6c6310f
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/Population.gif
Binary files differ
diff --git a/platform/ios/docs/img/runtime-styling/SnowLevels.gif b/platform/ios/docs/img/runtime-styling/SnowLevels.gif
new file mode 100644
index 0000000000..8ee2f9fddd
--- /dev/null
+++ b/platform/ios/docs/img/runtime-styling/SnowLevels.gif
Binary files differ
diff --git a/platform/ios/screenshot.png b/platform/ios/docs/img/screenshot.png
index 62c04746d4..62c04746d4 100644
--- a/platform/ios/screenshot.png
+++ b/platform/ios/docs/img/screenshot.png
Binary files differ
diff --git a/platform/ios/docs/img/studio-workflow/add-properties.gif b/platform/ios/docs/img/studio-workflow/add-properties.gif
new file mode 100644
index 0000000000..740fae655b
--- /dev/null
+++ b/platform/ios/docs/img/studio-workflow/add-properties.gif
Binary files differ
diff --git a/platform/ios/docs/img/studio-workflow/create-polygons.gif b/platform/ios/docs/img/studio-workflow/create-polygons.gif
new file mode 100644
index 0000000000..6eb2c0afb8
--- /dev/null
+++ b/platform/ios/docs/img/studio-workflow/create-polygons.gif
Binary files differ
diff --git a/platform/ios/docs/img/studio-workflow/property-values.png b/platform/ios/docs/img/studio-workflow/property-values.png
new file mode 100644
index 0000000000..95704241f9
--- /dev/null
+++ b/platform/ios/docs/img/studio-workflow/property-values.png
Binary files differ
diff --git a/platform/ios/docs/img/studio-workflow/stop-functions.png b/platform/ios/docs/img/studio-workflow/stop-functions.png
new file mode 100644
index 0000000000..4affecf005
--- /dev/null
+++ b/platform/ios/docs/img/studio-workflow/stop-functions.png
Binary files differ
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index 78647b2603..b1a763bcf1 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -4,7 +4,7 @@ The Mapbox iOS SDK is an open-source framework for embedding interactive map vie
For more information, check out the [Mapbox iOS SDK homepage](https://www.mapbox.com/ios-sdk/) and the [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/CHANGELOG.md) online.
-[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png)]()
+[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/docs/img/screenshot.png)]()
## Installation
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 6f2ee38e94..42ae50e942 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -86,20 +86,23 @@
3566C76F1D4A8DFA008152BC /* MGLRasterSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3566C76B1D4A8DFA008152BC /* MGLRasterSource.mm */; };
3566C7711D4A9198008152BC /* MGLSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3566C7701D4A9198008152BC /* MGLSource_Private.h */; };
3566C7721D4A9198008152BC /* MGLSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3566C7701D4A9198008152BC /* MGLSource_Private.h */; };
- 357579801D501E09000B822E /* MGLFillStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.m */; };
- 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.m */; };
- 357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.m */; };
- 357579871D502AFE000B822E /* MGLLineStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 357579861D502AFE000B822E /* MGLLineStyleLayerTests.m */; };
- 357579891D502B06000B822E /* MGLCircleStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 357579881D502B06000B822E /* MGLCircleStyleLayerTests.m */; };
- 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.m */; };
- 3575798E1D502EC7000B822E /* MGLRuntimeStylingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3575798D1D502EC7000B822E /* MGLRuntimeStylingHelper.m */; };
+ 357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.mm */; };
+ 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.mm */; };
+ 357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.mm */; };
+ 357579871D502AFE000B822E /* MGLLineStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357579861D502AFE000B822E /* MGLLineStyleLayerTests.mm */; };
+ 357579891D502B06000B822E /* MGLCircleStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357579881D502B06000B822E /* MGLCircleStyleLayerTests.mm */; };
+ 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm */; };
+ 357FE2DD1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */; };
+ 357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */; };
+ 357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */; };
+ 357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */; };
3599A3E61DF708BC00E77FB2 /* MGLStyleValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */; };
359F57461D2FDDA6005217F1 /* MGLUserLocationAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */; };
35B82BF81D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35B82BF61D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h */; };
35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35B82BF61D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h */; };
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35B82BF71D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm */; };
35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35B82BF71D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm */; };
- 35B8E08C1D6C8B5100E768D2 /* MGLFilterTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35B8E08B1D6C8B5100E768D2 /* MGLFilterTests.mm */; };
+ 35B8E08C1D6C8B5100E768D2 /* MGLPredicateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */; };
35CE61821D4165D9004F2359 /* UIColor+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35CE61801D4165D9004F2359 /* UIColor+MGLAdditions.h */; };
35CE61831D4165D9004F2359 /* UIColor+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35CE61801D4165D9004F2359 /* UIColor+MGLAdditions.h */; };
35CE61841D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35CE61811D4165D9004F2359 /* UIColor+MGLAdditions.mm */; };
@@ -112,6 +115,7 @@
35D13AC41D3D19DD00AFB4E0 /* MGLFillStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */; };
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */; };
+ 35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */; };
35E0CFE61D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; };
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; };
35E1A4D81D74336F007AA97F /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */; };
@@ -128,10 +132,6 @@
4018B1C91CDC288A00F666AF /* MGLAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */; };
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 4032C5BF1DE1FC780062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4032C5B81DE1EE7D0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 4032C5C01DE1FC780062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4032C5B81DE1EE7D0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 4032C5C11DE1FC7E0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4032C5BD1DE1FC690062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */; };
- 4032C5C21DE1FC7E0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4032C5BD1DE1FC690062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */; };
404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */; };
4049C29D1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
4049C29E1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -167,6 +167,7 @@
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D71E1D085500E2C41B /* MGLVersionNumber.m */; };
556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
55D8C9961D0F18CE00F42F10 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */; };
+ 6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */; };
7E016D7E1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
7E016D7F1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
7E016D801D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D7D1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.m */; };
@@ -225,6 +226,7 @@
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
+ DA35D0881E1A6309007DED41 /* one-liner.json in Resources */ = {isa = PBXBuildFile; fileRef = DA35D0871E1A6309007DED41 /* one-liner.json */; };
DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA6408DC1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
@@ -410,6 +412,7 @@
DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.mm */; };
DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.mm */; };
+ DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */; };
DAED38631D62D0FC00D7640F /* NSURL+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED38611D62D0FC00D7640F /* NSURL+MGLAdditions.h */; };
DAED38641D62D0FC00D7640F /* NSURL+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED38611D62D0FC00D7640F /* NSURL+MGLAdditions.h */; };
DAED38651D62D0FC00D7640F /* NSURL+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAED38621D62D0FC00D7640F /* NSURL+MGLAdditions.m */; };
@@ -555,26 +558,27 @@
3566C76A1D4A8DFA008152BC /* MGLRasterSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource.h; sourceTree = "<group>"; };
3566C76B1D4A8DFA008152BC /* MGLRasterSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRasterSource.mm; sourceTree = "<group>"; };
3566C7701D4A9198008152BC /* MGLSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSource_Private.h; sourceTree = "<group>"; };
- 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLFillStyleLayerTests.m; path = ../../darwin/test/MGLFillStyleLayerTests.m; sourceTree = "<group>"; };
- 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLRasterStyleLayerTests.m; path = ../../darwin/test/MGLRasterStyleLayerTests.m; sourceTree = "<group>"; };
- 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSymbolStyleLayerTests.m; path = ../../darwin/test/MGLSymbolStyleLayerTests.m; sourceTree = "<group>"; };
- 357579861D502AFE000B822E /* MGLLineStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLLineStyleLayerTests.m; path = ../../darwin/test/MGLLineStyleLayerTests.m; sourceTree = "<group>"; };
- 357579881D502B06000B822E /* MGLCircleStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCircleStyleLayerTests.m; path = ../../darwin/test/MGLCircleStyleLayerTests.m; sourceTree = "<group>"; };
- 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLBackgroundStyleLayerTests.m; path = ../../darwin/test/MGLBackgroundStyleLayerTests.m; sourceTree = "<group>"; };
- 3575798C1D502EC7000B822E /* MGLRuntimeStylingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLRuntimeStylingHelper.h; path = ../../darwin/test/MGLRuntimeStylingHelper.h; sourceTree = "<group>"; };
- 3575798D1D502EC7000B822E /* MGLRuntimeStylingHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLRuntimeStylingHelper.m; path = ../../darwin/test/MGLRuntimeStylingHelper.m; sourceTree = "<group>"; };
+ 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFillStyleLayerTests.mm; path = ../../darwin/test/MGLFillStyleLayerTests.mm; sourceTree = "<group>"; };
+ 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRasterStyleLayerTests.mm; path = ../../darwin/test/MGLRasterStyleLayerTests.mm; sourceTree = "<group>"; };
+ 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLSymbolStyleLayerTests.mm; path = ../../darwin/test/MGLSymbolStyleLayerTests.mm; sourceTree = "<group>"; };
+ 357579861D502AFE000B822E /* MGLLineStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLineStyleLayerTests.mm; path = ../../darwin/test/MGLLineStyleLayerTests.mm; sourceTree = "<group>"; };
+ 357579881D502B06000B822E /* MGLCircleStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLCircleStyleLayerTests.mm; path = ../../darwin/test/MGLCircleStyleLayerTests.mm; sourceTree = "<group>"; };
+ 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLBackgroundStyleLayerTests.mm; path = ../../darwin/test/MGLBackgroundStyleLayerTests.mm; sourceTree = "<group>"; };
357F09091DF84F3800941873 /* MGLStyleValueTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLStyleValueTests.h; path = ../../darwin/test/MGLStyleValueTests.h; sourceTree = "<group>"; };
+ 357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSCoder+MGLAdditions.h"; path = "../../darwin/src/NSCoder+MGLAdditions.h"; sourceTree = "<group>"; };
+ 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "NSCoder+MGLAdditions.mm"; path = "../../darwin/src/NSCoder+MGLAdditions.mm"; sourceTree = "<group>"; };
3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLStyleValueTests.m; path = ../../darwin/test/MGLStyleValueTests.m; sourceTree = "<group>"; };
359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationAnnotationView_Private.h; sourceTree = "<group>"; };
35B82BF61D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+MGLAdditions.h"; sourceTree = "<group>"; };
35B82BF71D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSPredicate+MGLAdditions.mm"; sourceTree = "<group>"; };
- 35B8E08B1D6C8B5100E768D2 /* MGLFilterTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFilterTests.mm; path = ../../darwin/test/MGLFilterTests.mm; sourceTree = "<group>"; };
+ 35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLPredicateTests.mm; path = ../../darwin/test/MGLPredicateTests.mm; sourceTree = "<group>"; };
35CE61801D4165D9004F2359 /* UIColor+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+MGLAdditions.h"; sourceTree = "<group>"; };
35CE61811D4165D9004F2359 /* UIColor+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIColor+MGLAdditions.mm"; sourceTree = "<group>"; };
35D13AB51D3D15E300AFB4E0 /* MGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayer.h; sourceTree = "<group>"; };
35D13AB61D3D15E300AFB4E0 /* MGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLStyleLayer.mm; sourceTree = "<group>"; };
35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFillStyleLayer.h; sourceTree = "<group>"; };
35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillStyleLayer.mm; sourceTree = "<group>"; };
+ 35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCodingTests.m; path = ../../darwin/test/MGLCodingTests.m; sourceTree = "<group>"; };
35E0CFE51D3E501500188327 /* MGLStyle_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyle_Private.h; sourceTree = "<group>"; };
35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLValueEvaluator.h; sourceTree = "<group>"; };
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNSDataAdditionsTests.m; sourceTree = "<group>"; };
@@ -587,10 +591,6 @@
4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAnnotationView.mm; sourceTree = "<group>"; };
4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = "<group>"; };
402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = "<group>"; };
- 4032C5B71DE1EBB90062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSValue+MGLStyleEnumAttributeAdditions.h.ejs"; sourceTree = "<group>"; };
- 4032C5B81DE1EE7D0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLStyleEnumAttributeAdditions.h"; sourceTree = "<group>"; };
- 4032C5BC1DE1FAFC0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSValue+MGLStyleEnumAttributeAdditions.mm.ejs"; sourceTree = "<group>"; };
- 4032C5BD1DE1FC690062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSValue+MGLStyleEnumAttributeAdditions.mm"; sourceTree = "<group>"; };
404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView_Private.h; sourceTree = "<group>"; };
4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = "<group>"; };
4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = "<group>"; };
@@ -616,6 +616,7 @@
556660D71E1D085500E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = "<group>"; };
55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
+ 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationExampleTests.swift; path = ../../darwin/test/MGLDocumentationExampleTests.swift; sourceTree = "<group>"; };
7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolyline+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D7D1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolyline+MGLAdditions.m"; sourceTree = "<group>"; };
7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolygon+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -667,6 +668,8 @@
DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLAdditions.h"; sourceTree = "<group>"; };
DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+MGLAdditions.m"; sourceTree = "<group>"; };
DA35A2D11CCAB25200E826B2 /* jazzy.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = jazzy.yml; sourceTree = "<group>"; };
+ DA35D0871E1A6309007DED41 /* one-liner.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "one-liner.json"; path = "../../darwin/test/one-liner.json"; sourceTree = "<group>"; };
+ DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "test-Bridging-Header.h"; path = "../../darwin/test/test-Bridging-Header.h"; sourceTree = "<group>"; };
DA4A26961CB6E795000B7809 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
@@ -767,7 +770,7 @@
DA8963341CC549A100684375 /* sprites */ = {isa = PBXFileReference; lastKnownFileType = folder; path = sprites; sourceTree = "<group>"; };
DA8963351CC549A100684375 /* styles */ = {isa = PBXFileReference; lastKnownFileType = folder; path = styles; sourceTree = "<group>"; };
DA8963361CC549A100684375 /* tiles */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tiles; sourceTree = "<group>"; };
- DA8F25B91D51D2570010E6B5 /* MGLStyleLayerTests.m.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.m.ejs; path = ../test/MGLStyleLayerTests.m.ejs; sourceTree = "<group>"; };
+ DA8F25B91D51D2570010E6B5 /* MGLStyleLayerTests.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.mm.ejs; path = ../test/MGLStyleLayerTests.mm.ejs; sourceTree = "<group>"; };
DA8F25BA1D51D2570010E6B5 /* MGLStyleLayer.h.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.h.ejs; sourceTree = "<group>"; };
DA8F25BB1D51D2570010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
DAA4E4021CBB5C2F00178DFB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -794,6 +797,7 @@
DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; };
DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeCollection.mm; sourceTree = "<group>"; };
+ DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLNSStringAdditionsTests.m; path = ../../darwin/test/MGLNSStringAdditionsTests.m; sourceTree = "<group>"; };
DAED38611D62D0FC00D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; };
DAED38621D62D0FC00D7640F /* NSURL+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MGLAdditions.m"; sourceTree = "<group>"; };
DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAttributionInfoTests.m; path = ../../darwin/test/MGLAttributionInfoTests.m; sourceTree = "<group>"; };
@@ -923,8 +927,6 @@
35599DB81D46AD7F0048254D /* Categories */ = {
isa = PBXGroup;
children = (
- 4032C5B81DE1EE7D0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */,
- 4032C5BD1DE1FC690062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */,
350098DA1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.h */,
350098DB1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm */,
);
@@ -935,11 +937,10 @@
isa = PBXGroup;
children = (
3575798F1D513EF1000B822E /* Layers */,
- 35B8E08B1D6C8B5100E768D2 /* MGLFilterTests.mm */,
+ 40CFA64E1D78754A008103BD /* Sources */,
357F09091DF84F3800941873 /* MGLStyleValueTests.h */,
3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */,
DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */,
- 40CFA64E1D78754A008103BD /* Sources */,
);
name = Styling;
sourceTree = "<group>";
@@ -949,14 +950,13 @@
children = (
DA2DBBCC1D51E80400D38FF9 /* MGLStyleLayerTests.h */,
DA2DBBCD1D51E80400D38FF9 /* MGLStyleLayerTests.m */,
- 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.m */,
- 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.m */,
- 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.m */,
- 357579861D502AFE000B822E /* MGLLineStyleLayerTests.m */,
- 357579881D502B06000B822E /* MGLCircleStyleLayerTests.m */,
- 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.m */,
- 3575798C1D502EC7000B822E /* MGLRuntimeStylingHelper.h */,
- 3575798D1D502EC7000B822E /* MGLRuntimeStylingHelper.m */,
+ DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */,
+ 3575797F1D501E09000B822E /* MGLFillStyleLayerTests.mm */,
+ 357579821D502AE6000B822E /* MGLRasterStyleLayerTests.mm */,
+ 357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.mm */,
+ 357579861D502AFE000B822E /* MGLLineStyleLayerTests.mm */,
+ 357579881D502B06000B822E /* MGLCircleStyleLayerTests.mm */,
+ 3575798A1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm */,
);
name = Layers;
sourceTree = "<group>";
@@ -968,6 +968,8 @@
35CE61811D4165D9004F2359 /* UIColor+MGLAdditions.mm */,
30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */,
30E578121DAA7D690050F07E /* UIImage+MGLAdditions.mm */,
+ 357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */,
+ 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */,
);
name = Categories;
sourceTree = "<group>";
@@ -1092,19 +1094,24 @@
DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */,
353D23951D0B0DFE002BE09D /* MGLAnnotationViewTests.m */,
DA35A2C31CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m */,
+ 35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */,
DA35A2C41CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */,
+ 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */,
+ DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */,
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */,
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */,
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */,
+ DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */,
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */,
DA2E885F1CC0382C00F24E7B /* MGLOfflineStorageTests.m */,
+ 35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */,
DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */,
- DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */,
556660D71E1D085500E2C41B /* MGLVersionNumber.m */,
DA2E88551CC036F400F24E7B /* Info.plist */,
DA2784FB1DF02FF4001D5B8D /* Media.xcassets */,
+ DA35D0871E1A6309007DED41 /* one-liner.json */,
);
name = "SDK Tests";
path = test;
@@ -1258,9 +1265,7 @@
children = (
DA8F25BA1D51D2570010E6B5 /* MGLStyleLayer.h.ejs */,
DA8F25BB1D51D2570010E6B5 /* MGLStyleLayer.mm.ejs */,
- DA8F25B91D51D2570010E6B5 /* MGLStyleLayerTests.m.ejs */,
- 4032C5B71DE1EBB90062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h.ejs */,
- 4032C5BC1DE1FAFC0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm.ejs */,
+ DA8F25B91D51D2570010E6B5 /* MGLStyleLayerTests.mm.ejs */,
);
name = "Foundation Templates";
path = ../../darwin/src;
@@ -1462,6 +1467,7 @@
4018B1C91CDC288A00F666AF /* MGLAnnotationView_Private.h in Headers */,
35E1A4D81D74336F007AA97F /* MGLValueEvaluator.h in Headers */,
DA88482C1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.h in Headers */,
+ 357FE2DD1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */,
7E016D7E1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */,
35D13AB71D3D15E300AFB4E0 /* MGLStyleLayer.h in Headers */,
DA88488E1CBB047F00AB86E3 /* reachability.h in Headers */,
@@ -1520,7 +1526,6 @@
DA88488B1CBB037E00AB86E3 /* SMCalloutView.h in Headers */,
DA8847FE1CBAFA5100AB86E3 /* MGLTypes.h in Headers */,
DA8847F11CBAFA5100AB86E3 /* MGLGeometry.h in Headers */,
- 4032C5BF1DE1FC780062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */,
DA8848221CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h in Headers */,
35136D4C1D4277FC00C20EFD /* MGLSource.h in Headers */,
3566C76C1D4A8DFA008152BC /* MGLRasterSource.h in Headers */,
@@ -1564,7 +1569,6 @@
buildActionMask = 2147483647;
files = (
556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */,
- 4032C5C01DE1FC780062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */,
35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */,
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
350098BC1D480108004B2AF0 /* MGLVectorSource.h in Headers */,
@@ -1617,6 +1621,7 @@
DA35A2B21CCA141D00E826B2 /* MGLCompassDirectionFormatter.h in Headers */,
DAF0D8141DFE0EC500B28378 /* MGLVectorSource_Private.h in Headers */,
DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */,
+ 357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */,
354B83971D2E873E005D9406 /* MGLUserLocationAnnotationView.h in Headers */,
DAF0D8111DFE0EA000B28378 /* MGLRasterSource_Private.h in Headers */,
DABFB86B1CBE99E500D62B32 /* MGLTilePyramidOfflineRegion.h in Headers */,
@@ -1779,16 +1784,19 @@
TargetAttributes = {
DA1DC9491CB6C1C2006E619F = {
CreatedOnToolsVersion = 7.3;
+ DevelopmentTeam = GJZR2MEM28;
+ LastSwiftMigration = 0820;
};
DA25D5B81CCD9EDE00607828 = {
CreatedOnToolsVersion = 7.3;
};
DA2E88501CC036F400F24E7B = {
CreatedOnToolsVersion = 7.3;
- LastSwiftMigration = 0800;
+ LastSwiftMigration = 0820;
};
DA8847D11CBAF91600AB86E3 = {
CreatedOnToolsVersion = 7.3;
+ LastSwiftMigration = 0820;
};
DA8933D41CCD306400E68420 = {
CreatedOnToolsVersion = 7.3;
@@ -1861,6 +1869,7 @@
files = (
DA2784FC1DF02FF4001D5B8D /* Media.xcassets in Resources */,
353BAEF71D646370009A8DA9 /* amsterdam.geojson in Resources */,
+ DA35D0881E1A6309007DED41 /* one-liner.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1945,29 +1954,31 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
3599A3E61DF708BC00E77FB2 /* MGLStyleValueTests.m in Sources */,
DA2E88651CC0382C00F24E7B /* MGLStyleTests.mm in Sources */,
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */,
- 357579801D501E09000B822E /* MGLFillStyleLayerTests.m in Sources */,
+ 357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */,
+ 35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
DA2E88641CC0382C00F24E7B /* MGLOfflineStorageTests.m in Sources */,
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
- 3575798E1D502EC7000B822E /* MGLRuntimeStylingHelper.m in Sources */,
+ DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */,
DAEDC4341D603417000224FF /* MGLAttributionInfoTests.m in Sources */,
- 357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.m in Sources */,
- 357579871D502AFE000B822E /* MGLLineStyleLayerTests.m in Sources */,
- 357579891D502B06000B822E /* MGLCircleStyleLayerTests.m in Sources */,
+ 357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.mm in Sources */,
+ 357579871D502AFE000B822E /* MGLLineStyleLayerTests.mm in Sources */,
+ 357579891D502B06000B822E /* MGLCircleStyleLayerTests.mm in Sources */,
DA2207BF1DC0805F0002F84D /* MGLStyleValueTests.swift in Sources */,
40CFA6511D7875BB008103BD /* MGLShapeSourceTests.mm in Sources */,
DA35A2C51CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m in Sources */,
- 35B8E08C1D6C8B5100E768D2 /* MGLFilterTests.mm in Sources */,
+ 35B8E08C1D6C8B5100E768D2 /* MGLPredicateTests.mm in Sources */,
DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */,
- 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.m in Sources */,
+ 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
- 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.m in Sources */,
+ 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */,
35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */,
DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */,
@@ -2021,6 +2032,7 @@
DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */,
+ 357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
DA88481C1CBAFA6200AB86E3 /* MGLGeometry.mm in Sources */,
3510FFF21D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */,
DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */,
@@ -2035,7 +2047,6 @@
DA8848301CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m in Sources */,
353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
- 4032C5C11DE1FC7E0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */,
DA8848241CBAFA6200AB86E3 /* MGLOfflineStorage.mm in Sources */,
DA88482A1CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm in Sources */,
4049C29F1DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */,
@@ -2096,6 +2107,7 @@
DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */,
DA35A2A21CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
+ 357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */,
3510FFF31D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */,
DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */,
@@ -2110,7 +2122,6 @@
DAA4E4231CBB730400178DFB /* MGLPolygon.mm in Sources */,
353AFA171D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
- 4032C5C21DE1FC7E0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */,
DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */,
DAA4E4211CBB730400178DFB /* MGLOfflineStorage.mm in Sources */,
4049C2A01DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */,
@@ -2333,6 +2344,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
+ SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -2345,6 +2357,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
+ SWIFT_VERSION = 3.0;
};
name = Release;
};
@@ -2441,6 +2454,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios;
PRODUCT_NAME = Mapbox;
SKIP_INSTALL = YES;
+ SWIFT_VERSION = 3.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "__attribute__((visibility (\"default\"))) ";
};
@@ -2474,6 +2488,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios;
PRODUCT_NAME = Mapbox;
SKIP_INSTALL = YES;
+ SWIFT_VERSION = 3.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "__attribute__((visibility (\"default\"))) ";
};
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index 2f62cfa305..71f6be37f2 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -15,63 +15,76 @@ umbrella_header: src/Mapbox.h
framework_root: ../darwin/src
custom_categories:
+ - name: Guides
+ children:
+ - Adding Points to a Map
+ - Runtime Styling
+ - Working with Mapbox Studio
+ - Working with GeoJSON Data
+ - For Style Authors
+ - Info.plist Keys
- name: Maps
children:
- MGLAccountManager
- MGLMapCamera
- MGLMapView
- MGLMapViewDelegate
- - MGLStyle
- MGLUserTrackingMode
- - name: Annotations
+ - name: Primitive Shapes
children:
- MGLAnnotation
- - MGLAnnotationImage
- - MGLAnnotationView
- - MGLCalloutView
- - MGLCalloutViewDelegate
+ - MGLOverlay
+ - MGLShape
- MGLMultiPoint
- - MGLMultiPolygon
- - MGLMultiPolyline
- MGLPointAnnotation
- MGLPointCollection
- MGLPolygon
- MGLPolyline
- - MGLOverlay
- - MGLShape
+ - MGLMultiPolygon
+ - MGLMultiPolyline
- MGLShapeCollection
+ - name: Annotations
+ children:
+ - MGLAnnotationImage
+ - MGLAnnotationView
- MGLUserLocation
- MGLUserLocationAnnotationView
- - name: Map Data
+ - name: User Interaction
+ children:
+ - MGLCalloutView
+ - MGLCalloutViewDelegate
+ - name: Styling the Map
+ children:
+ - MGLStyle
+ - MGLStyleValue
+ - name: Style Primitives
children:
- MGLFeature
- - MGLMultiPolygonFeature
- - MGLMultiPolylineFeature
- - MGLPointCollectionFeature
- MGLPointFeature
- MGLPolygonFeature
- MGLPolylineFeature
+ - MGLMultiPolygonFeature
+ - MGLMultiPolylineFeature
+ - MGLPointCollectionFeature
- MGLShapeCollectionFeature
+ - name: Style Content
+ children:
+ - MGLSource
+ - MGLTileSource
+ - MGLShapeSource
+ - MGLRasterSource
+ - MGLVectorSource
- name: Style Layers
children:
+ - MGLStyleLayer
+ - MGLForegroundStyleLayer
- MGLBackgroundStyleLayer
+ - MGLRasterStyleLayer
+ - MGLVectorStyleLayer
- MGLCircleStyleLayer
- MGLFillStyleLayer
- - MGLForegroundStyleLayer
- MGLLineStyleLayer
- - MGLRasterStyleLayer
- - MGLStyleLayer
- MGLSymbolStyleLayer
- - MGLVectorStyleLayer
- - name: Content Sources
- children:
- - MGLAttributionInfo
- - MGLRasterSource
- - MGLShapeSource
- - MGLSource
- - MGLTileCoordinateSystem
- - MGLTileSource
- - MGLVectorSource
- name: Offline Maps
children:
- MGLOfflineRegion
@@ -82,15 +95,13 @@ custom_categories:
- MGLTilePyramidOfflineRegion
- name: Geometry
children:
- - MGLClockDirectionFormatter
- - MGLCompassDirectionFormatter
- MGLCoordinateBounds
- MGLCoordinateBoundsEqualToCoordinateBounds
- MGLCoordinateBoundsGetCoordinateSpan
+ - MGLCoordinateBoundsIntersectsCoordinateBounds
- MGLCoordinateBoundsIsEmpty
- MGLCoordinateBoundsMake
- MGLCoordinateBoundsOffset
- - MGLCoordinateFormatter
- MGLCoordinateInCoordinateBounds
- MGLCoordinateSpan
- MGLCoordinateSpanEqualToCoordinateSpan
@@ -99,3 +110,8 @@ custom_categories:
- MGLDegreesFromRadians
- MGLRadiansFromDegrees
- MGLStringFromCoordinateBounds
+ - name: Formatters
+ children:
+ - MGLClockDirectionFormatter
+ - MGLCompassDirectionFormatter
+ - MGLCoordinateFormatter
diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh
index 8ad5e7abb1..2265afdba6 100755
--- a/platform/ios/scripts/deploy-packages.sh
+++ b/platform/ios/scripts/deploy-packages.sh
@@ -44,7 +44,7 @@ buildPackageStyle() {
--tag "ios-v${PUBLISH_VERSION}" \
--name ${file_name} \
--file "${BINARY_DIRECTORY}/${file_name}" > /dev/null
- fi
+ fi
}
export TRAVIS_REPO_SLUG=mapbox-gl-native
diff --git a/platform/ios/scripts/document.sh b/platform/ios/scripts/document.sh
index fddf5abb0f..d66742a33f 100755
--- a/platform/ios/scripts/document.sh
+++ b/platform/ios/scripts/document.sh
@@ -30,7 +30,7 @@ sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^## /q' -e 'p' -e 'ba' -e '}' platform/i
rm -rf ${OUTPUT}
mkdir -p ${OUTPUT}
-cp platform/ios/screenshot.png "${OUTPUT}"
+cp -r platform/ios/docs/img "${OUTPUT}/img"
DEFAULT_THEME="platform/darwin/docs/theme"
THEME=${JAZZY_THEME:-$DEFAULT_THEME}
@@ -41,7 +41,7 @@ jazzy \
--github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \
--module-version ${SHORT_VERSION} \
--readme ${README} \
- --documentation="platform/ios/docs/Info.plist Keys.md" \
+ --documentation="platform/{darwin,ios}/docs/guides/*.md" \
--root-url https://www.mapbox.com/ios-sdk/api/${RELEASE_VERSION}/ \
--theme ${THEME} \
--output ${OUTPUT}
diff --git a/platform/ios/src/MGLAPIClient.h b/platform/ios/src/MGLAPIClient.h
index 0f8926d360..4e5ea3b5e0 100644
--- a/platform/ios/src/MGLAPIClient.h
+++ b/platform/ios/src/MGLAPIClient.h
@@ -9,7 +9,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler;
- (void)postEvent:(MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler;
-- (void)cancelAll;
@end
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m
index 7fb6538e5d..5e8ee5fe1d 100644
--- a/platform/ios/src/MGLAPIClient.m
+++ b/platform/ios/src/MGLAPIClient.m
@@ -21,7 +21,6 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
@property (nonatomic, copy) NSData *geoTrustCert;
@property (nonatomic, copy) NSData *testServerCert;
@property (nonatomic, copy) NSString *userAgent;
-@property (nonatomic) NSMutableArray *dataTasks;
@property (nonatomic) BOOL usesTestServer;
@end
@@ -33,7 +32,6 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
if (self) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self delegateQueue:nil];
- _dataTasks = [NSMutableArray array];
[self loadCertificates];
[self setupBaseURL];
[self setupUserAgent];
@@ -59,24 +57,15 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
error = error ?: statusError;
completionHandler(error);
}
- [self.dataTasks removeObject:dataTask];
dataTask = nil;
}];
[dataTask resume];
- if (dataTask) {
- [self.dataTasks addObject:dataTask];
- }
}
- (void)postEvent:(nonnull MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler {
[self postEvents:@[event] completionHandler:completionHandler];
}
-- (void)cancelAll {
- [self.dataTasks makeObjectsPerformSelector:@selector(cancel)];
- [self.dataTasks removeAllObjects];
-}
-
#pragma mark Utilities
- (NSURLRequest *)requestForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events {
diff --git a/platform/ios/src/MGLAnnotationImage.h b/platform/ios/src/MGLAnnotationImage.h
index a7003d7f91..95bce21f51 100644
--- a/platform/ios/src/MGLAnnotationImage.h
+++ b/platform/ios/src/MGLAnnotationImage.h
@@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
objects and may be recycled later and put into a reuse queue that is maintained
by the map view.
*/
-@interface MGLAnnotationImage : NSObject
+@interface MGLAnnotationImage : NSObject <NSSecureCoding>
#pragma mark Initializing and Preparing the Image Object
diff --git a/platform/ios/src/MGLAnnotationImage.m b/platform/ios/src/MGLAnnotationImage.m
index e1085be98d..9c9c175ab9 100644
--- a/platform/ios/src/MGLAnnotationImage.m
+++ b/platform/ios/src/MGLAnnotationImage.m
@@ -30,6 +30,41 @@
return self;
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super init]) {
+ _image = [decoder decodeObjectOfClass:[UIImage class] forKey:@"image"];
+ _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"];
+ _enabled = [decoder decodeBoolForKey:@"enabled"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [coder encodeObject:_image forKey:@"image"];
+ [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"];
+ [coder encodeBool:_enabled forKey:@"enabled"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO;
+
+ MGLAnnotationImage *otherAnnotationImage = other;
+
+ return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier)
+ || [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier])
+ && _enabled == otherAnnotationImage.enabled
+ && (_image == otherAnnotationImage.image || [UIImagePNGRepresentation(_image) isEqualToData:UIImagePNGRepresentation(otherAnnotationImage.image)]);
+}
+
+- (NSUInteger)hash {
+ return _reuseIdentifier.hash + _enabled + _image.hash;
+}
+
- (void)setImage:(UIImage *)image {
_image = image;
[self.delegate annotationImageNeedsRedisplay:self];
diff --git a/platform/ios/src/MGLAnnotationView.h b/platform/ios/src/MGLAnnotationView.h
index 634e9ad723..d159976a4c 100644
--- a/platform/ios/src/MGLAnnotationView.h
+++ b/platform/ios/src/MGLAnnotationView.h
@@ -50,7 +50,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
interactivity such as dragging, you can use an `MGLAnnotationImage` instead to
conserve memory and optimize drawing performance.
*/
-@interface MGLAnnotationView : UIView
+@interface MGLAnnotationView : UIView <NSSecureCoding>
#pragma mark Initializing and Preparing the View
diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm
index 96ed8c733e..d2243bdf23 100644
--- a/platform/ios/src/MGLAnnotationView.mm
+++ b/platform/ios/src/MGLAnnotationView.mm
@@ -33,6 +33,34 @@
return self;
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"];
+ _annotation = [decoder decodeObjectOfClass:[NSObject class] forKey:@"annotation"];
+ _centerOffset = [decoder decodeCGVectorForKey:@"centerOffset"];
+ _scalesWithViewingDistance = [decoder decodeBoolForKey:@"scalesWithViewingDistance"];
+ _selected = [decoder decodeBoolForKey:@"selected"];
+ _enabled = [decoder decodeBoolForKey:@"enabled"];
+ self.draggable = [decoder decodeBoolForKey:@"draggable"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [super encodeWithCoder:coder];
+ [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"];
+ [coder encodeObject:_annotation forKey:@"annotation"];
+ [coder encodeCGVector:_centerOffset forKey:@"centerOffset"];
+ [coder encodeBool:_scalesWithViewingDistance forKey:@"scalesWithViewingDistance"];
+ [coder encodeBool:_selected forKey:@"selected"];
+ [coder encodeBool:_enabled forKey:@"enabled"];
+ [coder encodeBool:_draggable forKey:@"draggable"];
+}
+
- (void)prepareForReuse
{
// Intentionally left blank. The default implementation of this method does nothing.
diff --git a/platform/ios/src/MGLCalloutView.h b/platform/ios/src/MGLCalloutView.h
index 6918aad614..4dc9a25be4 100644
--- a/platform/ios/src/MGLCalloutView.h
+++ b/platform/ios/src/MGLCalloutView.h
@@ -46,6 +46,24 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)dismissCalloutAnimated:(BOOL)animated;
+@optional
+
+/**
+ A Boolean value indicating whether the callout view should be anchored to
+ the corresponding annotation. You can adjust the callout view’s precise location by
+ overriding -[UIView setCenter:]. The callout view will not be anchored to the
+ annotation if this optional property is unimplemented.
+ */
+@property (nonatomic, readonly, assign, getter=isAnchoredToAnnotation) BOOL anchoredToAnnotation;
+
+/**
+ A Boolean value indicating whether the callout view should be dismissed automatically
+ when the map view’s viewport changes. Note that a single tap on the map view
+ still dismisses the callout view regardless of the value of this property.
+ The callout view will be dismissed if this optional property is unimplemented.
+ */
+@property (nonatomic, readonly, assign) BOOL dismissesAutomatically;
+
@end
/**
diff --git a/platform/ios/src/MGLCompactCalloutView.m b/platform/ios/src/MGLCompactCalloutView.m
index 49812c51a4..3d2118ca38 100644
--- a/platform/ios/src/MGLCompactCalloutView.m
+++ b/platform/ios/src/MGLCompactCalloutView.m
@@ -14,6 +14,14 @@
return [[self alloc] init];
}
+- (BOOL)isAnchoredToAnnotation {
+ return YES;
+}
+
+- (BOOL)dismissesAutomatically {
+ return NO;
+}
+
- (void)setRepresentedObject:(id <MGLAnnotation>)representedObject
{
_representedObject = representedObject;
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 771a48c7ff..62f053e96b 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -123,6 +123,13 @@ IB_DESIGNABLE
Unlike the `styleURL` property, this property is set to an object that allows
you to manipulate every aspect of the style locally.
+ If the style is loading, this property is set to `nil` until the style finishes
+ loading. If the style has failed to load, this property is set to `nil`.
+ Because the style loads asynchronously, you should manipulate it in the
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
+ to manipulate the style before it has finished loading.
+
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style's sources and layers must first set the style URL to an
@@ -130,7 +137,7 @@ IB_DESIGNABLE
`+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`.
*/
-@property (nonatomic, readonly) MGLStyle *style;
+@property (nonatomic, readonly, nullable) MGLStyle *style;
/**
URLs of the styles bundled with the library.
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 608acf016d..c211d4419b 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -7,6 +7,7 @@
#import <GLKit/GLKit.h>
#import <OpenGLES/EAGL.h>
+#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/sprite/sprite_image.hpp>
@@ -347,6 +348,11 @@ public:
return self;
}
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle
+{
+ return [NSSet setWithObject:@"styleURL"];
+}
+
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL
{
return [NSSet setWithObjects:@"styleURL__", nil];
@@ -369,10 +375,8 @@ public:
}
styleURL = styleURL.mgl_URLByStandardizingScheme;
- [self willChangeValueForKey:@"style"];
- _style = [[MGLStyle alloc] initWithMapView:self];
+ self.style = nil;
_mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]);
- [self didChangeValueForKey:@"style"];
}
- (IBAction)reloadStyle:(__unused id)sender {
@@ -1734,7 +1738,7 @@ public:
_attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] linkColor:nil];
for (MGLAttributionInfo *info in _attributionInfos)
{
- NSString *title = [info.title.string capitalizedStringWithLocale:[NSLocale currentLocale]];
+ NSString *title = [info.title.string mgl_titleCasedStringWithLocale:[NSLocale currentLocale]];
[self.attributionSheet addButtonWithTitle:title];
}
@@ -3137,23 +3141,9 @@ public:
- (double)alphaForShapeAnnotation:(MGLShape *)annotation
{
- // The explicit -mapView:alphaForShapeAnnotation: delegate method is deprecated
- // but still used, if implemented. When not implemented, call the stroke or
- // fill color delegate methods and pull the alpha from the returned color.
if (_delegateHasAlphasForShapeAnnotations)
{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [self.delegate mapView:self alphaForShapeAnnotation:annotation];
-#pragma clang diagnostic pop
- }
- else if ([annotation isKindOfClass:[MGLPolygon class]])
- {
- return [self fillColorForPolygonAnnotation:(MGLPolygon *)annotation].a ?: 1.0;
- }
- else if ([annotation isKindOfClass:[MGLShape class]])
- {
- return [self strokeColorForShapeAnnotation:annotation].a ?: 1.0;
}
return 1.0;
}
@@ -4566,21 +4556,34 @@ public:
|| self.userTrackingMode == MGLUserTrackingModeNone
|| self.userTrackingState != MGLUserTrackingStateChanged)
{
- // Deselect annotation if it lies outside the viewport
- if (self.selectedAnnotation) {
- MGLAnnotationTag tag = [self annotationTagForAnnotation:self.selectedAnnotation];
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
- MGLAnnotationView *annotationView = annotationContext.annotationView;
-
- CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];
-
- if (annotationView)
- {
- rect = annotationView.frame;
- }
-
- if ( ! CGRectIntersectsRect(rect, self.frame)) {
- [self deselectAnnotation:self.selectedAnnotation animated:NO];
+ UIView<MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
+ BOOL dismissesAutomatically = (calloutView
+ && [calloutView respondsToSelector:@selector(dismissesAutomatically)]
+ && calloutView.dismissesAutomatically);
+ // dismissesAutomatically is an optional property and we want to dismiss
+ // the callout view if it's unimplemented.
+ if (dismissesAutomatically || ![calloutView respondsToSelector:@selector(dismissesAutomatically)])
+ {
+ [self deselectAnnotation:self.selectedAnnotation animated:NO];
+ }
+ else
+ {
+ // Deselect annotation if it lies outside the viewport
+ if (self.selectedAnnotation) {
+ MGLAnnotationTag tag = [self annotationTagForAnnotation:self.selectedAnnotation];
+ MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
+ MGLAnnotationView *annotationView = annotationContext.annotationView;
+
+ CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];
+
+ if (annotationView)
+ {
+ rect = annotationView.frame;
+ }
+
+ if ( ! CGRectIntersectsRect(rect, self.frame)) {
+ [self deselectAnnotation:self.selectedAnnotation animated:NO];
+ }
}
}
}
@@ -4690,11 +4693,7 @@ public:
}
case mbgl::MapChangeDidFinishLoadingStyle:
{
- [self.style willChangeValueForKey:@"name"];
- [self.style willChangeValueForKey:@"sources"];
- [self.style didChangeValueForKey:@"sources"];
- [self.style willChangeValueForKey:@"layers"];
- [self.style didChangeValueForKey:@"layers"];
+ self.style = [[MGLStyle alloc] initWithMapView:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];
@@ -4805,7 +4804,12 @@ public:
else
{
CGRect adjustedFrame = annotationView.frame;
- adjustedFrame.origin.x = CGRectGetWidth(annotationView.layer.presentationLayer.frame) * -2.0;
+ if (annotationView.layer.presentationLayer) {
+ adjustedFrame.origin.x = -CGRectGetWidth(annotationView.layer.presentationLayer.frame) * 10.0;
+ } else {
+ // views that are added off screen do not have a presentationLayer
+ adjustedFrame.origin.x = -CGRectGetWidth(adjustedFrame) * 10.0;
+ }
annotationView.frame = adjustedFrame;
[self enqueueAnnotationViewForAnnotationContext:annotationContext];
}
@@ -4820,7 +4824,12 @@ public:
UIView <MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
id <MGLAnnotation> annotation = calloutView.representedObject;
- if (calloutView && annotation)
+ BOOL isAnchoredToAnnotation = (calloutView
+ && annotation
+ && [calloutView respondsToSelector:@selector(isAnchoredToAnnotation)]
+ && calloutView.isAnchoredToAnnotation);
+
+ if (isAnchoredToAnnotation)
{
MGLAnnotationTag tag = [self annotationTagForAnnotation:annotation];
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 777af4ba63..09e2465a28 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -228,7 +228,22 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
-- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation __attribute__((deprecated("Use -mapView:strokeColorForShapeAnnotation: or -mapView:fillColorForPolygonAnnotation:.")));
+/**
+ Returns the alpha value to use when rendering a shape annotation.
+
+ A value of `0.0` results in a completely transparent shape. A value of `1.0`,
+ the default, results in a completely opaque shape.
+
+ This method sets the opacity of an entire shape, inclusive of its stroke and
+ fill. To independently set the values for stroke or fill, specify an alpha
+ component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or
+ `-mapView:fillColorForPolygonAnnotation:`.
+
+ @param mapView The map view rendering the shape annotation.
+ @param annotation The annotation being rendered.
+ @return An alpha value between `0` and `1.0`.
+ */
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
/**
Returns the color to use when rendering the outline of a shape annotation.
diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h
index 6b6a898f93..4e2765377c 100644
--- a/platform/ios/src/MGLMapView_Private.h
+++ b/platform/ios/src/MGLMapView_Private.h
@@ -1,11 +1,13 @@
#import <Mapbox/Mapbox.h>
-#import <mbgl/map/map.hpp>
+namespace mbgl {
+ class Map;
+}
/// Minimum size of an annotation’s accessibility element.
extern const CGSize MGLAnnotationAccessibilityElementMinimumSize;
-@interface MGLMapView (Internal)
+@interface MGLMapView (Private)
/// Currently shown popover representing the selected annotation.
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 2c25cf0a62..744b80047b 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -278,6 +278,7 @@ const NSTimeInterval MGLFlushInterval = 180;
if (self.paused && enabled) {
[self resumeMetricsCollection];
} else if (!self.paused && !enabled) {
+ [self flush];
[self pauseMetricsCollection];
}
}
@@ -434,25 +435,31 @@ const NSTimeInterval MGLFlushInterval = 180;
}
- (MGLMapboxEventAttributes *)locationEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
- MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeLocation,
- MGLEventKeySource: MGLEventSource,
- MGLEventKeySessionId: self.instanceID,
- MGLEventKeyOperatingSystem: self.data.iOSVersion} mutableCopy];
- [self addApplicationStateToAttributes:attributes];
+ MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary];
+ attributes[MGLEventKeyEvent] = MGLEventTypeLocation;
+ attributes[MGLEventKeySource] = MGLEventSource;
+ attributes[MGLEventKeySessionId] = self.instanceID;
+ attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion;
+ NSString *currentApplicationState = [self applicationState];
+ if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) {
+ attributes[MGLEventKeyApplicationState] = currentApplicationState;
+ }
+
return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
}
- (MGLMapboxEventAttributes *)mapLoadEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
- MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeMapLoad,
- MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
- MGLEventKeyVendorID: self.data.vendorId,
- MGLEventKeyModel: self.data.model,
- MGLEventKeyOperatingSystem: self.data.iOSVersion,
- MGLEventKeyResolution: @(self.data.scale),
- MGLEventKeyAccessibilityFontScale: @([self contentSizeScale]),
- MGLEventKeyOrientation: [self deviceOrientation],
- MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy];
- [self addBatteryStateToAttributes:attributes];
+ MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary];
+ attributes[MGLEventKeyEvent] = MGLEventTypeMapLoad;
+ attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]];
+ attributes[MGLEventKeyVendorID] = self.data.vendorId;
+ attributes[MGLEventKeyModel] = self.data.model;
+ attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion;
+ attributes[MGLEventKeyResolution] = @(self.data.scale);
+ attributes[MGLEventKeyAccessibilityFontScale] = @([self contentSizeScale]);
+ attributes[MGLEventKeyOrientation] = [self deviceOrientation];
+ attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]);
+
return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
}
@@ -465,19 +472,22 @@ const NSTimeInterval MGLFlushInterval = 180;
- (MGLMapboxEventAttributes *)mapDragEndEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
MGLMutableMapboxEventAttributes *attributes = [self interactionEvent];
attributes[MGLEventKeyEvent] = MGLEventTypeMapDragEnd;
+
return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
}
- (MGLMutableMapboxEventAttributes *)interactionEvent {
- MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
- MGLEventKeyOrientation: [self deviceOrientation],
- MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy];
- [self addBatteryStateToAttributes:attributes];
+ MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary];
+ attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]];
+ attributes[MGLEventKeyOrientation] = [self deviceOrientation];
+ attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]);
+
return attributes;
}
- (MGLMapboxEventAttributes *)eventForAttributes:(MGLMutableMapboxEventAttributes *)attributes attributeDictionary:(MGLMapboxEventAttributes *)attributeDictionary {
[attributes addEntriesFromDictionary:attributeDictionary];
+
return [attributes copy];
}
@@ -594,29 +604,6 @@ const NSTimeInterval MGLFlushInterval = 180;
return result;
}
-- (void)addBatteryStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes {
- UIDeviceBatteryState batteryState = [[UIDevice currentDevice] batteryState];
- switch (batteryState) {
- case UIDeviceBatteryStateCharging:
- case UIDeviceBatteryStateFull:
- attributes[MGLEventKeyPluggedIn] = @(YES);
- break;
- case UIDeviceBatteryStateUnplugged:
- attributes[MGLEventKeyPluggedIn] = @(NO);
- break;
- default:
- // do nothing
- break;
- }
-}
-
-- (void)addApplicationStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes {
- NSString *currentApplicationState = [self applicationState];
- if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) {
- attributes[MGLEventKeyApplicationState] = currentApplicationState;
- }
-}
-
+ (void)ensureMetricsOptoutExists {
NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"];
BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue];
diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h
index f2243815cf..1a27d31dd4 100644
--- a/platform/ios/src/MGLUserLocation.h
+++ b/platform/ios/src/MGLUserLocation.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
directly. Instead, you retrieve an existing MGLUserLocation object from the
`userLocation` property of the map view displayed in your application.
*/
-@interface MGLUserLocation : NSObject <MGLAnnotation>
+@interface MGLUserLocation : NSObject <MGLAnnotation, NSSecureCoding>
#pragma mark Determining the User’s Position
diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m
index a568ec8be1..97e3f740fc 100644
--- a/platform/ios/src/MGLUserLocation.m
+++ b/platform/ios/src/MGLUserLocation.m
@@ -26,6 +26,44 @@ NS_ASSUME_NONNULL_END
return self;
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super init]) {
+ _location = [decoder decodeObjectOfClass:[CLLocation class] forKey:@"location"];
+ _title = [decoder decodeObjectOfClass:[NSString class] forKey:@"title"];
+ _subtitle = [decoder decodeObjectOfClass:[NSString class] forKey:@"subtitle"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [coder encodeObject:_location forKey:@"location"];
+ [coder encodeObject:_title forKey:@"title"];
+ [coder encodeObject:_subtitle forKey:@"subtitle"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLUserLocation class]]) return NO;
+
+ MGLUserLocation *otherUserLocation = other;
+ return ((!self.location && !otherUserLocation.location) || [self.location distanceFromLocation:otherUserLocation.location] == 0)
+ && ((!self.title && !otherUserLocation.title) || [self.title isEqualToString:otherUserLocation.title])
+ && ((!self.subtitle && !otherUserLocation.subtitle) || [self.subtitle isEqualToString:otherUserLocation.subtitle]);
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [super hash];
+ hash += [_location hash];
+ hash += [_heading hash];
+ hash += [_title hash];
+ hash += [_subtitle hash];
+ return hash;
+}
+
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
return ! [key isEqualToString:@"location"] && ! [key isEqualToString:@"heading"];
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 88efdd5cb4..37c649781e 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -54,6 +54,5 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLUserLocation.h"
#import "MGLUserLocationAnnotationView.h"
#import "NSValue+MGLAdditions.h"
-#import "NSValue+MGLStyleEnumAttributeAdditions.h"
#import "MGLStyleValue.h"
#import "MGLAttributionInfo.h"
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 8f9ce6fa6a..fe1a316fab 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -9,20 +9,23 @@
## 0.3.0
+This version of the Mapbox macOS SDK corresponds to version 3.4.0 of the Mapbox iOS SDK. The two SDKs have very similar feature sets. The main differences are the lack of user location tracking and annotation views. Some APIs have been adapted to macOS conventions, particularly the use of NSPopover for callout views.
+
### Packaging
* Fixed an issue causing code signing failures and bloating the framework. ([#5850](https://github.com/mapbox/mapbox-gl-native/pull/5850))
* Xcode 7.3 or higher is now required for using this SDK. ([#6059](https://github.com/mapbox/mapbox-gl-native/issues/6059))
* Fixed an issue with symbols not being properly stripped from the dynamic framework when built with `make xpackage SYMBOLS=NO`. ([#6531](https://github.com/mapbox/mapbox-gl-native/pull/6531))
+* The API reference has a sharper look. ([#7422](https://github.com/mapbox/mapbox-gl-native/pull/7422))
* Added documentation for the Info.plist keys used by this SDK. ([#6833](https://github.com/mapbox/mapbox-gl-native/pull/6833))
### Styles and data
* A new runtime styling API allows you to adjust the style and content of the base map dynamically. All the options available in [Mapbox Studio](https://www.mapbox.com/studio/) are now exposed via MGLStyle and subclasses of MGLStyleLayer and MGLSource. ([#5727](https://github.com/mapbox/mapbox-gl-native/pull/5727))
* MGLMapView’s `styleURL` property can now be set to an absolute file URL. ([#6026](https://github.com/mapbox/mapbox-gl-native/pull/6026))
-* MGLShapeSource objects, as well as GeoJSON sources specified by the stylesheet at design time, now support `cluster`, `clusterMaxZoom`, and `clusterRadius` attributes for clustering point features on the base map. ([#5724](https://github.com/mapbox/mapbox-gl-native/pull/5724))
-* TileJSON manifests can now specify `"scheme": "tms"` to indicate the use of [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) coordinates. ([#2270](https://github.com/mapbox/mapbox-gl-native/pull/2270))
-* Fixed an issue causing abstract `MGLMultiPointFeature` objects to be returned in feature query results. Now concrete `MGLPointCollectionFeature` objects are returned. ([#6742](https://github.com/mapbox/mapbox-gl-native/pull/6742))
+* When creating an MGLShapeSource, you can now specify options for clustering point features within the shape source. Similarly, GeoJSON sources specified by the stylesheet at design time can specify the `cluster`, `clusterMaxZoom`, and `clusterRadius` attributes. ([#5724](https://github.com/mapbox/mapbox-gl-native/pull/5724))
+* When creating an MGLTileSource, you can now specify that the tile URLs use [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) coordinates by setting `MGLTileSourceOptionTileCoordinateSystem` to `MGLTileCoordinateSystemTMS`. TileJSON files can specify `"scheme": "tms"`. ([#2270](https://github.com/mapbox/mapbox-gl-native/pull/2270))
+* Fixed an issue causing abstract `MGLMultiPointFeature` objects to be returned in feature query results. Now concrete `MGLPointCollectionFeature` objects are returned. MGLMultiPointFeature is now an alias of MGLPointCollectionFeature. ([#6742](https://github.com/mapbox/mapbox-gl-native/pull/6742))
* Fixed rendering artifacts and missing glyphs that occurred after viewing a large number of CJK characters on the map. ([#5908](https://github.com/mapbox/mapbox-gl-native/pull/5908))
* Fixed an issue where the style zoom levels were not respected when deciding when to render a layer. ([#5811](https://github.com/mapbox/mapbox-gl-native/issues/5811))
* Fixed an issue where feature querying sometimes failed to return the expected features when the map was tilted. ([#6773](https://github.com/mapbox/mapbox-gl-native/pull/6773))
@@ -42,10 +45,11 @@
* Added `showAnnotations:animated:` and `showAnnotations:edgePadding:animated:`, which moves the map viewport to show the specified annotations. ([#5749](https://github.com/mapbox/mapbox-gl-native/pull/5749))
* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
* Added new APIs to MGLMapView to query for visible annotations. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
-* Deprecated `-[MGLMapViewDelegate mapView:alphaForShapeAnnotation:]` in favor of specifying an alpha component via `-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` or `-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`. ([#6706](https://github.com/mapbox/mapbox-gl-native/pull/6706))
+* Shape, feature, and annotation classes now conform to NSSecureCoding. ([#6559](https://github.com/mapbox/mapbox-gl-native/pull/6559))
* Various method arguments that are represented as C arrays of `CLLocationCoordinate2D` instances have been marked `const` to streamline bridging to Swift. ([#7215](https://github.com/mapbox/mapbox-gl-native/pull/7215))
* To make an MGLPolyline or MGLPolygon span the antimeridian, specify coordinates with longitudes greater than 180° or less than −180°. ([#6088](https://github.com/mapbox/mapbox-gl-native/pull/6088))
* Fixed an issue where placing a point annotation on Null Island also placed a duplicate annotation on its antipode. ([#3563](https://github.com/mapbox/mapbox-gl-native/pull/3563))
+* Fixed an issue that caused an assertion failure if a `MGLShapeCollection` (a GeoJSON GeometryCollection) was created with an empty array of shapes. ([#7632](https://github.com/mapbox/mapbox-gl-native/pull/7632))
* Improved the precision of annotations at zoom levels greater than 18. ([#5517](https://github.com/mapbox/mapbox-gl-native/pull/5517))
### Networking and offline maps
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index c8e064fbed..6737566a5c 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -96,6 +96,32 @@ To add a localization to the macOS SDK:
1. In the Project navigator, expand each .strings and .stringsdict file in the project. An additional version for your localization should be listed; translate it. Translate everything on the right side of the equals sign. Leave the left side and any comments unmodified. See Apple’s documentation on the [.strings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html) and [.stringsdict](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) formats.
1. You’re already most of the way towards localizing the iOS SDK too – consider [completing that localization](../ios/DEVELOPING.md#adding-a-localization).
+### Adding a code example
+
+To add an example code listing to the documentation for a class or class member:
+
+1. Add a test method named in the form `testMGLClass` or `testMGLClass$method`
+ to [MGLDocumentationExampleTests](test/MGLDocumentationExampleTests.swift).
+ Wrap the code you’d like to appear in the documentation within
+ `//#-example-code` and `//#-end-example-code` comments.
+1. Insert the code listings into the headers:
+
+```bash
+make darwin-update-examples
+```
+
+[SourceKitten](https://github.com/jpsim/SourceKitten/) is required and will be installed automatically using Homebrew.
+
+## Testing
+
+`make macos-test` builds and runs unit tests of cross-platform code as well as the SDK.
+
+To instead run the cross-platform tests in Xcode instead of on the command line:
+
+1. Run `make xproj` to set up the workspace.
+1. Change the scheme to “mbgl-test” and press Command-R to run core unit tests.
+1. Change the scheme to “CI” and press Command-U to run SDK integration tests.
+
## 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.
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index a4b944611d..f8b4c675de 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -11,6 +11,13 @@ The Mapbox macOS SDK requires the macOS 10.10.0 SDK (or above) and Xcode 7.3 (or
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. Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
+
+ ```
+ [sudo] gem install jazzy
+ ```
+
1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/macos/pkg/` folder.
### Installation
@@ -64,4 +71,4 @@ script AppDelegate
end script
```
-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.
+For further instructions, consult the [macOS SDK documentation](https://mapbox.github.io/mapbox-gl-native/macos/) or run `make xdocument` to generate the documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/) 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/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
new file mode 100644
index 0000000000..6de7f829a3
--- /dev/null
+++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
@@ -0,0 +1,30 @@
+Pod::Spec.new do |m|
+
+ version = '0.3.0-rc.1'
+
+ m.name = 'Mapbox-macOS-SDK-symbols'
+ m.version = "#{version}-symbols"
+
+ m.summary = 'Open-source, interactive, fully customizable vector maps.'
+ m.description = 'Interactive, fully customizable vector maps with tight platform integration and high-performance OpenGL rendering.'
+ m.homepage = 'https://mapbox.github.io/mapbox-gl-native/macos/'
+ m.license = { :type => 'BSD', :file => 'LICENSE.md' }
+ m.author = { 'Mapbox' => 'mobile@mapbox.com' }
+ m.screenshot = "https://mapbox.github.io/mapbox-gl-native/macos/#{version}/img/screenshot.jpg"
+ m.social_media_url = 'https://twitter.com/mapbox'
+ m.documentation_url = 'https://mapbox.github.io/mapbox-gl-native/macos/'
+
+ m.source = {
+ :http => "https://github.com/mapbox/mapbox-gl-native/releases/download/macos-v#{version}/mapbox-macos-sdk-#{m.version.to_s}.zip",
+ :flatten => true
+ }
+
+ m.platform = :osx
+ m.osx.deployment_target = '10.10'
+
+ m.requires_arc = true
+
+ m.vendored_frameworks = 'Mapbox.framework'
+ m.module_name = 'Mapbox'
+
+end
diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec
new file mode 100644
index 0000000000..03ef0eabe7
--- /dev/null
+++ b/platform/macos/Mapbox-macOS-SDK.podspec
@@ -0,0 +1,30 @@
+Pod::Spec.new do |m|
+
+ version = '0.3.0-rc.1'
+
+ m.name = 'Mapbox-macOS-SDK'
+ m.version = version
+
+ m.summary = 'Open-source, interactive, fully customizable vector maps.'
+ m.description = 'Interactive, fully customizable vector maps with tight platform integration and high-performance OpenGL rendering.'
+ m.homepage = 'https://mapbox.github.io/mapbox-gl-native/macos/'
+ m.license = { :type => 'BSD', :file => 'LICENSE.md' }
+ m.author = { 'Mapbox' => 'mobile@mapbox.com' }
+ m.screenshot = "https://mapbox.github.io/mapbox-gl-native/macos/#{version}/img/screenshot.jpg"
+ m.social_media_url = 'https://twitter.com/mapbox'
+ m.documentation_url = 'https://mapbox.github.io/mapbox-gl-native/macos/'
+
+ m.source = {
+ :http => "https://github.com/mapbox/mapbox-gl-native/releases/download/macos-v#{version}/mapbox-macos-sdk-#{m.version.to_s}.zip",
+ :flatten => true
+ }
+
+ m.platform = :osx
+ m.osx.deployment_target = '10.10'
+
+ m.requires_arc = true
+
+ m.vendored_frameworks = 'Mapbox.framework'
+ m.module_name = 'Mapbox'
+
+end
diff --git a/platform/macos/README.md b/platform/macos/README.md
index 211b238d55..aea5ba0d6a 100644
--- a/platform/macos/README.md
+++ b/platform/macos/README.md
@@ -2,11 +2,23 @@
[![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.
+Put interactive, scalable world maps into your native Cocoa application with the Mapbox macOS SDK.
-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.
+* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
+* Customize every aspect of the map’s appearance in code or visually using [Mapbox Studio](https://www.mapbox.com/mapbox-studio/).
+* High-performance OpenGL rendering and multitouch gestures keep your users happy.
+* A well-designed, fully documented API helps you stay productive.
+* Develop across [multiple platforms](../../README.md), including [iOS](../ios/README.md), using the same styles and similar APIs.
-* [Integrating the Mapbox macOS SDK into your application](INSTALL.md)
-* [Contributing to the Mapbox macOS SDK](DEVELOPING.md)
+![](docs/img/screenshot.jpg)
-<img alt="" src="screenshot.png" width="645">
+The Mapbox macOS SDK is compatible with macOS 10.10.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js/).
+
+* [Integrate the Mapbox macOS SDK into your application](INSTALL.md)
+* [Contribute to the Mapbox macOS SDK](DEVELOPING.md)
+* [Mapbox macOS SDK reference documentation](https://mapbox.github.io/mapbox-gl-native/macos/)
+* [See example styles designed in Mapbox Studio](https://www.mapbox.com/gallery/)
+* [Hand-authoring a macOS SDK–compatible style](https://www.mapbox.com/mapbox-gl-style-spec/)
+* [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/)
+
+Mapbox does not officially support the Mapbox macOS SDK to the same extent as the Mapbox iOS SDK; however, bug reports and pull requests are certainly welcome.
diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib
index e147ba83d0..4ba8f0a3ad 100644
--- a/platform/macos/app/Base.lproj/MapDocument.xib
+++ b/platform/macos/app/Base.lproj/MapDocument.xib
@@ -27,6 +27,7 @@
<declaredKeys>
<string>layers</string>
<string>name</string>
+ <string>reversedLayers</string>
</declaredKeys>
<connections>
<binding destination="jxx-uM-ZTC" name="contentObject" keyPath="selection.style" id="60N-aU-tgJ"/>
@@ -38,7 +39,7 @@
<string>visible</string>
</declaredKeys>
<connections>
- <binding destination="Xji-k6-iQ4" name="contentArray" keyPath="selection.layers" id="X25-Nb-Brf"/>
+ <binding destination="Xji-k6-iQ4" name="contentArray" keyPath="selection.reversedLayers" id="wtL-d8-GNd"/>
</connections>
</arrayController>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.h b/platform/macos/app/MGLStyle+MBXAdditions.h
new file mode 100644
index 0000000000..dcaf42af28
--- /dev/null
+++ b/platform/macos/app/MGLStyle+MBXAdditions.h
@@ -0,0 +1,7 @@
+#import <Mapbox/Mapbox.h>
+
+@interface MGLStyle (MBXAdditions)
+
+@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *reversedLayers;
+
+@end
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.m b/platform/macos/app/MGLStyle+MBXAdditions.m
new file mode 100644
index 0000000000..be571d8b30
--- /dev/null
+++ b/platform/macos/app/MGLStyle+MBXAdditions.m
@@ -0,0 +1,42 @@
+#import "MGLStyle+MBXAdditions.h"
+
+@implementation MGLStyle (MBXAdditions)
+
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingReversedLayers {
+ return [NSSet setWithObject:@"layers"];
+}
+
+- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+ return self.layers.reverseObjectEnumerator.allObjects;
+}
+
+- (void)setReversedLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+ self.layers = reversedLayers.reverseObjectEnumerator.allObjects;
+}
+
+- (NSUInteger)countOfReversedLayers {
+ return self.layers.count;
+}
+
+- (id)objectInReversedLayersAtIndex:(NSUInteger)index {
+ NSArray *layers = self.layers;
+ return layers[layers.count - 1 - index];
+}
+
+- (void)getReversedLayers:(__kindof MGLStyleLayer **)buffer range:(NSRange)inRange {
+ NSArray *layers = self.layers;
+ for (NSUInteger i = inRange.location; i < NSMaxRange(inRange); i++) {
+ MGLStyleLayer *styleLayer = layers[layers.count - 1 - i];
+ buffer[i] = styleLayer;
+ }
+}
+
+- (void)insertObject:(__kindof MGLStyleLayer *)object inReversedLayersAtIndex:(NSUInteger)index {
+ [self insertLayer:object atIndex:self.layers.count - index];
+}
+
+- (void)removeObjectFromReversedLayersAtIndex:(NSUInteger)index {
+ [self removeLayer:[self objectInReversedLayersAtIndex:index]];
+}
+
+@end
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.h b/platform/macos/app/MGLVectorSource+MBXAdditions.h
new file mode 100644
index 0000000000..312081ec51
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.h
@@ -0,0 +1,15 @@
+#import <Mapbox/Mapbox.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLVectorSource (MBXAdditions)
+
++ (nullable NSString *)preferredMapboxStreetsLanguage;
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
+
+@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.m b/platform/macos/app/MGLVectorSource+MBXAdditions.m
new file mode 100644
index 0000000000..f59b72aa9f
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.m
@@ -0,0 +1,49 @@
+#import "MGLVectorSource+MBXAdditions.h"
+
+@implementation MGLVectorSource (MBXAdditions)
+
++ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ static dispatch_once_t onceToken;
+ static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ dispatch_once(&onceToken, ^{
+ mapboxStreetsLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
+ });
+ return mapboxStreetsLanguages;
+}
+
++ (nullable NSString *)preferredMapboxStreetsLanguage {
+ for (NSString *language in [NSLocale preferredLanguages]) {
+ NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
+ if ([[MGLVectorSource mapboxStreetsLanguages] containsObject:languageCode]) {
+ return languageCode;
+ }
+ }
+ return nil;
+}
+
+- (BOOL)isMapboxStreets {
+ NSURL *url = self.configurationURL;
+ if (![url.scheme isEqualToString:@"mapbox"]) {
+ return NO;
+ }
+ NSArray *identifiers = [url.host componentsSeparatedByString:@","];
+ return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
+}
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
+ if (!self.mapboxStreets) {
+ return @{};
+ }
+
+ // Replace {name} and {name_*} with the matching localized name tag.
+ NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
+ NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
+ for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) {
+ NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
+ localizedKeysByKey[key] = localizedKey;
+ }
+ return localizedKeysByKey;
+}
+
+@end
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 2c31610779..64833a8560 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -4,6 +4,9 @@
#import "LimeGreenStyleLayer.h"
#import "DroppedPinAnnotation.h"
+#import "MGLStyle+MBXAdditions.h"
+#import "MGLVectorSource+MBXAdditions.h"
+
#import <Mapbox/Mapbox.h>
static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped";
@@ -143,11 +146,12 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (NSURL *)shareURL {
NSArray *components = self.mapView.styleURL.pathComponents;
- CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate;
+ MGLMapCamera *camera = self.mapView.camera;
return [NSURL URLWithString:
- [NSString stringWithFormat:@"https://api.mapbox.com/styles/v1/%@/%@.html?access_token=%@#%.2f/%.5f/%.5f/%.f",
+ [NSString stringWithFormat:@"https://api.mapbox.com/styles/v1/%@/%@.html?access_token=%@#%.2f/%.5f/%.5f/%.f/%.f",
components[1], components[2], [MGLAccountManager accessToken],
- self.mapView.zoomLevel, centerCoordinate.latitude, centerCoordinate.longitude, self.mapView.direction]];
+ self.mapView.zoomLevel, camera.centerCoordinate.latitude, camera.centerCoordinate.longitude,
+ camera.heading, camera.pitch]];
}
#pragma mark View methods
@@ -254,7 +258,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)toggleStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.layers objectsAtIndexes:indices];
+ NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
BOOL isVisible = layers.firstObject.visible;
[self.undoManager registerUndoWithTarget:self handler:^(MapDocument * _Nonnull target) {
[target toggleStyleLayersAtArrangedObjectIndexes:indices];
@@ -310,7 +314,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)deleteStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.layers objectsAtIndexes:indices];
+ NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertStyleLayers:layers atArrangedObjectIndexes:indices];
}];
@@ -331,56 +335,55 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)setLabelLanguage:(NSMenuItem *)sender {
_isLocalizingLabels = sender.tag;
- [self updateLabels];
+ [self reload:sender];
}
- (void)updateLabels {
- NSString *preferredLanguageCode = self.preferredLanguageCode;
- NSString *preferredNameToken = _isLocalizingLabels ? [NSString stringWithFormat:@"{name_%@}", preferredLanguageCode] : @"{name}";
- NSRegularExpression *nameTokenExpression = [NSRegularExpression regularExpressionWithPattern:@"\\{name(?:_\\w{2})?\\}" options:0 error:NULL];
-
- for (MGLSymbolStyleLayer *layer in self.mapView.style.layers) {
+ MGLStyle *style = self.mapView.style;
+ NSString *preferredLanguage = _isLocalizingLabels ? ([MGLVectorSource preferredMapboxStreetsLanguage] ?: @"en") : nil;
+ NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
+ for (MGLSymbolStyleLayer *layer in style.layers) {
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
continue;
}
- if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) {
- NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.textField rawValue];
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- layer.textField = [MGLStyleValue<NSString *> valueWithRawValue:textField];
- } else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.textField;
+ MGLVectorSource *source = (MGLVectorSource *)[style sourceWithIdentifier:layer.sourceIdentifier];
+ if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
+ continue;
+ }
+
+ NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
+ if (!localizedKeysByKey) {
+ localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
+ }
+
+ NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
+ NSMutableString *localizedString = string.mutableCopy;
+ [localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
+ NSAssert([key isKindOfClass:[NSString class]], @"key is not a string");
+ NSAssert([localizedKey isKindOfClass:[NSString class]], @"localizedKey is not a string");
+ [localizedString replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key]
+ withString:[NSString stringWithFormat:@"{%@}", localizedKey]
+ options:0
+ range:NSMakeRange(0, localizedString.length)];
+ }];
+ return localizedString;
+ };
+
+ if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) {
+ NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.text rawValue];
+ layer.text = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
+ } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) {
+ MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.text;
NSMutableDictionary *stops = function.stops.mutableCopy;
[stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue<NSString *> *stop, BOOL *done) {
NSString *textField = stop.rawValue;
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:textField];
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
}];
function.stops = stops;
- layer.textField = function;
- }
- }
-}
-
-- (NSString *)preferredLanguageCode {
- // Languages supported by Mapbox Streets v10.
- NSSet *supportedLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
- NSArray *preferredLanguages = [NSLocale preferredLanguages];
-
- for (NSString *language in preferredLanguages) {
- NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
- if ([supportedLanguages containsObject:languageCode]) {
- return languageCode;
+ layer.text = function;
}
}
-
- return @"en";
}
- (void)applyPendingState {
@@ -824,7 +827,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (row == -1) {
menuItem.title = @"Show";
} else {
- BOOL isVisible = self.mapView.style.layers[row].visible;
+ BOOL isVisible = self.mapView.style.reversedLayers[row].visible;
menuItem.title = isVisible ? @"Hide" : @"Show";
}
return row != -1;
@@ -836,7 +839,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
menuItem.state = menuItem.tag == _isLocalizingLabels ? NSOnState: NSOffState;
if (menuItem.tag) {
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:[NSBundle mainBundle].developmentLocalization];
- menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:self.preferredLanguageCode];
+ NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
+ menuItem.enabled = !!preferredLanguage;
+ menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:preferredLanguage ?: @"Preferred Language"];
}
return YES;
}
@@ -1083,9 +1088,8 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
-- (NSColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation {
- NSColor *color = [[NSColor selectedMenuItemColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
- return [color colorWithAlphaComponent:0.8];
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation {
+ return 0.8;
}
@end
diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md
index 4aba26afd9..391b3dfca5 100644
--- a/platform/macos/docs/doc-README.md
+++ b/platform/macos/docs/doc-README.md
@@ -1,9 +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 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.
+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, Interface Builder, or AppleScript. The Mapbox macOS SDK takes stylesheets that conform to the [Mapbox 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.
-<img alt="Mapbox macOS SDK screenshot" src="screenshot.png" width="645">
+![](img/screenshot.jpg)
-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.
+For setup information, consult the README.md that comes with this documentation. For further instructions, consult the [macOS SDK documentation](https://mapbox.github.io/mapbox-gl-native/macos/). 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/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
new file mode 100644
index 0000000000..cf25ae09c4
--- /dev/null
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -0,0 +1,300 @@
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+-->
+# Information for Style Authors
+
+A _style_ defines a map view’s content and appearance. If you’ve authored a
+style using
+[Mapbox Studio’s Styles editor](https://www.mapbox.com/studio/styles/) or as
+JSON in a text editor, you can use that style in this SDK and manipulate it
+afterwards in code. This document provides information you can use to ensure a
+seamless transition from Mapbox Studio to your application.
+
+## Designing for macOS
+
+When designing your style, consider the context in which your application shows
+the style. There are a number of considerations specific to macOS that may
+not be obvious when designing your style in Mapbox Studio on the Web. A map view
+is essentially a graphical user interface element, so many of same issues in
+user interface design also apply when designing a map style.
+
+### Color
+
+Ensure sufficient contrast in your application’s user interface when your map
+style is present. Standard user interface elements such as toolbars, sidebars,
+and sheets often overlap the map view with a translucent, blurred background, so
+make sure the contents of these elements remain legible with the map view
+underneath.
+
+### Typography and graphics
+
+
+Design sprite images and choose font weights that look crisp on both
+standard-resolution displays and Retina displays. This SDK supports the same
+resolutions as macOS.
+Standard-resolution displays are often found on external monitors. Even with
+built-in screens, some of your users may use the Larger Text option in Display
+Preferences, which is essentially standard resolution, to make text easier to
+read.
+
+Icon and text labels should be legible regardless of the map’s orientation.
+By default, this SDK makes it easy for your users to rotate or tilt the map
+using multitouch trackpad gestures or keyboard shortcuts.
+If you do not intend your design to accommodate rotation and tilting, disable
+these gestures using the `MGLMapView.rotateEnabled` and
+`MGLMapView.pitchEnabled` properties, respectively, or the corresponding
+inspectables in Interface Builder.
+
+### Interactivity
+
+Pay attention to whether elements of your style appear to be interactive.
+An icon with a shadow or shading effect may appear to be clickable.
+You can make an icon or text label interactive by installing a gesture
+recognizer and performing feature querying (e.g.,
+`-[MGLMapView visibleFeaturesAtPoint:]`) to get details about the selected
+feature.
+You can install cursor or tooltip tracking rectangles to indicate interactive
+features as an alternative to prominent hover effects.
+
+Make sure your users can easily distinguish any interactive elements from the
+surrounding map, such as pins or a route line. If your application supports
+printing, consider using the
+[runtime styling API](#manipulating-the-style-at-runtime) to optimize your style
+for ink economy before printing the map view.
+
+For more information about user interface design, consult Apple’s
+[_macOS Human Interface Guidelines_](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/OSXHIGuidelines/).
+
+## Applying your style
+
+You set an `MGLMapView` object’s style either in code, by setting the
+`MGLMapView.styleURL` property, or in Interface Builder, by setting the “Style
+URL” inspectable. The URL must point to a local or remote style JSON file. The
+style JSON file format is defined by the
+[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/). This
+SDK supports the functionality defined by version 8 of the specification unless
+otherwise noted in the
+[style specification documentation](https://www.mapbox.com/mapbox-gl-style-spec/).
+
+## Manipulating the style at runtime
+
+The _runtime styling API_ enables you to modify every aspect of a style
+dynamically as a user interacts with your application. The style itself is
+represented at runtime by an `MGLStyle` object, which provides access to various
+`MGLSource` and `MGLStyleLayer` objects that represent content sources and style
+layers, respectively.
+
+The names of runtime styling classes and properties on macOS are generally
+consistent with the style specification and Mapbox Studio’s Styles editor. Any
+exceptions are listed in this document.
+
+To avoid conflicts with Objective-C keywords or Cocoa terminology, this SDK uses
+the following terms for concepts defined in the style specification:
+
+In the style specification | In the SDK
+---------------------------|---------
+class | style class
+filter | predicate
+id | identifier
+image | style image
+layer | style layer
+property | attribute
+SDF icon | template image
+source | content source
+
+## Specifying the map’s content
+
+Each source defined by a style JSON file is represented at runtime by a content
+source object that you can use to initialize new style layers. The content
+source object is a member of one of the following subclasses of `MGLSource`:
+
+In style JSON | In the SDK
+--------------|-----------
+`geojson` | `MGLShapeSource`
+`raster` | `MGLRasterSource`
+`vector` | `MGLVectorSource`
+
+`image` and `video` sources are not supported.
+
+### Tile sources
+
+Raster and vector sources may be defined in TileJSON configuration files. This
+SDK supports the properties defined in the style specification, which are a
+subset of the keys defined in version 2.1.0 of the
+[TileJSON](https://github.com/mapbox/tilejson-spec/tree/master/2.1.0)
+specification. As an alternative to authoring a custom TileJSON file, you may
+supply various tile source options when creating a raster or vector source.
+These options are detailed in the `MGLTileSourceOption` documentation:
+
+In style JSON | In TileJSON | In the SDK
+--------------|---------------|-----------
+`url` | — | `configurationURL` parameter in `-[MGLTileSource initWithIdentifier:configurationURL:]`
+`tiles` | `tiles` | `tileURLTemplates` parameter in `-[MGLTileSource initWithIdentifier:tileURLTemplates:options:]`
+`minzoom` | `minzoom` | `MGLTileSourceOptionMinimumZoomLevel`
+`maxzoom` | `maxzoom` | `MGLTileSourceOptionMaximumZoomLevel`
+`tileSize` | — | `MGLTileSourceOptionTileSize`
+`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
+`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
+
+### Shape sources
+
+Shape sources also accept various options. These options are detailed in the
+`MGLShapeSourceOption` documentation:
+
+In style JSON | In the SDK
+-----------------|-----------
+`data` | `url` parameter in `-[MGLShapeSource initWithIdentifier:URL:options:]`
+`maxzoom` | `MGLShapeSourceOptionMaximumZoomLevel`
+`buffer` | `MGLShapeSourceOptionBuffer`
+`tolerance` | `MGLShapeSourceOptionSimplificationTolerance`
+`cluster` | `MGLShapeSourceOptionClustered`
+`clusterRadius` | `MGLShapeSourceOptionClusterRadius`
+`clusterMaxZoom` | `MGLShapeSourceOptionMaximumZoomLevelForClustering`
+
+To create a shape source from local GeoJSON data, first
+[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
+then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+
+## Configuring the map content’s appearance
+
+Each layer defined by the style JSON file is represented at runtime by a style
+layer object, which you can use to refine the map’s appearance. The style layer
+object is a member of one of the following subclasses of `MGLStyleLayer`:
+
+In style JSON | In the SDK
+--------------|-----------
+`background` | `MGLBackgroundStyleLayer`
+`circle` | `MGLCircleStyleLayer`
+`fill` | `MGLFillStyleLayer`
+`line` | `MGLLineStyleLayer`
+`raster` | `MGLRasterStyleLayer`
+`symbol` | `MGLSymbolStyleLayer`
+
+You configure layout and paint attributes by setting properties on these style
+layer objects. The property names generally correspond to the style JSON
+properties, except for the use of camelCase instead of kebab-case. Properties
+whose names differ from the style specification are listed below:
+
+### Circle style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`circle-pitch-scale` | `MGLCircleStyleLayer.circleScaleAlignment` | `MGLCircleStyleLayer.circleScaleAlignment`
+`circle-translate` | `MGLCircleStyleLayer.circleTranslation` | `MGLCircleStyleLayer.circleTranslation`
+`circle-translate-anchor` | `MGLCircleStyleLayer.circleTranslationAnchor` | `MGLCircleStyleLayer.circleTranslationAnchor`
+
+### Fill style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`fill-antialias` | `MGLFillStyleLayer.fillAntialiased` | `MGLFillStyleLayer.isFillAntialiased`
+`fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation`
+`fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor`
+
+### Line style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`line-dasharray` | `MGLLineStyleLayer.lineDashPattern` | `MGLLineStyleLayer.lineDashPattern`
+`line-translate` | `MGLLineStyleLayer.lineTranslation` | `MGLLineStyleLayer.lineTranslation`
+`line-translate-anchor` | `MGLLineStyleLayer.lineTranslationAnchor` | `MGLLineStyleLayer.lineTranslationAnchor`
+
+### Raster style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`raster-brightness-max` | `MGLRasterStyleLayer.maximumRasterBrightness` | `MGLRasterStyleLayer.maximumRasterBrightness`
+`raster-brightness-min` | `MGLRasterStyleLayer.minimumRasterBrightness` | `MGLRasterStyleLayer.minimumRasterBrightness`
+`raster-hue-rotate` | `MGLRasterStyleLayer.rasterHueRotation` | `MGLRasterStyleLayer.rasterHueRotation`
+
+### Symbol style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`icon-allow-overlap` | `MGLSymbolStyleLayer.iconAllowsOverlap` | `MGLSymbolStyleLayer.iconAllowsOverlap`
+`icon-ignore-placement` | `MGLSymbolStyleLayer.iconIgnoresPlacement` | `MGLSymbolStyleLayer.iconIgnoresPlacement`
+`icon-image` | `MGLSymbolStyleLayer.iconImageName` | `MGLSymbolStyleLayer.iconImageName`
+`icon-optional` | `MGLSymbolStyleLayer.iconOptional` | `MGLSymbolStyleLayer.isIconOptional`
+`icon-rotate` | `MGLSymbolStyleLayer.iconRotation` | `MGLSymbolStyleLayer.iconRotation`
+`icon-size` | `MGLSymbolStyleLayer.iconScale` | `MGLSymbolStyleLayer.iconScale`
+`icon-keep-upright` | `MGLSymbolStyleLayer.keepsIconUpright` | `MGLSymbolStyleLayer.keepsIconUpright`
+`text-keep-upright` | `MGLSymbolStyleLayer.keepsTextUpright` | `MGLSymbolStyleLayer.keepsTextUpright`
+`text-max-angle` | `MGLSymbolStyleLayer.maximumTextAngle` | `MGLSymbolStyleLayer.maximumTextAngle`
+`text-max-width` | `MGLSymbolStyleLayer.maximumTextWidth` | `MGLSymbolStyleLayer.maximumTextWidth`
+`symbol-avoid-edges` | `MGLSymbolStyleLayer.symbolAvoidsEdges` | `MGLSymbolStyleLayer.symbolAvoidsEdges`
+`text-field` | `MGLSymbolStyleLayer.text` | `MGLSymbolStyleLayer.text`
+`text-allow-overlap` | `MGLSymbolStyleLayer.textAllowsOverlap` | `MGLSymbolStyleLayer.textAllowsOverlap`
+`text-font` | `MGLSymbolStyleLayer.textFontNames` | `MGLSymbolStyleLayer.textFontNames`
+`text-size` | `MGLSymbolStyleLayer.textFontSize` | `MGLSymbolStyleLayer.textFontSize`
+`text-ignore-placement` | `MGLSymbolStyleLayer.textIgnoresPlacement` | `MGLSymbolStyleLayer.textIgnoresPlacement`
+`text-justify` | `MGLSymbolStyleLayer.textJustification` | `MGLSymbolStyleLayer.textJustification`
+`text-optional` | `MGLSymbolStyleLayer.textOptional` | `MGLSymbolStyleLayer.isTextOptional`
+`text-rotate` | `MGLSymbolStyleLayer.textRotation` | `MGLSymbolStyleLayer.textRotation`
+`icon-translate` | `MGLSymbolStyleLayer.iconTranslation` | `MGLSymbolStyleLayer.iconTranslation`
+`icon-translate-anchor` | `MGLSymbolStyleLayer.iconTranslationAnchor` | `MGLSymbolStyleLayer.iconTranslationAnchor`
+`text-translate` | `MGLSymbolStyleLayer.textTranslation` | `MGLSymbolStyleLayer.textTranslation`
+`text-translate-anchor` | `MGLSymbolStyleLayer.textTranslationAnchor` | `MGLSymbolStyleLayer.textTranslationAnchor`
+
+## Setting attribute values
+
+Each property representing a layout or paint attribute is set to an
+`MGLStyleValue` object, which is either an `MGLStyleConstantValue` object (for
+constant values) or an `MGLStyleFunction` object (for zoom level functions). The
+style value object is a container for the raw value or function parameters that
+you want the attribute to be set to.
+
+In contrast to the JSON type that the style specification defines for each
+layout or paint property, the style value object often contains a more specific
+Foundation or Cocoa type. General rules for attribute types are listed below.
+Pay close attention to the SDK documentation for the attribute you want to get
+or set.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+Color | `NSColor` | `NSColor`
+Enum | `NSValue` (see `NSValue(MGLAdditions)`) | `NSValue` (see `NSValue(MGLAdditions)`)
+String | `NSString` | `String`
+Boolean | `NSNumber.boolValue` | `Bool`
+Number | `NSNumber.floatValue` | `Float`
+Array (`-dasharray`) | `NSArray<NSNumber>` | `[Float]`
+Array (`-font`) | `NSArray<NSString>` | `[String]`
+Array (`-offset`, `-translate`) | `NSValue` containing `CGVector` | `NSValue` containing `CGVector`
+Array (`-padding`) | `NSValue.edgeInsetsValue` | `NSValue.edgeInsetsValue`
+
+For padding attributes, note that the arguments to
+`NSEdgeInsetsMake()` in Objective-C and
+`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
+order, in contrast to the clockwise order defined by the style specification.
+
+Additionally, on macOS, a screen coordinate of (0, 0) is located at the
+lower-left corner of the screen. Therefore, a positive `CGVector.dy` means an
+offset or translation upward, while a negative `CGVector.dy` means an offset or
+translation downward. This is the reverse of how `CGVector` is interpreted on
+iOS.
+
+## Filtering sources
+
+You can filter a shape or vector source by setting the
+`MGLVectorStyleLayer.predicate` property to an `NSPredicate` object. Below is a
+table of style JSON operators and the corresponding operators used in the
+predicate format string:
+
+In style JSON | In the format string
+--------------------------|---------------------
+`["has", key]` | `key != nil`
+`["!has", key]` | `key == nil`
+`["==", key, value]` | `key == value`
+`["!=", key, value]` | `key != value`
+`[">", key, value]` | `key > value`
+`[">=", key, value]` | `key >= value`
+`["<", key, value]` | `key < value`
+`["<=", key, value]` | `key <= value`
+`["in", key, v0, …, vn]` | `key IN {v0, …, vn}`
+`["!in", key, v0, …, vn]` | `NOT key IN {v0, …, vn}`
+`["all", f0, …, fn]` | `p0 AND … AND pn`
+`["any", f0, …, fn]` | `p0 OR … OR pn`
+`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+
+See the `MGLVectorStyleLayer.predicate` documentation for a full description of
+the supported operators and operand types.
diff --git a/platform/macos/docs/Info.plist Keys.md b/platform/macos/docs/guides/Info.plist Keys.md
index a92b6fe296..f61ad8c7a7 100644
--- a/platform/macos/docs/Info.plist Keys.md
+++ b/platform/macos/docs/guides/Info.plist Keys.md
@@ -1,6 +1,6 @@
# Info.plist Keys
-The Mapbox macOS SDK supports custom `Info.plist` keys in your application in order to configure various settings.
+The Mapbox macOS SDK supports custom `Info.plist` keys in your application in order to configure various settings.
## MGLMapboxAccessToken
@@ -8,10 +8,10 @@ Set the [Mapbox access token](https://www.mapbox.com/help/define-access-token/)
Mapbox-hosted vector tiles and styles require an API access token, which you can obtain from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). Access tokens associate requests to Mapbox’s vector tile and style APIs with your Mapbox account. They also deter other developers from using your styles without your permission.
-As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private.
+As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private.
## MGLMapboxAPIBaseURL
-Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used.
+Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used.
-The default value is `https://api.mapbox.com`.
+The default value is `https://api.mapbox.com`.
diff --git a/platform/macos/docs/img/screenshot.jpg b/platform/macos/docs/img/screenshot.jpg
new file mode 100644
index 0000000000..5341a3d6f0
--- /dev/null
+++ b/platform/macos/docs/img/screenshot.jpg
Binary files differ
diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md
index 8af262cc8f..6d45a68c34 100644
--- a/platform/macos/docs/pod-README.md
+++ b/platform/macos/docs/pod-README.md
@@ -1,18 +1,37 @@
# [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, Interface Builder, or AppleScript. It takes stylesheets that conform to the [Mapbox 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.
+Put interactive, scalable world maps into your native Cocoa application with the open-source Mapbox macOS SDK.
-<img alt="" src="https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/screenshot.png" width="645">
+* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
+* Customize every aspect of the map’s appearance in code or visually using [Mapbox Studio](https://www.mapbox.com/mapbox-studio/).
+* High-performance OpenGL rendering and multitouch gestures keep your users happy.
+* A well-designed, fully documented API helps you stay productive.
+* Develop across [multiple platforms](https://www.mapbox.com/maps/), including [iOS](https://www.mapbox.com/ios-sdk/), using the same styles and similar APIs.
+
+![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/docs/img/screenshot.jpg)
+
+The Mapbox macOS SDK is compatible with macOS 10.10.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/).
+
+Mapbox macOS SDK releases are [available on GitHub](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “macos-”. You can also integrate the Mapbox macOS SDK into your application using CocoaPods.
## 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. 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 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/).
+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:
+In a storyboard or XIB:
+
+1. Add a view to your view controller or window. (Drag Custom View from the Object library to the View Controller scene on the Interface Builder canvas. In a XIB, drag it instead to the window on the canvas.)
+2. In the Identity inspector, set the view’s custom class to `MGLMapView`.
+3. MGLMapView needs to be layer-backed:
+ * You can make the window layer-backed by selecting the window and checking Full Size Content View in the Attributes inspector. This allows the map view to underlap the title bar and toolbar.
+ * Alternatively, if you don’t want the entire window to be layer-backed, you can make just the map view layer-backed by selecting it and checking its entry under the View Effects inspector’s Core Animation Layer section.
+4. Add a map feedback item to your Help menu. (Drag Menu Item from the Object library into Main Menu ‣ Help ‣ Menu.) Title it “Improve This Map” or similar, and connect it to the `giveFeedback:` action of First Responder.
+
+If you need to manipulate the map view programmatically:
1. Switch to the Assistant Editor.
1. Import the `Mapbox` module.
@@ -46,6 +65,6 @@ script AppDelegate
end script
```
-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.
+Full API documentation is included in this package, within the `documentation` folder, and [online](https://mapbox.github.io/mapbox-gl-native/macos/). 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
index ae437377a7..56f7255636 100644
--- a/platform/macos/jazzy.yml
+++ b/platform/macos/jazzy.yml
@@ -2,6 +2,7 @@ module: Mapbox
author: Mapbox
author_url: https://www.mapbox.com/
github_url: https://github.com/mapbox/mapbox-gl-native
+dash_url: https://mapbox.github.io/mapbox-gl-native/macos/docsets/Mapbox.xml
copyright: '© 2014–2017 [Mapbox](https://www.mapbox.com/). See [license](https://github.com/mapbox/mapbox-gl-native/blob/master/LICENSE.md) for more details.'
head: |
@@ -14,58 +15,64 @@ umbrella_header: src/Mapbox.h
framework_root: ../darwin/src
custom_categories:
+ - name: Guides
+ children:
+ - Working with GeoJSON Data
+ - For Style Authors
+ - Info.plist Keys
- name: Maps
children:
- MGLAccountManager
- MGLMapCamera
- MGLMapView
- MGLMapViewDelegate
- - MGLStyle
- MGLUserTrackingMode
- - name: Annotations
+ - name: Shapes and Annotations
children:
- MGLAnnotation
- MGLAnnotationImage
+ - MGLOverlay
+ - MGLShape
- MGLMultiPoint
- - MGLMultiPolygon
- - MGLMultiPolyline
- MGLPointAnnotation
- MGLPointCollection
- MGLPolygon
- MGLPolyline
- - MGLOverlay
- - MGLShape
+ - MGLMultiPolygon
+ - MGLMultiPolyline
- MGLShapeCollection
- - name: Map Data
+ - name: Styling the Map
+ children:
+ - MGLStyle
+ - MGLStyleValue
+ - name: Content Primitives
children:
- - MGLFeature
+ - MGLFeature
+ - MGLPointFeature
+ - MGLPolygonFeature
+ - MGLPolylineFeature
- MGLMultiPolygonFeature
- MGLMultiPolylineFeature
- MGLPointCollectionFeature
- - MGLPointFeature
- - MGLPolygonFeature
- - MGLPolylineFeature
- MGLShapeCollectionFeature
+ - name: Content Sources
+ children:
+ - MGLSource
+ - MGLTileSource
+ - MGLShapeSource
+ - MGLRasterSource
+ - MGLVectorSource
- name: Style Layers
children:
+ - MGLStyleLayer
+ - MGLForegroundStyleLayer
- MGLBackgroundStyleLayer
+ - MGLRasterStyleLayer
+ - MGLVectorStyleLayer
- MGLCircleStyleLayer
- MGLFillStyleLayer
- - MGLForegroundStyleLayer
- MGLLineStyleLayer
- - MGLRasterStyleLayer
- - MGLStyleLayer
- MGLSymbolStyleLayer
- - MGLVectorStyleLayer
- - name: Content Sources
- children:
- - MGLAttributionInfo
- - MGLRasterSource
- - MGLShapeSource
- - MGLSource
- - MGLTileCoordinateSystem
- - MGLTileSource
- - MGLVectorSource
- name: Offline Maps
children:
- MGLOfflineRegion
@@ -76,15 +83,13 @@ custom_categories:
- MGLTilePyramidOfflineRegion
- name: Geometry
children:
- - MGLClockDirectionFormatter
- - MGLCompassDirectionFormatter
- MGLCoordinateBounds
- MGLCoordinateBoundsEqualToCoordinateBounds
- MGLCoordinateBoundsGetCoordinateSpan
+ - MGLCoordinateBoundsIntersectsCoordinateBounds
- MGLCoordinateBoundsIsEmpty
- MGLCoordinateBoundsMake
- MGLCoordinateBoundsOffset
- - MGLCoordinateFormatter
- MGLCoordinateInCoordinateBounds
- MGLCoordinateSpan
- MGLCoordinateSpanEqualToCoordinateSpan
@@ -93,3 +98,8 @@ custom_categories:
- MGLDegreesFromRadians
- MGLRadiansFromDegrees
- MGLStringFromCoordinateBounds
+ - name: Formatters
+ children:
+ - MGLClockDirectionFormatter
+ - MGLCompassDirectionFormatter
+ - MGLCoordinateFormatter
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 6f6aad2436..fc9e0c74e1 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
30E5781B1DAA857E0050F07E /* NSImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */; };
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */; };
3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */; };
+ 3526EABD1DF9B19800006B43 /* MGLCodingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3526EABC1DF9B19800006B43 /* MGLCodingTests.m */; };
352742781D4C220900A1ECE6 /* MGLStyleValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 352742771D4C220900A1ECE6 /* MGLStyleValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
352742811D4C243B00A1ECE6 /* MGLSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 3527427F1D4C243B00A1ECE6 /* MGLSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
352742821D4C243B00A1ECE6 /* MGLSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 352742801D4C243B00A1ECE6 /* MGLSource.mm */; };
@@ -34,6 +35,8 @@
35602C001D3EA9B40050646F /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.m */; };
35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */ = {isa = PBXBuildFile; fileRef = 358EB3AE1D61F0DB00E46D9C /* amsterdam.geojson */; };
+ 359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 359819571E02F611008FC139 /* NSCoder+MGLAdditions.h */; };
+ 3598195A1E02F611008FC139 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 359819581E02F611008FC139 /* NSCoder+MGLAdditions.mm */; };
3599A3E81DF70E2000E77FB2 /* MGLStyleValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3599A3E71DF70E2000E77FB2 /* MGLStyleValueTests.m */; };
35C5D8471D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35C5D8431D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h */; };
35C5D8481D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D8441D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm */; };
@@ -41,8 +44,6 @@
35C5D84A1D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D8461D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm */; };
35D65C5A1D65AD5500722C23 /* NSDate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */; };
35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */; };
- 4032C5C51DE1FE930062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4032C5B91DE1EEBA0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 4032C5C61DE1FE9B0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4032C5C31DE1FE810062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */; };
4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
4049C2AD1DB8020600B3F799 /* MGLPointCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */; };
408AA85B1DAEECFE00022900 /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA85A1DAEECF100022900 /* MGLShape_Private.h */; };
@@ -67,7 +68,7 @@
DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */; };
DA2207BC1DC076940002F84D /* MGLStyleValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */; };
DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA2784FD1DF03060001D5B8D /* Media.xcassets */; };
- DA2DBBCB1D51E30A00D38FF9 /* MGLStyleLayerTests.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */; };
+ DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2987591E1A4290002299F5 /* MGLDocumentationExampleTests.swift */; };
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 */; };
@@ -79,6 +80,7 @@
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 */; };
+ DA35D08A1E1A631B007DED41 /* one-liner.json in Resources */ = {isa = PBXBuildFile; fileRef = DA35D0891E1A631B007DED41 /* one-liner.json */; };
DA551B821DB496AC0009AFAF /* MGLTileSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DA551B7F1DB496AC0009AFAF /* MGLTileSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA551B831DB496AC0009AFAF /* MGLTileSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA551B801DB496AC0009AFAF /* MGLTileSource_Private.h */; };
DA551B841DB496AC0009AFAF /* MGLTileSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA551B811DB496AC0009AFAF /* MGLTileSource.mm */; };
@@ -98,15 +100,14 @@
DA87A9981DC9D88400810D09 /* MGLShapeSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA87A9961DC9D88400810D09 /* MGLShapeSourceTests.mm */; };
DA87A9991DC9D88400810D09 /* MGLTileSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA87A9971DC9D88400810D09 /* MGLTileSetTests.mm */; };
DA87A99C1DC9D8DD00810D09 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA87A99B1DC9D8DD00810D09 /* MGLShapeSource_Private.h */; };
- DA87A99E1DC9DC2100810D09 /* MGLFilterTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D84B1D6DD75B00E95907 /* MGLFilterTests.mm */; };
+ DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */; };
DA87A9A01DC9DC6200810D09 /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = DA87A99F1DC9DC6200810D09 /* MGLValueEvaluator.h */; };
- DA87A9A11DC9DCB400810D09 /* MGLRuntimeStylingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F257B1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.m */; };
- DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.m */; };
- DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.m */; };
- DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.m */; };
- DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.m */; };
- DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.m */; };
- DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.m */; };
+ DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.mm */; };
+ DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.mm */; };
+ DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.mm */; };
+ DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.mm */; };
+ DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.mm */; };
+ DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.mm */; };
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 */; };
@@ -125,9 +126,11 @@
DA8F259C1D51CB000010E6B5 /* MGLStyleValue_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8F259B1D51CB000010E6B5 /* MGLStyleValue_Private.h */; };
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8F25A61D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h */; };
DA8F25B31D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25A71D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm */; };
+ DAA1BB4A1E2D425C00ABB750 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */; };
DAA48EFD1D6A4731006A7E36 /* StyleLayerIconTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */; };
DAB2CCE51DF632ED001B2FE1 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */; };
DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; };
+ DACB0C391E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DACB0C381E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m */; };
DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22121CF3D3E200D220D9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; };
DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DACC22131CF3D3E200D220D9 /* MGLFeature.mm */; };
DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */; };
@@ -207,12 +210,14 @@
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 */; };
+ DAE7DEC41E24549F007505A6 /* MGLNSStringAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */; };
DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */; };
DAED38601D62CED700D7640F /* NSURL+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAED385E1D62CED700D7640F /* NSURL+MGLAdditions.m */; };
DAEDC4321D6033F1000224FF /* MGLAttributionInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */; };
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */; };
DAF0D80E1DFE0E5D00B28378 /* MGLPointCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF0D80D1DFE0E5D00B28378 /* MGLPointCollection_Private.h */; };
DAF0D8161DFE6B1800B28378 /* MGLAttributionInfo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */; };
+ DAF0D81C1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */; };
DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */; };
DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */; };
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */; };
@@ -253,6 +258,7 @@
30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+MGLAdditions.h"; path = "src/NSImage+MGLAdditions.h"; sourceTree = SOURCE_ROOT; };
3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSExpression+MGLAdditions.h"; sourceTree = "<group>"; };
3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSExpression+MGLAdditions.mm"; sourceTree = "<group>"; };
+ 3526EABC1DF9B19800006B43 /* MGLCodingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCodingTests.m; path = ../../darwin/test/MGLCodingTests.m; sourceTree = "<group>"; };
352742771D4C220900A1ECE6 /* MGLStyleValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleValue.h; sourceTree = "<group>"; };
3527427F1D4C243B00A1ECE6 /* MGLSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSource.h; sourceTree = "<group>"; };
352742801D4C243B00A1ECE6 /* MGLSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSource.mm; sourceTree = "<group>"; };
@@ -277,18 +283,16 @@
35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLForegroundStyleLayer.h; sourceTree = "<group>"; };
35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLForegroundStyleLayer.m; sourceTree = "<group>"; };
358EB3AE1D61F0DB00E46D9C /* amsterdam.geojson */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = amsterdam.geojson; path = ../../darwin/test/amsterdam.geojson; sourceTree = "<group>"; };
+ 359819571E02F611008FC139 /* NSCoder+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSCoder+MGLAdditions.h"; sourceTree = "<group>"; };
+ 359819581E02F611008FC139 /* NSCoder+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSCoder+MGLAdditions.mm"; sourceTree = "<group>"; };
3599A3E71DF70E2000E77FB2 /* MGLStyleValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLStyleValueTests.m; sourceTree = "<group>"; };
35C5D8431D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSComparisonPredicate+MGLAdditions.h"; sourceTree = "<group>"; };
35C5D8441D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSComparisonPredicate+MGLAdditions.mm"; sourceTree = "<group>"; };
35C5D8451D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSCompoundPredicate+MGLAdditions.h"; sourceTree = "<group>"; };
35C5D8461D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSCompoundPredicate+MGLAdditions.mm"; sourceTree = "<group>"; };
- 35C5D84B1D6DD75B00E95907 /* MGLFilterTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFilterTests.mm; sourceTree = "<group>"; };
+ 35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLPredicateTests.mm; path = ../../darwin/test/MGLPredicateTests.mm; sourceTree = "<group>"; };
35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+MGLAdditions.h"; sourceTree = "<group>"; };
35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+MGLAdditions.mm"; sourceTree = "<group>"; };
- 4032C5B91DE1EEBA0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLStyleEnumAttributeAdditions.h"; sourceTree = "<group>"; };
- 4032C5BA1DE1EECB0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h.ejs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSValue+MGLStyleEnumAttributeAdditions.h.ejs"; sourceTree = "<group>"; };
- 4032C5C31DE1FE810062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSValue+MGLStyleEnumAttributeAdditions.mm"; sourceTree = "<group>"; };
- 4032C5C71DE1FEAB0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm.ejs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSValue+MGLStyleEnumAttributeAdditions.mm.ejs"; sourceTree = "<group>"; };
4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = "<group>"; };
4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = "<group>"; };
405C03961DB0004E001AC280 /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -318,7 +322,7 @@
DA2207BA1DC076930002F84D /* test-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Bridging-Header.h"; sourceTree = "<group>"; };
DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLStyleValueTests.swift; sourceTree = "<group>"; };
DA2784FD1DF03060001D5B8D /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = ../../darwin/test/Media.xcassets; sourceTree = "<group>"; };
- DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MGLStyleLayerTests.xib; sourceTree = "<group>"; };
+ DA2987591E1A4290002299F5 /* MGLDocumentationExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationExampleTests.swift; path = ../../darwin/test/MGLDocumentationExampleTests.swift; sourceTree = "<group>"; };
DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = "<group>"; };
DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = "<group>"; };
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCoordinateFormatterTests.m; path = ../../darwin/test/MGLCoordinateFormatterTests.m; sourceTree = "<group>"; };
@@ -330,6 +334,7 @@
DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLClockDirectionFormatterTests.m; path = ../../darwin/test/MGLClockDirectionFormatterTests.m; sourceTree = "<group>"; };
DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLAdditions.h"; sourceTree = "<group>"; };
DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+MGLAdditions.m"; sourceTree = "<group>"; };
+ DA35D0891E1A631B007DED41 /* one-liner.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "one-liner.json"; path = "../../darwin/test/one-liner.json"; sourceTree = "<group>"; };
DA551B7F1DB496AC0009AFAF /* MGLTileSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource.h; sourceTree = "<group>"; };
DA551B801DB496AC0009AFAF /* MGLTileSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource_Private.h; sourceTree = "<group>"; };
DA551B811DB496AC0009AFAF /* MGLTileSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSource.mm; sourceTree = "<group>"; };
@@ -360,14 +365,12 @@
DA8933AC1CCD290700E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
DA8933B41CCD2C2500E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Foundation.strings; sourceTree = "<group>"; };
DA8933B71CCD2C2D00E68420 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
- DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLFillStyleLayerTests.m; path = ../../darwin/test/MGLFillStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLRasterStyleLayerTests.m; path = ../../darwin/test/MGLRasterStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSymbolStyleLayerTests.m; path = ../../darwin/test/MGLSymbolStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLLineStyleLayerTests.m; path = ../../darwin/test/MGLLineStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCircleStyleLayerTests.m; path = ../../darwin/test/MGLCircleStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLBackgroundStyleLayerTests.m; path = ../../darwin/test/MGLBackgroundStyleLayerTests.m; sourceTree = "<group>"; };
- DA8F257A1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLRuntimeStylingHelper.h; path = ../../darwin/test/MGLRuntimeStylingHelper.h; sourceTree = "<group>"; };
- DA8F257B1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLRuntimeStylingHelper.m; path = ../../darwin/test/MGLRuntimeStylingHelper.m; sourceTree = "<group>"; };
+ DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillStyleLayerTests.mm; sourceTree = "<group>"; };
+ DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRasterStyleLayerTests.mm; sourceTree = "<group>"; };
+ DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSymbolStyleLayerTests.mm; sourceTree = "<group>"; };
+ DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLineStyleLayerTests.mm; sourceTree = "<group>"; };
+ DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCircleStyleLayerTests.mm; sourceTree = "<group>"; };
+ DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLBackgroundStyleLayerTests.mm; sourceTree = "<group>"; };
DA8F25851D51C9E10010E6B5 /* MGLBackgroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLBackgroundStyleLayer.h; sourceTree = "<group>"; };
DA8F25861D51C9E10010E6B5 /* MGLBackgroundStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLBackgroundStyleLayer.mm; sourceTree = "<group>"; };
DA8F25891D51CA540010E6B5 /* MGLLineStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLineStyleLayer.h; sourceTree = "<group>"; };
@@ -382,14 +385,17 @@
DA8F259B1D51CB000010E6B5 /* MGLStyleValue_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleValue_Private.h; sourceTree = "<group>"; };
DA8F25A61D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLStyleAttributeAdditions.h"; sourceTree = "<group>"; };
DA8F25A71D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSValue+MGLStyleAttributeAdditions.mm"; sourceTree = "<group>"; };
- DA8F25B51D51D2240010E6B5 /* MGLStyleLayerTests.m.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.m.ejs; path = ../test/MGLStyleLayerTests.m.ejs; sourceTree = "<group>"; };
+ DA8F25B51D51D2240010E6B5 /* MGLStyleLayerTests.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.mm.ejs; path = ../test/MGLStyleLayerTests.mm.ejs; sourceTree = "<group>"; };
DA8F25B61D51D2240010E6B5 /* MGLStyleLayer.h.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.h.ejs; sourceTree = "<group>"; };
DA8F25B71D51D2240010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
+ DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/macos/Debug/libmbgl-loop.a"; sourceTree = "<group>"; };
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleLayerIconTransformer.h; sourceTree = "<group>"; };
DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleLayerIconTransformer.m; sourceTree = "<group>"; };
DAB2CCE31DF632ED001B2FE1 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LimeGreenStyleLayer.h; sourceTree = "<group>"; };
DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LimeGreenStyleLayer.m; sourceTree = "<group>"; };
DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; };
+ DACB0C371E18DFFD005DDBEA /* MGLStyle+MBXAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLStyle+MBXAdditions.h"; sourceTree = "<group>"; };
+ DACB0C381E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLStyle+MBXAdditions.m"; sourceTree = "<group>"; };
DACC22121CF3D3E200D220D9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; };
DACC22131CF3D3E200D220D9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; };
@@ -475,12 +481,15 @@
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineStorageTests.m; path = ../../darwin/test/MGLOfflineStorageTests.m; sourceTree = "<group>"; };
DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
+ DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLNSStringAdditionsTests.m; path = ../../darwin/test/MGLNSStringAdditionsTests.m; sourceTree = "<group>"; };
DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; };
DAED385E1D62CED700D7640F /* NSURL+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MGLAdditions.m"; sourceTree = "<group>"; };
DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAttributionInfoTests.m; path = ../../darwin/test/MGLAttributionInfoTests.m; sourceTree = "<group>"; };
DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButtonTests.m; sourceTree = "<group>"; };
DAF0D80D1DFE0E5D00B28378 /* MGLPointCollection_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection_Private.h; sourceTree = "<group>"; };
DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
+ DAF0D81A1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLVectorSource+MBXAdditions.h"; sourceTree = "<group>"; };
+ DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLVectorSource+MBXAdditions.m"; sourceTree = "<group>"; };
DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLExpressionTests.mm; path = ../../darwin/test/MGLExpressionTests.mm; sourceTree = "<group>"; };
@@ -511,6 +520,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ DAA1BB4A1E2D425C00ABB750 /* libmbgl-loop.a in Frameworks */,
DAE0DD7A1D5F015A005A6BB1 /* libmbgl-core.a in Frameworks */,
DAE6C3321CC30DB200DB3429 /* Mapbox.framework in Frameworks */,
);
@@ -550,8 +560,6 @@
352742791D4C235C00A1ECE6 /* Categories */ = {
isa = PBXGroup;
children = (
- 4032C5B91DE1EEBA0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h */,
- 4032C5C31DE1FE810062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm */,
DA8F25A61D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h */,
DA8F25A71D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm */,
);
@@ -629,6 +637,10 @@
DA839E9B1CC2E3400062CAFB /* MapDocument.h */,
DA839E9C1CC2E3400062CAFB /* MapDocument.m */,
DA839E9E1CC2E3400062CAFB /* MapDocument.xib */,
+ DACB0C371E18DFFD005DDBEA /* MGLStyle+MBXAdditions.h */,
+ DACB0C381E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m */,
+ DAF0D81A1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.h */,
+ DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */,
DAE6C2E91CC3050F00DB3429 /* OfflinePackNameValueTransformer.h */,
DAE6C2EA1CC3050F00DB3429 /* OfflinePackNameValueTransformer.m */,
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */,
@@ -691,15 +703,12 @@
40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */,
40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */,
DA2207BA1DC076930002F84D /* test-Bridging-Header.h */,
- DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.m */,
- DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.m */,
- DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.m */,
- DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.m */,
- DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.m */,
- DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.m */,
- DA8F257A1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.h */,
- DA8F257B1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.m */,
- DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */,
+ DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.mm */,
+ DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.mm */,
+ DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.mm */,
+ DA8F25771D51C5F40010E6B5 /* MGLLineStyleLayerTests.mm */,
+ DA8F25781D51C5F40010E6B5 /* MGLCircleStyleLayerTests.mm */,
+ DA8F25791D51C5F40010E6B5 /* MGLBackgroundStyleLayerTests.mm */,
);
name = Layers;
sourceTree = "<group>";
@@ -709,7 +718,6 @@
children = (
DA8F257C1D51C5F40010E6B5 /* Layers */,
DA87A99A1DC9D88800810D09 /* Sources */,
- 35C5D84B1D6DD75B00E95907 /* MGLFilterTests.mm */,
353722EB1DF850ED004D2F3F /* MGLStyleValueTests.h */,
3599A3E71DF70E2000E77FB2 /* MGLStyleValueTests.m */,
DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */,
@@ -723,9 +731,7 @@
children = (
DA8F25B61D51D2240010E6B5 /* MGLStyleLayer.h.ejs */,
DA8F25B71D51D2240010E6B5 /* MGLStyleLayer.mm.ejs */,
- DA8F25B51D51D2240010E6B5 /* MGLStyleLayerTests.m.ejs */,
- 4032C5BA1DE1EECB0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h.ejs */,
- 4032C5C71DE1FEAB0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm.ejs */,
+ DA8F25B51D51D2240010E6B5 /* MGLStyleLayerTests.mm.ejs */,
);
name = "Foundation Templates";
path = ../../darwin/src;
@@ -815,6 +821,8 @@
40B77E421DB11BB0003DA2FE /* NSArray+MGLAdditions.mm */,
DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */,
DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */,
+ 359819571E02F611008FC139 /* NSCoder+MGLAdditions.h */,
+ 359819581E02F611008FC139 /* NSCoder+MGLAdditions.mm */,
35C5D8431D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h */,
35C5D8441D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm */,
35C5D8451D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h */,
@@ -843,6 +851,7 @@
DAE6C31E1CC308BC00DB3429 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */,
558F18211D0B13B000123F46 /* libmbgl-loop.a */,
5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */,
5548BE791D0ACBB2005DDE81 /* libmbgl-loop-darwin.a */,
@@ -877,18 +886,23 @@
DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */,
DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */,
DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */,
+ 3526EABC1DF9B19800006B43 /* MGLCodingTests.m */,
DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */,
+ DA2987591E1A4290002299F5 /* MGLDocumentationExampleTests.swift */,
+ DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */,
DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */,
DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */,
+ DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */,
DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */,
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */,
DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */,
+ 35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */,
DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */,
- DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */,
556660D51E1D07E400E2C41B /* MGLVersionNumber.m */,
DAE6C33A1CC30DB200DB3429 /* Info.plist */,
DA2784FD1DF03060001D5B8D /* Media.xcassets */,
+ DA35D0891E1A631B007DED41 /* one-liner.json */,
);
name = "SDK Tests";
path = test;
@@ -984,7 +998,6 @@
352742781D4C220900A1ECE6 /* MGLStyleValue.h in Headers */,
DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */,
35602BFF1D3EA9B40050646F /* MGLStyleLayer_Private.h in Headers */,
- 4032C5C51DE1FE930062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.h in Headers */,
DAF0D8161DFE6B1800B28378 /* MGLAttributionInfo_Private.h in Headers */,
DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */,
DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */,
@@ -1019,6 +1032,7 @@
DAE6C39A1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h in Headers */,
DA8F258B1D51CA540010E6B5 /* MGLLineStyleLayer.h in Headers */,
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */,
+ 359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */,
DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */,
408AA8661DAEEE3600022900 /* MGLPolyline+MGLAdditions.h in Headers */,
DA87A9A01DC9DC6200810D09 /* MGLValueEvaluator.h in Headers */,
@@ -1210,7 +1224,7 @@
files = (
35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */,
DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */,
- DA2DBBCB1D51E30A00D38FF9 /* MGLStyleLayerTests.xib in Resources */,
+ DA35D08A1E1A631B007DED41 /* one-liner.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1227,8 +1241,10 @@
DAE6C2EE1CC3050F00DB3429 /* LocationCoordinate2DTransformer.m in Sources */,
DAB2CCE51DF632ED001B2FE1 /* LimeGreenStyleLayer.m in Sources */,
DAE6C2F11CC3050F00DB3429 /* TimeIntervalTransformer.m in Sources */,
+ DACB0C391E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m in Sources */,
DA839E9A1CC2E3400062CAFB /* main.m in Sources */,
DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */,
+ DAF0D81C1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m in Sources */,
DAE6C2F01CC3050F00DB3429 /* OfflinePackNameValueTransformer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1255,7 +1271,7 @@
DAE6C3931CC31E2A00DB3429 /* MGLShape.mm in Sources */,
352742861D4C244700A1ECE6 /* MGLRasterSource.mm in Sources */,
DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */,
- 4032C5C61DE1FE9B0062E8BD /* NSValue+MGLStyleEnumAttributeAdditions.mm in Sources */,
+ 3598195A1E02F611008FC139 /* NSCoder+MGLAdditions.mm in Sources */,
DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */,
DAE6C3871CC31E2A00DB3429 /* MGLGeometry.mm in Sources */,
3527428E1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.mm in Sources */,
@@ -1307,25 +1323,27 @@
files = (
DA35A2C21CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m in Sources */,
DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */,
- DA87A9A11DC9DCB400810D09 /* MGLRuntimeStylingHelper.m in Sources */,
DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */,
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */,
DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */,
- DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.m in Sources */,
+ DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.mm in Sources */,
DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */,
40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */,
- DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.m in Sources */,
- DA87A99E1DC9DC2100810D09 /* MGLFilterTests.mm in Sources */,
+ DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */,
+ DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */,
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */,
- DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.m in Sources */,
+ DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */,
+ DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */,
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
- DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.m in Sources */,
- DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.m in Sources */,
+ DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */,
+ DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.mm in Sources */,
DA87A9991DC9D88400810D09 /* MGLTileSetTests.mm in Sources */,
DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
+ DAE7DEC41E24549F007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
DA87A9981DC9D88400810D09 /* MGLShapeSourceTests.mm in Sources */,
- DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.m in Sources */,
+ 3526EABD1DF9B19800006B43 /* MGLCodingTests.m in Sources */,
+ DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.mm in Sources */,
3599A3E81DF70E2000E77FB2 /* MGLStyleValueTests.m in Sources */,
DAEDC4321D6033F1000224FF /* MGLAttributionInfoTests.m in Sources */,
DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */,
@@ -1615,6 +1633,7 @@
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
@@ -1638,6 +1657,7 @@
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
diff --git a/platform/macos/screenshot.png b/platform/macos/screenshot.png
deleted file mode 100644
index 3bf0c46ab0..0000000000
--- a/platform/macos/screenshot.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/scripts/deploy-packages.sh b/platform/macos/scripts/deploy-packages.sh
index c137401748..d0c545f8f5 100755
--- a/platform/macos/scripts/deploy-packages.sh
+++ b/platform/macos/scripts/deploy-packages.sh
@@ -4,32 +4,29 @@ set -e
set -o pipefail
set -u
-usage() {
-cat <<EOF
-# Usage: sh $0 version target_directory [argument]
-
-# version: The semver version plus optional alpha beta distinction (i.e. {major.minor.patch}{-alpha.N})
-# target_directory: The directory where build output should be placed
-
-# argument:
-# -g: Upload to github
+# dynamic environment variables:
+# VERSION_TAG={determined automatically}: Version tag in format macos-vX.X.X-pre.X
+# GITHUB_RELEASE=true: Upload to github
+# BINARY_DIRECTORY=build/macos/deploy: Directory in which to save test packages
# environment variables and dependencies:
# - You must run "mbx auth ..." before running
# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
# - "wget" is required for downloading the zip files from s3
-# - The "github-release" gem is required to use GITHUB_RELEASE
-EOF
-}
+# - The "github-release" command is required to use GITHUB_RELEASE
+
+function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
+function finish { >&2 echo -en "\033[0m"; }
+trap finish EXIT
buildPackageStyle() {
local package=$1 style=""
if [[ ${#} -eq 2 ]]; then
style="$2"
fi
- echo "make ${package} ${style}"
+ step "Building: make ${package} ${style}"
make ${package}
- echo "publish ${package} with ${style}"
+ step "Publishing ${package} with ${style}"
local file_name=""
if [ -z ${style} ]
then
@@ -37,47 +34,86 @@ buildPackageStyle() {
else
file_name=mapbox-macos-sdk-${PUBLISH_VERSION}-${style}.zip
fi
- echo "compress ${file_name}"
+ step "Compressing ${file_name}…"
cd build/macos/pkg
- rm -f ../${file_name}
- zip -r ../${file_name} *
+ rm -f ../deploy/${file_name}
+ zip -r ../deploy/${file_name} *
cd -
if [[ "${GITHUB_RELEASE}" == true ]]; then
- echo "publish ${file_name} to GitHub"
- github-release --verbose upload --tag "macos-v${PUBLISH_VERSION}" --name ${file_name} --file "build/macos/${file_name}"
- fi
+ echo "Uploading ${file_name} to GitHub"
+ github-release upload \
+ --tag "macos-v${PUBLISH_VERSION}" \
+ --name ${file_name} \
+ --file "${BINARY_DIRECTORY}/${file_name}" > /dev/null
+ fi
}
-if [ ${#} -eq 0 -o ${#} -gt 3 ]; then
- usage
- exit 1
-fi
-
export TRAVIS_REPO_SLUG=mapbox-gl-native
-export PUBLISH_VERSION=$1
export GITHUB_USER=mapbox
export GITHUB_REPO=mapbox-gl-native
export BUILDTYPE=Release
-BINARY_DIRECTORY=$2
+VERSION_TAG=${VERSION_TAG:-''}
+PUBLISH_VERSION=
+BINARY_DIRECTORY=${BINARY_DIRECTORY:-build/macos/deploy}
+GITHUB_RELEASE=${GITHUB_RELEASE:-true}
PUBLISH_PRE_FLAG=''
-GITHUB_RELEASE=false
-echo "Deploying version ${PUBLISH_VERSION}..."
+if [[ ${GITHUB_RELEASE} = "true" ]]; then
+ GITHUB_RELEASE=true # Assign bool, not just a string
+
+ if [[ -z `which github-release` ]]; then
+ step "Installing github-release…"
+ brew install github-release
+ if [ -z `which github-release` ]; then
+ echo "Unable to install github-release. See: https://github.com/aktau/github-release"
+ exit 1
+ fi
+ fi
+fi
+
+if [[ -z ${VERSION_TAG} ]]; then
+ step "Determining version number from most recent relevant git tag…"
+ VERSION_TAG=$( git describe --tags --match=macos-v*.*.* --abbrev=0 )
+ echo "Found tag: ${VERSION_TAG}"
+fi
+
+if [[ $( echo ${VERSION_TAG} | grep --invert-match macos-v ) ]]; then
+ echo "Error: ${VERSION_TAG} is not a valid macOS version tag"
+ echo "VERSION_TAG should be in format: macos-vX.X.X-pre.X"
+ exit 1
+fi
+
+if [[ $( wget --spider -O- https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/releases/tags/${VERSION_TAG} 2>&1 | grep -c "404 Not Found" ) == 0 ]]; then
+ echo "Error: ${VERSION_TAG} has already been published on GitHub"
+ echo "See: https://github.com/${GITHUB_USER}/${GITHUB_REPO}/releases/tag/${VERSION_TAG}"
+ exit 1
+fi
+
+PUBLISH_VERSION=$( echo ${VERSION_TAG} | sed 's/^macos-v//' )
+git checkout ${VERSION_TAG}
+
+step "Deploying version ${PUBLISH_VERSION}…"
if [[ ${#} -eq 3 && $3 == "-g" ]]; then
GITHUB_RELEASE=true
fi
make clean && make distclean
+mkdir -p ${BINARY_DIRECTORY}
if [[ "${GITHUB_RELEASE}" == true ]]; then
- echo "Create GitHub release..."
+ step "Create GitHub release…"
if [[ $( echo ${PUBLISH_VERSION} | awk '/[0-9]-/' ) ]]; then
PUBLISH_PRE_FLAG='--pre-release'
fi
- github-release --verbose release --tag "macos-v${PUBLISH_VERSION}" --name "macos-v${PUBLISH_VERSION}" --draft ${PUBLISH_PRE_FLAG}
+ github-release release \
+ --tag "macos-v${PUBLISH_VERSION}" \
+ --name "macos-v${PUBLISH_VERSION}" \
+ --draft ${PUBLISH_PRE_FLAG}
fi
buildPackageStyle "xpackage" "symbols"
buildPackageStyle "xpackage SYMBOLS=NO"
+
+step "Finished deploying ${PUBLISH_VERSION} in $(($SECONDS / 60)) minutes and $(($SECONDS % 60)) seconds"
diff --git a/platform/macos/scripts/document.sh b/platform/macos/scripts/document.sh
index d03ad91674..69c9aaa871 100755
--- a/platform/macos/scripts/document.sh
+++ b/platform/macos/scripts/document.sh
@@ -22,15 +22,21 @@ RELEASE_VERSION=$( echo ${SHORT_VERSION} | sed -e 's/^macos-v//' -e 's/-.*//' )
rm -rf /tmp/mbgl
mkdir -p /tmp/mbgl/
README=/tmp/mbgl/README.md
-cp platform/macos/docs/doc-README.md "${README}"
+if [[ ${STANDALONE:-} ]]; then
+ cp platform/macos/docs/pod-README.md "${README}"
+ perl -pi -e 's|https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/docs/||' \
+ "${README}"
+else
+ cp platform/macos/docs/doc-README.md "${README}"
+fi
# 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}"
+echo "## Changes in [version ${RELEASE_VERSION}](https://github.com/mapbox/mapbox-gl-native/releases/tag/${BRANCH})" >> "${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}
-cp platform/macos/screenshot.png "${OUTPUT}"
+cp -r platform/macos/docs/img "${OUTPUT}/img"
jazzy \
--config platform/macos/jazzy.yml \
@@ -38,7 +44,7 @@ jazzy \
--github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \
--module-version ${SHORT_VERSION} \
--readme ${README} \
- --documentation="platform/macos/docs/Info.plist Keys.md" \
+ --documentation="platform/{darwin,macos}/docs/guides/*.md" \
--theme platform/darwin/docs/theme \
--output ${OUTPUT}
# https://github.com/realm/jazzy/issues/411
diff --git a/platform/macos/scripts/package.sh b/platform/macos/scripts/package.sh
index 2f30b0917d..6ae0cc65cc 100755
--- a/platform/macos/scripts/package.sh
+++ b/platform/macos/scripts/package.sh
@@ -68,6 +68,19 @@ if [[ ${BUILDTYPE} == Release ]]; then
"${OUTPUT}/${NAME}.framework/${NAME}"
fi
+function create_podspec {
+ step "Creating local podspec…"
+ [[ $SYMBOLS = YES ]] && POD_SUFFIX="-symbols" || POD_SUFFIX=""
+ POD_SOURCE_PATH=' :path => ".",'
+ POD_FRAMEWORKS=" m.vendored_frameworks = '"${NAME}".framework'"
+ INPUT_PODSPEC=platform/macos/${NAME}-macOS-SDK${POD_SUFFIX}.podspec
+ OUTPUT_PODSPEC=${OUTPUT}/${NAME}-macOS-SDK${POD_SUFFIX}.podspec
+ sed "s/.*:http.*/${POD_SOURCE_PATH}/" ${INPUT_PODSPEC} > ${OUTPUT_PODSPEC}
+ sed -i '' "s/.*vendored_frameworks.*/${POD_FRAMEWORKS}/" ${OUTPUT_PODSPEC}
+}
+
+create_podspec
+
step "Copying library resources…"
cp -pv LICENSE.md "${OUTPUT}"
cp -pv platform/macos/docs/pod-README.md "${OUTPUT}/README.md"
diff --git a/platform/macos/src/MGLAnnotationImage.h b/platform/macos/src/MGLAnnotationImage.h
index d41fd32ec4..0f248c721c 100644
--- a/platform/macos/src/MGLAnnotationImage.h
+++ b/platform/macos/src/MGLAnnotationImage.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
and put into a reuse queue that is maintained by the map view.
*/
MGL_EXPORT
-@interface MGLAnnotationImage : NSObject
+@interface MGLAnnotationImage : NSObject <NSSecureCoding>
#pragma mark Initializing and Preparing the Image Object
diff --git a/platform/macos/src/MGLAnnotationImage.m b/platform/macos/src/MGLAnnotationImage.m
index 1b545651d2..d19dbe5dfc 100644
--- a/platform/macos/src/MGLAnnotationImage.m
+++ b/platform/macos/src/MGLAnnotationImage.m
@@ -23,4 +23,41 @@
return self;
}
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super init]) {
+ _image = [decoder decodeObjectOfClass:[NSImage class] forKey:@"image"];
+ _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"];
+ _cursor = [decoder decodeObjectOfClass:[NSCursor class] forKey:@"cursor"];
+ _selectable = [decoder decodeBoolForKey:@"selectable"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+ [coder encodeObject:_image forKey:@"image"];
+ [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"];
+ [coder encodeObject:_cursor forKey:@"cursor"];
+ [coder encodeBool:_selectable forKey:@"selectable"];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (self == other) return YES;
+ if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO;
+
+ MGLAnnotationImage *otherAnnotationImage = other;
+
+ return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier) || [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier])
+ && _selectable == otherAnnotationImage.selectable
+ && ((!_cursor && !otherAnnotationImage.cursor) || [_cursor isEqual:otherAnnotationImage.cursor])
+ && (_image == otherAnnotationImage.image || [[_image TIFFRepresentation] isEqualToData:[otherAnnotationImage.image TIFFRepresentation]]);
+}
+
+- (NSUInteger)hash {
+ return _reuseIdentifier.hash + @(_selectable).hash + _image.hash;
+}
+
@end
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index c934ba6e97..efe83d1573 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -95,6 +95,13 @@ MGL_EXPORT IB_DESIGNABLE
Unlike the `styleURL` property, this property is set to an object that allows
you to manipulate every aspect of the style locally.
+ If the style is loading, this property is set to `nil` until the style finishes
+ loading. If the style has failed to load, this property is set to `nil`.
+ Because the style loads asynchronously, you should manipulate it in the
+ `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
+ to manipulate the style before it has finished loading.
+
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style's sources and layers must first set the style URL to an
@@ -102,7 +109,7 @@ MGL_EXPORT IB_DESIGNABLE
`+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`.
*/
-@property (nonatomic, readonly) MGLStyle *style;
+@property (nonatomic, readonly, nullable) MGLStyle *style;
/**
URL of the style currently displayed in the receiver.
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 92aa0a6c6b..0db059dcf2 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -19,6 +19,7 @@
#import "MGLAnnotationImage.h"
#import "MGLMapViewDelegate.h"
+#import <mbgl/map/map.hpp>
#import <mbgl/map/view.hpp>
#import <mbgl/annotation/annotation.hpp>
#import <mbgl/map/camera.hpp>
@@ -597,6 +598,10 @@ public:
#pragma mark Style
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle {
+ return [NSSet setWithObject:@"styleURL"];
+}
+
- (nonnull NSURL *)styleURL {
NSString *styleURLString = @(_mbglMap->getStyleURL().c_str()).mgl_stringOrNilIfEmpty;
return styleURLString ? [NSURL URLWithString:styleURLString] : [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
@@ -618,10 +623,8 @@ public:
}
styleURL = styleURL.mgl_URLByStandardizingScheme;
- [self willChangeValueForKey:@"style"];
- _style = [[MGLStyle alloc] initWithMapView:self];
+ self.style = nil;
_mbglMap->setStyleURL(styleURL.absoluteString.UTF8String);
- [self didChangeValueForKey:@"style"];
}
- (IBAction)reloadStyle:(__unused id)sender {
@@ -630,6 +633,10 @@ public:
self.styleURL = styleURL;
}
+- (mbgl::Map *)mbglMap {
+ return _mbglMap;
+}
+
#pragma mark View hierarchy and drawing
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
@@ -922,11 +929,7 @@ public:
}
case mbgl::MapChangeDidFinishLoadingStyle:
{
- [self.style willChangeValueForKey:@"name"];
- [self.style willChangeValueForKey:@"sources"];
- [self.style didChangeValueForKey:@"sources"];
- [self.style willChangeValueForKey:@"layers"];
- [self.style didChangeValueForKey:@"layers"];
+ self.style = [[MGLStyle alloc] initWithMapView:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];
@@ -2274,28 +2277,11 @@ public:
}
}
-#pragma mark - Runtime styling
-
-- (mbgl::Map *)mbglMap
-{
- return _mbglMap;
-}
-
#pragma mark MGLMultiPointDelegate methods
- (double)alphaForShapeAnnotation:(MGLShape *)annotation {
- // The explicit -mapView:alphaForShapeAnnotation: delegate method is deprecated
- // but still used, if implemented. When not implemented, call the stroke or
- // fill color delegate methods and pull the alpha from the returned color.
if (_delegateHasAlphasForShapeAnnotations) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [self.delegate mapView:self alphaForShapeAnnotation:annotation];
-#pragma clang diagnostic pop
- } else if ([annotation isKindOfClass:[MGLPolygon class]]) {
- return [self fillColorForPolygonAnnotation:(MGLPolygon *)annotation].a ?: 1.0;
- } else if ([annotation isKindOfClass:[MGLShape class]]) {
- return [self strokeColorForShapeAnnotation:annotation].a ?: 1.0;
}
return 1.0;
}
@@ -2492,7 +2478,7 @@ public:
if (menuItem.action == @selector(giveFeedback:)) {
return YES;
}
- return [super validateMenuItem:menuItem];
+ return NO;
}
#pragma mark Interface Builder methods
diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h
index c5af93f8ad..1cf86263f3 100644
--- a/platform/macos/src/MGLMapViewDelegate.h
+++ b/platform/macos/src/MGLMapViewDelegate.h
@@ -156,7 +156,22 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
-- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation __attribute__((deprecated("Use -mapView:strokeColorForShapeAnnotation: or -mapView:fillColorForPolygonAnnotation:.")));
+/**
+ Returns the alpha value to use when rendering a shape annotation.
+
+ A value of 0.0 results in a completely transparent shape. A value of 1.0, the
+ default, results in a completely opaque shape.
+
+ This method sets the opacity of an entire shape, inclusive of its stroke and
+ fill. To independently set the values for stroke or fill, specify an alpha
+ component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or
+ `-mapView:fillColorForPolygonAnnotation:`.
+
+ @param mapView The map view rendering the shape annotation.
+ @param annotation The annotation being rendered.
+ @return An alpha value between 0 and 1.0.
+ */
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
/**
Returns the color to use when rendering the outline of a shape annotation.
@@ -257,7 +272,7 @@ NS_ASSUME_NONNULL_BEGIN
such as `title` and `subtitle`.
If each annotation should have an identical callout, you can set the
- `MGLMapView` instance’s `-setCalloutViewController:` method instead.
+ `MGLMapView.calloutViewController` property instead.
@param mapView The map view that is requesting a callout view controller.
@param annotation The object representing the annotation.
diff --git a/platform/macos/src/MGLMapView_Private.h b/platform/macos/src/MGLMapView_Private.h
index 0980252fb5..5ac75768a1 100644
--- a/platform/macos/src/MGLMapView_Private.h
+++ b/platform/macos/src/MGLMapView_Private.h
@@ -1,6 +1,8 @@
#import "MGLMapView.h"
-#include <mbgl/map/map.hpp>
+namespace mbgl {
+ class Map;
+}
@interface MGLMapView (Private)
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index b16aaf7e67..1f30497184 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -50,6 +50,5 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "NSValue+MGLAdditions.h"
-#import "NSValue+MGLStyleEnumAttributeAdditions.h"
#import "MGLStyleValue.h"
#import "MGLAttributionInfo.h"
diff --git a/platform/macos/src/NSImage+MGLAdditions.mm b/platform/macos/src/NSImage+MGLAdditions.mm
index 72ddec83f7..9c30d3c37b 100644
--- a/platform/macos/src/NSImage+MGLAdditions.mm
+++ b/platform/macos/src/NSImage+MGLAdditions.mm
@@ -6,7 +6,7 @@
std::string png = encodePNG(spriteImage->image);
NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:data];
- if ([self initWithSize:NSMakeSize(spriteImage->getWidth(), spriteImage->getHeight())]) {
+ if (self = [self initWithSize:NSMakeSize(spriteImage->getWidth(), spriteImage->getHeight())]) {
[self addRepresentation:rep];
[self setTemplate:spriteImage->sdf];
}
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 7480438132..62726cd127 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -18,7 +18,7 @@ void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
impl->setGeoJSON(geoJSON);
}
-optional<std::string> GeoJSONSource::getURL() {
+optional<std::string> GeoJSONSource::getURL() const {
return impl->getURL();
}
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 7f41e0e321..3f3bc879f7 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -47,7 +47,7 @@ void GeoJSONSource::Impl::setURL(std::string url_) {
}
}
-optional<std::string> GeoJSONSource::Impl::getURL() {
+optional<std::string> GeoJSONSource::Impl::getURL() const {
return url;
}
@@ -63,15 +63,9 @@ void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
cache.clear();
- if (!options.cluster) {
- mapbox::geojsonvt::Options vtOptions;
- vtOptions.maxZoom = options.maxzoom;
- vtOptions.extent = util::EXTENT;
- vtOptions.buffer = std::round(scale * options.buffer);
- vtOptions.tolerance = scale * options.tolerance;
- geoJSONOrSupercluster = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(geoJSON, vtOptions);
-
- } else {
+ if (options.cluster
+ && geoJSON.is<mapbox::geometry::feature_collection<double>>()
+ && !geoJSON.get<mapbox::geometry::feature_collection<double>>().empty()) {
mapbox::supercluster::Options clusterOptions;
clusterOptions.maxZoom = options.clusterMaxZoom;
clusterOptions.extent = util::EXTENT;
@@ -80,6 +74,13 @@ void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
const auto& features = geoJSON.get<mapbox::geometry::feature_collection<double>>();
geoJSONOrSupercluster =
std::make_unique<mapbox::supercluster::Supercluster>(features, clusterOptions);
+ } else {
+ mapbox::geojsonvt::Options vtOptions;
+ vtOptions.maxZoom = options.maxzoom;
+ vtOptions.extent = util::EXTENT;
+ vtOptions.buffer = std::round(scale * options.buffer);
+ vtOptions.tolerance = scale * options.tolerance;
+ geoJSONOrSupercluster = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(geoJSON, vtOptions);
}
for (auto const &item : tiles) {
diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp
index 13994d9078..eec7cf0605 100644
--- a/src/mbgl/style/sources/geojson_source_impl.hpp
+++ b/src/mbgl/style/sources/geojson_source_impl.hpp
@@ -17,7 +17,7 @@ public:
~Impl() final;
void setURL(std::string);
- optional<std::string> getURL();
+ optional<std::string> getURL() const;
void setGeoJSON(const GeoJSON&);
void setTileData(GeoJSONTile&, const OverscaledTileID& tileID);
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
index 3c65476df0..94fdbcef12 100644
--- a/src/mbgl/style/sources/raster_source.cpp
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -5,7 +5,17 @@ namespace mbgl {
namespace style {
RasterSource::RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize)
- : Source(SourceType::Raster, std::make_unique<RasterSource::Impl>(std::move(id), *this, std::move(urlOrTileset), tileSize)) {
+ : Source(SourceType::Raster, std::make_unique<RasterSource::Impl>(std::move(id), *this, std::move(urlOrTileset), tileSize)),
+ impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+optional<std::string> RasterSource::getURL() const {
+ auto urlOrTileset = impl->getURLOrTileset();
+ if (urlOrTileset.is<std::string>()) {
+ return urlOrTileset.get<std::string>();
+ } else {
+ return {};
+ }
}
} // namespace style
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
index f2a6b166a9..4bcd3b8985 100644
--- a/src/mbgl/style/sources/vector_source.cpp
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -5,7 +5,17 @@ namespace mbgl {
namespace style {
VectorSource::VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset)
- : Source(SourceType::Vector, std::make_unique<VectorSource::Impl>(std::move(id), *this, std::move(urlOrTileset))) {
+ : Source(SourceType::Vector, std::make_unique<VectorSource::Impl>(std::move(id), *this, std::move(urlOrTileset))),
+ impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+optional<std::string> VectorSource::getURL() const {
+ auto urlOrTileset = impl->getURLOrTileset();
+ if (urlOrTileset.is<std::string>()) {
+ return urlOrTileset.get<std::string>();
+ } else {
+ return {};
+ }
}
} // namespace style