diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 4169c7a5d..e11ceb028 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -40,8 +40,10 @@ #endif @interface MGLStyle() -@property (nonatomic, weak) MGLMapView *mapView; + +@property (nonatomic, readwrite, weak) MGLMapView *mapView; @property (readonly, copy, nullable) NSURL *URL; + @end @implementation MGLStyle @@ -98,17 +100,24 @@ static NSURL *MGLStyleURL_emerald; return MGLStyleURL_emerald; } -#pragma mark Metadata +#pragma mark - -- (NSString *)name { - std::string name = self.mapView.mbglMap->getStyleName(); - return name.empty() ? nil : @(name.c_str()); +- (instancetype)initWithMapView:(MGLMapView *)mapView { + if (self = [super init]) { + _mapView = mapView; + } + return self; } - (NSURL *)URL { return [NSURL URLWithString:@(self.mapView.mbglMap->getStyleURL().c_str())]; } +- (NSString *)name { + std::string name = self.mapView.mbglMap->getStyleName(); + return name.empty() ? nil : @(name.c_str()); +} + #pragma mark Sources - (NS_MUTABLE_SET_OF(MGLSource *) *)sources { @@ -158,8 +167,7 @@ static NSURL *MGLStyleURL_emerald; } else if (mbglSource->is()) { source = [[MGLRasterSource alloc] initWithIdentifier:identifier]; } else { - NSAssert(NO, @"Unrecognized source type"); - return nil; + source = [[MGLSource alloc] initWithIdentifier:identifier]; } source.rawSource = mbglSource; @@ -320,7 +328,9 @@ static NSURL *MGLStyleURL_emerald; @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", layer]; } - [layer removeFromMapView:self.mapView]; + [self willChangeValueForKey:@"layers"]; + [layer removeFromMapView:self.mapView]; + [self didChangeValueForKey:@"layers"]; } - (void)addLayer:(MGLStyleLayer *)layer @@ -331,7 +341,9 @@ static NSURL *MGLStyleURL_emerald; @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", layer]; } + [self willChangeValueForKey:@"layers"]; [layer addToMapView:self.mapView]; + [self didChangeValueForKey:@"layers"]; } - (void)insertLayer:(MGLStyleLayer *)layer atIndex:(NSUInteger)index { diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h index 46291b37b..b7c2fa4cd 100644 --- a/platform/darwin/src/MGLStyle_Private.h +++ b/platform/darwin/src/MGLStyle_Private.h @@ -6,7 +6,10 @@ #include @interface MGLStyle (Private) -@property (nonatomic, weak) MGLMapView *mapView; + +- (instancetype)initWithMapView:(MGLMapView *)mapView; + +@property (nonatomic, readonly, weak) MGLMapView *mapView; - (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration; diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index e467495a4..e066387e2 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -117,6 +117,14 @@ IB_DESIGNABLE #pragma mark Configuring the Map’s Appearance +/** + The style currently displayed in the receiver. + + Unlike the `styleURL` property, this property is set to an object that allows + you to manipulate every aspect of the style locally. + */ +@property (nonatomic, readonly) MGLStyle *style; + /** URLs of the styles bundled with the library. @@ -134,6 +142,9 @@ IB_DESIGNABLE If you set this property to `nil`, the receiver will use the default style and this property will automatically be set to that style’s URL. + + If you want to modify the current style without replacing it outright, or if + you want to introspect individual style attributes, use the `style` property. */ @property (nonatomic, null_resettable) NSURL *styleURL; @@ -1077,10 +1088,6 @@ IB_DESIGNABLE */ - (void)removeOverlays:(NS_ARRAY_OF(id ) *)overlays; -#pragma mark - Runtime styling API - -- (MGLStyle *)style; - #pragma mark Accessing the Underlying Map Data /** diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index e857a9fa4..b1ecf1c41 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -236,6 +236,9 @@ public: @property (nonatomic, readwrite) UIButton *attributionButton; @property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints; @property (nonatomic) UIActionSheet *attributionSheet; + +@property (nonatomic, readwrite) MGLStyle *style; + @property (nonatomic) UIPanGestureRecognizer *pan; @property (nonatomic) UIPinchGestureRecognizer *pinch; @property (nonatomic) UIRotationGestureRecognizer *rotate; @@ -284,6 +287,8 @@ public: std::vector _annotationsNearbyLastTap; CGPoint _initialImplicitCalloutViewOffset; NSDate *_userLocationAnimationCompletionDate; + /// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending. + BOOL _isChangingAnnotationLayers; BOOL _isWaitingForRedundantReachableNotification; BOOL _isTargetingInterfaceBuilder; @@ -355,14 +360,17 @@ public: - (void)setStyleURL:(nullable NSURL *)styleURL { if (_isTargetingInterfaceBuilder) return; - + if ( ! styleURL) { styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion]; } styleURL = styleURL.mgl_URLByStandardizingScheme; + [self willChangeValueForKey:@"style"]; + _style = [[MGLStyle alloc] initWithMapView:self]; _mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]); + [self didChangeValueForKey:@"style"]; } - (IBAction)reloadStyle:(__unused id)sender { @@ -620,13 +628,6 @@ public: return image; } -- (MGLStyle *)style -{ - MGLStyle *style = [[MGLStyle alloc] init]; - style.mapView = self; - return style; -} - - (void)reachabilityChanged:(NSNotification *)notification { MGLReachability *reachability = [notification object]; @@ -2895,6 +2896,7 @@ public: continue; } + _isChangingAnnotationLayers = YES; MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]); MGLAnnotationContext context; context.annotation = annotation; @@ -2991,6 +2993,10 @@ public: [self updateAnnotationContainerViewWithAnnotationViews:newAnnotationViews]; [self didChangeValueForKey:@"annotations"]; + if (_isChangingAnnotationLayers) + { + [self.style willChangeValueForKey:@"layers"]; + } if ([self.delegate respondsToSelector:@selector(mapView:didAddAnnotationViews:)]) { @@ -3213,11 +3219,16 @@ public: [(NSObject *)annotation removeObserver:self forKeyPath:@"coordinates" context:(void *)(NSUInteger)annotationTag]; } + _isChangingAnnotationLayers = YES; _mbglMap->removeAnnotation(annotationTag); } [self didChangeValueForKey:@"annotations"]; UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); + if (_isChangingAnnotationLayers) + { + [self.style willChangeValueForKey:@"layers"]; + } } - (void)addOverlay:(id )overlay @@ -4559,6 +4570,10 @@ public: } case mbgl::MapChangeDidFinishLoadingMap: { + [self.style willChangeValueForKey:@"sources"]; + [self.style didChangeValueForKey:@"sources"]; + [self.style willChangeValueForKey:@"layers"]; + [self.style didChangeValueForKey:@"layers"]; if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) { [self.delegate mapViewDidFinishLoadingMap:self]; @@ -4602,6 +4617,11 @@ public: case mbgl::MapChangeDidFinishRenderingFrame: case mbgl::MapChangeDidFinishRenderingFrameFullyRendered: { + if (_isChangingAnnotationLayers) + { + _isChangingAnnotationLayers = NO; + [self.style didChangeValueForKey:@"layers"]; + } [self updateAnnotationViews]; if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) { @@ -4611,6 +4631,11 @@ public: } case mbgl::MapChangeDidFinishLoadingStyle: { + [self.style willChangeValueForKey:@"name"]; + [self.style willChangeValueForKey:@"sources"]; + [self.style didChangeValueForKey:@"sources"]; + [self.style willChangeValueForKey:@"layers"]; + [self.style didChangeValueForKey:@"layers"]; if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)]) { [self.delegate mapView:self didFinishLoadingStyle:self.style]; diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h index 3dbbbe3d8..5ffc04e65 100644 --- a/platform/macos/src/MGLMapView.h +++ b/platform/macos/src/MGLMapView.h @@ -88,6 +88,14 @@ IB_DESIGNABLE #pragma mark Configuring the Map’s Appearance +/** + The style currently displayed in the receiver. + + Unlike the `styleURL` property, this property is set to an object that allows + you to manipulate every aspect of the style locally. + */ +@property (nonatomic, readonly) MGLStyle *style; + /** URL of the style currently displayed in the receiver. @@ -97,6 +105,9 @@ IB_DESIGNABLE If you set this property to `nil`, the receiver will use the default style and this property will automatically be set to that style’s URL. + + If you want to modify the current style without replacing it outright, or if + you want to introspect individual style attributes, use the `style` property. */ @property (nonatomic, null_resettable) NSURL *styleURL; @@ -926,10 +937,6 @@ IB_DESIGNABLE */ @property (nonatomic) MGLMapDebugMaskOptions debugMask; -#pragma mark Runtime styling API - -- (MGLStyle *)style; - @end NS_ASSUME_NONNULL_END diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index c50d3d564..50b77bc81 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -152,6 +152,8 @@ public: @property (nonatomic, readwrite) NSImageView *logoView; @property (nonatomic, readwrite) NSView *attributionView; +@property (nonatomic, readwrite) MGLStyle *style; + /// Mapping from reusable identifiers to annotation images. @property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier; /// Currently shown popover representing the selected annotation. @@ -186,6 +188,8 @@ public: BOOL _wantsToolTipRects; /// True if any annotation images that have custom cursors have been installed. BOOL _wantsCursorRects; + /// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending. + BOOL _isChangingAnnotationLayers; // Cached checks for delegate method implementations that may be called from // MGLMultiPointDelegate methods. @@ -576,7 +580,7 @@ public: if (_isTargetingInterfaceBuilder) { return; } - + // Default to Streets. if (!styleURL) { // An access token is required to load any default style, including @@ -588,7 +592,10 @@ public: } styleURL = styleURL.mgl_URLByStandardizingScheme; + [self willChangeValueForKey:@"style"]; + _style = [[MGLStyle alloc] initWithMapView:self]; _mbglMap->setStyleURL(styleURL.absoluteString.UTF8String); + [self didChangeValueForKey:@"style"]; } - (IBAction)reloadStyle:(__unused id)sender { @@ -849,6 +856,10 @@ public: } case mbgl::MapChangeDidFinishLoadingMap: { + [self.style willChangeValueForKey:@"sources"]; + [self.style didChangeValueForKey:@"sources"]; + [self.style willChangeValueForKey:@"layers"]; + [self.style didChangeValueForKey:@"layers"]; if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) { [self.delegate mapViewDidFinishLoadingMap:self]; } @@ -888,6 +899,10 @@ public: case mbgl::MapChangeDidFinishRenderingFrame: case mbgl::MapChangeDidFinishRenderingFrameFullyRendered: { + if (_isChangingAnnotationLayers) { + _isChangingAnnotationLayers = NO; + [self.style didChangeValueForKey:@"layers"]; + } if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) { BOOL fullyRendered = change == mbgl::MapChangeDidFinishRenderingFrameFullyRendered; [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:fullyRendered]; @@ -896,6 +911,11 @@ public: } case mbgl::MapChangeDidFinishLoadingStyle: { + [self.style willChangeValueForKey:@"name"]; + [self.style willChangeValueForKey:@"sources"]; + [self.style didChangeValueForKey:@"sources"]; + [self.style willChangeValueForKey:@"layers"]; + [self.style didChangeValueForKey:@"layers"]; if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)]) { [self.delegate mapView:self didFinishLoadingStyle:self.style]; @@ -1705,6 +1725,7 @@ public: continue; } + _isChangingAnnotationLayers = YES; MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]); MGLAnnotationContext context; context.annotation = annotation; @@ -1762,6 +1783,9 @@ public: } [self didChangeValueForKey:@"annotations"]; + if (_isChangingAnnotationLayers) { + [self.style willChangeValueForKey:@"layers"]; + } [self updateAnnotationTrackingAreas]; } @@ -1843,10 +1867,14 @@ public: [(NSObject *)annotation removeObserver:self forKeyPath:@"coordinates" context:(void *)(NSUInteger)annotationTag]; } + _isChangingAnnotationLayers = YES; _mbglMap->removeAnnotation(annotationTag); } [self didChangeValueForKey:@"annotations"]; + if (_isChangingAnnotationLayers) { + [self.style willChangeValueForKey:@"layers"]; + } [self updateAnnotationTrackingAreas]; } @@ -2200,13 +2228,6 @@ public: #pragma mark - Runtime styling -- (MGLStyle *)style -{ - MGLStyle *style = [[MGLStyle alloc] init]; - style.mapView = self; - return style; -} - - (mbgl::Map *)mbglMap { return _mbglMap;