From 96145ef1707516484913447de95f33a77d8a59eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Tue, 1 Dec 2015 09:45:29 -0800 Subject: [PATCH] [osx] Drop Pin context menu item --- include/mbgl/osx/MGLMapView.h | 2 + platform/osx/app/AppDelegate.m | 18 ++++- platform/osx/app/MainMenu.xib | 6 ++ platform/osx/sdk/MGLMapView.mm | 127 ++++++++++++++++++--------------- 4 files changed, 96 insertions(+), 57 deletions(-) diff --git a/include/mbgl/osx/MGLMapView.h b/include/mbgl/osx/MGLMapView.h index 27c67bd38..cb0df30f5 100644 --- a/include/mbgl/osx/MGLMapView.h +++ b/include/mbgl/osx/MGLMapView.h @@ -69,6 +69,8 @@ IB_DESIGNABLE - (void)selectAnnotation:(id )annotation animated:(BOOL)animated; - (void)deselectAnnotation:(id )annotation animated:(BOOL)animated; +- (id )annotationAtPoint:(NSPoint)point; + - (void)addOverlay:(id )overlay; - (void)addOverlays:(NS_ARRAY_OF(id ) *)overlays; - (void)removeOverlay:(id )overlay; diff --git a/platform/osx/app/AppDelegate.m b/platform/osx/app/AppDelegate.m index 4c8ce92ab..4e6f0746c 100644 --- a/platform/osx/app/AppDelegate.m +++ b/platform/osx/app/AppDelegate.m @@ -271,6 +271,14 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken [self.mapView selectAnnotation:annotation animated:YES]; } +- (IBAction)removePin:(NSMenuItem *)sender { + [self removePinAtPoint:_mouseLocationForMapViewContextMenu]; +} + +- (void)removePinAtPoint:(NSPoint)point { + [self.mapView removeAnnotation:[self.mapView annotationAtPoint:point]]; +} + #pragma mark User interface validation - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { @@ -319,6 +327,13 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken return YES; } if (menuItem.action == @selector(dropPin:)) { + BOOL isOverAnnotation = [self.mapView annotationAtPoint:_mouseLocationForMapViewContextMenu]; + menuItem.hidden = isOverAnnotation; + return YES; + } + if (menuItem.action == @selector(removePin:)) { + BOOL isOverAnnotation = [self.mapView annotationAtPoint:_mouseLocationForMapViewContextMenu]; + menuItem.hidden = !isOverAnnotation; return YES; } if (menuItem.action == @selector(toggleTileBoundaries:)) { @@ -423,7 +438,8 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken - (void)menuWillOpen:(NSMenu *)menu { if (menu == self.mapViewContextMenu) { - _mouseLocationForMapViewContextMenu = self.window.mouseLocationOutsideOfEventStream; + _mouseLocationForMapViewContextMenu = [self.window.contentView convertPoint:self.window.mouseLocationOutsideOfEventStream + toView:self.mapView]; } } diff --git a/platform/osx/app/MainMenu.xib b/platform/osx/app/MainMenu.xib index c96169b09..a47e7dcf7 100644 --- a/platform/osx/app/MainMenu.xib +++ b/platform/osx/app/MainMenu.xib @@ -669,6 +669,12 @@ + + + + + + diff --git a/platform/osx/sdk/MGLMapView.mm b/platform/osx/sdk/MGLMapView.mm index 76ad50bd3..79067095e 100644 --- a/platform/osx/sdk/MGLMapView.mm +++ b/platform/osx/sdk/MGLMapView.mm @@ -217,6 +217,7 @@ public: _annotationContextsByAnnotationID = {}; _selectedAnnotationID = MGLAnnotationNotFound; _lastSelectedAnnotationID = MGLAnnotationNotFound; + _annotationsNearbyLastClick = {}; mbgl::CameraOptions options; options.center = mbgl::LatLng(0, 0); @@ -873,62 +874,8 @@ public: return; } - // Look for any annotation near the click. An annotation is “near” if the - // distance between its center and the click is less than the maximum height - // or width of an installed annotation image. NSPoint gesturePoint = [gestureRecognizer locationInView:self]; - NSRect queryRect = NSInsetRect({ gesturePoint, NSZeroSize }, - -_unionedAnnotationImageSize.width / 2, - -_unionedAnnotationImageSize.height / 2); - queryRect = NSInsetRect(queryRect, -MGLAnnotationImagePaddingForHitTest, - -MGLAnnotationImagePaddingForHitTest); - mbgl::LatLngBounds queryBounds = [self convertRectToLatLngBounds:queryRect]; - std::vector nearbyAnnotations = _mbglMap->getPointAnnotationsInBounds(queryBounds); - - if (nearbyAnnotations.size()) { - NSRect hitRect = NSInsetRect({ gesturePoint, NSZeroSize }, - -MGLAnnotationImagePaddingForHitTest, - -MGLAnnotationImagePaddingForHitTest); - mbgl::util::erase_if(nearbyAnnotations, [&](const MGLAnnotationID annotationID) { - NSAssert(_annotationContextsByAnnotationID.count(annotationID) != 0, @"Unknown annotation found nearby click"); - id annotation = [self annotationWithID:annotationID]; - if (!annotation) { - return true; - } - - MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID]; - if (!annotationImage.selectable) { - return true; - } - - NSRect annotationRect = [self frameOfImage:annotationImage.image - centeredAtCoordinate:annotation.coordinate]; - return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect - context:nil hints:nil flipped:NO]; - }); - } - - MGLAnnotationID hitAnnotationID = MGLAnnotationNotFound; - if (nearbyAnnotations.size()) { - std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end()); - - if (nearbyAnnotations == _annotationsNearbyLastClick) { - if (_lastSelectedAnnotationID == _annotationsNearbyLastClick.back() - || _lastSelectedAnnotationID == MGLAnnotationNotFound) { - hitAnnotationID = _annotationsNearbyLastClick.front(); - } else { - auto result = std::find(_annotationsNearbyLastClick.begin(), - _annotationsNearbyLastClick.end(), - _lastSelectedAnnotationID); - auto distance = std::distance(_annotationsNearbyLastClick.begin(), result); - hitAnnotationID = _annotationsNearbyLastClick[distance + 1]; - } - } else { - _annotationsNearbyLastClick = nearbyAnnotations; - hitAnnotationID = _annotationsNearbyLastClick.front(); - } - } - + MGLAnnotationID hitAnnotationID = [self annotationIDAtPoint:gesturePoint persistingResults:YES]; if (hitAnnotationID != MGLAnnotationNotFound) { if (hitAnnotationID != _selectedAnnotationID) { id annotation = [self annotationWithID:hitAnnotationID]; @@ -1282,6 +1229,73 @@ public: return self.annotationImagesByIdentifier[identifier]; } +- (id )annotationAtPoint:(NSPoint)point { + return [self annotationWithID:[self annotationIDAtPoint:point persistingResults:NO]]; +} + +- (MGLAnnotationID)annotationIDAtPoint:(NSPoint)point persistingResults:(BOOL)persist { + // Look for any annotation near the click. An annotation is “near” if the + // distance between its center and the click is less than the maximum height + // or width of an installed annotation image. + NSRect queryRect = NSInsetRect({ point, NSZeroSize }, + -_unionedAnnotationImageSize.width / 2, + -_unionedAnnotationImageSize.height / 2); + queryRect = NSInsetRect(queryRect, -MGLAnnotationImagePaddingForHitTest, + -MGLAnnotationImagePaddingForHitTest); + mbgl::LatLngBounds queryBounds = [self convertRectToLatLngBounds:queryRect]; + std::vector nearbyAnnotations = _mbglMap->getPointAnnotationsInBounds(queryBounds); + + if (nearbyAnnotations.size()) { + NSRect hitRect = NSInsetRect({ point, NSZeroSize }, + -MGLAnnotationImagePaddingForHitTest, + -MGLAnnotationImagePaddingForHitTest); + mbgl::util::erase_if(nearbyAnnotations, [&](const MGLAnnotationID annotationID) { + NSAssert(_annotationContextsByAnnotationID.count(annotationID) != 0, @"Unknown annotation found nearby click"); + id annotation = [self annotationWithID:annotationID]; + if (!annotation) { + return true; + } + + MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID]; + if (!annotationImage.selectable) { + return true; + } + + NSRect annotationRect = [self frameOfImage:annotationImage.image + centeredAtCoordinate:annotation.coordinate]; + return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect + context:nil hints:nil flipped:NO]; + }); + } + + MGLAnnotationID hitAnnotationID = MGLAnnotationNotFound; + if (nearbyAnnotations.size()) { + std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end()); + + if (nearbyAnnotations == _annotationsNearbyLastClick) { + if (_lastSelectedAnnotationID == _annotationsNearbyLastClick.back() + || _lastSelectedAnnotationID == MGLAnnotationNotFound) { + hitAnnotationID = _annotationsNearbyLastClick.front(); + } else { + auto result = std::find(_annotationsNearbyLastClick.begin(), + _annotationsNearbyLastClick.end(), + _lastSelectedAnnotationID); + auto distance = std::distance(_annotationsNearbyLastClick.begin(), result); + hitAnnotationID = _annotationsNearbyLastClick[distance + 1]; + } + } else { + if (persist) { + _annotationsNearbyLastClick = nearbyAnnotations; + } + if (_annotationsNearbyLastClick.size()) { + hitAnnotationID = _annotationsNearbyLastClick.front(); + } + } + } + + return hitAnnotationID; +} + - (NS_ARRAY_OF(id ) *)selectedAnnotations { id selectedAnnotation = self.selectedAnnotation; return selectedAnnotation ? @[selectedAnnotation] : @[]; @@ -1391,7 +1405,8 @@ public: } - (MGLAnnotationImage *)imageOfAnnotationWithID:(MGLAnnotationID)annotationID { - if (annotationID == MGLAnnotationNotFound) { + if (annotationID == MGLAnnotationNotFound + || _annotationContextsByAnnotationID.count(annotationID) == 0) { return nil; }