From 174c8fa7e4927ebf28a3d0e07c995d3e3d69de76 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Tue, 19 Mar 2019 14:53:35 -0700 Subject: [ios, macos] Add text-color support to format expressions. (#14146) Added the possibility of overriding paint properties inside the format expression. Added an example of how to create an MGLAttributedExpression object and documented the attributes keys and value types. Fixed a bug that ignored the font names. --- .../darwin/docs/guides/For Style Authors.md.ejs | 11 ++++++ .../docs/guides/Predicates and Expressions.md | 8 +++++ platform/darwin/src/MGLAttributedExpression.h | 41 ++++++++++++++++++++-- platform/darwin/src/MGLAttributedExpression.m | 13 +++++-- platform/darwin/src/NSExpression+MGLAdditions.mm | 27 ++++++++++++-- .../darwin/test/MGLDocumentationExampleTests.swift | 18 ++++++++++ platform/darwin/test/MGLExpressionTests.mm | 37 +++++++++++++++++++ platform/ios/docs/guides/For Style Authors.md | 11 ++++++ platform/ios/src/UIColor+MGLAdditions.h | 1 + platform/macos/docs/guides/For Style Authors.md | 11 ++++++ platform/macos/src/NSColor+MGLAdditions.h | 1 + platform/macos/src/NSColor+MGLAdditions.mm | 6 ++-- 12 files changed, 176 insertions(+), 9 deletions(-) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index cf0f79f419..cff6e2f41c 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -431,5 +431,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontSizeAttribute` | `.fontSizeAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md index 5f5d9a22a8..51617c8508 100644 --- a/platform/darwin/docs/guides/Predicates and Expressions.md +++ b/platform/darwin/docs/guides/Predicates and Expressions.md @@ -546,6 +546,14 @@ operator in the Mapbox Style Specification. Concatenates and returns the array of `MGLAttributedExpression` objects, for use with the `MGLSymbolStyleLayer.text` property. +`MGLAttributedExpression.attributes` valid attributes. + + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | `NSArray*` + `MGLFontSizeAttribute` | `NSNumber` + `MGLFontColorAttribute` | `UIColor` or `NSColor` on macos + This function corresponds to the [`format`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-format) operator in the Mapbox Style Specification. diff --git a/platform/darwin/src/MGLAttributedExpression.h b/platform/darwin/src/MGLAttributedExpression.h index aa5d51c66e..32f1a96dae 100644 --- a/platform/darwin/src/MGLAttributedExpression.h +++ b/platform/darwin/src/MGLAttributedExpression.h @@ -6,10 +6,23 @@ typedef NSString * MGLAttributedExpressionKey NS_EXTENSIBLE_STRING_ENUM; FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontNamesAttribute; FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontSizeAttribute; +FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontColorAttribute; /** An `MGLAttributedExpression` object associates text formatting attibutes (such as font size or font names) to an `NSExpression`. + + ### Example + ```swift + let redColor = UIColor.red + let expression = NSExpression(forConstantValue: "Foo") + let attributes: Dictionary = [.fontNamesAttribute : ["DIN Offc Pro Italic", + "Arial Unicode MS Regular"], + .fontSizeAttribute: 1.2, + .fontColorAttribute: redColor] + let attributedExpression = MGLAttributedExpression(expression, attributes:attributes) + ``` + */ MGL_EXPORT @interface MGLAttributedExpression : NSObject @@ -19,10 +32,29 @@ MGL_EXPORT */ @property (strong, nonatomic) NSExpression *expression; +#if TARGET_OS_IPHONE /** - The formatting attributes. + The formatting attributes dictionary. + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | `NSArray*` + `MGLFontSizeAttribute` | `NSNumber` + `MGLFontColorAttribute` | `UIColor` + + */ +@property (strong, nonatomic, readonly) NSDictionary *attributes; +#else +/** + The formatting attributes dictionary. + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | `NSArray*` + `MGLFontSizeAttribute` | `NSNumber` + `MGLFontColorAttribute` | `NSColor` */ @property (strong, nonatomic, readonly) NSDictionary *attributes; +#endif + /** Returns an `MGLAttributedExpression` object initialized with an expression and no attribute information. @@ -32,13 +64,18 @@ MGL_EXPORT /** Returns an `MGLAttributedExpression` object initialized with an expression and text format attributes. */ -- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nullable NSDictionary *)attrs; +- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary *)attrs; /** Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes for font names and font size. */ + (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray *)fontNames fontSize:(nullable NSNumber *)fontSize; +/** + Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes dictionary. + */ ++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary *)attrs; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLAttributedExpression.m b/platform/darwin/src/MGLAttributedExpression.m index 715f74e42f..000701f7cf 100644 --- a/platform/darwin/src/MGLAttributedExpression.m +++ b/platform/darwin/src/MGLAttributedExpression.m @@ -3,11 +3,12 @@ const MGLAttributedExpressionKey MGLFontNamesAttribute = @"text-font"; const MGLAttributedExpressionKey MGLFontSizeAttribute = @"font-scale"; +const MGLAttributedExpressionKey MGLFontColorAttribute = @"text-color"; @implementation MGLAttributedExpression - (instancetype)initWithExpression:(NSExpression *)expression { - self = [self initWithExpression:expression attributes:nil]; + self = [self initWithExpression:expression attributes:@{}]; return self; } @@ -28,7 +29,15 @@ const MGLAttributedExpressionKey MGLFontSizeAttribute = @"font-scale"; return attributedExpression; } -- (instancetype)initWithExpression:(NSExpression *)expression attributes:(NSDictionary *)attrs { ++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary *)attrs { + MGLAttributedExpression *attributedExpression; + + attributedExpression = [[self alloc] initWithExpression:expression attributes:attrs]; + + return attributedExpression; +} + +- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary *)attrs { if (self = [super init]) { MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class])); diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index c4e2908888..f0f1d62ef7 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -1,3 +1,4 @@ +#import "MGLFoundation_Private.h" #import "NSExpression+MGLPrivateAdditions.h" #import "MGLTypes.h" @@ -878,9 +879,23 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { NSExpression *expression = [NSExpression expressionWithMGLJSONObject:argumentObjects[index]]; NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; if ((index + 1) < argumentObjects.count) { - attrs = argumentObjects[index + 1]; + attrs = [NSMutableDictionary dictionaryWithDictionary:argumentObjects[index + 1]]; } + if (attrs.count) { + if (NSArray *fontNames = MGL_OBJC_DYNAMIC_CAST(attrs[MGLFontNamesAttribute], NSArray)) { + attrs[MGLFontNamesAttribute] = fontNames[1]; + } + if (NSArray *colorArray = MGL_OBJC_DYNAMIC_CAST(attrs[MGLFontColorAttribute], NSArray)) { + if ([colorArray[0] isEqualToString:@"rgb"] || [colorArray[0] isEqualToString:@"rgba"]) { + NSArray *colorArguments = [colorArray subarrayWithRange:NSMakeRange(1, colorArray.count - 1)]; + NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(colorArguments); + MGLColor *color = [NSExpression mgl_colorWithRGBComponents:subexpressions]; + + attrs[MGLFontColorAttribute] = color; + } + } + } MGLAttributedExpression *attributedExpression = [[MGLAttributedExpression alloc] initWithExpression:expression attributes:attrs]; [attributedExpressions addObject:[NSExpression expressionForConstantValue:attributedExpression]]; @@ -1008,7 +1023,15 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { [attributes addObject:jsonObject]; } if (attributedExpression.attributes) { - [attributes addObject:attributedExpression.attributes]; + NSMutableDictionary *attributedDictionary = [NSMutableDictionary dictionaryWithDictionary:attributedExpression.attributes]; + if (attributedDictionary[MGLFontNamesAttribute]) { + attributedDictionary[MGLFontNamesAttribute] = @[@"literal", attributedDictionary[MGLFontNamesAttribute]]; + } + if (attributedDictionary[MGLFontColorAttribute] && [attributedDictionary[MGLFontColorAttribute] isKindOfClass:[MGLColor class]]) { + MGLColor *color = attributedDictionary[MGLFontColorAttribute]; + attributedDictionary[MGLFontColorAttribute] = color.mgl_jsonExpressionObject; + } + [attributes addObject:attributedDictionary]; } else { [attributes addObject:@{}]; } diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 91fb02dfd2..45efe4c591 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -542,6 +542,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { } } + func testMGLAttributedExpression() { + //#-example-code + #if os(macOS) + let redColor = NSColor.red + #else + let redColor = UIColor.red + #endif + let expression = NSExpression(forConstantValue: "Foo") + let attributes: Dictionary = [.fontNamesAttribute : ["DIN Offc Pro Italic", + "Arial Unicode MS Regular"], + .fontSizeAttribute: 1.2, + .fontColorAttribute: redColor] + let attributedExpression = MGLAttributedExpression(expression, attributes:attributes) + //#-end-example-code + + XCTAssertNotNil(attributedExpression) + } + // For testMGLMapView(). func myCustomFunction() {} } diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 8b8a79f184..8e99ed596e 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -1049,6 +1049,43 @@ using namespace std::string_literals; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); } + { + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontSizeAttribute: @(1.2), + MGLFontColorAttribute: @"yellow"}] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSExpression *compatibilityExpression = [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[MGLConstantExpression(attribute1)]]; + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" } ]; + XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, expression.mgl_jsonExpressionObject); + XCTAssertEqualObjects(compatibilityExpression, expression); + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontSizeAttribute: @(1.2), + MGLFontColorAttribute: @"yellow", + MGLFontNamesAttribute: @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ] + }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontSizeAttribute: @(1.2), + MGLFontColorAttribute: [MGLColor redColor], + MGLFontNamesAttribute: @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ] + }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @[@"rgb", @255, @0, @0] , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } { MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"] fontNames:nil diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 73394ff6ed..44d5e47262 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -418,5 +418,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontSizeAttribute` | `.fontSizeAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/ios/src/UIColor+MGLAdditions.h b/platform/ios/src/UIColor+MGLAdditions.h index 60cfe1c58b..19702fa105 100644 --- a/platform/ios/src/UIColor+MGLAdditions.h +++ b/platform/ios/src/UIColor+MGLAdditions.h @@ -17,5 +17,6 @@ + (NSExpression *)mgl_expressionForRGBComponents:(NSArray *)components; + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray *)components; ++ (UIColor *)mgl_colorWithRGBComponents:(NSArray *)components; @end diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md index 038ddf1f93..220ce3d50e 100644 --- a/platform/macos/docs/guides/For Style Authors.md +++ b/platform/macos/docs/guides/For Style Authors.md @@ -411,5 +411,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontSizeAttribute` | `.fontSizeAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/macos/src/NSColor+MGLAdditions.h b/platform/macos/src/NSColor+MGLAdditions.h index 21c939fec6..a3c5aba63f 100644 --- a/platform/macos/src/NSColor+MGLAdditions.h +++ b/platform/macos/src/NSColor+MGLAdditions.h @@ -23,5 +23,6 @@ + (NSExpression *)mgl_expressionForRGBComponents:(NSArray *)components; + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray *)components; ++ (NSColor *)mgl_colorWithRGBComponents:(NSArray *)componentExpressions; @end diff --git a/platform/macos/src/NSColor+MGLAdditions.mm b/platform/macos/src/NSColor+MGLAdditions.mm index c73c1a41b7..ea7d99f66d 100644 --- a/platform/macos/src/NSColor+MGLAdditions.mm +++ b/platform/macos/src/NSColor+MGLAdditions.mm @@ -37,7 +37,7 @@ @implementation NSExpression (MGLColorAdditions) + (NSExpression *)mgl_expressionForRGBComponents:(NSArray *)components { - if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) { + if (NSColor *color = [self mgl_colorWithRGBComponents:components]) { return [NSExpression expressionForConstantValue:color]; } @@ -49,7 +49,7 @@ } + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray *)components { - if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) { + if (NSColor *color = [self mgl_colorWithRGBComponents:components]) { return [NSExpression expressionForConstantValue:color]; } @@ -62,7 +62,7 @@ /** Returns a color object corresponding to the given component expressions. */ -+ (NSColor *)mgl_colorWithComponentExpressions:(NSArray *)componentExpressions { ++ (NSColor *)mgl_colorWithRGBComponents:(NSArray *)componentExpressions { // Map the component expressions to constant components. If any component is // a non-constant expression, the components cannot be converted into a // constant color value. -- cgit v1.2.1