From 16c435b1517b15a5ea8654987979ef58800b838b Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 22 Jun 2016 16:28:21 -0700 Subject: [core, node] Implement bindings for addLayer --- include/mbgl/style/conversion/layer.hpp | 208 +++++++++++++++++++++ .../style/conversion/make_property_setters.hpp | 133 +++++++++++++ .../style/conversion/make_property_setters.hpp.ejs | 45 +++++ include/mbgl/style/conversion/property_setter.hpp | 55 ++++++ include/mbgl/style/conversion/property_value.hpp | 4 +- 5 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 include/mbgl/style/conversion/layer.hpp create mode 100644 include/mbgl/style/conversion/make_property_setters.hpp create mode 100644 include/mbgl/style/conversion/make_property_setters.hpp.ejs create mode 100644 include/mbgl/style/conversion/property_setter.hpp (limited to 'include/mbgl/style/conversion') diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp new file mode 100644 index 0000000000..0539dcf9ad --- /dev/null +++ b/include/mbgl/style/conversion/layer.hpp @@ -0,0 +1,208 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +optional setLayoutProperty(Layer& layer, const std::string& name, const V& value) { + static const auto setters = makeLayoutPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value); +} + +template +optional setPaintProperty(Layer& layer, const std::string& name, const V& value, const optional& klass) { + static const auto setters = makePaintPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value, klass); +} + +template +optional setPaintProperties(Layer& layer, const V& value) { + return eachMember(value, [&] (const std::string& paintName, const V& paintValue) -> optional { + if (paintName.compare(0, 5, "paint") != 0) { + return {}; + } + + optional klass; + if (paintName.compare(0, 6, "paint.") == 0) { + klass = paintName.substr(6); + } + + return eachMember(paintValue, [&] (const std::string& k, const V& v) { + return setPaintProperty(layer, k, v, klass); + }); + }); +} + +template <> +struct Converter> { +public: + template + Result> operator()(const V& value) const { + if (!isObject(value)) { + return Error { "layer must be an object" }; + } + + auto idValue = objectMember(value, "id"); + if (!idValue) { + return Error { "layer must have an id" }; + } + + optional id = toString(*idValue); + if (!id) { + return Error { "layer id must be a string" }; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + return Error { "layer must have a type" }; + } + + optional type = toString(*typeValue); + if (!type) { + return Error { "layer type must be a string" }; + } + + Result> converted; + + if (*type == "fill") { + converted = convertVectorLayer(*id, value); + } else if (*type == "line") { + converted = convertVectorLayer(*id, value); + } else if (*type == "circle") { + converted = convertVectorLayer(*id, value); + } else if (*type == "symbol") { + converted = convertVectorLayer(*id, value); + } else if (*type == "raster") { + converted = convertRasterLayer(*id, value); + } else if (*type == "background") { + converted = convertBackgroundLayer(*id, value); + } else { + return Error { "invalid layer type" }; + } + + if (!converted) { + return converted; + } + + std::unique_ptr layer = std::move(*converted); + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional minzoom = toNumber(*minzoomValue); + if (!minzoom) { + return Error { "minzoom must be numeric" }; + } + layer->setMinZoom(*minzoom); + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional maxzoom = toNumber(*maxzoomValue); + if (!maxzoom) { + return Error { "maxzoom must be numeric" }; + } + layer->setMaxZoom(*maxzoom); + } + + auto layoutValue = objectMember(value, "layout"); + if (layoutValue) { + if (!isObject(*layoutValue)) { + return Error { "layout must be an object" }; + } + optional error = eachMember(*layoutValue, [&] (const std::string& k, const V& v) { + return setLayoutProperty(*layer, k, v); + }); + if (error) { + return *error; + } + } + + optional error = setPaintProperties(*layer, value); + if (error) { + return *error; + } + + return std::move(layer); + } + +private: + template + Result> convertVectorLayer(const std::string& id, const V& value) const { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + return Error { "layer must have a source" }; + } + + optional source = toString(*sourceValue); + if (!source) { + return Error { "layer source must be a string" }; + } + + std::unique_ptr layer = std::make_unique(id, *source); + + auto sourceLayerValue = objectMember(value, "source-layer"); + if (sourceLayerValue) { + optional sourceLayer = toString(*sourceLayerValue); + if (!sourceLayer) { + return Error { "layer source-layer must be a string" }; + } + layer->setSourceLayer(*sourceLayer); + } + + auto filterValue = objectMember(value, "filter"); + if (filterValue) { + Result filter = convert(*filterValue); + if (!filter) { + return filter.error(); + } + layer->setFilter(*filter); + } + + return std::move(layer); + } + + template + Result> convertRasterLayer(const std::string& id, const V& value) const { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + return Error { "layer must have a source" }; + } + + optional source = toString(*sourceValue); + if (!source) { + return Error { "layer source must be a string" }; + } + + return std::make_unique(id, *source); + } + + template + Result> convertBackgroundLayer(const std::string& id, const V&) const { + return std::make_unique(id); + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp new file mode 100644 index 0000000000..4c0089deaf --- /dev/null +++ b/include/mbgl/style/conversion/make_property_setters.hpp @@ -0,0 +1,133 @@ +// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +auto makeLayoutPropertySetters() { + std::unordered_map> result; + + result["visibility"] = &setVisibility; + + + result["line-cap"] = makePropertySetter(&LineLayer::setLineCap); + result["line-join"] = makePropertySetter(&LineLayer::setLineJoin); + result["line-miter-limit"] = makePropertySetter(&LineLayer::setLineMiterLimit); + result["line-round-limit"] = makePropertySetter(&LineLayer::setLineRoundLimit); + + result["symbol-placement"] = makePropertySetter(&SymbolLayer::setSymbolPlacement); + result["symbol-spacing"] = makePropertySetter(&SymbolLayer::setSymbolSpacing); + result["symbol-avoid-edges"] = makePropertySetter(&SymbolLayer::setSymbolAvoidEdges); + result["icon-allow-overlap"] = makePropertySetter(&SymbolLayer::setIconAllowOverlap); + result["icon-ignore-placement"] = makePropertySetter(&SymbolLayer::setIconIgnorePlacement); + result["icon-optional"] = makePropertySetter(&SymbolLayer::setIconOptional); + result["icon-rotation-alignment"] = makePropertySetter(&SymbolLayer::setIconRotationAlignment); + result["icon-size"] = makePropertySetter(&SymbolLayer::setIconSize); + result["icon-text-fit"] = makePropertySetter(&SymbolLayer::setIconTextFit); + result["icon-text-fit-padding"] = makePropertySetter(&SymbolLayer::setIconTextFitPadding); + result["icon-image"] = makePropertySetter(&SymbolLayer::setIconImage); + result["icon-rotate"] = makePropertySetter(&SymbolLayer::setIconRotate); + result["icon-padding"] = makePropertySetter(&SymbolLayer::setIconPadding); + result["icon-keep-upright"] = makePropertySetter(&SymbolLayer::setIconKeepUpright); + result["icon-offset"] = makePropertySetter(&SymbolLayer::setIconOffset); + result["text-pitch-alignment"] = makePropertySetter(&SymbolLayer::setTextPitchAlignment); + result["text-rotation-alignment"] = makePropertySetter(&SymbolLayer::setTextRotationAlignment); + result["text-field"] = makePropertySetter(&SymbolLayer::setTextField); + result["text-font"] = makePropertySetter(&SymbolLayer::setTextFont); + result["text-size"] = makePropertySetter(&SymbolLayer::setTextSize); + result["text-max-width"] = makePropertySetter(&SymbolLayer::setTextMaxWidth); + result["text-line-height"] = makePropertySetter(&SymbolLayer::setTextLineHeight); + result["text-letter-spacing"] = makePropertySetter(&SymbolLayer::setTextLetterSpacing); + result["text-justify"] = makePropertySetter(&SymbolLayer::setTextJustify); + result["text-anchor"] = makePropertySetter(&SymbolLayer::setTextAnchor); + result["text-max-angle"] = makePropertySetter(&SymbolLayer::setTextMaxAngle); + result["text-rotate"] = makePropertySetter(&SymbolLayer::setTextRotate); + result["text-padding"] = makePropertySetter(&SymbolLayer::setTextPadding); + result["text-keep-upright"] = makePropertySetter(&SymbolLayer::setTextKeepUpright); + result["text-transform"] = makePropertySetter(&SymbolLayer::setTextTransform); + result["text-offset"] = makePropertySetter(&SymbolLayer::setTextOffset); + result["text-allow-overlap"] = makePropertySetter(&SymbolLayer::setTextAllowOverlap); + result["text-ignore-placement"] = makePropertySetter(&SymbolLayer::setTextIgnorePlacement); + result["text-optional"] = makePropertySetter(&SymbolLayer::setTextOptional); + + + + + return result; +} + +template +auto makePaintPropertySetters() { + std::unordered_map> result; + + result["fill-antialias"] = makePropertySetter(&FillLayer::setFillAntialias); + result["fill-opacity"] = makePropertySetter(&FillLayer::setFillOpacity); + result["fill-color"] = makePropertySetter(&FillLayer::setFillColor); + result["fill-outline-color"] = makePropertySetter(&FillLayer::setFillOutlineColor); + result["fill-translate"] = makePropertySetter(&FillLayer::setFillTranslate); + result["fill-translate-anchor"] = makePropertySetter(&FillLayer::setFillTranslateAnchor); + result["fill-pattern"] = makePropertySetter(&FillLayer::setFillPattern); + + result["line-opacity"] = makePropertySetter(&LineLayer::setLineOpacity); + result["line-color"] = makePropertySetter(&LineLayer::setLineColor); + result["line-translate"] = makePropertySetter(&LineLayer::setLineTranslate); + result["line-translate-anchor"] = makePropertySetter(&LineLayer::setLineTranslateAnchor); + result["line-width"] = makePropertySetter(&LineLayer::setLineWidth); + result["line-gap-width"] = makePropertySetter(&LineLayer::setLineGapWidth); + result["line-offset"] = makePropertySetter(&LineLayer::setLineOffset); + result["line-blur"] = makePropertySetter(&LineLayer::setLineBlur); + result["line-dasharray"] = makePropertySetter(&LineLayer::setLineDasharray); + result["line-pattern"] = makePropertySetter(&LineLayer::setLinePattern); + + result["icon-opacity"] = makePropertySetter(&SymbolLayer::setIconOpacity); + result["icon-color"] = makePropertySetter(&SymbolLayer::setIconColor); + result["icon-halo-color"] = makePropertySetter(&SymbolLayer::setIconHaloColor); + result["icon-halo-width"] = makePropertySetter(&SymbolLayer::setIconHaloWidth); + result["icon-halo-blur"] = makePropertySetter(&SymbolLayer::setIconHaloBlur); + result["icon-translate"] = makePropertySetter(&SymbolLayer::setIconTranslate); + result["icon-translate-anchor"] = makePropertySetter(&SymbolLayer::setIconTranslateAnchor); + result["text-opacity"] = makePropertySetter(&SymbolLayer::setTextOpacity); + result["text-color"] = makePropertySetter(&SymbolLayer::setTextColor); + result["text-halo-color"] = makePropertySetter(&SymbolLayer::setTextHaloColor); + result["text-halo-width"] = makePropertySetter(&SymbolLayer::setTextHaloWidth); + result["text-halo-blur"] = makePropertySetter(&SymbolLayer::setTextHaloBlur); + result["text-translate"] = makePropertySetter(&SymbolLayer::setTextTranslate); + result["text-translate-anchor"] = makePropertySetter(&SymbolLayer::setTextTranslateAnchor); + + result["circle-radius"] = makePropertySetter(&CircleLayer::setCircleRadius); + result["circle-color"] = makePropertySetter(&CircleLayer::setCircleColor); + result["circle-blur"] = makePropertySetter(&CircleLayer::setCircleBlur); + result["circle-opacity"] = makePropertySetter(&CircleLayer::setCircleOpacity); + result["circle-translate"] = makePropertySetter(&CircleLayer::setCircleTranslate); + result["circle-translate-anchor"] = makePropertySetter(&CircleLayer::setCircleTranslateAnchor); + + result["raster-opacity"] = makePropertySetter(&RasterLayer::setRasterOpacity); + result["raster-hue-rotate"] = makePropertySetter(&RasterLayer::setRasterHueRotate); + result["raster-brightness-min"] = makePropertySetter(&RasterLayer::setRasterBrightnessMin); + result["raster-brightness-max"] = makePropertySetter(&RasterLayer::setRasterBrightnessMax); + result["raster-saturation"] = makePropertySetter(&RasterLayer::setRasterSaturation); + result["raster-contrast"] = makePropertySetter(&RasterLayer::setRasterContrast); + result["raster-fade-duration"] = makePropertySetter(&RasterLayer::setRasterFadeDuration); + + result["background-color"] = makePropertySetter(&BackgroundLayer::setBackgroundColor); + result["background-pattern"] = makePropertySetter(&BackgroundLayer::setBackgroundPattern); + result["background-opacity"] = makePropertySetter(&BackgroundLayer::setBackgroundOpacity); + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/include/mbgl/style/conversion/make_property_setters.hpp.ejs new file mode 100644 index 0000000000..493c68ea31 --- /dev/null +++ b/include/mbgl/style/conversion/make_property_setters.hpp.ejs @@ -0,0 +1,45 @@ +// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. + +#include + +<% for (const layer of locals.layers) { -%> +#include _layer.hpp> +<% } -%> + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +auto makeLayoutPropertySetters() { + std::unordered_map> result; + + result["visibility"] = &setVisibility; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.layoutProperties) { -%> + result["<%- property.name %>"] = makePropertySetter(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>); +<% } -%> + +<% } -%> + return result; +} + +template +auto makePaintPropertySetters() { + std::unordered_map> result; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.paintProperties) { -%> + result["<%- property.name %>"] = makePropertySetter(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>); +<% } -%> + +<% } -%> + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp new file mode 100644 index 0000000000..38dd934252 --- /dev/null +++ b/include/mbgl/style/conversion/property_setter.hpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +using LayoutPropertySetter = std::function (Layer&, const V&)>; + +template +using PaintPropertySetter = std::function (Layer&, const V&, const optional&)>; + +template +auto makePropertySetter(void (L::*setter)(PropertyValue, const Args&...args)) { + return [setter] (Layer& layer, const V& value, const Args&...args) -> optional { + L* typedLayer = layer.as(); + if (!typedLayer) { + return Error { "layer doesn't support this property" }; + } + + Result> typedValue = convert>(value); + if (!typedValue) { + return typedValue.error(); + } + + (typedLayer->*setter)(*typedValue, args...); + return {}; + }; +} + +template +optional setVisibility(Layer& layer, const V& value) { + if (isUndefined(value)) { + layer.setVisibility(VisibilityType::Visible); + return {}; + } + + Result visibility = convert(value); + if (!visibility) { + return visibility.error(); + } + + layer.setVisibility(*visibility); + return {}; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index 840643abbe..de95b56155 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -13,7 +13,9 @@ template struct Converter> { template Result> operator()(const V& value) const { - if (isObject(value)) { + if (isUndefined(value)) { + return {}; + } else if (isObject(value)) { Result> function = convert>(value); if (!function) { return function.error(); -- cgit v1.2.1