From d0cd49f516d053620147e9f047252bd88374ac5d Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 19 Sep 2018 15:20:03 -0700 Subject: [ios, macos] Minimal darwin wrappers of 'format' expression Add support for `MGL_FUNCTION('format', , )` --- include/mbgl/style/expression/dsl.hpp | 6 +++++- platform/darwin/scripts/generate-style-code.js | 7 +++++++ platform/darwin/src/MGLStyleLayer.mm.ejs | 5 +++++ platform/darwin/src/MGLStyleValue_Private.h | 10 ++++++++++ platform/darwin/src/MGLSymbolStyleLayer.mm | 8 ++++---- platform/darwin/src/NSExpression+MGLAdditions.mm | 5 +++++ platform/darwin/test/MGLStyleLayerTests.mm.ejs | 20 +++++++++++++++++++- platform/darwin/test/MGLSymbolStyleLayerTests.mm | 20 ++++++++++++-------- 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index a4483a6fe6..bd94a765e7 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -38,7 +38,8 @@ std::unique_ptr boolean(std::unique_ptr); std::unique_ptr toColor(std::unique_ptr); std::unique_ptr toString(std::unique_ptr); - +std::unique_ptr toFormatted(std::unique_ptr); + std::unique_ptr get(const char* value); std::unique_ptr get(std::unique_ptr); @@ -78,6 +79,9 @@ std::unique_ptr interpolate(Interpolator interpolator, double input3, std::unique_ptr output3); std::unique_ptr concat(std::vector> inputs); + +std::unique_ptr format(const char* value); +std::unique_ptr format(std::unique_ptr); } // namespace dsl } // namespace expression diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index bc676e9cba..c4c28c7946 100755 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -103,6 +103,11 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { case 'number': return '@"1"'; case 'formatted': + // Special 'string' case to handle constant expression text-field that automatically + // converts Formatted back to string. + return layerType === 'string' ? + `@"'${_.startCase(propertyName)}'"` : + `@"MGL_FUNCTION('format', '${_.startCase(propertyName)}', %@)", @{}`; case 'string': return `@"'${_.startCase(propertyName)}'"`; case 'enum': @@ -559,6 +564,7 @@ global.valueTransformerArguments = function (property) { case 'number': return ['float', objCType]; case 'formatted': + return ['mbgl::style::expression::Formatted', objCType]; case 'string': return ['std::string', objCType]; case 'enum': @@ -593,6 +599,7 @@ global.mbglType = function(property) { case 'number': return 'float'; case 'formatted': + return 'mbgl::style::expression::Formatted'; case 'string': return 'std::string'; case 'enum': { diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs index 49ac04ce05..6d0c4bfdd9 100644 --- a/platform/darwin/src/MGLStyleLayer.mm.ejs +++ b/platform/darwin/src/MGLStyleLayer.mm.ejs @@ -125,8 +125,13 @@ namespace mbgl { if (<%- objCName(property) %> && <%- objCName(property) %>.expressionType == NSConstantValueExpressionType) { std::string string = ((NSString *)<%- objCName(property) %>.constantValue).UTF8String; if (mbgl::style::conversion::hasTokens(string)) { +<% if (property.type === 'formatted') { -%> + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbgl::style::PropertyValue( + mbgl::style::conversion::convertTokenStringToFormatExpression(string))); +<% } else { -%> self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbgl::style::PropertyValue( mbgl::style::conversion::convertTokenStringToExpression(string))); +<% } -%> return; } } diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 75e422fb45..cc1950bfb8 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -162,6 +162,11 @@ private: // Private utilities for converting from mgl to mbgl values mbglValue = rawValue.UTF8String; } + // Formatted + void getMBGLValue(NSString *rawValue, mbgl::style::expression::Formatted &mbglValue) { + mbglValue = mbgl::style::expression::Formatted(rawValue.UTF8String); + } + // Offsets void getMBGLValue(id rawValue, std::array &mbglValue) { if ([rawValue isKindOfClass:[NSValue class]]) { @@ -250,6 +255,11 @@ private: // Private utilities for converting from mbgl to mgl values return @(mbglStopValue.c_str()); } + // Formatted + static NSString *toMGLRawStyleValue(const mbgl::style::expression::Formatted &mbglStopValue) { + return @(mbglStopValue.toString().c_str()); + } + // Offsets static NSValue *toMGLRawStyleValue(const std::array &mbglStopValue) { return [NSValue mgl_valueWithOffsetArray:mbglStopValue]; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index 4c0fcfe539..e1bc7e7d20 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -601,12 +601,12 @@ namespace mbgl { if (text && text.expressionType == NSConstantValueExpressionType) { std::string string = ((NSString *)text.constantValue).UTF8String; if (mbgl::style::conversion::hasTokens(string)) { - self.rawLayer->setTextField(mbgl::style::PropertyValue( - mbgl::style::conversion::convertTokenStringToExpression(string))); + self.rawLayer->setTextField(mbgl::style::PropertyValue( + mbgl::style::conversion::convertTokenStringToFormatExpression(string))); return; } } - auto mbglValue = MGLStyleValueTransformer().toPropertyValue>(text, true); + auto mbglValue = MGLStyleValueTransformer().toPropertyValue>(text, true); self.rawLayer->setTextField(mbglValue); } @@ -617,7 +617,7 @@ namespace mbgl { if (propertyValue.isUndefined()) { propertyValue = self.rawLayer->getDefaultTextField(); } - return MGLStyleValueTransformer().toExpression(propertyValue); + return MGLStyleValueTransformer().toExpression(propertyValue); } - (void)setTextField:(NSExpression *)textField { diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 58f5816416..1a8dff060c 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -1111,6 +1111,11 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { // Avoid wrapping collator options object in literal expression. return @[@"collator", self.arguments[1].constantValue]; } + if (op.expressionType == NSConstantValueExpressionType + && [op.constantValue isEqualToString:@"format"]) { + // Avoid wrapping format options object in literal expression. + return @[@"format", self.arguments[1].mgl_jsonExpressionObject, self.arguments[2].constantValue]; + } return self.arguments.mgl_jsonExpressionObject; } else if (op == [MGLColor class] && [function isEqualToString:@"colorWithRed:green:blue:alpha:"]) { NSArray *arguments = self.arguments.mgl_jsonExpressionObject; diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs index 89b6cbe7e4..c97813eca2 100644 --- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs +++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs @@ -68,7 +68,11 @@ @"<%- originalPropertyName(property) %> should be unset initially."); NSExpression *defaultExpression = layer.<%- objCName(property) %>; +<% if (property.type === 'formatted') { -%> + NSExpression *constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, 'string', true, 3) %>]; +<% } else { -%> NSExpression *constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, type, true, 3) %>]; +<% } -%> layer.<%- objCName(property) %> = constantExpression; mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> }; XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue, @@ -83,7 +87,11 @@ { using namespace mbgl::style::expression::dsl; propertyValue = mbgl::style::PropertyExpression<<%- mbglType(property) %>>( +<% if (property.type === 'formatted') { -%> + step(zoom(), format(<%- mbglExpressionTestValue(property, type) %>), 18.0, format(<%- mbglExpressionTestValue(property, type) %>)) +<% } else { -%> step(zoom(), literal(<%- mbglExpressionTestValue(property, type) %>), 18.0, literal(<%- mbglExpressionTestValue(property, type) %>)) +<% } -%> ); } @@ -160,13 +168,23 @@ { using namespace mbgl::style::expression::dsl; propertyValue = mbgl::style::PropertyExpression<<%- mbglType(property) %>>( +<% if (property.type === 'formatted') { -%> + format(toString(get(literal("token")))) +<% } else { -%> toString(get(literal("token"))) +<% } -%> ); } XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue, @"Setting <%- objCName(property) %> to a constant string with tokens should convert to an expression."); - XCTAssertEqualObjects(layer.<%- objCName(property) %>, [NSExpression expressionWithFormat:@"CAST(token, \"NSString\")"], + +<% if (property.type === 'formatted') { -%> + NSExpression* tokenExpression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('format', CAST(token, 'NSString'), %@)", @{}]; +<% } else { -%> + NSExpression* tokenExpression = [NSExpression expressionWithFormat:@"CAST(token, \"NSString\")"]; +<% } -%> + XCTAssertEqualObjects(layer.<%- objCName(property) %>, tokenExpression, @"Setting <%- objCName(property) %> to a constant string with tokens should convert to an expression."); <% } -%> } diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm index 865de68933..42430940cd 100644 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -224,7 +224,9 @@ XCTAssertEqual(rawLayer->getIconImage(), propertyValue, @"Setting iconImageName to a constant string with tokens should convert to an expression."); - XCTAssertEqualObjects(layer.iconImageName, [NSExpression expressionWithFormat:@"CAST(token, \"NSString\")"], + + NSExpression* tokenExpression = [NSExpression expressionWithFormat:@"CAST(token, \"NSString\")"]; + XCTAssertEqualObjects(layer.iconImageName, tokenExpression, @"Setting iconImageName to a constant string with tokens should convert to an expression."); } @@ -1096,20 +1098,20 @@ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Text Field'"]; layer.text = constantExpression; - mbgl::style::PropertyValue propertyValue = { "Text Field" }; + mbgl::style::PropertyValue propertyValue = { "Text Field" }; XCTAssertEqual(rawLayer->getTextField(), propertyValue, @"Setting text to a constant value expression should update text-field."); XCTAssertEqualObjects(layer.text, constantExpression, @"text should round-trip constant value expressions."); - constantExpression = [NSExpression expressionWithFormat:@"'Text Field'"]; + constantExpression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('format', 'Text Field', %@)", @{}]; NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}]; layer.text = functionExpression; { using namespace mbgl::style::expression::dsl; - propertyValue = mbgl::style::PropertyExpression( - step(zoom(), literal("Text Field"), 18.0, literal("Text Field")) + propertyValue = mbgl::style::PropertyExpression( + step(zoom(), format("Text Field"), 18.0, format("Text Field")) ); } @@ -1130,14 +1132,16 @@ { using namespace mbgl::style::expression::dsl; - propertyValue = mbgl::style::PropertyExpression( - toString(get(literal("token"))) + propertyValue = mbgl::style::PropertyExpression( + format(toString(get(literal("token")))) ); } XCTAssertEqual(rawLayer->getTextField(), propertyValue, @"Setting text to a constant string with tokens should convert to an expression."); - XCTAssertEqualObjects(layer.text, [NSExpression expressionWithFormat:@"CAST(token, \"NSString\")"], + + NSExpression* tokenExpression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('format', CAST(token, 'NSString'), %@)", @{}]; + XCTAssertEqualObjects(layer.text, tokenExpression, @"Setting text to a constant string with tokens should convert to an expression."); } -- cgit v1.2.1