From f542d7b2a73ca63e2ab0099e998bd62bd57da9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Tue, 1 Dec 2015 13:55:54 -0800 Subject: [osx] Annotation tooltips Annotations can optionally have tooltips. osxapp has an option, off by default, to assign a (localized) tooltip to each dropped pin. --- include/mbgl/darwin/MGLAnnotation.h | 8 +++++++ include/mbgl/darwin/MGLShape.h | 7 ++++++ platform/osx/app/AppDelegate.m | 22 +++++++++++++++++++ platform/osx/app/MainMenu.xib | 9 +++++++- platform/osx/sdk/MGLMapView.mm | 43 +++++++++++++++++++++++++++++++++++-- 5 files changed, 86 insertions(+), 3 deletions(-) diff --git a/include/mbgl/darwin/MGLAnnotation.h b/include/mbgl/darwin/MGLAnnotation.h index aef21ecbc6..34b086f22e 100644 --- a/include/mbgl/darwin/MGLAnnotation.h +++ b/include/mbgl/darwin/MGLAnnotation.h @@ -1,5 +1,6 @@ #import #import +#import #import "MGLTypes.h" @@ -29,6 +30,13 @@ NS_ASSUME_NONNULL_BEGIN * This string is displayed in the callout for the associated annotation. */ @property (nonatomic, readonly, copy, nullable) NSString *subtitle; +#if !TARGET_OS_IPHONE + +/** The string containing the annotation’s tooltip. */ +@property (nonatomic, readonly, copy, nullable) NSString *toolTip; + +#endif + @end NS_ASSUME_NONNULL_END diff --git a/include/mbgl/darwin/MGLShape.h b/include/mbgl/darwin/MGLShape.h index f54d4bfb74..c1b84816f2 100644 --- a/include/mbgl/darwin/MGLShape.h +++ b/include/mbgl/darwin/MGLShape.h @@ -15,6 +15,13 @@ NS_ASSUME_NONNULL_BEGIN /** The subtitle of the shape annotation. The default value of this property is `nil`. */ @property (nonatomic, copy, nullable) NSString *subtitle; +#if !TARGET_OS_IPHONE + +/** The tooltip of the shape annotation. The default value of this property is `nil`. */ +@property (nonatomic, copy, nullable) NSString *toolTip; + +#endif + @end NS_ASSUME_NONNULL_END diff --git a/platform/osx/app/AppDelegate.m b/platform/osx/app/AppDelegate.m index 4e6f0746ce..1b14aa4454 100644 --- a/platform/osx/app/AppDelegate.m +++ b/platform/osx/app/AppDelegate.m @@ -20,6 +20,10 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken @implementation AppDelegate { NSPoint _mouseLocationForMapViewContextMenu; + NSUInteger _droppedPinCounter; + NSNumberFormatter *_spellOutNumberFormatter; + + BOOL _showsToolTipsOnDroppedPins; } #pragma mark Lifecycle @@ -64,6 +68,8 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken [self showPreferences:nil]; } + _spellOutNumberFormatter = [[NSNumberFormatter alloc] init]; + NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)]; [self.mapView addGestureRecognizer:pressGestureRecognizer]; } @@ -204,6 +210,8 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken [self.mapView reloadStyle:sender]; } +#pragma mark Debug methods + - (IBAction)toggleTileBoundaries:(id)sender { self.mapView.debugMask ^= MGLMapDebugTileBoundariesMask; } @@ -220,6 +228,10 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken self.mapView.debugMask ^= MGLMapDebugCollisionBoxesMask; } +- (IBAction)toggleShowsToolTipsOnDroppedPins:(id)sender { + _showsToolTipsOnDroppedPins = !_showsToolTipsOnDroppedPins; +} + #pragma mark Help methods - (IBAction)showShortcuts:(id)sender { @@ -267,6 +279,11 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init]; annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; annotation.title = @"Dropped Pin"; + _spellOutNumberFormatter.numberStyle = NSNumberFormatterSpellOutStyle; + if (_showsToolTipsOnDroppedPins) { + NSString *formattedNumber = [_spellOutNumberFormatter stringFromNumber:@(++_droppedPinCounter)]; + annotation.toolTip = formattedNumber; + } [self.mapView addAnnotation:annotation]; [self.mapView selectAnnotation:annotation animated:YES]; } @@ -356,6 +373,11 @@ static NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken menuItem.title = isShown ? @"Hide Collision Boxes" : @"Show Collision Boxes"; return YES; } + if (menuItem.action == @selector(toggleShowsToolTipsOnDroppedPins:)) { + BOOL isShown = _showsToolTipsOnDroppedPins; + menuItem.title = isShown ? @"Hide Tooltips on Dropped Pins" : @"Show Tooltips on Dropped Pins"; + return YES; + } if (menuItem.action == @selector(showShortcuts:)) { return YES; } diff --git a/platform/osx/app/MainMenu.xib b/platform/osx/app/MainMenu.xib index a47e7dcf75..b7dfb3fa7b 100644 --- a/platform/osx/app/MainMenu.xib +++ b/platform/osx/app/MainMenu.xib @@ -10,7 +10,7 @@ - + @@ -456,6 +456,13 @@ + + + + + + + diff --git a/platform/osx/sdk/MGLMapView.mm b/platform/osx/sdk/MGLMapView.mm index 79067095e8..81d5edfdd0 100644 --- a/platform/osx/sdk/MGLMapView.mm +++ b/platform/osx/sdk/MGLMapView.mm @@ -591,6 +591,7 @@ public: [self updateZoomControls]; [self updateCompass]; [self updateAnnotationCallouts]; + [self updateToolTips]; if ([self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) { BOOL animated = change == mbgl::MapChangeRegionDidChangeAnimated; @@ -1150,6 +1151,8 @@ public: _annotationContextsByAnnotationID[shapeAnnotationIDs[i]] = context; } } + + [self updateToolTips]; } - (void)installAnnotationImage:(MGLAnnotationImage *)annotationImage { @@ -1212,6 +1215,8 @@ public: } _mbglMap->removeAnnotations(annotationIDsToRemove); + + [self updateToolTips]; } - (id )selectedAnnotation { @@ -1242,8 +1247,7 @@ public: -_unionedAnnotationImageSize.height / 2); queryRect = NSInsetRect(queryRect, -MGLAnnotationImagePaddingForHitTest, -MGLAnnotationImagePaddingForHitTest); - mbgl::LatLngBounds queryBounds = [self convertRectToLatLngBounds:queryRect]; - std::vector nearbyAnnotations = _mbglMap->getPointAnnotationsInBounds(queryBounds); + std::vector nearbyAnnotations = [self annotationIDsInRect:queryRect]; if (nearbyAnnotations.size()) { NSRect hitRect = NSInsetRect({ point, NSZeroSize }, @@ -1296,6 +1300,11 @@ public: return hitAnnotationID; } +- (std::vector)annotationIDsInRect:(NSRect)rect { + mbgl::LatLngBounds queryBounds = [self convertRectToLatLngBounds:rect]; + return _mbglMap->getPointAnnotationsInBounds(queryBounds); +} + - (NS_ARRAY_OF(id ) *)selectedAnnotations { id selectedAnnotation = self.selectedAnnotation; return selectedAnnotation ? @[selectedAnnotation] : @[]; @@ -1509,6 +1518,36 @@ public: [self removeAnnotations:overlays]; } +#pragma mark Tooltips + +- (void)updateToolTips { + [self removeAllToolTips]; + + std::vector annotationIDs = [self annotationIDsInRect:self.bounds]; + for (MGLAnnotationID annotationID : annotationIDs) { + MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithID:annotationID]; + id 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]; + } + } + } +} + +- (NSString *)view:(__unused NSView *)view stringForToolTip:(__unused NSToolTipTag)tag point:(__unused NSPoint)point userData:(void *)data { + if ((NSUInteger)data >= MGLAnnotationNotFound) { + return nil; + } + MGLAnnotationID annotationID = (NSUInteger)data; + id annotation = [self annotationWithID:annotationID]; + return annotation.toolTip; +} + #pragma mark Interface Builder methods - (void)prepareForInterfaceBuilder { -- cgit v1.2.1