[osx] Drop Pin context menu item
This commit is contained in:
committed by
Minh Nguyễn
parent
cc35f5a2a7
commit
96145ef170
@@ -69,6 +69,8 @@ IB_DESIGNABLE
|
||||
- (void)selectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated;
|
||||
- (void)deselectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated;
|
||||
|
||||
- (id <MGLAnnotation>)annotationAtPoint:(NSPoint)point;
|
||||
|
||||
- (void)addOverlay:(id <MGLOverlay>)overlay;
|
||||
- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
|
||||
- (void)removeOverlay:(id <MGLOverlay>)overlay;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -669,6 +669,12 @@
|
||||
<action selector="dropPin:" target="Voe-Tx-rLC" id="eDR-iw-JUG"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Remove Pin" id="rgF-cY-qgP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="removePin:" target="Voe-Tx-rLC" id="38n-9m-8Wp"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="MsV-YU-f4X"/>
|
||||
|
||||
@@ -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<MGLAnnotationID> 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 <MGLAnnotation> 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 <MGLAnnotation> annotation = [self annotationWithID:hitAnnotationID];
|
||||
@@ -1282,6 +1229,73 @@ public:
|
||||
return self.annotationImagesByIdentifier[identifier];
|
||||
}
|
||||
|
||||
- (id <MGLAnnotation>)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<MGLAnnotationID> 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 <MGLAnnotation> 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 <MGLAnnotation>) *)selectedAnnotations {
|
||||
id <MGLAnnotation> 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user