diff options
Diffstat (limited to 'platform/darwin')
-rw-r--r-- | platform/darwin/scripts/generate-style-code.js | 14 | ||||
-rw-r--r-- | platform/darwin/src/MGLSymbolStyleLayer.h | 86 | ||||
-rw-r--r-- | platform/darwin/src/MGLSymbolStyleLayer.mm | 45 | ||||
-rw-r--r-- | platform/darwin/test/MGLSymbolStyleLayerTests.mm | 50 |
4 files changed, 185 insertions, 10 deletions
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 5a4936c0ee..4ee86e65da 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -148,6 +148,9 @@ global.mbglTestValue = function (property, layerType) { if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) { type = 'Alignment'; } + if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) { + type = 'SymbolAnchor' + } let value = camelize(_.last(_.keys(property.values))); if (property['light-property']) { return `mbgl::style::Light${type}Type::${value}`; @@ -500,6 +503,9 @@ global.mbglType = function(property) { if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) { type = 'Alignment'; } + if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) { + type = 'SymbolAnchor' + } return `mbgl::style::${type}Type`; } case 'color': @@ -648,10 +654,10 @@ 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; } @@ -663,13 +669,13 @@ global.guideExample = function (guide, exampleId, os) { console.error(`MGLDocumentationExampleTests.test${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\b\n?/gm, function (m, indentation, ifOs, ifCase, elseCase) { return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), ''); }).replace(/\n$/, ''); - + return '```swift\n' + example + '\n```'; }; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index d8dded7dbd..bc39df5b16 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -8,6 +8,51 @@ NS_ASSUME_NONNULL_BEGIN /** + Part of the icon placed closest to the anchor. + + Values of this type are used in the `MGLSymbolStyleLayer.iconAnchor` + property. + */ +typedef NS_ENUM(NSUInteger, MGLIconAnchor) { + /** + The center of the icon is placed closest to the anchor. + */ + MGLIconAnchorCenter, + /** + The left side of the icon is placed closest to the anchor. + */ + MGLIconAnchorLeft, + /** + The right side of the icon is placed closest to the anchor. + */ + MGLIconAnchorRight, + /** + The top of the icon is placed closest to the anchor. + */ + MGLIconAnchorTop, + /** + The bottom of the icon is placed closest to the anchor. + */ + MGLIconAnchorBottom, + /** + The top left corner of the icon is placed closest to the anchor. + */ + MGLIconAnchorTopLeft, + /** + The top right corner of the icon is placed closest to the anchor. + */ + MGLIconAnchorTopRight, + /** + The bottom left corner of the icon is placed closest to the anchor. + */ + MGLIconAnchorBottomLeft, + /** + The bottom right corner of the icon is placed closest to the anchor. + */ + MGLIconAnchorBottomRight, +}; + +/** Orientation of icon when map is pitched. Values of this type are used in the `MGLSymbolStyleLayer.iconPitchAlignment` @@ -345,6 +390,34 @@ MGL_EXPORT @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead."))); /** + Part of the icon placed closest to the anchor. + + The default value of this property is an `MGLStyleValue` object containing an + `NSValue` object containing `MGLIconAnchorCenter`. 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. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLSourceStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + * `MGLInterpolationModeIdentity` + * `MGLCompositeStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconAnchor; + +/** 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 @@ -1984,6 +2057,19 @@ MGL_EXPORT #pragma mark Working with Symbol Style Layer Attribute Values /** + Creates a new value object containing the given `MGLIconAnchor` enumeration. + + @param iconAnchor The value for the new object. + @return A new value object that contains the enumeration value. + */ ++ (instancetype)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor; + +/** + The `MGLIconAnchor` enumeration representation of the value. + */ +@property (readonly) MGLIconAnchor MGLIconAnchorValue; + +/** Creates a new value object containing the given `MGLIconPitchAlignment` enumeration. @param iconPitchAlignment The value for the new object. diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index 2541e6b0a4..7e8b0b247b 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -13,6 +13,18 @@ namespace mbgl { + MBGL_DEFINE_ENUM(MGLIconAnchor, { + { MGLIconAnchorCenter, "center" }, + { MGLIconAnchorLeft, "left" }, + { MGLIconAnchorRight, "right" }, + { MGLIconAnchorTop, "top" }, + { MGLIconAnchorBottom, "bottom" }, + { MGLIconAnchorTopLeft, "top-left" }, + { MGLIconAnchorTopRight, "top-right" }, + { MGLIconAnchorBottomLeft, "bottom-left" }, + { MGLIconAnchorBottomRight, "bottom-right" }, + }); + MBGL_DEFINE_ENUM(MGLIconPitchAlignment, { { MGLIconPitchAlignmentMap, "map" }, { MGLIconPitchAlignmentViewport, "viewport" }, @@ -166,6 +178,23 @@ namespace mbgl { return self.iconAllowsOverlap; } +- (void)setIconAnchor:(MGLStyleValue<NSValue *> *)iconAnchor { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenPropertyValue(iconAnchor); + self.rawLayer->setIconAnchor(mbglValue); +} + +- (MGLStyleValue<NSValue *> *)iconAnchor { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getIconAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconAnchor()); + } + return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(propertyValue); +} + - (void)setIconIgnoresPlacement:(MGLStyleValue<NSNumber *> *)iconIgnoresPlacement { MGLAssertStyleLayerIsValid(); @@ -586,7 +615,7 @@ namespace mbgl { - (void)setTextAnchor:(MGLStyleValue<NSValue *> *)textAnchor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor); + auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor); self.rawLayer->setTextAnchor(mbglValue); } @@ -595,9 +624,9 @@ namespace mbgl { auto propertyValue = self.rawLayer->getTextAnchor(); if (propertyValue.isUndefined()) { - return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor()); + return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor()); } - return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue); + return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue); } - (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames { @@ -1344,6 +1373,16 @@ namespace mbgl { @implementation NSValue (MGLSymbolStyleLayerAdditions) ++ (NSValue *)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor { + return [NSValue value:&iconAnchor withObjCType:@encode(MGLIconAnchor)]; +} + +- (MGLIconAnchor)MGLIconAnchorValue { + MGLIconAnchor iconAnchor; + [self getValue:&iconAnchor]; + return iconAnchor; +} + + (NSValue *)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment { return [NSValue value:&iconPitchAlignment withObjCType:@encode(MGLIconPitchAlignment)]; } diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm index 6b0b20354b..abbaef9159 100644 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -87,6 +87,40 @@ XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } + // icon-anchor + { + XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(), + @"icon-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconAnchor; + + MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight]]; + layer.iconAnchor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight }; + XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue, + @"Setting iconAnchor to a constant value should update icon-anchor."); + XCTAssertEqualObjects(layer.iconAnchor, constantStyleValue, + @"iconAnchor should round-trip constant values."); + + MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconAnchor = functionStyleValue; + + mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} }; + propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops }; + + XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue, + @"Setting iconAnchor to a camera function should update icon-anchor."); + XCTAssertEqualObjects(layer.iconAnchor, functionStyleValue, + @"iconAnchor should round-trip camera functions."); + + + + layer.iconAnchor = nil; + XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(), + @"Unsetting iconAnchor should return icon-anchor to the default value."); + XCTAssertEqualObjects(layer.iconAnchor, defaultStyleValue, + @"iconAnchor should return the default value after being unset."); + } + // icon-ignore-placement { XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(), @@ -931,7 +965,7 @@ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]]; layer.textAnchor = constantStyleValue; - mbgl::style::DataDrivenPropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight }; + mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight }; XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, @"Setting textAnchor to a constant value should update text-anchor."); XCTAssertEqualObjects(layer.textAnchor, constantStyleValue, @@ -940,8 +974,8 @@ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; layer.textAnchor = functionStyleValue; - mbgl::style::IntervalStops<mbgl::style::TextAnchorType> intervalStops = { {{18, mbgl::style::TextAnchorType::BottomRight}} }; - propertyValue = mbgl::style::CameraFunction<mbgl::style::TextAnchorType> { intervalStops }; + mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} }; + propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops }; XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, @"Setting textAnchor to a camera function should update text-anchor."); @@ -2345,6 +2379,7 @@ - (void)testPropertyNames { [self testPropertyName:@"icon-allows-overlap" isBoolean:YES]; + [self testPropertyName:@"icon-anchor" isBoolean:NO]; [self testPropertyName:@"icon-ignores-placement" isBoolean:YES]; [self testPropertyName:@"icon-image-name" isBoolean:NO]; [self testPropertyName:@"icon-offset" isBoolean:NO]; @@ -2396,6 +2431,15 @@ } - (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorCenter].MGLIconAnchorValue, MGLIconAnchorCenter); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorLeft].MGLIconAnchorValue, MGLIconAnchorLeft); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorRight].MGLIconAnchorValue, MGLIconAnchorRight); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTop].MGLIconAnchorValue, MGLIconAnchorTop); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottom].MGLIconAnchorValue, MGLIconAnchorBottom); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopLeft].MGLIconAnchorValue, MGLIconAnchorTopLeft); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopRight].MGLIconAnchorValue, MGLIconAnchorTopRight); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomLeft].MGLIconAnchorValue, MGLIconAnchorBottomLeft); + XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight].MGLIconAnchorValue, MGLIconAnchorBottomRight); XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentMap].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentMap); XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentViewport].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentViewport); XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentAuto); |