summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/osx/MGLAnnotationImage.h3
-rw-r--r--platform/osx/app/AppDelegate.m44
-rw-r--r--platform/osx/app/MainMenu.xib6
-rw-r--r--platform/osx/sdk/MGLMapView.mm89
4 files changed, 118 insertions, 24 deletions
diff --git a/include/mbgl/osx/MGLAnnotationImage.h b/include/mbgl/osx/MGLAnnotationImage.h
index e42e062022..66b623a5c1 100644
--- a/include/mbgl/osx/MGLAnnotationImage.h
+++ b/include/mbgl/osx/MGLAnnotationImage.h
@@ -12,6 +12,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) NSString *reuseIdentifier;
@property (nonatomic, getter=isSelectable) BOOL selectable;
+/** The cursor that appears above any annotation using this annotation image. By default this property is set to `nil`, representing the current cursor. */
+@property (nonatomic, nullable) NSCursor *cursor;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/osx/app/AppDelegate.m b/platform/osx/app/AppDelegate.m
index 1b14aa4454..d788a0a271 100644
--- a/platform/osx/app/AppDelegate.m
+++ b/platform/osx/app/AppDelegate.m
@@ -7,6 +7,7 @@
#import <mbgl/osx/Mapbox.h>
static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
+static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped";
@interface AppDelegate () <NSApplicationDelegate, NSSharingServicePickerDelegate, NSMenuDelegate, MGLMapViewDelegate>
@@ -24,6 +25,7 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken
NSNumberFormatter *_spellOutNumberFormatter;
BOOL _showsToolTipsOnDroppedPins;
+ BOOL _randomizesCursorsOnDroppedPins;
}
#pragma mark Lifecycle
@@ -232,6 +234,10 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken
_showsToolTipsOnDroppedPins = !_showsToolTipsOnDroppedPins;
}
+- (IBAction)toggleRandomizesCursorsOnDroppedPins:(id)sender {
+ _randomizesCursorsOnDroppedPins = !_randomizesCursorsOnDroppedPins;
+}
+
#pragma mark Help methods
- (IBAction)showShortcuts:(id)sender {
@@ -378,6 +384,11 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken
menuItem.title = isShown ? @"Hide Tooltips on Dropped Pins" : @"Show Tooltips on Dropped Pins";
return YES;
}
+ if (menuItem.action == @selector(toggleRandomizesCursorsOnDroppedPins:)) {
+ BOOL isRandom = _randomizesCursorsOnDroppedPins;
+ menuItem.title = isRandom ? @"Use Default Cursor for Dropped Pins" : @"Use Random Cursors for Dropped Pins";
+ return _showsToolTipsOnDroppedPins;
+ }
if (menuItem.action == @selector(showShortcuts:)) {
return YES;
}
@@ -471,6 +482,37 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken
return YES;
}
+- (MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation {
+ MGLAnnotationImage *annotationImage = [self.mapView dequeueReusableAnnotationImageWithIdentifier:MGLDroppedPinAnnotationImageIdentifier];
+ if (!annotationImage) {
+ NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"default_marker" ofType:@"pdf"];
+ NSImage *image = [[NSImage alloc] initWithContentsOfFile:imagePath];
+ NSRect alignmentRect = image.alignmentRect;
+ alignmentRect.origin.y = NSMidY(alignmentRect);
+ alignmentRect.size.height /= 2;
+ image.alignmentRect = alignmentRect;
+ annotationImage = [MGLAnnotationImage annotationImageWithImage:image
+ reuseIdentifier:MGLDroppedPinAnnotationImageIdentifier];
+ }
+ if (_randomizesCursorsOnDroppedPins) {
+ NSArray *cursors = @[
+ [NSCursor IBeamCursor],
+ [NSCursor crosshairCursor],
+ [NSCursor pointingHandCursor],
+ [NSCursor disappearingItemCursor],
+ [NSCursor IBeamCursorForVerticalLayout],
+ [NSCursor operationNotAllowedCursor],
+ [NSCursor dragLinkCursor],
+ [NSCursor dragCopyCursor],
+ [NSCursor contextualMenuCursor],
+ ];
+ annotationImage.cursor = cursors[arc4random_uniform(cursors.count)];
+ } else {
+ annotationImage.cursor = nil;
+ }
+ return annotationImage;
+}
+
- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
DroppedPinAnnotation *droppedPin = annotation;
@@ -478,7 +520,7 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken
}
}
-- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id<MGLAnnotation>)annotation {
+- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
DroppedPinAnnotation *droppedPin = annotation;
[droppedPin pause];
diff --git a/platform/osx/app/MainMenu.xib b/platform/osx/app/MainMenu.xib
index b7dfb3fa7b..bc476d2766 100644
--- a/platform/osx/app/MainMenu.xib
+++ b/platform/osx/app/MainMenu.xib
@@ -463,6 +463,12 @@
<action selector="toggleShowsToolTipsOnDroppedPins:" target="-1" id="1YC-Co-QQ6"/>
</connections>
</menuItem>
+ <menuItem title="Use Random Cursors for Dropped Pins" id="ZTk-lc-Jgu">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleRandomizesCursorsOnDroppedPins:" target="-1" id="Mpw-b8-oub"/>
+ </connections>
+ </menuItem>
</items>
</menu>
</menuItem>
diff --git a/platform/osx/sdk/MGLMapView.mm b/platform/osx/sdk/MGLMapView.mm
index 81d5edfdd0..5cee56cd7d 100644
--- a/platform/osx/sdk/MGLMapView.mm
+++ b/platform/osx/sdk/MGLMapView.mm
@@ -111,6 +111,7 @@ public:
std::shared_ptr<mbgl::SQLiteCache> _mbglFileCache;
mbgl::DefaultFileSource *_mbglFileSource;
+ NSPanGestureRecognizer *_panGestureRecognizer;
NSMagnificationGestureRecognizer *_magnificationGestureRecognizer;
NSRotationGestureRecognizer *_rotationGestureRecognizer;
double _scaleAtBeginningOfGesture;
@@ -122,6 +123,8 @@ public:
MGLAnnotationID _lastSelectedAnnotationID;
NSSize _unionedAnnotationImageSize;
std::vector<MGLAnnotationID> _annotationsNearbyLastClick;
+ BOOL _wantsToolTipRects;
+ BOOL _wantsCursorRects;
BOOL _delegateHasAlphasForShapeAnnotations;
BOOL _delegateHasStrokeColorsForShapeAnnotations;
BOOL _delegateHasFillColorsForShapeAnnotations;
@@ -294,9 +297,9 @@ public:
_rotateEnabled = YES;
_pitchEnabled = YES;
- NSPanGestureRecognizer *panGestureRecognizer = [[NSPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
- panGestureRecognizer.delaysKeyEvents = YES;
- [self addGestureRecognizer:panGestureRecognizer];
+ _panGestureRecognizer = [[NSPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
+ _panGestureRecognizer.delaysKeyEvents = YES;
+ [self addGestureRecognizer:_panGestureRecognizer];
NSClickGestureRecognizer *clickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleClickGesture:)];
clickGestureRecognizer.delaysPrimaryMouseButtonEvents = NO;
@@ -591,7 +594,7 @@ public:
[self updateZoomControls];
[self updateCompass];
[self updateAnnotationCallouts];
- [self updateToolTips];
+ [self updateAnnotationTrackingAreas];
if ([self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) {
BOOL animated = change == mbgl::MapChangeRegionDidChangeAnimated;
@@ -830,7 +833,7 @@ public:
_mbglMap->cancelTransitions();
if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- [[NSCursor closedHandCursor] push];
+ [self.window invalidateCursorRectsForView:self];
_mbglMap->setGestureInProgress(true);
} else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
delta.y *= -1;
@@ -839,7 +842,7 @@ public:
} else if (gestureRecognizer.state == NSGestureRecognizerStateEnded
|| gestureRecognizer.state == NSGestureRecognizerStateCancelled) {
_mbglMap->setGestureInProgress(false);
- [[NSCursor arrowCursor] pop];
+ [self.window invalidateCursorRectsForView:self];
}
}
}
@@ -1128,6 +1131,10 @@ public:
NSString *symbolName = [MGLAnnotationSpritePrefix stringByAppendingString:annotationImage.reuseIdentifier];
points.emplace_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate), symbolName ? [symbolName UTF8String] : "");
+
+ if (annotation.toolTip.length) {
+ _wantsToolTipRects = YES;
+ }
}
}
@@ -1152,7 +1159,7 @@ public:
}
}
- [self updateToolTips];
+ [self updateAnnotationTrackingAreas];
}
- (void)installAnnotationImage:(MGLAnnotationImage *)annotationImage {
@@ -1180,6 +1187,10 @@ public:
// Union this slop area with any existing slop areas.
_unionedAnnotationImageSize = NSMakeSize(MAX(_unionedAnnotationImageSize.width, size.width),
MAX(_unionedAnnotationImageSize.height, size.height));
+
+ if (annotationImage.cursor) {
+ _wantsCursorRects = YES;
+ }
}
- (void)removeAnnotation:(id <MGLAnnotation>)annotation {
@@ -1216,7 +1227,7 @@ public:
_mbglMap->removeAnnotations(annotationIDsToRemove);
- [self updateToolTips];
+ [self updateAnnotationTrackingAreas];
}
- (id <MGLAnnotation>)selectedAnnotation {
@@ -1518,25 +1529,33 @@ public:
[self removeAnnotations:overlays];
}
-#pragma mark Tooltips
+#pragma mark Tooltips and cursors
-- (void)updateToolTips {
- [self removeAllToolTips];
-
- std::vector<MGLAnnotationID> annotationIDs = [self annotationIDsInRect:self.bounds];
- for (MGLAnnotationID annotationID : annotationIDs) {
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID];
- id <MGLAnnotation> annotation = [self annotationWithID:annotationID];
- if (annotation.toolTip.length) {
- NSImage *image = annotationImage.image;
- NSRect annotationRect = [self frameOfImage:image
- centeredAtCoordinate:annotation.coordinate];
- annotationRect = NSOffsetRect(image.alignmentRect, annotationRect.origin.x, annotationRect.origin.y);
- if (!NSIsEmptyRect(annotationRect)) {
- [self addToolTipRect:annotationRect owner:self userData:(void *)(NSUInteger)annotationID];
+- (void)updateAnnotationTrackingAreas {
+ if (_wantsToolTipRects) {
+ [self removeAllToolTips];
+ std::vector<MGLAnnotationID> annotationIDs = [self annotationIDsInRect:self.bounds];
+ for (MGLAnnotationID annotationID : annotationIDs) {
+ MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID];
+ id <MGLAnnotation> annotation = [self annotationWithID:annotationID];
+ if (annotation.toolTip.length) {
+ NSImage *image = annotationImage.image;
+ NSRect annotationRect = [self frameOfImage:image
+ centeredAtCoordinate:annotation.coordinate];
+ annotationRect = NSOffsetRect(image.alignmentRect, annotationRect.origin.x, annotationRect.origin.y);
+ if (!NSIsEmptyRect(annotationRect)) {
+ [self addToolTipRect:annotationRect owner:self userData:(void *)(NSUInteger)annotationID];
+ }
+ }
+ if (annotationImage.cursor) {
+ _wantsCursorRects = YES;
}
}
}
+
+ if (_wantsCursorRects) {
+ [self.window invalidateCursorRectsForView:self];
+ }
}
- (NSString *)view:(__unused NSView *)view stringForToolTip:(__unused NSToolTipTag)tag point:(__unused NSPoint)point userData:(void *)data {
@@ -1548,6 +1567,30 @@ public:
return annotation.toolTip;
}
+- (void)resetCursorRects {
+ if (_panGestureRecognizer.state == NSGestureRecognizerStateBegan
+ || _panGestureRecognizer.state == NSGestureRecognizerStateChanged) {
+ [self addCursorRect:self.bounds cursor:[NSCursor closedHandCursor]];
+ return;
+ }
+ if (!_wantsCursorRects) {
+ return;
+ }
+
+ std::vector<MGLAnnotationID> annotationIDs = [self annotationIDsInRect:self.bounds];
+ for (MGLAnnotationID annotationID : annotationIDs) {
+ id <MGLAnnotation> annotation = [self annotationWithID:annotationID];
+ MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID];
+ if (annotationImage.cursor) {
+ NSImage *image = annotationImage.image;
+ NSRect annotationRect = [self frameOfImage:image
+ centeredAtCoordinate:annotation.coordinate];
+ annotationRect = NSOffsetRect(image.alignmentRect, annotationRect.origin.x, annotationRect.origin.y);
+ [self addCursorRect:annotationRect cursor:annotationImage.cursor];
+ }
+ }
+}
+
#pragma mark Interface Builder methods
- (void)prepareForInterfaceBuilder {