diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2016-01-15 08:25:56 -0800 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2016-01-18 16:54:57 -0800 |
commit | c86646519a4887d47003d11061a6a82e7ff4241c (patch) | |
tree | 804e8e03499c4032eef79757c0ccd235e5c7540e | |
parent | 143f8a78170065fc46afba1eaf987258e9c9f99b (diff) | |
download | qtlocation-mapboxgl-c86646519a4887d47003d11061a6a82e7ff4241c.tar.gz |
[osx] Content insets
Added a contentInsets property to MGLMapView that behaves similarly to NSScrollView.contentInsets. Adjust it according to the window’s content layout rectangle using KVO. Automatically apply the content insets whenever creating a CameraOptions or getting the center coordinates.
-rw-r--r-- | include/mbgl/osx/MGLMapView.h | 25 | ||||
-rw-r--r-- | platform/osx/src/MGLMapView.mm | 64 |
2 files changed, 86 insertions, 3 deletions
diff --git a/include/mbgl/osx/MGLMapView.h b/include/mbgl/osx/MGLMapView.h index df4b597847..971477b42e 100644 --- a/include/mbgl/osx/MGLMapView.h +++ b/include/mbgl/osx/MGLMapView.h @@ -308,6 +308,31 @@ IB_DESIGNABLE and zooming or `NO` to immediately display the given bounds. */ - (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated; +/** A Boolean value indicating whether the receiver automatically adjusts its + content insets. + + When the value of this property is `YES`, the map view automatically updates + its `contentInsets` property to account for any overlapping title bar or + toolbar. To overlap with the title bar or toolbar, the containing window’s + style mask must have `NSFullSizeContentViewWindowMask` set, and the title + bar must not be transparent. + + The default value of this property is `YES`. */ +@property (nonatomic, assign) BOOL automaticallyAdjustsContentInsets; + +/** The distance from the edges of the map view’s frame to the edges of the map + view’s logical viewport. + + When the value of this property is equal to `NSEdgeInsetsZero`, viewport + properties such as `centerCoordinate` assume a viewport that matches the map + view’s frame. Otherwise, those properties are inset, excluding part of the + frame from the viewport. For instance, if the only the top edge is inset, + the map center is effectively shifted downward. + + When the value of the `automaticallyAdjustsContentInsets` property is `YES`, + the value of this property may be overridden at any time. */ +@property (nonatomic, assign) NSEdgeInsets contentInsets; + #pragma mark Configuring gesture recognition /** @name Configuring How the User Interacts with the Map */ diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm index 57df0af6a0..be52ed84a9 100644 --- a/platform/osx/src/MGLMapView.mm +++ b/platform/osx/src/MGLMapView.mm @@ -284,8 +284,10 @@ public: _annotationsNearbyLastClick = {}; // Jump to Null Island initially. + self.automaticallyAdjustsContentInsets = YES; mbgl::CameraOptions options; options.center = mbgl::LatLng(0, 0); + options.padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); options.zoom = _mbglMap->getMinZoom(); _mbglMap->jumpTo(options); _pendingLatitude = NAN; @@ -442,6 +444,8 @@ public: - (void)dealloc { [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; + [self.window removeObserver:self forKeyPath:@"contentLayoutRect"]; + [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"]; // Close any annotation callout immediately. [self.calloutForSelectedAnnotation close]; @@ -468,6 +472,9 @@ public: if (![accessToken isKindOfClass:[NSNull class]]) { _mbglFileSource->setAccessToken((std::string)accessToken.UTF8String); } + } else if ([keyPath isEqualToString:@"contentLayoutRect"] || + [keyPath isEqualToString:@"titlebarAppearsTransparent"]) { + [self adjustContentInsets]; } } @@ -546,6 +553,9 @@ public: self.dormant = YES; _mbglMap->pause(); } + + [self.window removeObserver:self forKeyPath:@"contentLayoutRect"]; + [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"]; } - (void)viewDidMoveToWindow { @@ -553,6 +563,15 @@ public: _mbglMap->resume(); self.dormant = NO; } + + [self.window addObserver:self + forKeyPath:@"contentLayoutRect" + options:NSKeyValueObservingOptionInitial + context:NULL]; + [self.window addObserver:self + forKeyPath:@"titlebarAppearsTransparent" + options:NSKeyValueObservingOptionInitial + context:NULL]; } - (BOOL)wantsLayer { @@ -808,7 +827,8 @@ public: } - (CLLocationCoordinate2D)centerCoordinate { - return MGLLocationCoordinate2DFromLatLng(_mbglMap->getLatLng()); + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); + return MGLLocationCoordinate2DFromLatLng(_mbglMap->getLatLng(padding)); } - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate { @@ -818,6 +838,7 @@ public: - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate animated:(BOOL)animated { [self willChangeValueForKey:@"centerCoordinate"]; _mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate), + MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets), MGLDurationInSeconds(animated ? MGLAnimationDuration : 0)); [self didChangeValueForKey:@"centerCoordinate"]; } @@ -1023,6 +1044,7 @@ public: - (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera { mbgl::CameraOptions options; options.center = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate); + options.padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); options.zoom = MGLZoomLevelForAltitude(camera.altitude, camera.pitch, camera.centerCoordinate.latitude, self.frame.size); @@ -1054,8 +1076,9 @@ public: - (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated { _mbglMap->cancelTransitions(); - mbgl::EdgeInsets mbglInsets = MGLEdgeInsetsFromNSEdgeInsets(insets); - mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), mbglInsets); + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets); + padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); + mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding); mbgl::AnimationOptions animationOptions; if (animated) { animationOptions.duration = MGLDurationInSeconds(MGLAnimationDuration); @@ -1068,6 +1091,41 @@ public: _mbglMap->easeTo(cameraOptions, animationOptions); } +- (void)setAutomaticallyAdjustsContentInsets:(BOOL)automaticallyAdjustsContentInsets { + _automaticallyAdjustsContentInsets = automaticallyAdjustsContentInsets; + [self adjustContentInsets]; +} + +/// Updates `contentInsets` to reflect the current window geometry. +- (void)adjustContentInsets { + if (!_automaticallyAdjustsContentInsets) { + return; + } + + NSEdgeInsets contentInsets = self.contentInsets; + if ((self.window.styleMask & NSFullSizeContentViewWindowMask) + && !self.window.titlebarAppearsTransparent) { + NSRect contentLayoutRect = [self convertRect:self.window.contentLayoutRect fromView:nil]; + if (NSMaxX(contentLayoutRect) > 0 && NSMaxY(contentLayoutRect) > 0) { + contentInsets = NSEdgeInsetsMake(NSHeight(self.bounds) - NSMaxY(contentLayoutRect), + NSMinX(contentLayoutRect), + NSMinY(contentLayoutRect), + NSWidth(self.bounds) - NSMaxX(contentLayoutRect)); + } + } else { + contentInsets = NSEdgeInsetsZero; + } + + if (!NSEdgeInsetsEqual(contentInsets, self.contentInsets)) { + // After adjusting the content insets, move the center coordinate from + // the old frame of reference to the new one represented by the newly + // set content insets. + CLLocationCoordinate2D oldCenter = self.centerCoordinate; + self.contentInsets = contentInsets; + self.centerCoordinate = oldCenter; + } +} + #pragma mark Mouse events and gestures - (BOOL)acceptsFirstResponder { |