-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Conversation
f0d8a22
to
6f19b2f
Compare
style::Layer* getLayer(const std::string& layerID); | ||
void setLayers(std::vector<style::Layer*>&); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map
/Style
must have ownership of the layers, so this signature needs to be void setLayers(std::vector<std::unique_ptr<style::Layer>>)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in e43fbf4.
25f0c27
to
03d59a0
Compare
b11c4d6
to
40d77ae
Compare
40d77ae
to
25f1529
Compare
abe1845
to
dc4aef8
Compare
@@ -794,6 +798,16 @@ style::Layer* Map::getLayer(const std::string& layerID) { | |||
return nullptr; | |||
} | |||
|
|||
void Map::setLayers(std::vector<std::unique_ptr<style::Layer>> layers) { | |||
impl->view.activate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs an if (!impl->style)
guard and impl->styleMutated = true;
like the other mutators.
std::vector<std::unique_ptr<mbgl::style::Layer>> rawLayers; | ||
rawLayers.reserve(layers.count); | ||
for (MGLStyleLayer *layer in layers.reverseObjectEnumerator) { | ||
rawLayers.push_back(std::unique_ptr<mbgl::style::Layer>(layer.layer)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructing a std::unique_ptr
from anything other than the result of new
is usually incorrect (and even then, you should be using std::make_unique
). What's the ownership model of layer.layer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s complicated: #6254. 😕 Maybe we need to tackle that issue first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To respect ownership of the layers passed into -setLayers:
– some of which may exist in the style and some of which may be new – we need to ability to remove a layer from the style and regain ownership of it in order to re-add it. So we’re blocked on mbgl::Map::removeLayer()
returning ownership of the layer: #6959.
297337a
to
a789dd5
Compare
a789dd5
to
ec57aea
Compare
Great work here @1ec5 |
c45be63
to
3dd8910
Compare
if (impl->style) { | ||
impl->styleMutated = true; | ||
return impl->style->getLayer(layerID); | ||
} | ||
return nullptr; | ||
} | ||
|
||
void Map::setLayers(std::vector<std::unique_ptr<Layer>> layers) { | ||
if (!impl->style) { | ||
impl->styleMutated = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This goes in the opposite branch -- we're only mutating the style if we have one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I ended up not using this method in the SDK due to the memory management conundrum in the PR description. Should I keep this method around to complement getLayers()
or remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please remove it if it's not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
@@ -51,6 +51,9 @@ - (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLaye | |||
- (void)removeFromMapView:(MGLMapView *)mapView | |||
{ | |||
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); | |||
if (!removedLayer) { | |||
return; | |||
} | |||
_pendingLayer = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::BackgroundLayer> &>(removedLayer)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not part of this PR, but this cast is undefined behavior. You need to write something like:
template <class T, class U>
std::unique_ptr<T> dynamic_ptr_cast(std::unique_ptr<U> p) {
T* t = dynamic_cast<T*>(p.get());
if (!t) return nullptr;
p.release();
return t;
}
And be aware that this will return a null unique_ptr
(and deallocate the input) if the dynamic_cast
fails, i.e. if the input is not the anticipated derived type. In this particular code, it looks like this could happen if the user was aliasing *StyleLayer
objects while at the same time removing a layer and adding another layer with the same identifier but a different layer type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
→ #7211
3dd8910
to
f331b89
Compare
Added new layers and sources properties to MGLStyle that contain all the style’s layers and sources, respectively. These properties are KVC-compliant with all the mutable to-many methods. Layers are ordered from topmost to bottommost, for consistency with Cocoa APIs where front/first means top and back/last means bottom. Also added storage for mbgl::style::Source in MGLSource proper for wrapping AnnotationSource. Until the style finishes loading, its name property is set to nil. Fixes #6003.
Replaced -[MGLMapView style] with a property. Keep the MGLStyle object around for the lifetime of the style. Bracket changes to layers in willChange and didChange calls. The built-in point annotation layer is added after the style is finished loading but before the map is finished loading. Cause a second wave of change notifications to go out, about both sources and layers. Issue change notifications for style layers when shape annotations are added or removed.
Fixed a crash that often occurred when switching styles. MGLMapView was ahead of MapDocument in the responder chain, so calls to -setStyle: were going to MGLMapView’s private -setStyle: method. The sender was being passed in the first parameter instead of an MGLStyle method.
Added a sidebar to the main document window in macosapp that lists the layers in the current style and updates whenever the style changes or a layer is added or removed programmatically. Display an icon beside each layer in the sidebar that indicates the kind of layer. Double-click a layer or layers to toggle their visibility, which is an undoable action. Added a menu item and toolbar button to toggle the Layers sidebar. Added a context menu for toggling visibility of and deleting layers selected in the Layers sidebar. Checked in the original SVGs for layer icons.
Display the custom style’s name in the Style toolbar button.
Added a setting to macosapp to change all symbol layers in the current style to use the preferred language if available. If the setting is off, change all symbol layers to use local languages.
f331b89
to
83e134e
Compare
This PR makes the runtime styling API’s entry points key-value coding compliant.
The
-[MGLMapView style]
factory method has been replaced with a KVC-compliantstyle
property whose value changes only when reloading the style or changing the style URL. This makes the API more convenient in Swift and more predictable overall.New
layers
andsources
properties have been added to MGLStyle that make it easy to enumerate style layers or sources without having to hard-code style-specific identifiers in application code. See #5999, #7030, and #7031 for examples of how these properties would be used.The
layers
array is ordered from front to back, for consistency with Cocoa, as opposed to mbgl’s back-to-front ordering. There are complementary-insertLayer:aboveLayer:
and-insertLayer:belowLayer:
methods, for consistency with MapKit’s-[MKMapView insertOverlay:aboveOverlay:]
and-[MKMapView insertOverlay:belowOverlay:]
. Please double-check my index arithmetic to make sure I didn’t make any off-by-one errors. Thesources
property is a unordered set. A dictionary mapping identifiers to source objects would better conform to the style specification but would encourage some antipatterns we want to avoid; see #7011 (comment) for details.The mutable
layers
andsources
collections comply with KVC conventions for to-many relationships, which entails additional methods thatmbgl::Map
andmbgl::style::Style
wouldn’t ordinarily provide. These KVC methods could be optimized further with corresponding methods in mbgl; however, memory management would become a lot less clear. For example, who owns anmbgl::style::Layer
if it’s already part of a style but is included in an array passed into-[MGLStyle setLayers:]
? Rather than muddle the pointer ownership model or implement complex array diffing, this PR sticks to the safest, most straightforward implementation despite a possible performance tradeoff.As a real-world stress test of KVC compliance, a sidebar has been added to macosapp that displays the layers in the current style and updates the list automatically using Cocoa bindings. The sidebar can be opened and closed via View ‣ Show/Hide Layers or ⇧⌘L. Layers are shown with their identifiers and icons representing their types. Hidden layers are shown in italics. To toggle one or more layers’ visibility, select them and double-click on them. Or use the context menu, which also has an option to delete the selected layers.
Finally, to illustrate one common use of the new APIs, macosapp now has an option to localize all labels in the user’s preferred language, and the Style toolbar button displays the name of the current style when a custom style is shown.
Hiding layers using the new Layers sidebar in macosapp.
style
property KVC-compliant-[MGLStyle insertLayer:aboveLayer:]
(reprising [macos, ios] Insert layer above #6730)Fixes #6003, fixes #6096, fixes #6931.
/cc @frederoni @jfirebaugh