summaryrefslogtreecommitdiff
path: root/platform/macos/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/macos/src')
-rw-r--r--platform/macos/src/MGLAnnotationImage.h65
-rw-r--r--platform/macos/src/MGLAnnotationImage.m63
-rw-r--r--platform/macos/src/MGLAnnotationImage_Private.h8
-rw-r--r--platform/macos/src/MGLAttributionButton.h25
-rw-r--r--platform/macos/src/MGLAttributionButton.mm55
-rw-r--r--platform/macos/src/MGLCompassCell.h5
-rw-r--r--platform/macos/src/MGLCompassCell.m34
-rw-r--r--platform/macos/src/MGLMapView+IBAdditions.h68
-rw-r--r--platform/macos/src/MGLMapView+IBAdditions.mm120
-rw-r--r--platform/macos/src/MGLMapView+Impl.h44
-rw-r--r--platform/macos/src/MGLMapView+Impl.mm101
-rw-r--r--platform/macos/src/MGLMapView+OpenGL.h45
-rw-r--r--platform/macos/src/MGLMapView+OpenGL.mm89
-rw-r--r--platform/macos/src/MGLMapView.h1247
-rw-r--r--platform/macos/src/MGLMapView.mm3081
-rw-r--r--platform/macos/src/MGLMapViewDelegate.h352
-rw-r--r--platform/macos/src/MGLMapView_Private.h62
-rw-r--r--platform/macos/src/MGLOpenGLLayer.h10
-rw-r--r--platform/macos/src/MGLOpenGLLayer.mm58
-rw-r--r--platform/macos/src/Mapbox.h71
-rw-r--r--platform/macos/src/NSColor+MGLAdditions.h28
-rw-r--r--platform/macos/src/NSColor+MGLAdditions.mm124
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.h19
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.mm49
-rw-r--r--platform/macos/src/NSProcessInfo+MGLAdditions.h11
-rw-r--r--platform/macos/src/NSProcessInfo+MGLAdditions.m10
26 files changed, 0 insertions, 5844 deletions
diff --git a/platform/macos/src/MGLAnnotationImage.h b/platform/macos/src/MGLAnnotationImage.h
deleted file mode 100644
index d7336133d1..0000000000
--- a/platform/macos/src/MGLAnnotationImage.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#import <AppKit/AppKit.h>
-
-#import "MGLFoundation.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- The `MGLAnnotationImage` class is responsible for presenting point-based
- annotations visually on an `MGLMapView` instance. Annotation image objects pair
- `NSImage` objects with annotation-related metadata. They may be recycled later
- and put into a reuse queue that is maintained by the map view.
- */
-MGL_EXPORT
-@interface MGLAnnotationImage : NSObject <NSSecureCoding>
-
-#pragma mark Initializing and Preparing the Image Object
-
-/**
- Initializes and returns a new annotation image object.
-
- @param image The image to display for the annotation.
- @param reuseIdentifier The string that identifies this annotation image in the
- reuse queue.
- @return The initialized annotation image object or `nil` if there was a problem
- initializing the object.
- */
-+ (instancetype)annotationImageWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier;
-
-#pragma mark Getting and Setting Attributes
-
-/** The image to display for the annotation. */
-@property (nonatomic, readonly) NSImage *image;
-
-/**
- The string that identifies this annotation image in the reuse queue.
- (read-only)
-
- You specify the reuse identifier when you create the image object. You use this
- type later to retrieve an annotation image object that was created previously
- but which is currently unused because its annotation is not on-screen.
-
- If you define distinctly different types of annotations (with distinctly
- different annotation images to go with them), you can differentiate between the
- annotation types by specifying different reuse identifiers for each one.
- */
-@property (nonatomic, readonly) NSString *reuseIdentifier;
-
-/**
- A Boolean value indicating whether the annotation is selectable.
-
- The default value of this property is `YES`. If the value of this property is
- `NO`, the annotation image ignores click events and cannot be selected.
- */
-@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/macos/src/MGLAnnotationImage.m b/platform/macos/src/MGLAnnotationImage.m
deleted file mode 100644
index 8d715b427b..0000000000
--- a/platform/macos/src/MGLAnnotationImage.m
+++ /dev/null
@@ -1,63 +0,0 @@
-#import "MGLAnnotationImage_Private.h"
-
-@interface MGLAnnotationImage ()
-
-@property (nonatomic) NSImage *image;
-@property (nonatomic) NSString *reuseIdentifier;
-@property (nonatomic, strong, nullable) NSString *styleIconIdentifier;
-
-@end
-
-@implementation MGLAnnotationImage
-
-+ (instancetype)annotationImageWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier {
- return [[self alloc] initWithImage:image reuseIdentifier:reuseIdentifier];
-}
-
-- (instancetype)initWithImage:(NSImage *)image reuseIdentifier:(NSString *)reuseIdentifier {
- if (self = [super init]) {
- _image = image;
- _reuseIdentifier = [reuseIdentifier copy];
- _selectable = YES;
- }
- return self;
-}
-
-+ (BOOL)supportsSecureCoding {
- return YES;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)decoder {
- if (self = [super init]) {
- _image = [decoder decodeObjectOfClass:[NSImage class] forKey:@"image"];
- _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"];
- _cursor = [decoder decodeObjectOfClass:[NSCursor class] forKey:@"cursor"];
- _selectable = [decoder decodeBoolForKey:@"selectable"];
- }
- return self;
-}
-
-- (void)encodeWithCoder:(NSCoder *)coder {
- [coder encodeObject:_image forKey:@"image"];
- [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"];
- [coder encodeObject:_cursor forKey:@"cursor"];
- [coder encodeBool:_selectable forKey:@"selectable"];
-}
-
-- (BOOL)isEqual:(id)other {
- if (self == other) return YES;
- if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO;
-
- MGLAnnotationImage *otherAnnotationImage = other;
-
- return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier) || [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier])
- && _selectable == otherAnnotationImage.selectable
- && ((!_cursor && !otherAnnotationImage.cursor) || [_cursor isEqual:otherAnnotationImage.cursor])
- && (_image == otherAnnotationImage.image || [[_image TIFFRepresentation] isEqualToData:[otherAnnotationImage.image TIFFRepresentation]]);
-}
-
-- (NSUInteger)hash {
- return _reuseIdentifier.hash + @(_selectable).hash + _image.hash;
-}
-
-@end
diff --git a/platform/macos/src/MGLAnnotationImage_Private.h b/platform/macos/src/MGLAnnotationImage_Private.h
deleted file mode 100644
index 428f1db5d9..0000000000
--- a/platform/macos/src/MGLAnnotationImage_Private.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#import "Mapbox.h"
-
-@interface MGLAnnotationImage (Private)
-
-/// Unique identifier of the sprite image used by the style to represent the receiver’s `image`.
-@property (nonatomic, strong, nullable) NSString *styleIconIdentifier;
-
-@end
diff --git a/platform/macos/src/MGLAttributionButton.h b/platform/macos/src/MGLAttributionButton.h
deleted file mode 100644
index 3e0b53a6d0..0000000000
--- a/platform/macos/src/MGLAttributionButton.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-#import "MGLFoundation.h"
-#import "MGLTypes.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@class MGLAttributionInfo;
-
-/// Button that looks like a hyperlink and opens a URL.
-MGL_EXPORT
-@interface MGLAttributionButton : NSButton
-
-/// Returns an `MGLAttributionButton` instance with the given info.
-- (instancetype)initWithAttributionInfo:(MGLAttributionInfo *)info;
-
-/// The URL to open and display as a tooltip.
-@property (nonatomic, readonly, nullable) NSURL *URL;
-
-/// Opens the URL.
-- (IBAction)openURL:(nullable id)sender;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/MGLAttributionButton.mm b/platform/macos/src/MGLAttributionButton.mm
deleted file mode 100644
index 3df415f60d..0000000000
--- a/platform/macos/src/MGLAttributionButton.mm
+++ /dev/null
@@ -1,55 +0,0 @@
-#import "MGLAttributionButton.h"
-#import "MGLAttributionInfo.h"
-
-#import "NSBundle+MGLAdditions.h"
-#import "NSString+MGLAdditions.h"
-
-@implementation MGLAttributionButton
-
-- (instancetype)initWithAttributionInfo:(MGLAttributionInfo *)info {
- if (self = [super initWithFrame:NSZeroRect]) {
- self.bordered = NO;
- self.bezelStyle = NSRegularSquareBezelStyle;
-
- // Extract any prefix consisting of intellectual property symbols.
- NSScanner *scanner = [NSScanner scannerWithString:info.title.string];
- NSCharacterSet *symbolSet = [NSCharacterSet characterSetWithCharactersInString:@"©℗®℠™ &"];
- NSString *symbol;
- [scanner scanCharactersFromSet:symbolSet intoString:&symbol];
-
- // Remove the underline from the symbol for aesthetic reasons.
- NSMutableAttributedString *title = info.title.mutableCopy;
- [title removeAttribute:NSUnderlineStyleAttributeName range:NSMakeRange(0, symbol.length)];
-
- self.attributedTitle = title;
- [self sizeToFit];
-
- _URL = info.URL;
- if (_URL) {
- self.toolTip = _URL.absoluteString;
- }
-
- self.target = self;
- self.action = @selector(openURL:);
- }
- return self;
-}
-
-- (BOOL)wantsLayer {
- return YES;
-}
-
-- (void)resetCursorRects {
- if (self.URL) {
- // The whole button gets a pointing hand cursor, just like a hyperlink.
- [self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]];
- }
-}
-
-- (IBAction)openURL:(__unused id)sender {
- if (self.URL) {
- [[NSWorkspace sharedWorkspace] openURL:self.URL];
- }
-}
-
-@end
diff --git a/platform/macos/src/MGLCompassCell.h b/platform/macos/src/MGLCompassCell.h
deleted file mode 100644
index 5ed70dcb06..0000000000
--- a/platform/macos/src/MGLCompassCell.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-/// Circular slider with an arrow pointing north.
-@interface MGLCompassCell : NSSliderCell
-@end
diff --git a/platform/macos/src/MGLCompassCell.m b/platform/macos/src/MGLCompassCell.m
deleted file mode 100644
index b3a4ad4544..0000000000
--- a/platform/macos/src/MGLCompassCell.m
+++ /dev/null
@@ -1,34 +0,0 @@
-#import "MGLCompassCell.h"
-
-@implementation MGLCompassCell
-
-- (instancetype)init {
- if (self = [super init]) {
- self.sliderType = NSCircularSlider;
- // A tick mark for each cardinal direction.
- self.numberOfTickMarks = 4;
- // This slider goes backwards!
- self.minValue = -360;
- self.maxValue = 0;
- }
- return self;
-}
-
-- (void)drawKnob:(NSRect)knobRect {
- // Draw a red triangle pointing whichever way the slider is facing.
- NSBezierPath *trianglePath = [NSBezierPath bezierPath];
- [trianglePath moveToPoint:NSMakePoint(NSMinX(knobRect), NSMaxY(knobRect))];
- [trianglePath lineToPoint:NSMakePoint(NSMaxX(knobRect), NSMaxY(knobRect))];
- [trianglePath lineToPoint:NSMakePoint(NSMidX(knobRect), NSMinY(knobRect))];
- [trianglePath closePath];
- NSAffineTransform *transform = [NSAffineTransform transform];
- [transform translateXBy:NSMidX(knobRect) yBy:NSMidY(knobRect)];
- [transform scaleBy:0.8];
- [transform rotateByDegrees:self.doubleValue];
- [transform translateXBy:-NSMidX(knobRect) yBy:-NSMidY(knobRect)];
- [trianglePath transformUsingAffineTransform:transform];
- [[NSColor redColor] setFill];
- [trianglePath fill];
-}
-
-@end
diff --git a/platform/macos/src/MGLMapView+IBAdditions.h b/platform/macos/src/MGLMapView+IBAdditions.h
deleted file mode 100644
index 29d914a7d9..0000000000
--- a/platform/macos/src/MGLMapView+IBAdditions.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#import <Foundation/Foundation.h>
-
-#import "MGLMapView.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface MGLMapView (IBAdditions)
-
-#if TARGET_INTERFACE_BUILDER
-
-// Core properties that can be manipulated in the Attributes inspector in
-// Interface Builder. These redeclarations merely add the IBInspectable keyword.
-// They appear here to ensure that they appear above the convenience properties;
-// inspectables declared in MGLMapView.h are always sorted before those in
-// MGLMapView+IBAdditions.h, due to ASCII sort order.
-
-// We want this property to look like a URL bar in the Attributes inspector, but
-// just calling it styleURL would violate Cocoa naming conventions and conflict
-// with the existing NSURL property. Fortunately, IB strips out the two
-// underscores for display.
-
-/** URL of the style currently displayed in the receiver.
-
- The URL may be a full HTTP or HTTPS URL, a Mapbox
- style URL (`mapbox://styles/<user>/<style>`), or a path to a local file
- relative to the application’s resource path. Leave this field blank for the
- default style. */
-@property (nonatomic, nullable) IBInspectable NSString *styleURL__;
-
-// Convenience properties related to the initial viewport. These properties
-// are not meant to be used outside of Interface Builder. latitude and longitude
-// are backed by properties of type CLLocationDegrees, but these declarations
-// must use the type double because Interface Builder is unaware that
-// CLLocationDegrees is a typedef for double.
-
-/** The initial center latitude. */
-@property (nonatomic) IBInspectable double latitude;
-
-/** The initial center longitude. */
-@property (nonatomic) IBInspectable double longitude;
-
-@property (nonatomic) IBInspectable double zoomLevel;
-
-// Renamed properties. Interface Builder derives the display name of each
-// inspectable from the runtime name, but runtime names don’t always make sense
-// in UI.
-
-/** A Boolean value that determines whether the user may zoom the map, changing
- its zoom level. */
-@property (nonatomic) IBInspectable BOOL allowsZooming;
-
-/** A Boolean value that determines whether the user may scroll around the map,
- changing its center coordinate. */
-@property (nonatomic) IBInspectable BOOL allowsScrolling;
-
-/** A Boolean value that determines whether the user may rotate the map,
- changing its direction. */
-@property (nonatomic) IBInspectable BOOL allowsRotating;
-
-/** A Boolean value that determines whether the user may tilt the map, changing
- its pitch. */
-@property (nonatomic) IBInspectable BOOL allowsTilting;
-
-#endif
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/MGLMapView+IBAdditions.mm b/platform/macos/src/MGLMapView+IBAdditions.mm
deleted file mode 100644
index 0c65abc031..0000000000
--- a/platform/macos/src/MGLMapView+IBAdditions.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-#import "MGLMapView+IBAdditions.h"
-
-#import "MGLStyle.h"
-
-#import "MGLMapView_Private.h"
-
-@implementation MGLMapView (IBAdditions)
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL__ {
- return [NSSet setWithObject:@"styleURL"];
-}
-
-- (nullable NSString *)styleURL__ {
- return self.styleURL.absoluteString;
-}
-
-- (void)setStyleURL__:(nullable NSString *)URLString {
- URLString = [URLString stringByTrimmingCharactersInSet:
- [NSCharacterSet whitespaceAndNewlineCharacterSet]];
- NSURL *url = URLString.length ? [NSURL URLWithString:URLString] : nil;
- if (URLString.length && !url) {
- [NSException raise:MGLInvalidStyleURLException
- format:@"“%@” is not a valid style URL.", URLString];
- }
- self.styleURL = url;
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingLatitude {
- return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
-}
-
-- (double)latitude {
- return self.centerCoordinate.latitude;
-}
-
-- (void)setLatitude:(double)latitude {
- if (!isnan(self.pendingLongitude)) {
- // With both components present, set the real center coordinate and
- // forget the pending parts.
- self.centerCoordinate = CLLocationCoordinate2DMake(latitude, self.pendingLongitude);
- self.pendingLatitude = NAN;
- self.pendingLongitude = NAN;
- } else {
- // Not enough info to make a valid center coordinate yet. Stash this
- // latitude away until the longitude is set too.
- self.pendingLatitude = latitude;
- }
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingLongitude {
- return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
-}
-
-- (double)longitude {
- return self.centerCoordinate.longitude;
-}
-
-- (void)setLongitude:(double)longitude {
- if (!isnan(self.pendingLatitude)) {
- // With both components present, set the real center coordinate and
- // forget the pending parts.
- self.centerCoordinate = CLLocationCoordinate2DMake(self.pendingLatitude, longitude);
- self.pendingLatitude = NAN;
- self.pendingLongitude = NAN;
- } else {
- // Not enough info to make a valid center coordinate yet. Stash this
- // longitude away until the latitude is set too.
- self.pendingLongitude = longitude;
- }
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsZooming {
- return [NSSet setWithObject:@"zoomEnabled"];
-}
-
-- (BOOL)allowsZooming {
- return self.zoomEnabled;
-}
-
-- (void)setAllowsZooming:(BOOL)allowsZooming {
- self.zoomEnabled = allowsZooming;
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsScrolling {
- return [NSSet setWithObject:@"scrollEnabled"];
-}
-
-- (BOOL)allowsScrolling {
- return self.scrollEnabled;
-}
-
-- (void)setAllowsScrolling:(BOOL)allowsScrolling {
- self.scrollEnabled = allowsScrolling;
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsRotating {
- return [NSSet setWithObject:@"rotateEnabled"];
-}
-
-- (BOOL)allowsRotating {
- return self.rotateEnabled;
-}
-
-- (void)setAllowsRotating:(BOOL)allowsRotating {
- self.rotateEnabled = allowsRotating;
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsTilting {
- return [NSSet setWithObject:@"pitchEnabled"];
-}
-
-- (BOOL)allowsTilting {
- return self.pitchEnabled;
-}
-
-- (void)setAllowsTilting:(BOOL)allowsTilting {
- self.pitchEnabled = allowsTilting;
-}
-
-@end
diff --git a/platform/macos/src/MGLMapView+Impl.h b/platform/macos/src/MGLMapView+Impl.h
deleted file mode 100644
index d33a19dbab..0000000000
--- a/platform/macos/src/MGLMapView+Impl.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#import <mbgl/gfx/renderer_backend.hpp>
-#import <mbgl/map/map_observer.hpp>
-#import <mbgl/util/image.hpp>
-
-@class MGLMapView;
-
-typedef struct _CGLContextObject* CGLContextObj;
-
-class MGLMapViewImpl : public mbgl::MapObserver {
-public:
- static std::unique_ptr<MGLMapViewImpl> Create(MGLMapView*);
-
- MGLMapViewImpl(MGLMapView*);
- virtual ~MGLMapViewImpl() = default;
-
- virtual mbgl::gfx::RendererBackend& getRendererBackend() = 0;
-
- // We need a static image of what was rendered for printing.
- virtual mbgl::PremultipliedImage readStillImage() = 0;
-
- virtual CGLContextObj getCGLContextObj() {
- return nullptr;
- }
-
- // mbgl::MapObserver implementation
- void onCameraWillChange(mbgl::MapObserver::CameraChangeMode) override;
- void onCameraIsChanging() override;
- void onCameraDidChange(mbgl::MapObserver::CameraChangeMode) override;
- void onWillStartLoadingMap() override;
- void onDidFinishLoadingMap() override;
- void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
- void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus) override;
- void onWillStartRenderingMap() override;
- void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
- void onDidFinishLoadingStyle() override;
- void onSourceChanged(mbgl::style::Source& source) override;
- void onDidBecomeIdle() override;
- bool onCanRemoveUnusedStyleImage(const std::string& imageIdentifier) override;
-
-protected:
- /// Cocoa map view that this adapter bridges to.
- __weak MGLMapView *mapView = nullptr;
-};
diff --git a/platform/macos/src/MGLMapView+Impl.mm b/platform/macos/src/MGLMapView+Impl.mm
deleted file mode 100644
index c00f858153..0000000000
--- a/platform/macos/src/MGLMapView+Impl.mm
+++ /dev/null
@@ -1,101 +0,0 @@
-#import "MGLMapView+Impl.h"
-#import "MGLMapView+OpenGL.h"
-#import "MGLStyle_Private.h"
-#import "NSBundle+MGLAdditions.h"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/style/style.hpp>
-
-std::unique_ptr<MGLMapViewImpl> MGLMapViewImpl::Create(MGLMapView* nativeView) {
- return std::make_unique<MGLMapViewOpenGLImpl>(nativeView);
-}
-
-MGLMapViewImpl::MGLMapViewImpl(MGLMapView* nativeView_) : mapView(nativeView_) {
-}
-
-void MGLMapViewImpl::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) {
- bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
- [mapView cameraWillChangeAnimated:animated];
-}
-
-void MGLMapViewImpl::onCameraIsChanging() {
- [mapView cameraIsChanging];
-}
-
-void MGLMapViewImpl::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) {
- bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
- [mapView cameraDidChangeAnimated:animated];
-}
-
-void MGLMapViewImpl::onWillStartLoadingMap() {
- [mapView mapViewWillStartLoadingMap];
-}
-
-void MGLMapViewImpl::onDidFinishLoadingMap() {
- [mapView mapViewDidFinishLoadingMap];
-}
-
-void MGLMapViewImpl::onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) {
- NSString *description;
- MGLErrorCode code;
- switch (mapError) {
- case mbgl::MapLoadError::StyleParseError:
- code = MGLErrorCodeParseStyleFailed;
- description = NSLocalizedStringWithDefaultValue(@"PARSE_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style is corrupted.", @"User-friendly error description");
- break;
- case mbgl::MapLoadError::StyleLoadError:
- code = MGLErrorCodeLoadStyleFailed;
- description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
- break;
- case mbgl::MapLoadError::NotFoundError:
- code = MGLErrorCodeNotFound;
- description = NSLocalizedStringWithDefaultValue(@"STYLE_NOT_FOUND_DESC", nil, nil, @"The map failed to load because the style can’t be found or is incompatible.", @"User-friendly error description");
- break;
- default:
- code = MGLErrorCodeUnknown;
- description = NSLocalizedStringWithDefaultValue(@"LOAD_MAP_FAILED_DESC", nil, nil, @"The map failed to load because an unknown error occurred.", @"User-friendly error description");
- }
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: description,
- NSLocalizedFailureReasonErrorKey: @(what.c_str()),
- };
- NSError *error = [NSError errorWithDomain:MGLErrorDomain code:code userInfo:userInfo];
- [mapView mapViewDidFailLoadingMapWithError:error];
-}
-
-void MGLMapViewImpl::onWillStartRenderingFrame() {
- [mapView mapViewWillStartRenderingFrame];
-}
-
-void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus status) {
- bool fullyRendered = status.mode == mbgl::MapObserver::RenderMode::Full;
- [mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
-}
-
-void MGLMapViewImpl::onWillStartRenderingMap() {
- [mapView mapViewWillStartRenderingMap];
-}
-
-void MGLMapViewImpl::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) {
- bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
- [mapView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
-}
-
-void MGLMapViewImpl::onDidBecomeIdle() {
- [mapView mapViewDidBecomeIdle];
-}
-
-void MGLMapViewImpl::onDidFinishLoadingStyle() {
- [mapView mapViewDidFinishLoadingStyle];
-}
-
-void MGLMapViewImpl::onSourceChanged(mbgl::style::Source& source) {
- NSString *identifier = @(source.getID().c_str());
- MGLSource * nativeSource = [mapView.style sourceWithIdentifier:identifier];
- [mapView sourceDidChange:nativeSource];
-}
-
-bool MGLMapViewImpl::onCanRemoveUnusedStyleImage(const std::string &imageIdentifier) {
- NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()];
- return [mapView shouldRemoveStyleImage:imageName];
-}
diff --git a/platform/macos/src/MGLMapView+OpenGL.h b/platform/macos/src/MGLMapView+OpenGL.h
deleted file mode 100644
index d4c6a448cd..0000000000
--- a/platform/macos/src/MGLMapView+OpenGL.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#import "MGLMapView+Impl.h"
-#import "MGLMapView_Private.h"
-
-#include <mbgl/gfx/renderable.hpp>
-#include <mbgl/gl/renderer_backend.hpp>
-
-/// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa.
-class MGLMapViewOpenGLImpl final : public MGLMapViewImpl,
- public mbgl::gl::RendererBackend,
- public mbgl::gfx::Renderable {
-public:
- MGLMapViewOpenGLImpl(MGLMapView*);
- ~MGLMapViewOpenGLImpl() override = default;
-
-public:
- void restoreFramebufferBinding();
-
- // Implementation of mbgl::gfx::RendererBackend
-public:
- mbgl::gfx::Renderable& getDefaultRenderable() override {
- return *this;
- }
-
-private:
- void activate() override;
- void deactivate() override;
- // End implementation of mbgl::gfx::RendererBackend
-
- // Implementation of mbgl::gl::RendererBackend
-public:
- void updateAssumedState() override;
-
-private:
- mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override;
- // End implementation of mbgl::gl::Rendererbackend
-
- // Implementation of MGLMapViewImpl
-public:
- mbgl::gfx::RendererBackend& getRendererBackend() override {
- return *this;
- }
-
- mbgl::PremultipliedImage readStillImage() override;
- CGLContextObj getCGLContextObj() override;
-};
diff --git a/platform/macos/src/MGLMapView+OpenGL.mm b/platform/macos/src/MGLMapView+OpenGL.mm
deleted file mode 100644
index f6168a4b80..0000000000
--- a/platform/macos/src/MGLMapView+OpenGL.mm
+++ /dev/null
@@ -1,89 +0,0 @@
-#import "MGLMapView+OpenGL.h"
-#import "MGLOpenGLLayer.h"
-
-#include <mbgl/gl/renderable_resource.hpp>
-
-#import <OpenGL/gl.h>
-
-class MGLMapViewOpenGLRenderableResource final : public mbgl::gl::RenderableResource {
-public:
- MGLMapViewOpenGLRenderableResource(MGLMapViewOpenGLImpl& backend_) : backend(backend_) {
- }
-
- void bind() override {
- backend.restoreFramebufferBinding();
- }
-
-private:
- MGLMapViewOpenGLImpl& backend;
-
-public:
- // The current framebuffer of the NSOpenGLLayer we are painting to.
- GLint fbo = 0;
-
- // The reference counted count of activation calls
- NSUInteger activationCount = 0;
-};
-
-MGLMapViewOpenGLImpl::MGLMapViewOpenGLImpl(MGLMapView* nativeView_)
- : MGLMapViewImpl(nativeView_),
- mbgl::gl::RendererBackend(mbgl::gfx::ContextMode::Unique),
- mbgl::gfx::Renderable(mapView.framebufferSize,
- std::make_unique<MGLMapViewOpenGLRenderableResource>(*this)) {
-
- // Install the OpenGL layer. Interface Builder’s synchronous drawing means
- // we can’t display a map, so don’t even bother to have a map layer.
- mapView.layer =
- mapView.isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
-}
-
-mbgl::gl::ProcAddress MGLMapViewOpenGLImpl::getExtensionFunctionPointer(const char* name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- return reinterpret_cast<mbgl::gl::ProcAddress>(CFBundleGetFunctionPointerForName(
- framework, (__bridge CFStringRef)[NSString stringWithUTF8String:name]));
-}
-
-void MGLMapViewOpenGLImpl::activate() {
- auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
- if (resource.activationCount++) {
- return;
- }
-
- MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
- [layer.openGLContext makeCurrentContext];
-}
-
-void MGLMapViewOpenGLImpl::deactivate() {
- auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
- if (--resource.activationCount) {
- return;
- }
-
- [NSOpenGLContext clearCurrentContext];
-}
-
-void MGLMapViewOpenGLImpl::updateAssumedState() {
- auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
- glGetIntegerv(GL_FRAMEBUFFER_BINDING, &resource.fbo);
- assumeFramebufferBinding(resource.fbo);
- assumeViewport(0, 0, mapView.framebufferSize);
-}
-
-void MGLMapViewOpenGLImpl::restoreFramebufferBinding() {
- auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
- setFramebufferBinding(resource.fbo);
- setViewport(0, 0, mapView.framebufferSize);
-}
-
-mbgl::PremultipliedImage MGLMapViewOpenGLImpl::readStillImage() {
- return readFramebuffer(mapView.framebufferSize);
-}
-
-CGLContextObj MGLMapViewOpenGLImpl::getCGLContextObj() {
- MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
- return layer.openGLContext.CGLContextObj;
-}
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
deleted file mode 100644
index 374d4eeab7..0000000000
--- a/platform/macos/src/MGLMapView.h
+++ /dev/null
@@ -1,1247 +0,0 @@
-#import <Cocoa/Cocoa.h>
-#import <CoreLocation/CoreLocation.h>
-
-#import "MGLFoundation.h"
-#import "MGLTypes.h"
-#import "MGLGeometry.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@class MGLAnnotationImage;
-@class MGLMapCamera;
-@class MGLStyle;
-@class MGLShape;
-
-@protocol MGLAnnotation;
-@protocol MGLMapViewDelegate;
-@protocol MGLOverlay;
-@protocol MGLFeature;
-
-/**
- An interactive, customizable map view with an interface similar to the one
- provided by Apple’s MapKit.
-
- Using `MGLMapView`, you can embed the map inside a view, allow users to
- manipulate it with standard gestures, animate the map between different
- viewpoints, and present information in the form of annotations and overlays.
-
- The map view loads scalable vector tiles that conform to the
- <a href="https://github.com/mapbox/vector-tile-spec">Mapbox Vector Tile Specification</a>.
- It styles them with a style that conforms to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/">Mapbox Style Specification</a>.
- Such styles can be designed in
- <a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
- mapbox.com.
-
- A collection of Mapbox-hosted styles is available through the `MGLStyle` class.
- These basic styles use
- <a href="https://www.mapbox.com/developers/vector-tiles/mapbox-streets">Mapbox Streets</a>
- or <a href="https://www.mapbox.com/satellite/">Mapbox Satellite</a> data
- sources, but you can specify a custom style that makes use of your own data.
-
- Mapbox-hosted vector tiles and styles require an API access token, which you
- can obtain from the
- <a href="https://www.mapbox.com/studio/account/tokens/">Mapbox account page</a>.
- Access tokens associate requests to Mapbox’s vector tile and style APIs with
- your Mapbox account. They also deter other developers from using your styles
- without your permission.
-
- Adding your own gesture recognizer to `MGLMapView` will block the corresponding
- gesture recognizer built into `MGLMapView`. To avoid conflicts, define which
- gesture recognizer takes precedence. For example, you can subclass
- `NSClickGestureRecognizer` and override `-[NSGestureRecognizer shouldRequireFailureOfGestureRecognizer:]`,
- so that your subclass will be invoked only if the default `MGLMapView` click
- gesture recognizer fails:
-
- ```swift
- class MapClickGestureRecognizer: NSClickGestureRecognizer {
- override func shouldRequireFailure(of otherGestureRecognizer: NSGestureRecognizer) -> Bool {
- return otherGestureRecognizer is NSClickGestureRecognizer
- }
- }
- ```
-
- @note You are responsible for getting permission to use the map data and for
- ensuring that your use adheres to the relevant terms of use.
- */
-MGL_EXPORT IB_DESIGNABLE
-@interface MGLMapView : NSView
-
-#pragma mark Creating Instances
-
-/**
- Initializes and returns a newly allocated map view with the specified frame and
- the default style.
-
- @param frame The frame for the view, measured in points.
- @return An initialized map view.
- */
-- (instancetype)initWithFrame:(NSRect)frame;
-
-/**
- Initializes and returns a newly allocated map view with the specified frame and
- style URL.
-
- @param frame The frame for the view, measured in points.
- @param styleURL URL of the map style to display. The URL may be a full HTTP or
- HTTPS URL, a Mapbox style URL
- (`mapbox://styles/<user>/<style>`), or a path to a local file relative to
- the application’s resource path. Specify `nil` for the default style.
- @return An initialized map view.
- */
-- (instancetype)initWithFrame:(NSRect)frame styleURL:(nullable NSURL *)styleURL;
-
-#pragma mark Accessing the Delegate
-
-/**
- The receiver’s delegate.
-
- A map view sends messages to its delegate to notify it of changes to its
- contents or the viewpoint. The delegate also provides information about
- annotations displayed on the map, such as the styles to apply to individual
- annotations.
- */
-@property (nonatomic, weak, nullable) IBOutlet id <MGLMapViewDelegate> delegate;
-
-#pragma mark Configuring the Map’s Appearance
-
-/**
- The style currently displayed in the receiver.
-
- Unlike the `styleURL` property, this property is set to an object that allows
- you to manipulate every aspect of the style locally.
-
- If the style is loading, this property is set to `nil` until the style finishes
- loading. If the style has failed to load, this property is set to `nil`.
- Because the style loads asynchronously, you should manipulate it in the
- `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
- to manipulate the style before it has finished loading.
-
- @note The default styles provided by Mapbox contain sources and layers with
- identifiers that will change over time. Applications that use APIs that
- manipulate a style's sources and layers must first set the style URL to an
- explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`.
- */
-@property (nonatomic, readonly, nullable) MGLStyle *style;
-
-/**
- URL of the style currently displayed in the receiver.
-
- The URL may be a full HTTP or HTTPS URL, a Mapbox
- style URL (`mapbox://styles/<user>/<style>`), or a path to a local file relative
- to the application’s resource path.
-
- If you set this property to `nil`, the receiver will use the default style and
- this property will automatically be set to that style’s URL.
-
- If you want to modify the current style without replacing it outright, or if
- you want to introspect individual style attributes, use the `style` property.
- */
-@property (nonatomic, null_resettable) NSURL *styleURL;
-
-/**
- Reloads the style.
-
- You do not normally need to call this method. The map view automatically
- responds to changes in network connectivity by reloading the style. You may
- need to call this method if you change the access token after a style has
- loaded but before loading a style associated with a different Mapbox account.
- */
-- (IBAction)reloadStyle:(id)sender;
-
-/**
- A control for zooming in and out, positioned in the lower-right corner.
- */
-@property (nonatomic, readonly) NSSegmentedControl *zoomControls;
-
-/**
- A control indicating the map’s direction and allowing the user to manipulate
- the direction, positioned above the zoom controls in the lower-right corner.
- */
-@property (nonatomic, readonly) NSSlider *compass;
-
-/**
- The Mapbox logo, positioned in the lower-left corner.
-
- @note The Mapbox terms of service, which governs the use of Mapbox-hosted
- vector tiles and styles,
- <a href="https://www.mapbox.com/help/mapbox-logo/">requires</a> most Mapbox
- customers to display the Mapbox logo. If this applies to you, do not hide
- this view or change its contents.
- */
-@property (nonatomic, readonly) NSImageView *logoView;
-
-/**
- A view showing legally required copyright notices, positioned along the bottom
- of the map view, to the left of the Mapbox logo.
-
- @note The Mapbox terms of service, which governs the use of Mapbox-hosted
- vector tiles and styles,
- <a href="https://www.mapbox.com/help/attribution/">requires</a> these
- copyright notices to accompany any map that features Mapbox-designed styles,
- OpenStreetMap data, or other Mapbox data such as satellite or terrain data.
- If that applies to this map view, do not hide this view or remove any
- notices from it.
- */
-@property (nonatomic, readonly) NSView *attributionView;
-
-/**
- A Boolean value indicating whether the map should prefetch tiles.
-
- When this property is set to `YES`, the map view prefetches tiles designed for
- a low zoom level and displays them until receiving more detailed tiles for the
- current zoom level. The prefetched tiles typically contain simplified versions
- of each shape, improving the map view’s perceived performance.
-
- The default value of this property is `YES`.
- */
-@property (nonatomic, assign) BOOL prefetchesTiles;
-
-
-#pragma mark Manipulating the Viewpoint
-
-/**
- The geographic coordinate at the center of the map view.
-
- Changing the value of this property centers the map on the new coordinate
- without changing the current zoom level.
-
- Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setCenterCoordinate:animated:` method
- instead.
- */
-@property (nonatomic) CLLocationCoordinate2D centerCoordinate;
-
-/**
- Changes the center coordinate of the map and optionally animates the change.
-
- Changing the center coordinate centers the map on the new coordinate without
- changing the current zoom level.
-
- @param coordinate The new center coordinate for the map.
- @param animated Specify `YES` if you want the map view to scroll to the new
- location or `NO` if you want the map to display the new location
- immediately.
- */
-- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
-
-/**
- The zoom level of the receiver.
-
- In addition to affecting the visual size and detail of features on the map, the
- zoom level affects the size of the vector tiles that are loaded. At zoom level
- 0, each tile covers the entire world map; at zoom level 1, it covers ¼ of the
- world; at zoom level 2, <sup>1</sup>⁄<sub>16</sub> of the world, and so on.
-
- Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setZoomLevel:animated:` method instead.
- */
-@property (nonatomic) double zoomLevel;
-
-/**
- The minimum zoom level at which the map can be shown.
-
- Depending on the map view’s aspect ratio, the map view may be prevented from
- reaching the minimum zoom level, in order to keep the map from repeating within
- the current viewport.
-
- If the value of this property is greater than that of the `maximumZoomLevel`
- property, the behavior is undefined.
-
- The default value of this property is 0.
- */
-@property (nonatomic) IBInspectable double minimumZoomLevel;
-
-/**
- The maximum zoom level the map can be shown at.
-
- If the value of this property is smaller than that of the `minimumZoomLevel`
- property, the behavior is undefined.
-
- The default value of this property is 22. The upper bound for this property
- is 25.5.
- */
-@property (nonatomic) IBInspectable double maximumZoomLevel;
-
-/**
- Changes the zoom level of the map and optionally animates the change.
-
- Changing the zoom level scales the map without changing the current center
- coordinate.
-
- @param zoomLevel The new zoom level for the map.
- @param animated Specify `YES` if you want the map view to animate the change
- to the new zoom level or `NO` if you want the map to display the new zoom
- level immediately.
- */
-- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated;
-
-/**
- The heading of the map, measured in degrees clockwise from true north.
-
- The value `0` means that the top edge of the map view corresponds to true
- north. The value `90` means the top of the map is pointing due east. The value
- `180` means the top of the map points due south, and so on.
-
- Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setDirection:animated:` method instead.
- */
-@property (nonatomic) CLLocationDirection direction;
-
-/**
- Changes the heading of the map and optionally animates the change.
-
- Changing the heading rotates the map without changing the current center
- coordinate or zoom level.
-
- @param direction The heading of the map, measured in degrees clockwise from
- true north.
- @param animated Specify `YES` if you want the map view to animate the change
- to the new heading or `NO` if you want the map to display the new heading
- immediately.
- */
-- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated;
-
-/**
- A camera representing the current viewpoint of the map.
- */
-@property (nonatomic, copy) MGLMapCamera *camera;
-
-/**
- Moves the viewpoint to a different location with respect to the map with an
- optional transition animation.
-
- @param camera The new viewpoint.
- @param animated Specify `YES` if you want the map view to animate the change to
- the new viewpoint or `NO` if you want the map to display the new viewpoint
- immediately.
- */
-- (void)setCamera:(MGLMapCamera *)camera animated:(BOOL)animated;
-
-/**
- Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function.
-
- @param camera The new viewpoint.
- @param duration The amount of time, measured in seconds, that the transition
- animation should take. Specify `0` to jump to the new viewpoint
- instantaneously.
- @param function A timing function used for the animation. Set this parameter to
- `nil` for a transition that matches most system animations. If the duration
- is `0`, this parameter is ignored.
- @param completion The block to execute after the animation finishes.
- */
-- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
-
- /**
- Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function, and optionally some additional
- padding on each side.
-
- @param camera The new viewpoint.
- @param duration The amount of time, measured in seconds, that the transition
- animation should take. Specify `0` to jump to the new viewpoint
- instantaneously.
- @param function A timing function used for the animation. Set this parameter to
- `nil` for a transition that matches most system animations. If the duration
- is `0`, this parameter is ignored.
- @param edgePadding The minimum padding (in screen points) that would be visible
- around the returned camera object if it were set as the receiver’s camera.
- @param completion The block to execute after the animation finishes.
- */
-- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function edgePadding:(NSEdgeInsets)edgePadding completionHandler:(nullable void (^)(void))completion;
-
-
-/**
- Moves the viewpoint to a different location using a transition animation that
- evokes powered flight and a default duration based on the length of the flight
- path.
-
- The transition animation seamlessly incorporates zooming and panning to help
- the user find his or her bearings even after traversing a great distance.
-
- @param camera The new viewpoint.
- @param completion The block to execute after the animation finishes.
- */
-- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion;
-
-/**
- Moves the viewpoint to a different location using a transition animation that
- evokes powered flight and an optional transition duration.
-
- The transition animation seamlessly incorporates zooming and panning to help
- the user find his or her bearings even after traversing a great distance.
-
- @param camera The new viewpoint.
- @param duration The amount of time, measured in seconds, that the transition
- animation should take. Specify `0` to jump to the new viewpoint
- instantaneously. Specify a negative value to use the default duration, which
- is based on the length of the flight path.
- @param completion The block to execute after the animation finishes.
- */
-- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion;
-
-/**
- Moves the viewpoint to a different location using a transition animation that
- evokes powered flight and an optional transition duration and peak altitude.
-
- The transition animation seamlessly incorporates zooming and panning to help
- the user find his or her bearings even after traversing a great distance.
-
- @param camera The new viewpoint.
- @param duration The amount of time, measured in seconds, that the transition
- animation should take. Specify `0` to jump to the new viewpoint
- instantaneously. Specify a negative value to use the default duration, which
- is based on the length of the flight path.
- @param peakAltitude The altitude, measured in meters, at the midpoint of the
- animation. The value of this parameter is ignored if it is negative or if
- the animation transition resulting from a similar call to
- `-setCamera:animated:` would have a midpoint at a higher altitude.
- @param completion The block to execute after the animation finishes.
- */
-- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion;
-
-/**
- The geographic coordinate bounds visible in the receiver’s viewport.
-
- Changing the value of this property updates the receiver immediately. If you
- want to animate the change, use the `-setVisibleCoordinateBounds:animated:`
- method instead.
-
- If a longitude is less than −180 degrees or greater than 180 degrees, the
- visible bounds straddles the antimeridian or international date line. For
- example, if both Tokyo and San Francisco are visible, the visible bounds might
- extend from (35.68476, −220.24257) to (37.78428, −122.41310).
- */
-@property (nonatomic) MGLCoordinateBounds visibleCoordinateBounds;
-
-/**
- Changes the receiver’s viewport to fit the given coordinate bounds, optionally
- animating the change.
-
- To bring both sides of the antimeridian or international date line into view,
- specify some longitudes less than −180 degrees or greater than 180 degrees. For
- example, to show both Tokyo and San Francisco simultaneously, you could set the
- visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310).
-
- @param bounds The bounds that the viewport will show in its entirety.
- @param animated Specify `YES` to animate the change by smoothly scrolling and
- zooming or `NO` to immediately display the given bounds.
- */
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated;
-
-/**
- Changes the receiver’s viewport to fit the given coordinate bounds with some
- additional padding on each side.
-
- To bring both sides of the antimeridian or international date line into view,
- specify some longitudes less than −180 degrees or greater than 180 degrees. For
- example, to show both Tokyo and San Francisco simultaneously, you could set the
- visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310).
-
- To specify a completion handler to execute after the animation finishes, use
- the `-setVisibleCoordinateBounds:edgePadding:animated:completionHandler:` method.
-
- @param bounds The bounds that the viewport will show in its entirety.
- @param insets The minimum padding (in screen points) that will be visible
- around the given coordinate bounds.
- @param animated Specify `YES` to animate the change by smoothly scrolling and
- zooming or `NO` to immediately display the given bounds.
- */
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
-
-/**
- Changes the receiver’s viewport to fit the given coordinate bounds with some
- additional padding on each side, optionally calling a completion handler.
-
- To bring both sides of the antimeridian or international date line into view,
- specify some longitudes less than −180 degrees or greater than 180 degrees. For
- example, to show both Tokyo and San Francisco simultaneously, you could set the
- visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310).
-
- @param bounds The bounds that the viewport will show in its entirety.
- @param insets The minimum padding (in screen points) that will be visible
- around the given coordinate bounds.
- @param animated Specify `YES` to animate the change by smoothly scrolling and
- zooming or `NO` to immediately display the given bounds.
- @param completion The block executed after the animation finishes.
- */
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
-
-/**
- Sets the visible region so that the map displays the specified annotations.
-
- Calling this method updates the value in the `visibleCoordinateBounds` property
- and potentially other properties to reflect the new map region. A small amount
- of padding is reserved around the edges of the map view. To specify a different
- amount of padding, use the `-showAnnotations:edgePadding:animated:` method.
-
- @param annotations The annotations that you want to be visible in the map.
- @param animated `YES` if you want the map region change to be animated, or `NO`
- if you want the map to display the new region immediately without animations.
- */
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated;
-
-/**
- Sets the visible region so that the map displays the specified annotations with
- the specified amount of padding on each side.
-
- Calling this method updates the value in the `visibleCoordinateBounds` property
- and potentially other properties to reflect the new map region.
-
- To specify a completion handler to execute after the animation finishes, use
- the `-showAnnotations:edgePadding:animated:completionHandler:` method.
-
- @param annotations The annotations that you want to be visible in the map.
- @param insets The minimum padding (in screen points) around the edges of the
- map view to keep clear of annotations.
- @param animated `YES` if you want the map region change to be animated, or `NO`
- if you want the map to display the new region immediately without animations.
- */
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
-
-/**
- Sets the visible region so that the map displays the specified annotations with
- the specified amount of padding on each side and an optional completion
- handler.
-
- Calling this method updates the value in the `visibleCoordinateBounds` property
- and potentially other properties to reflect the new map region.
-
- @param annotations The annotations that you want to be visible in the map.
- @param insets The minimum padding (in screen points) around the edges of the
- map view to keep clear of annotations.
- @param animated `YES` if you want the map region change to be animated, or `NO`
- if you want the map to display the new region immediately without animations.
- @param completion The block executed after the animation finishes.
- */
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
-
-/**
- Returns the camera that best fits the given coordinate bounds.
-
- @param bounds The coordinate bounds to fit to the receiver’s viewport.
- @return A camera object centered on the same location as the coordinate bounds
- with zoom level as high (close to the ground) as possible while still
- including the entire coordinate bounds. The camera object uses the current
- direction and pitch.
- */
-- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds;
-
-/**
- Returns the camera that best fits the given coordinate bounds with some
- additional padding on each side.
-
- @param bounds The coordinate bounds to fit to the receiver’s viewport.
- @param insets The minimum padding (in screen points) that would be visible
- around the returned camera object if it were set as the receiver’s camera.
- @return A camera object centered on the same location as the coordinate bounds
- with zoom level as high (close to the ground) as possible while still
- including the entire coordinate bounds. The camera object uses the current
- direction and pitch.
- */
-- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets;
-
-/**
- Returns the camera that best fits the given coordinate bounds with some
- additional padding on each side, matching an existing camera as much as
- possible.
-
- @param camera The camera that the return camera should adhere to. All values
- on this camera will be manipulated except for pitch and direction.
- @param bounds The coordinate bounds to fit to the receiver’s viewport.
- @param insets The minimum padding (in screen points) that would be visible
- around the returned camera object if it were set as the receiver’s camera.
- @return A camera object centered on the same location as the coordinate bounds
- with zoom level as high (close to the ground) as possible while still
- including the entire coordinate bounds. The initial camera's pitch and
- direction will be honored.
- */
-- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets;
-
-/**
- Returns the camera that best fits the given shape with some additional padding
- on each side, matching an existing camera as much as possible.
-
- @param camera The camera that the return camera should adhere to. All values
- on this camera will be manipulated except for pitch and direction.
- @param shape The shape to fit to the receiver’s viewport.
- @param insets The minimum padding (in screen points) that would be visible
- around the returned camera object if it were set as the receiver’s camera.
- @return A camera object centered on the shape's center with zoom level as high
- (close to the ground) as possible while still including the entire shape.
- The initial camera's pitch and direction will be honored.
- */
-- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingShape:(MGLShape *)shape edgePadding:(NSEdgeInsets)insets;
-
-/**
- Returns the camera that best fits the given shape with some additional padding
- on each side while looking in the specified direction.
-
- @param shape The shape to fit to the receiver’s viewport.
- @param direction The direction of the viewport, measured in degrees clockwise
- from true north.
- @param insets The minimum padding (in screen points) that would be visible
- around the returned camera object if it were set as the receiver’s camera.
- @return A camera object centered on the shape's center with zoom level as high
- (close to the ground) as possible while still including the entire shape.
- The camera object uses the current pitch.
- */
-- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(NSEdgeInsets)insets;
-
-/**
- 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.
-
- Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setContentInset:animated:completionHandler:`
- method instead.
- */
-@property (nonatomic, assign) NSEdgeInsets contentInsets;
-
-/**
- Deprecated. Sets the distance from the edges of the map view’s frame to the
- edges of the map view’s logical viewport, with an optional transition animation.
-
- 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.
-
- To specify a completion handler to execute after the animation finishes, use
- the `-setContentInsets:animated:completionHandler:` method.
-
- @param contentInsets The new values to inset the content by.
- @param animated Specify `YES` if you want the map view to animate the change to
- the content insets or `NO` if you want the map to inset the content
- immediately.
- */
-- (void)setContentInsets:(NSEdgeInsets)contentInsets animated:(BOOL)animated __attribute__((deprecated("Use `-setContentInsets:animated:completionHandler:` instead.")));
-
-/**
- Sets the distance from the edges of the map view’s frame to the edges of the
- map view’s logical viewport with an optional transition animation and
- completion handler.
-
- 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.
-
- @param contentInsets The new values to inset the content by.
- @param animated Specify `YES` if you want the map view to animate the change to
- the content insets or `NO` if you want the map to inset the content
- immediately.
- @param completion The block executed after the animation finishes.
- */
-- (void)setContentInsets:(NSEdgeInsets)contentInsets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
-
-#pragma mark Configuring How the User Interacts with the Map
-
-/**
- A Boolean value that determines whether the user may zoom the map in and out,
- changing the zoom level.
-
- When this property is set to `YES`, the default, the user may zoom the map in
- and out by pinching two fingers, by using a scroll wheel on a traditional
- mouse, or by dragging the mouse cursor up and down while holding down the Shift
- key. When the receiver has focus, the user may also zoom by pressing the up and
- down arrow keys while holding down the Option key.
-
- This property controls only user interactions with the map. If you set the
- value of this property to `NO`, you may still change the map zoom
- programmatically.
- */
-@property (nonatomic, getter=isZoomEnabled) BOOL zoomEnabled;
-
-/**
- A Boolean value that determines whether the user may scroll around the map,
- changing the center coordinate.
-
- When this property is set to `YES`, the default, the user may scroll the map by
- swiping with two fingers or dragging the mouse cursor. When the receiver has
- focus, the user may also scroll around the map by pressing the arrow keys.
-
- This property controls only user interactions with the map. If you set the
- value of this property to `NO`, you may still change the map location
- programmatically.
- */
-@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
-
-/**
- A Boolean value that determines whether the user may rotate the map, changing
- the direction.
-
- When this property is set to `YES`, the default, the user may rotate the map by
- moving two fingers in a circular motion or by dragging the mouse cursor left
- and right while holding down the Option key. When the receiver has focus, the
- user may also zoom by pressing the left and right arrow keys while holding down
- the Option key.
-
- This property controls only user interactions with the map. If you set the
- value of this property to `NO`, you may still rotate the map programmatically.
- */
-@property (nonatomic, getter=isRotateEnabled) BOOL rotateEnabled;
-
-/**
- A Boolean value that determines whether the user may tilt of the map, changing
- the pitch.
-
- When this property is set to `YES`, the default, the user may rotate the map by
- dragging the mouse cursor up and down while holding down the Option key.
-
- This property controls only user interactions with the map. If you set the
- value of this property to `NO`, you may still change the pitch of the map
- programmatically.
- */
-@property (nonatomic, getter=isPitchEnabled) BOOL pitchEnabled;
-
-#pragma mark Annotating the Map
-
-/**
- The complete list of annotations associated with the receiver. (read-only)
-
- The objects in this array must adopt the `MGLAnnotation` protocol. If no
- annotations are associated with the map view, the value of this property is
- `nil`.
- */
-@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *annotations;
-
-/**
- Adds an annotation to the map view.
-
- @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
- cannot be added to the map view at this time. Nor can `MGLMultiPoint`
- objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any
- multipoint, multipolyline, multipolygon, or shape collection object that is
- specified is silently ignored.
-
- @param annotation The annotation object to add to the receiver. This object
- must conform to the `MGLAnnotation` protocol. The map view retains the
- annotation object.
- */
-- (void)addAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Adds an array of annotations to the map view.
-
- @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
- cannot be added to the map view at this time. Nor can `MGLMultiPoint`
- objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any
- multipoint, multipolyline, multipolygon, or shape collection objects that
- are specified are silently ignored.
-
- @param annotations An array of annotation objects. Each object in the array
- must conform to the `MGLAnnotation` protocol. The map view retains each
- individual annotation object.
- */
-- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
-
-/**
- The complete list of annotations associated with the receiver that are
- currently visible.
-
- The objects in this array must adopt the `MGLAnnotation` protocol. If no
- annotations are associated with the map view or if no annotations associated
- with the map view are currently visible, the value of this property is `nil`.
- */
-@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *visibleAnnotations;
-
-/**
- Removes an annotation from the map view, deselecting it if it is selected.
-
- Removing an annotation object dissociates it from the map view entirely,
- preventing it from being displayed on the map. Thus you would typically call
- this method only when you want to hide or delete a given annotation.
-
- @param annotation The annotation object to remove. This object must conform to
- the `MGLAnnotation` protocol.
- */
-- (void)removeAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Removes an array of annotations from the map view, deselecting any selected
- annotations in the array.
-
- Removing annotation objects dissociates them from the map view entirely,
- preventing them from being displayed on the map. Thus you would typically call
- this method only when you want to hide or delete the given annotations.
-
- @param annotations The array of annotation objects to remove. Objects in the
- array must conform to the `MGLAnnotation` protocol.
- */
-- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
-
-/**
- Returns a reusable annotation image object associated with its identifier.
-
- For performance reasons, you should generally reuse `MGLAnnotationImage`
- objects for identical-looking annotations in your map views. Dequeueing saves
- time and memory during performance-critical operations such as scrolling.
-
- @param identifier A string identifying the annotation image to be reused. This
- string is the same one you specify when initially returning the annotation
- image object using the `-mapView:imageForAnnotation:` method.
- @return An annotation image object with the given identifier, or `nil` if no
- such object exists in the reuse queue.
- */
-- (nullable MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier;
-
-/**
- Returns the list of annotations associated with the receiver that intersect with
- the given rectangle.
-
- @param rect A rectangle expressed in the map view’s coordinate system.
- @return An array of objects that adopt the `MGLAnnotation` protocol or `nil` if
- no annotations associated with the map view are currently visible in the
- rectangle.
- */
-- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect;
-
-#pragma mark Managing Annotation Selections
-
-/**
- The currently selected annotations.
-
- Assigning a new array to this property selects only the first annotation in the
- array.
-
- If the annotation is of type `MGLPointAnnotation` and is offscreen, the map is
- panned so that the annotation and its callout are brought just onscreen. The
- annotation is *not* centered within the viewport.
-
- @note In versions prior to `4.0.0` if the annotation was offscreen it was not
- selected.
- */
-@property (nonatomic, copy) NSArray<id <MGLAnnotation>> *selectedAnnotations;
-
-/**
- Selects an annotation and displays a callout popover for it.
-
- If the annotation is of type `MGLPointAnnotation` and is offscreen, the map is
- panned so that the annotation and its callout are brought just onscreen. The
- annotation is *not* centered within the viewport.
-
- @param annotation The annotation object to select.
- */
-- (void)selectAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Deselects an annotation and hides its callout popover.
-
- @param annotation The annotation object to deselect.
- */
-- (void)deselectAnnotation:(nullable id <MGLAnnotation>)annotation;
-
-/**
- A common view controller for managing a callout popover’s content view.
-
- Like any instance of `NSPopover`, an annotation callout manages its contents
- with a view controller. The annotation object is the view controller’s
- represented object. This means that you can bind controls in the view
- controller’s content view to KVO-compliant properties of the annotation object,
- such as `title` and `subtitle`.
-
- This property defines a common view controller that is used for every
- annotation’s callout view. If you set this property to `nil`, a default view
- controller will be used that manages a simple title label and subtitle label.
- If you need distinct view controllers for different annotations, the map view’s
- delegate should implement `-mapView:calloutViewControllerForAnnotation:`
- instead.
- */
-@property (nonatomic, strong, null_resettable) IBOutlet NSViewController *calloutViewController;
-
-#pragma mark Finding Annotations
-
-/**
- Returns a point annotation located at the given point.
-
- @param point A point in the view’s coordinate system.
- @return A point annotation whose annotation image coincides with the point. If
- multiple point annotations coincide with the point, the return value is the
- annotation that would be selected if the user clicks at this point.
- */
-- (id <MGLAnnotation>)annotationAtPoint:(NSPoint)point;
-
-#pragma mark Overlaying the Map
-
-/**
- The complete list of overlays associated with the receiver. (read-only)
-
- The objects in this array must adopt the `MGLOverlay` protocol. If no
- overlays are associated with the map view, the value of this property is
- empty array.
- */
-@property (nonatomic, readonly, nonnull) NSArray<id <MGLOverlay>> *overlays;
-
-/**
- Adds a single overlay to the map.
-
- To remove an overlay from a map, use the `-removeOverlay:` method.
-
- @param overlay The overlay object to add. This object must conform to the
- `MGLOverlay` protocol.
- */
-- (void)addOverlay:(id <MGLOverlay>)overlay;
-
-/**
- Adds an array of overlays to the map.
-
- To remove multiple overlays from a map, use the `-removeOverlays:` method.
-
- @param overlays An array of objects, each of which must conform to the
- `MGLOverlay` protocol.
- */
-- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays;
-
-/**
- Removes a single overlay from the map.
-
- If the specified overlay is not currently associated with the map view, this
- method does nothing.
-
- @param overlay The overlay object to remove.
- */
-- (void)removeOverlay:(id <MGLOverlay>)overlay;
-
-/**
- Removes an array of overlays from the map.
-
- If a given overlay object is not associated with the map view, it is ignored.
-
- @param overlays An array of objects, each of which conforms to the `MGLOverlay`
- protocol.
- */
-- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays;
-
-#pragma mark Accessing the Underlying Map Data
-
-/**
- Returns an array of rendered map features that intersect with a given point.
-
- This method may return features from any of the map’s style layers. To restrict
- the search to a particular layer or layers, use the
- `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
- information about searching for map features, see that method’s documentation.
-
- @param point A point expressed in the map view’s coordinate system.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
-
-/**
- Returns an array of rendered map features that intersect with a given point,
- restricted to the given style layers.
-
- This method returns all the intersecting features from the specified layers. To
- filter the returned features, use the
- `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:predicate:` method. For
- more information about searching for map features, see that method’s
- documentation.
-
- @param point A point expressed in the map view’s coordinate system.
- @param styleLayerIdentifiers A set of strings that correspond to the names of
- layers defined in the current style. Only the features contained in these
- layers are included in the returned array.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
-
-/**
- Returns an array of rendered map features that intersect with a given point,
- restricted to the given style layers and filtered by the given predicate.
-
- Each object in the returned array represents a feature rendered by the
- current style and provides access to attributes specified by the relevant map
- content sources. The returned array includes features loaded by
- `MGLShapeSource` and `MGLVectorTileSource` objects but does not include
- anything from `MGLRasterTileSource` objects, or from video or canvas sources,
- which are unsupported by this SDK.
-
- The returned features are drawn by a style layer in the current style. For
- example, suppose the current style uses the
- <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
- but none of the specified style layers includes features that have the `maki`
- property set to `bus`. If you pass a point corresponding to the location of a
- bus stop into this method, the bus stop feature does not appear in the
- resulting array. On the other hand, if the style does include bus stops, an
- `MGLFeature` object representing that bus stop is returned and its
- `attributes` dictionary has the `maki` key set to `bus` (along with other
- attributes). The dictionary contains only the attributes provided by the
- tile source; it does not include computed attribute values or rules about how
- the feature is rendered by the current style.
-
- The returned array is sorted by z-order, starting with the topmost rendered
- feature and ending with the bottommost rendered feature. A feature that is
- rendered multiple times due to wrapping across the antimeridian at low zoom
- levels is included only once, subject to the caveat that follows.
-
- Features come from tiled vector data or GeoJSON data that is converted to tiles
- internally, so feature geometries are clipped at tile boundaries and features
- may appear duplicated across tiles. For example, suppose the specified point
- lies along a road that spans the screen. The resulting array includes those
- parts of the road that lie within the map tile that contain the specified
- point, even if the road extends into other tiles.
-
- To find out the layer names in a particular style, view the style in
- <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
- Only visible features are returned. To obtain features regardless of
- visibility, use the
- `-[MGLVectorTileSource featuresInSourceLayersWithIdentifiers:predicate:]` and
- `-[MGLShapeSource featuresMatchingPredicate:]` methods on the relevant sources.
-
- @note Layer identifiers are not guaranteed to exist across styles or different
- versions of the same style. Applications that use this API must first set
- the style URL to an explicitly versioned style using a convenience method
- like `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`. This
- approach also avoids layer identifer name changes that will occur in the
- default style’s layers over time.
-
- @param point A point expressed in the map view’s coordinate system.
- @param styleLayerIdentifiers A set of strings that correspond to the names of
- layers defined in the current style. Only the features contained in these
- layers are included in the returned array.
- @param predicate A predicate to filter the returned features.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
-
-/**
- Returns an array of rendered map features that intersect with the given
- rectangle.
-
- This method may return features from any of the map’s style layers. To restrict
- the search to a particular layer or layers, use the
- `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
- information about searching for map features, see that method’s documentation.
-
- @param rect A rectangle expressed in the map view’s coordinate system.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
-
-/**
- Returns an array of rendered map features that intersect with the given
- rectangle, restricted to the given style layers.
-
- This method returns all the intersecting features from the specified layers. To
- filter the returned features, use the
- `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:predicate:` method. For
- more information about searching for map features, see that method’s
- documentation.
-
- @param rect A rectangle expressed in the map view’s coordinate system.
- @param styleLayerIdentifiers A set of strings that correspond to the names of
- layers defined in the current style. Only the features contained in these
- layers are included in the returned array.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
-
-/**
- Returns an array of rendered map features that intersect with the given
- rectangle, restricted to the given style layers and filtered by the given
- predicate.
-
- Each object in the returned array represents a feature rendered by the
- current style and provides access to attributes specified by the relevant map
- content sources. The returned array includes features loaded by
- `MGLShapeSource` and `MGLVectorTileSource` objects but does not include
- anything from `MGLRasterTileSource` objects, or from video or canvas sources,
- which are unsupported by this SDK.
-
- The returned features are drawn by a style layer in the current style. For
- example, suppose the current style uses the
- <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
- but none of the specified style layers includes features that have the `maki`
- property set to `bus`. If you pass a rectangle containing the location of a bus
- stop into this method, the bus stop feature does not appear in the resulting
- array. On the other hand, if the style does include bus stops, an `MGLFeature`
- object representing that bus stop is returned and its `attributes` dictionary
- has the `maki` key set to `bus` (along with other attributes). The dictionary
- contains only the attributes provided by the tile source; it does not include
- computed attribute values or rules about how the feature is rendered by the
- current style.
-
- The returned array is sorted by z-order, starting with the topmost rendered
- feature and ending with the bottommost rendered feature. A feature that is
- rendered multiple times due to wrapping across the antimeridian at low zoom
- levels is included only once, subject to the caveat that follows.
-
- Features come from tiled vector data or GeoJSON data that is converted to tiles
- internally, so feature geometries are clipped at tile boundaries and features
- may appear duplicated across tiles. For example, suppose the specified
- rectangle intersects with a road that spans the screen. The resulting array
- includes those parts of the road that lie within the map tiles covering the
- specified rectangle, even if the road extends into other tiles. The portion of
- the road within each map tile is included individually.
-
- To find out the layer names in a particular style, view the style in
- <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
- Only visible features are returned. To obtain features regardless of
- visibility, use the
- `-[MGLVectorTileSource featuresInSourceLayersWithIdentifiers:predicate:]` and
- `-[MGLShapeSource featuresMatchingPredicate:]` methods on the relevant sources.
-
- @note Layer identifiers are not guaranteed to exist across styles or different
- versions of the same style. Applications that use this API must first set
- the style URL to an explicitly versioned style using a convenience method
- like `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`. This
- approach also avoids layer identifer name changes that will occur in the
- default style’s layers over time.
-
- @param rect A rectangle expressed in the map view’s coordinate system.
- @param styleLayerIdentifiers A set of strings that correspond to the names of
- layers defined in the current style. Only the features contained in these
- layers are included in the returned array.
- @param predicate A predicate to filter the returned features.
- @return An array of objects conforming to the `MGLFeature` protocol that
- represent features in the sources used by the current style.
- */
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
-
-#pragma mark Converting Geographic Coordinates
-
-/**
- Converts a geographic coordinate to a point in the given view’s coordinate
- system.
-
- @param coordinate The geographic coordinate to convert.
- @param view The view in whose coordinate system the returned point should be
- expressed. If this parameter is `nil`, the returned point is expressed in
- the window’s coordinate system. If `view` is not `nil`, it must belong to
- the same window as the map view.
- @return The point (in the appropriate view or window coordinate system)
- corresponding to the given geographic coordinate.
- */
-- (NSPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable NSView *)view;
-
-/**
- Converts a point in the given view’s coordinate system to a geographic
- coordinate.
-
- @param point The point to convert.
- @param view The view in whose coordinate system the point is expressed.
- @return The geographic coordinate at the given point.
- */
-- (CLLocationCoordinate2D)convertPoint:(NSPoint)point toCoordinateFromView:(nullable NSView *)view;
-
-/**
- Converts a geographic bounding box to a rectangle in the given view’s
- coordinate system.
-
- To bring both sides of the antimeridian or international date line into view,
- specify some longitudes less than −180 degrees or greater than 180 degrees. For
- example, to show both Tokyo and San Francisco simultaneously, you could set the
- visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310).
-
- @param bounds The geographic bounding box to convert.
- @param view The view in whose coordinate system the returned rectangle should
- be expressed. If this parameter is `nil`, the returned rectangle is
- expressed in the window’s coordinate system. If `view` is not `nil`, it must
- belong to the same window as the map view.
- */
-- (NSRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable NSView *)view;
-
-/**
- Converts a rectangle in the given view’s coordinate system to a geographic
- bounding box.
-
- If a longitude is less than −180 degrees or greater than 180 degrees, the
- bounding box straddles the antimeridian or international date line.
-
- @param rect The rectangle to convert.
- @param view The view in whose coordinate system the rectangle is expressed.
- @return The geographic bounding box coextensive with the given rectangle.
- */
-- (MGLCoordinateBounds)convertRect:(NSRect)rect toCoordinateBoundsFromView:(nullable NSView *)view;
-
-/**
- Returns the distance spanned by one point in the map view’s coordinate system
- at the given latitude and current zoom level.
-
- The distance between points decreases as the latitude approaches the poles.
- This relationship parallels the relationship between longitudinal coordinates
- at different latitudes.
-
- @param latitude The latitude of the geographic coordinate represented by the
- point.
- @return The distance in meters spanned by a single point.
- */
-- (CLLocationDistance)metersPerPointAtLatitude:(CLLocationDegrees)latitude;
-
-#pragma mark Giving Feedback to Improve the Map
-
-/**
- Opens one or more webpages in the default Web browser in which the user can
- provide feedback about the map data.
-
- You should add a menu item to the Help menu of your application that invokes
- this method. Title it “Improve This Map” or similar. Set its target to the
- first responder and its action to `giveFeedback:`.
-
- This map view searches the current style’s sources for webpages to open.
- Specifically, each source’s tile set has an `attribution` property containing
- HTML code; if an <code>&lt;a></code> tag (link) within that code has an
- <code>class</code> attribute set to <code>mapbox-improve-map</code>, its
- <code>href</code> attribute defines the URL to open. Such links are omitted
- from the attribution view.
- */
-- (IBAction)giveFeedback:(id)sender;
-
-#pragma mark Debugging the Map
-
-/**
- The options that determine which debugging aids are shown on the map.
-
- These options are all disabled by default and should remain disabled in
- released software for performance and aesthetic reasons.
- */
-@property (nonatomic) MGLMapDebugMaskOptions debugMask;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
deleted file mode 100644
index aec9cea0bc..0000000000
--- a/platform/macos/src/MGLMapView.mm
+++ /dev/null
@@ -1,3081 +0,0 @@
-#import "MGLMapView_Private.h"
-
-#import "MGLAttributionButton.h"
-#import "MGLCompassCell.h"
-#import "MGLStyle.h"
-#import "MGLRendererFrontend.h"
-#import "MGLRendererConfiguration.h"
-
-#import "MGLAnnotationImage_Private.h"
-#import "MGLAttributionInfo_Private.h"
-#import "MGLFeature_Private.h"
-#import "MGLFoundation_Private.h"
-#import "MGLGeometry_Private.h"
-#import "MGLMultiPoint_Private.h"
-#import "MGLOfflineStorage_Private.h"
-#import "MGLStyle_Private.h"
-#import "MGLShape_Private.h"
-
-#import "MGLAccountManager.h"
-#import "MGLMapCamera.h"
-#import "MGLPolygon.h"
-#import "MGLPolyline.h"
-#import "MGLAnnotationImage.h"
-#import "MGLMapViewDelegate.h"
-#import "MGLImageSource.h"
-
-#import <mbgl/map/map.hpp>
-#import <mbgl/map/map_options.hpp>
-#import <mbgl/style/style.hpp>
-#import <mbgl/annotation/annotation.hpp>
-#import <mbgl/map/camera.hpp>
-#import <mbgl/storage/reachability.h>
-#import <mbgl/style/image.hpp>
-#import <mbgl/renderer/renderer.hpp>
-#import <mbgl/storage/network_status.hpp>
-#import <mbgl/storage/resource_options.hpp>
-#import <mbgl/math/wrap.hpp>
-#import <mbgl/util/constants.hpp>
-#import <mbgl/util/chrono.hpp>
-#import <mbgl/util/exception.hpp>
-#import <mbgl/util/run_loop.hpp>
-#import <mbgl/util/string.hpp>
-#import <mbgl/util/projection.hpp>
-
-#import <map>
-#import <unordered_map>
-#import <unordered_set>
-
-#import "MGLMapView+Impl.h"
-#import "NSBundle+MGLAdditions.h"
-#import "NSDate+MGLAdditions.h"
-#import "NSProcessInfo+MGLAdditions.h"
-#import "NSException+MGLAdditions.h"
-#import "NSString+MGLAdditions.h"
-#import "NSURL+MGLAdditions.h"
-#import "NSColor+MGLAdditions.h"
-#import "NSImage+MGLAdditions.h"
-#import "NSPredicate+MGLPrivateAdditions.h"
-#import "MGLLoggingConfiguration_Private.h"
-#import "MGLNetworkIntegrationManager.h"
-
-class MGLAnnotationContext;
-
-/// Distance from the edge of the view to ornament views (logo, attribution, etc.).
-const CGFloat MGLOrnamentPadding = 12;
-
-/// Alpha value of the ornament views (logo, attribution, etc.).
-const CGFloat MGLOrnamentOpacity = 0.9;
-
-/// Default duration for programmatic animations.
-const NSTimeInterval MGLAnimationDuration = 0.3;
-
-/// Distance in points that a single press of the panning keyboard shortcut pans the map by.
-const CGFloat MGLKeyPanningIncrement = 150;
-
-/// Degrees that a single press of the rotation keyboard shortcut rotates the map by.
-const CLLocationDegrees MGLKeyRotationIncrement = 25;
-
-/// Key for the user default that, when true, causes the map view to zoom in and out on scroll wheel events.
-NSString * const MGLScrollWheelZoomsMapViewDefaultKey = @"MGLScrollWheelZoomsMapView";
-
-/// Reuse identifier and file name of the default point annotation image.
-static NSString * const MGLDefaultStyleMarkerSymbolName = @"default_marker";
-
-/// Prefix that denotes a sprite installed by MGLMapView, to avoid collisions
-/// with style-defined sprites.
-static NSString * const MGLAnnotationSpritePrefix = @"com.mapbox.sprites.";
-
-/// Slop area around the hit testing point, allowing for imprecise annotation selection.
-const CGFloat MGLAnnotationImagePaddingForHitTest = 4;
-
-/// Distance from the callout’s anchor point to the annotation it points to.
-const CGFloat MGLAnnotationImagePaddingForCallout = 4;
-
-/// Padding to edge of view that an offscreen annotation must have when being brought onscreen (by being selected)
-const NSEdgeInsets MGLMapViewOffscreenAnnotationPadding = NSEdgeInsetsMake(-30.0f, -30.0f, -30.0f, -30.0f);
-
-/// Unique identifier representing a single annotation in mbgl.
-typedef uint64_t MGLAnnotationTag;
-
-/// An indication that the requested annotation was not found or is nonexistent.
-enum { MGLAnnotationTagNotFound = UINT64_MAX };
-
-/// Mapping from an annotation tag to metadata about that annotation, including
-/// the annotation itself.
-typedef std::unordered_map<MGLAnnotationTag, MGLAnnotationContext> MGLAnnotationTagContextMap;
-
-/// Mapping from an annotation object to an annotation tag.
-typedef std::map<id<MGLAnnotation>, MGLAnnotationTag> MGLAnnotationObjectTagMap;
-
-/// Returns an NSImage for the default marker image.
-NSImage *MGLDefaultMarkerImage() {
- NSString *path = [[NSBundle mgl_frameworkBundle] pathForResource:MGLDefaultStyleMarkerSymbolName
- ofType:@"pdf"];
- return [[NSImage alloc] initWithContentsOfFile:path];
-}
-
-/// Converts a media timing function into a unit bezier object usable in mbgl.
-mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function) {
- if (!function) {
- function = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
- }
- float p1[2], p2[2];
- [function getControlPointAtIndex:0 values:p1];
- [function getControlPointAtIndex:1 values:p2];
- return { p1[0], p1[1], p2[0], p2[1] };
-}
-
-/// Lightweight container for metadata about an annotation, including the annotation itself.
-class MGLAnnotationContext {
-public:
- id <MGLAnnotation> annotation;
- /// The annotation’s image’s reuse identifier.
- NSString *imageReuseIdentifier;
-};
-
-@interface MGLMapView () <NSPopoverDelegate, MGLMultiPointDelegate, NSGestureRecognizerDelegate>
-
-@property (nonatomic, readwrite) NSSegmentedControl *zoomControls;
-@property (nonatomic, readwrite) NSSlider *compass;
-@property (nonatomic, readwrite) NSImageView *logoView;
-@property (nonatomic, readwrite) NSView *attributionView;
-
-@property (nonatomic, readwrite) MGLStyle *style;
-
-/// Mapping from reusable identifiers to annotation images.
-@property (nonatomic) NSMutableDictionary<NSString *, MGLAnnotationImage *> *annotationImagesByIdentifier;
-/// Currently shown popover representing the selected annotation.
-@property (nonatomic) NSPopover *calloutForSelectedAnnotation;
-
-@property (nonatomic, readwrite, getter=isDormant) BOOL dormant;
-
-@end
-
-@implementation MGLMapView {
- /// Cross-platform map view controller.
- mbgl::Map *_mbglMap;
- std::unique_ptr<MGLMapViewImpl> _mbglView;
- std::unique_ptr<MGLRenderFrontend> _rendererFrontend;
-
- NSPanGestureRecognizer *_panGestureRecognizer;
- NSMagnificationGestureRecognizer *_magnificationGestureRecognizer;
- NSRotationGestureRecognizer *_rotationGestureRecognizer;
- NSClickGestureRecognizer *_singleClickRecognizer;
- double _zoomAtBeginningOfGesture;
- CLLocationDirection _directionAtBeginningOfGesture;
- CGFloat _pitchAtBeginningOfGesture;
- BOOL _didHideCursorDuringGesture;
-
- MGLAnnotationTagContextMap _annotationContextsByAnnotationTag;
- MGLAnnotationObjectTagMap _annotationTagsByAnnotation;
- MGLAnnotationTag _selectedAnnotationTag;
- MGLAnnotationTag _lastSelectedAnnotationTag;
- /// Size of the rectangle formed by unioning the maximum slop area around every annotation image.
- NSSize _unionedAnnotationImageSize;
- std::vector<MGLAnnotationTag> _annotationsNearbyLastClick;
- /// True if any annotations that have tooltips have been installed.
- BOOL _wantsToolTipRects;
- /// True if any annotation images that have custom cursors have been installed.
- BOOL _wantsCursorRects;
- /// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending.
- BOOL _isChangingAnnotationLayers;
-
- // Cached checks for delegate method implementations that may be called from
- // MGLMultiPointDelegate methods.
-
- BOOL _delegateHasAlphasForShapeAnnotations;
- BOOL _delegateHasStrokeColorsForShapeAnnotations;
- BOOL _delegateHasFillColorsForShapeAnnotations;
- BOOL _delegateHasLineWidthsForShapeAnnotations;
-
- /// True if the current process is the Interface Builder designable
- /// renderer. When drawing the designable, the map is paused, so any call to
- /// it may hang the process.
- BOOL _isTargetingInterfaceBuilder;
- CLLocationDegrees _pendingLatitude;
- CLLocationDegrees _pendingLongitude;
-
- /// True if the view is currently printing itself.
- BOOL _isPrinting;
-
- /// reachability instance
- MGLReachability *_reachability;
-}
-
-#pragma mark Lifecycle
-
-+ (void)initialize {
- if (self == [MGLMapView class]) {
- [[NSUserDefaults standardUserDefaults] registerDefaults:@{
- MGLScrollWheelZoomsMapViewDefaultKey: @NO,
- }];
- }
-}
-
-- (instancetype)initWithFrame:(NSRect)frameRect {
- if (self = [super initWithFrame:frameRect]) {
- MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class]));
- MGLLogDebug(@"Initializing frame: %@", NSStringFromRect(frameRect));
- [self commonInit];
- self.styleURL = nil;
- MGLLogInfo(@"Finalizing %@ initialization.", NSStringFromClass([self class]));
- }
- return self;
-}
-
-- (instancetype)initWithFrame:(NSRect)frame styleURL:(nullable NSURL *)styleURL {
- if (self = [super initWithFrame:frame]) {
- MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class]));
- MGLLogDebug(@"Initializing frame: %@ styleURL: %@", NSStringFromRect(frame), styleURL);
- [self commonInit];
- self.styleURL = styleURL;
- MGLLogInfo(@"Finalizing %@ initialization.", NSStringFromClass([self class]));
- }
- return self;
-}
-
-- (instancetype)initWithCoder:(nonnull NSCoder *)decoder {
- if (self = [super initWithCoder:decoder]) {
- MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class]));
- [self commonInit];
- MGLLogInfo(@"Finalizing %@ initialization.", NSStringFromClass([self class]));
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
-
- // If the Style URL inspectable was not set, make sure to go through
- // -setStyleURL: to load the default style.
- if (_mbglMap->getStyle().getURL().empty()) {
- self.styleURL = nil;
- }
-}
-
-+ (NSArray *)restorableStateKeyPaths {
- return @[@"camera", @"debugMask"];
-}
-
-- (void)commonInit {
- MGLNativeNetworkManager.sharedManager.delegate = MGLNetworkIntegrationManager.sharedManager;
- _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
-
- // Set up cross-platform controllers and resources.
- _mbglView = MGLMapViewImpl::Create(self);
-
- // Delete the pre-offline ambient cache at
- // ~/Library/Caches/com.mapbox.MapboxGL/cache.db.
- NSURL *cachesDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
- inDomain:NSUserDomainMask
- appropriateForURL:nil
- create:NO
- error:nil];
- cachesDirectoryURL = [cachesDirectoryURL URLByAppendingPathComponent:@"com.mapbox.MapboxGL"];
- NSURL *legacyCacheURL = [cachesDirectoryURL URLByAppendingPathComponent:@"cache.db"];
- [[NSFileManager defaultManager] removeItemAtURL:legacyCacheURL error:NULL];
-
- MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
-
- auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName);
- BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
- _rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend(), true);
-
- mbgl::MapOptions mapOptions;
- mapOptions.withMapMode(mbgl::MapMode::Continuous)
- .withSize(self.size)
- .withPixelRatio(config.scaleFactor)
- .withConstrainMode(mbgl::ConstrainMode::None)
- .withViewportMode(mbgl::ViewportMode::Default)
- .withCrossSourceCollisions(enableCrossSourceCollisions);
-
- mbgl::ResourceOptions resourceOptions;
- resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath])
- .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String);
-
- _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, mapOptions, resourceOptions);
-
- // Notify map object when network reachability status changes.
- _reachability = [MGLReachability reachabilityForInternetConnection];
- _reachability.reachableBlock = ^(MGLReachability *) {
- mbgl::NetworkStatus::Reachable();
- };
- [_reachability startNotifier];
-
- // Install ornaments and gesture recognizers.
- [self installZoomControls];
- [self installCompass];
- [self installLogoView];
- [self installAttributionView];
- [self installGestureRecognizers];
-
- // Set up annotation management and selection state.
- _annotationImagesByIdentifier = [NSMutableDictionary dictionary];
- _annotationContextsByAnnotationTag = {};
- _annotationTagsByAnnotation = {};
- _selectedAnnotationTag = MGLAnnotationTagNotFound;
- _lastSelectedAnnotationTag = MGLAnnotationTagNotFound;
- _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->getBounds().minZoom;
- _mbglMap->jumpTo(options);
- _pendingLatitude = NAN;
- _pendingLongitude = NAN;
-}
-
-- (mbgl::Size)size {
- // check for minimum texture size supported by OpenGL ES 2.0
- //
- CGSize size = CGSizeMake(MAX(self.bounds.size.width, 64), MAX(self.bounds.size.height, 64));
- return { static_cast<uint32_t>(size.width),
- static_cast<uint32_t>(size.height) };
-}
-
-- (mbgl::Size)framebufferSize {
- NSRect bounds = [self convertRectToBacking:self.bounds];
- return { static_cast<uint32_t>(bounds.size.width), static_cast<uint32_t>(bounds.size.height) };
-}
-
-/// Adds zoom controls to the lower-right corner.
-- (void)installZoomControls {
- _zoomControls = [[NSSegmentedControl alloc] initWithFrame:NSZeroRect];
- _zoomControls.wantsLayer = YES;
- _zoomControls.layer.opacity = MGLOrnamentOpacity;
- [(NSSegmentedCell *)_zoomControls.cell setTrackingMode:NSSegmentSwitchTrackingMomentary];
- _zoomControls.continuous = YES;
- _zoomControls.segmentCount = 2;
- [_zoomControls setLabel:NSLocalizedStringWithDefaultValue(@"ZOOM_OUT_LABEL", nil, nil, @"−", @"Label of Zoom Out button; U+2212 MINUS SIGN") forSegment:0];
- [(NSSegmentedCell *)_zoomControls.cell setTag:0 forSegment:0];
- [(NSSegmentedCell *)_zoomControls.cell setToolTip:NSLocalizedStringWithDefaultValue(@"ZOOM_OUT_TOOLTIP", nil, nil, @"Zoom Out", @"Tooltip of Zoom Out button") forSegment:0];
- [_zoomControls setLabel:NSLocalizedStringWithDefaultValue(@"ZOOM_IN_LABEL", nil, nil, @"+", @"Label of Zoom In button") forSegment:1];
- [(NSSegmentedCell *)_zoomControls.cell setTag:1 forSegment:1];
- [(NSSegmentedCell *)_zoomControls.cell setToolTip:NSLocalizedStringWithDefaultValue(@"ZOOM_IN_TOOLTIP", nil, nil, @"Zoom In", @"Tooltip of Zoom In button") forSegment:1];
- _zoomControls.target = self;
- _zoomControls.action = @selector(zoomInOrOut:);
- _zoomControls.controlSize = NSRegularControlSize;
- [_zoomControls sizeToFit];
- _zoomControls.translatesAutoresizingMaskIntoConstraints = NO;
- [self addSubview:_zoomControls];
-}
-
-/// Adds a rudimentary compass control to the lower-right corner.
-- (void)installCompass {
- _compass = [[NSSlider alloc] initWithFrame:NSZeroRect];
- _compass.wantsLayer = YES;
- _compass.layer.opacity = MGLOrnamentOpacity;
- _compass.cell = [[MGLCompassCell alloc] init];
- _compass.continuous = YES;
- _compass.target = self;
- _compass.action = @selector(rotate:);
- [_compass sizeToFit];
- _compass.translatesAutoresizingMaskIntoConstraints = NO;
- [self addSubview:_compass];
-}
-
-/// Adds a Mapbox logo to the lower-left corner.
-- (void)installLogoView {
- _logoView = [[NSImageView alloc] initWithFrame:NSZeroRect];
- _logoView.wantsLayer = YES;
- NSImage *logoImage = [[NSImage alloc] initWithContentsOfFile:
- [[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]];
- // Account for the image’s built-in padding when aligning other controls to the logo.
- logoImage.alignmentRect = NSOffsetRect(logoImage.alignmentRect, 0, 3);
- _logoView.image = logoImage;
- _logoView.translatesAutoresizingMaskIntoConstraints = NO;
- _logoView.accessibilityTitle = NSLocalizedStringWithDefaultValue(@"MAP_A11Y_TITLE", nil, nil, @"Mapbox", @"Accessibility title");
- [self addSubview:_logoView];
-}
-
-/// Adds legally required map attribution to the lower-left corner.
-- (void)installAttributionView {
- [_attributionView removeFromSuperview];
- _attributionView = [[NSView alloc] initWithFrame:NSZeroRect];
- _attributionView.wantsLayer = YES;
-
- // Make the background and foreground translucent to be unobtrusive.
- _attributionView.layer.opacity = 0.6;
-
- // Blur the background to prevent text underneath the view from running into
- // the text in the view, rendering it illegible.
- CIFilter *attributionBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
- [attributionBlurFilter setDefaults];
-
- // Brighten the background. This is similar to applying a translucent white
- // background on the view, but the effect is a bit more subtle and works
- // well with the blur above.
- CIFilter *attributionColorFilter = [CIFilter filterWithName:@"CIColorControls"];
- [attributionColorFilter setDefaults];
- [attributionColorFilter setValue:@(0.1) forKey:kCIInputBrightnessKey];
-
- // Apply the background effects and a standard button corner radius.
- _attributionView.backgroundFilters = @[attributionColorFilter, attributionBlurFilter];
- _attributionView.layer.cornerRadius = 4;
-
- _attributionView.translatesAutoresizingMaskIntoConstraints = NO;
- [self addSubview:_attributionView];
- [self updateAttributionView];
-}
-
-/// Adds gesture recognizers for manipulating the viewport and selecting annotations.
-- (void)installGestureRecognizers {
- _scrollEnabled = YES;
- _zoomEnabled = YES;
- _rotateEnabled = YES;
- _pitchEnabled = YES;
-
- _panGestureRecognizer = [[NSPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
- _panGestureRecognizer.delaysKeyEvents = YES;
- [self addGestureRecognizer:_panGestureRecognizer];
-
- _singleClickRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleClickGesture:)];
- _singleClickRecognizer.delaysPrimaryMouseButtonEvents = NO;
- _singleClickRecognizer.delegate = self;
- [self addGestureRecognizer:_singleClickRecognizer];
-
- NSClickGestureRecognizer *rightClickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightClickGesture:)];
- rightClickGestureRecognizer.buttonMask = 0x2;
- [self addGestureRecognizer:rightClickGestureRecognizer];
-
- NSClickGestureRecognizer *doubleClickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleClickGesture:)];
- doubleClickGestureRecognizer.numberOfClicksRequired = 2;
- doubleClickGestureRecognizer.delaysPrimaryMouseButtonEvents = NO;
- [self addGestureRecognizer:doubleClickGestureRecognizer];
-
- _magnificationGestureRecognizer = [[NSMagnificationGestureRecognizer alloc] initWithTarget:self action:@selector(handleMagnificationGesture:)];
- [self addGestureRecognizer:_magnificationGestureRecognizer];
-
- _rotationGestureRecognizer = [[NSRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotationGesture:)];
- [self addGestureRecognizer:_rotationGestureRecognizer];
-}
-
-/// Updates the attribution view to reflect the sources used. For now, this is
-/// hard-coded to the standard Mapbox and OpenStreetMap attribution.
-- (void)updateAttributionView {
- NSView *attributionView = self.attributionView;
- for (NSView *button in attributionView.subviews) {
- [button removeConstraints:button.constraints];
- }
- attributionView.subviews = @[];
- [attributionView removeConstraints:attributionView.constraints];
-
- // Make the whole string mini by default.
- // Force links to be black, because the default blue is distracting.
- CGFloat miniSize = [NSFont systemFontSizeForControlSize:NSMiniControlSize];
- NSArray *attributionInfos = [self.style attributionInfosWithFontSize:miniSize linkColor:[NSColor blackColor]];
- for (MGLAttributionInfo *info in attributionInfos) {
- // Feedback links are added to the Help menu.
- if (info.feedbackLink) {
- continue;
- }
-
- // For each attribution, add a borderless button that responds to clicks
- // and feels like a hyperlink.
- NSButton *button = [[MGLAttributionButton alloc] initWithAttributionInfo:info];
- button.controlSize = NSMiniControlSize;
- button.translatesAutoresizingMaskIntoConstraints = NO;
-
- // Set the new button flush with the buttom of the container and to the
- // right of the previous button, with standard spacing. If there is no
- // previous button, align to the container instead.
- NSView *previousView = attributionView.subviews.lastObject;
- [attributionView addSubview:button];
- [attributionView addConstraint:
- [NSLayoutConstraint constraintWithItem:button
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:attributionView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:0]];
- [attributionView addConstraint:
- [NSLayoutConstraint constraintWithItem:button
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:previousView ? previousView : attributionView
- attribute:previousView ? NSLayoutAttributeTrailing : NSLayoutAttributeLeading
- multiplier:1
- constant:8]];
- [attributionView addConstraint:
- [NSLayoutConstraint constraintWithItem:button
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:attributionView
- attribute:NSLayoutAttributeTop
- multiplier:1
- constant:0]];
- }
-
- if (attributionInfos.count) {
- [attributionView addConstraint:
- [NSLayoutConstraint constraintWithItem:attributionView
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:attributionView.subviews.lastObject
- attribute:NSLayoutAttributeTrailing
- multiplier:1
- constant:8]];
- }
-}
-
-- (void)dealloc {
-
- [_reachability stopNotifier];
-
-
- [self.window removeObserver:self forKeyPath:@"contentLayoutRect"];
- [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"];
-
- // Close any annotation callout immediately.
- [self.calloutForSelectedAnnotation close];
- self.calloutForSelectedAnnotation = nil;
-
- // Removing the annotations unregisters any outstanding KVO observers.
- [self removeAnnotations:self.annotations];
-
- if (_mbglMap) {
- delete _mbglMap;
- _mbglMap = nullptr;
- }
- _mbglView.reset();
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(__unused NSDictionary *)change context:(void *)context {
- if ([keyPath isEqualToString:@"contentLayoutRect"] ||
- [keyPath isEqualToString:@"titlebarAppearsTransparent"]) {
- [self adjustContentInsets];
- } else if ([keyPath isEqualToString:@"coordinate"] &&
- [object conformsToProtocol:@protocol(MGLAnnotation)] &&
- ![object isKindOfClass:[MGLMultiPoint class]]) {
- id <MGLAnnotation> annotation = object;
- MGLAnnotationTag annotationTag = (MGLAnnotationTag)(NSUInteger)context;
- // We can get here because a subclass registered itself as an observer
- // of the coordinate key path of a non-multipoint annotation but failed
- // to handle the change. This check deters us from treating the
- // subclass’s context as an annotation tag. If the context happens to
- // match a valid annotation tag, the annotation will be unnecessarily
- // but safely updated.
- if (annotation == [self annotationWithTag:annotationTag]) {
- const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(annotation.coordinate);
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, annotationImage.styleIconIdentifier.UTF8String ?: "" });
- [self updateAnnotationCallouts];
- }
- } else if ([keyPath isEqualToString:@"coordinates"] &&
- [object isKindOfClass:[MGLMultiPoint class]]) {
- MGLMultiPoint *annotation = object;
- MGLAnnotationTag annotationTag = (MGLAnnotationTag)(NSUInteger)context;
- // We can get here because a subclass registered itself as an observer
- // of the coordinates key path of a multipoint annotation but failed
- // to handle the change. This check deters us from treating the
- // subclass’s context as an annotation tag. If the context happens to
- // match a valid annotation tag, the annotation will be unnecessarily
- // but safely updated.
- if (annotation == [self annotationWithTag:annotationTag]) {
- _mbglMap->updateAnnotation(annotationTag, [annotation annotationObjectWithDelegate:self]);
- [self updateAnnotationCallouts];
- }
- }
-}
-
-+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
- return [key isEqualToString:@"annotations"] ? YES : [super automaticallyNotifiesObserversForKey:key];
-}
-
-- (void)setDelegate:(id<MGLMapViewDelegate>)delegate {
- _delegate = delegate;
-
- // Cache checks for delegate method implementations that may be called in a
- // hot loop, namely the annotation style methods.
- _delegateHasAlphasForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:alphaForShapeAnnotation:)];
- _delegateHasStrokeColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)];
- _delegateHasFillColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)];
- _delegateHasLineWidthsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:lineWidthForPolylineAnnotation:)];
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wundeclared-selector"
- if ([self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) {
- NSLog(@"-mapView:regionWillChangeAnimated: is not supported by the macOS SDK, but %@ implements it anyways. "
- @"Please implement -[%@ mapView:cameraWillChangeAnimated:] instead.",
- NSStringFromClass([delegate class]), NSStringFromClass([delegate class]));
- }
- if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)]) {
- NSLog(@"-mapViewRegionIsChanging: is not supported by the macOS SDK, but %@ implements it anyways. "
- @"Please implement -[%@ mapViewCameraIsChanging:] instead.",
- NSStringFromClass([delegate class]), NSStringFromClass([delegate class]));
- }
- if ([self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) {
- NSLog(@"-mapView:regionDidChangeAnimated: is not supported by the macOS SDK, but %@ implements it anyways. "
- @"Please implement -[%@ mapView:cameraDidChangeAnimated:] instead.",
- NSStringFromClass([delegate class]), NSStringFromClass([delegate class]));
- }
-#pragma clang diagnostic pop
-}
-
-#pragma mark Style
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingStyle {
- return [NSSet setWithObject:@"styleURL"];
-}
-
-- (nonnull NSURL *)styleURL {
- NSString *styleURLString = @(_mbglMap->getStyle().getURL().c_str()).mgl_stringOrNilIfEmpty;
- return styleURLString ? [NSURL URLWithString:styleURLString] : [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
-}
-
-- (void)setStyleURL:(nullable NSURL *)styleURL {
- if (_isTargetingInterfaceBuilder) {
- return;
- }
-
- // Default to Streets.
- if (!styleURL) {
- styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
- }
- MGLLogDebug(@"Setting styleURL: %@", styleURL);
- // An access token is required to load any default style, including Streets.
- if (![MGLAccountManager accessToken] && [styleURL.scheme isEqualToString:@"mapbox"]) {
- NSLog(@"Cannot set the style URL to %@ because no access token has been specified.", styleURL);
- return;
- }
-
- styleURL = styleURL.mgl_URLByStandardizingScheme;
- self.style = nil;
- _mbglMap->getStyle().loadURL(styleURL.absoluteString.UTF8String);
-}
-
-- (IBAction)reloadStyle:(__unused id)sender {
- MGLLogInfo(@"Reloading style.");
- NSURL *styleURL = self.styleURL;
- _mbglMap->getStyle().loadURL("");
- self.styleURL = styleURL;
-}
-
-- (void)setPrefetchesTiles:(BOOL)prefetchesTiles
-{
- _mbglMap->setPrefetchZoomDelta(prefetchesTiles ? mbgl::util::DEFAULT_PREFETCH_ZOOM_DELTA : 0);
-}
-
-- (mbgl::Map *)mbglMap {
- return _mbglMap;
-}
-
-- (mbgl::Renderer *)renderer {
- return _rendererFrontend->getRenderer();
-}
-
-#pragma mark View hierarchy and drawing
-
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
- [self deselectAnnotation:self.selectedAnnotation];
- if (!self.dormant && !newWindow) {
- self.dormant = YES;
- }
-
- [self.window removeObserver:self forKeyPath:@"contentLayoutRect"];
- [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"];
-}
-
-- (void)viewDidMoveToWindow {
- NSWindow *window = self.window;
- if (self.dormant && window) {
- self.dormant = NO;
- }
-
- if (window && _mbglMap->getMapOptions().constrainMode() == mbgl::ConstrainMode::None) {
- _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly);
- }
-
- [window addObserver:self
- forKeyPath:@"contentLayoutRect"
- options:NSKeyValueObservingOptionInitial
- context:NULL];
- [window addObserver:self
- forKeyPath:@"titlebarAppearsTransparent"
- options:NSKeyValueObservingOptionInitial
- context:NULL];
-}
-
-- (BOOL)wantsLayer {
- return YES;
-}
-
-- (BOOL)wantsBestResolutionOpenGLSurface {
- // Use an OpenGL layer, except when drawing the designable, which is just
- // ordinary Cocoa.
- return !_isTargetingInterfaceBuilder;
-}
-
-- (CGLContextObj)context {
- return _mbglView->getCGLContextObj();
-}
-
-- (void)setFrame:(NSRect)frame {
- super.frame = frame;
- if (!_isTargetingInterfaceBuilder) {
- _mbglMap->setSize(self.size);
- }
-}
-
-- (void)updateConstraints {
- // Place the zoom controls at the lower-right corner of the view.
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:_zoomControls
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:MGLOrnamentPadding]];
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:_zoomControls
- attribute:NSLayoutAttributeTrailing
- multiplier:1
- constant:MGLOrnamentPadding]];
-
- // Center the compass above the zoom controls, assuming that the compass is
- // narrower than the zoom controls.
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:_compass
- attribute:NSLayoutAttributeCenterX
- relatedBy:NSLayoutRelationEqual
- toItem:_zoomControls
- attribute:NSLayoutAttributeCenterX
- multiplier:1
- constant:0]];
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:_zoomControls
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:_compass
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:8]];
-
- // Place the logo view in the lower-left corner of the view, accounting for
- // the logo’s alignment rect.
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:_logoView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:MGLOrnamentPadding - _logoView.image.alignmentRect.origin.y]];
- [self addConstraint:
- [NSLayoutConstraint constraintWithItem:_logoView
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:self
- attribute:NSLayoutAttributeLeading
- multiplier:1
- constant:MGLOrnamentPadding - _logoView.image.alignmentRect.origin.x]];
-
- // Place the attribution view to the right of the logo view and size it to
- // fit the buttons inside.
- [self addConstraint:[NSLayoutConstraint constraintWithItem:_logoView
- attribute:NSLayoutAttributeBaseline
- relatedBy:NSLayoutRelationEqual
- toItem:_attributionView
- attribute:NSLayoutAttributeBaseline
- multiplier:1
- constant:_logoView.image.alignmentRect.origin.y]];
- [self addConstraint:[NSLayoutConstraint constraintWithItem:_attributionView
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:_logoView
- attribute:NSLayoutAttributeTrailing
- multiplier:1
- constant:8]];
-
- [super updateConstraints];
-}
-
-- (void)renderSync {
- if (!self.dormant && _rendererFrontend) {
- _rendererFrontend->render();
-
- if (_isPrinting) {
- _isPrinting = NO;
- NSImage *image = [[NSImage alloc] initWithMGLPremultipliedImage:_mbglView->readStillImage()];
- [self performSelector:@selector(printWithImage:) withObject:image afterDelay:0];
- }
-
-// [self updateUserLocationAnnotationView];
- }
-}
-
-- (BOOL)isTargetingInterfaceBuilder {
- return _isTargetingInterfaceBuilder;
-}
-
-- (void)setNeedsRerender {
- MGLAssertIsMainThread();
-
- [self.layer setNeedsDisplay];
-}
-
-- (void)cameraWillChangeAnimated:(BOOL)animated {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapView:cameraWillChangeAnimated:)]) {
- [self.delegate mapView:self cameraWillChangeAnimated:animated];
- }
-}
-
-- (void)cameraIsChanging {
- if (!_mbglMap) {
- return;
- }
-
- // Update a minimum of UI that needs to stay attached to the map
- // while animating.
- [self updateCompass];
- [self updateAnnotationCallouts];
-
- if ([self.delegate respondsToSelector:@selector(mapViewCameraIsChanging:)]) {
- [self.delegate mapViewCameraIsChanging:self];
- }
-}
-
-- (void)cameraDidChangeAnimated:(BOOL)animated {
- if (!_mbglMap) {
- return;
- }
-
- // Update all UI at the end of an animation or atomic change to the
- // viewport. More expensive updates can happen here, but care should
- // still be taken to minimize the work done here because scroll
- // gesture recognition and momentum scrolling is performed as a
- // series of atomic changes, not an animation.
- [self updateZoomControls];
- [self updateCompass];
- [self updateAnnotationCallouts];
- [self updateAnnotationTrackingAreas];
-
- if ([self.delegate respondsToSelector:@selector(mapView:cameraDidChangeAnimated:)]) {
- [self.delegate mapView:self cameraDidChangeAnimated:animated];
- }
-}
-
-- (void)mapViewWillStartLoadingMap {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
- [self.delegate mapViewWillStartLoadingMap:self];
- }
-}
-
-- (void)mapViewDidFinishLoadingMap {
- if (!_mbglMap) {
- return;
- }
-
- [self.style willChangeValueForKey:@"sources"];
- [self.style didChangeValueForKey:@"sources"];
- [self.style willChangeValueForKey:@"layers"];
- [self.style didChangeValueForKey:@"layers"];
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
- [self.delegate mapViewDidFinishLoadingMap:self];
- }
-}
-
-- (void)mapViewDidFailLoadingMapWithError:(NSError *)error {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
- [self.delegate mapViewDidFailLoadingMap:self withError:error];
- }
-}
-
-- (void)mapViewWillStartRenderingFrame {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)]) {
- [self.delegate mapViewWillStartRenderingFrame:self];
- }
-}
-
-- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered {
- if (!_mbglMap) {
- return;
- }
-
- if (_isChangingAnnotationLayers) {
- _isChangingAnnotationLayers = NO;
- [self.style didChangeValueForKey:@"layers"];
- }
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) {
- [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:fullyRendered];
- }
-}
-
-- (void)mapViewWillStartRenderingMap {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
- [self.delegate mapViewWillStartRenderingMap:self];
- }
-}
-
-- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
- [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:fullyRendered];
- }
-}
-
-- (void)mapViewDidBecomeIdle {
- if (!_mbglMap) {
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(mapViewDidBecomeIdle:)]) {
- [self.delegate mapViewDidBecomeIdle:self];
- }
-}
-
-- (void)mapViewDidFinishLoadingStyle {
- if (!_mbglMap) {
- return;
- }
-
- self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
- if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
- {
- [self.delegate mapView:self didFinishLoadingStyle:self.style];
- }
-}
-
-- (void)sourceDidChange:(MGLSource *)source {
- if (!_mbglMap) {
- return;
- }
- // Attribution only applies to tiled sources
- if ([source isKindOfClass:[MGLTileSource class]]) {
- [self installAttributionView];
- }
- self.needsUpdateConstraints = YES;
- self.needsDisplay = YES;
-}
-
-- (BOOL)shouldRemoveStyleImage:(NSString *)imageName {
- if ([self.delegate respondsToSelector:@selector(mapView:shouldRemoveStyleImage:)]) {
- return [self.delegate mapView:self shouldRemoveStyleImage:imageName];
- }
-
- return YES;
-}
-
-#pragma mark Printing
-
-- (void)print:(__unused id)sender {
- _isPrinting = YES;
- [self setNeedsRerender];
-}
-
-- (void)printWithImage:(NSImage *)image {
- NSImageView *imageView = [[NSImageView alloc] initWithFrame:self.bounds];
- imageView.image = image;
-
- NSPrintOperation *op = [NSPrintOperation printOperationWithView:imageView];
- [op runOperation];
-}
-
-#pragma mark Viewport
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingCenterCoordinate {
- return [NSSet setWithObjects:@"latitude", @"longitude", @"camera", nil];
-}
-
-- (CLLocationCoordinate2D)centerCoordinate {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
- return MGLLocationCoordinate2DFromLatLng(*_mbglMap->getCameraOptions(padding).center);
-}
-
-- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate {
- MGLLogDebug(@"Setting centerCoordinate: %@", MGLStringFromCLLocationCoordinate2D(centerCoordinate));
- [self setCenterCoordinate:centerCoordinate animated:NO];
-}
-
-- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate animated:(BOOL)animated {
- [self setCenterCoordinate:centerCoordinate animated:animated completionHandler:nil];
-}
-
-- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion {
- MGLLogDebug(@"Setting centerCoordinate: %@ animated: %@", MGLStringFromCLLocationCoordinate2D(centerCoordinate), MGLStringFromBOOL(animated));
- mbgl::AnimationOptions animationOptions = MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0);
- animationOptions.transitionFinishFn = ^() {
- [self didChangeValueForKey:@"centerCoordinate"];
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
- }
- };
-
- [self willChangeValueForKey:@"centerCoordinate"];
- _mbglMap->easeTo(mbgl::CameraOptions()
- .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
- .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets)),
- animationOptions);
-}
-
-- (void)offsetCenterCoordinateBy:(NSPoint)delta animated:(BOOL)animated {
- [self willChangeValueForKey:@"centerCoordinate"];
- _mbglMap->cancelTransitions();
- MGLMapCamera *oldCamera = self.camera;
- _mbglMap->moveBy({ delta.x, delta.y },
- MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
- if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- [self didChangeValueForKey:@"centerCoordinate"];
-}
-
-- (CLLocationDegrees)pendingLatitude {
- return _pendingLatitude;
-}
-
-- (void)setPendingLatitude:(CLLocationDegrees)pendingLatitude {
- _pendingLatitude = pendingLatitude;
-}
-
-- (CLLocationDegrees)pendingLongitude {
- return _pendingLongitude;
-}
-
-- (void)setPendingLongitude:(CLLocationDegrees)pendingLongitude {
- _pendingLongitude = pendingLongitude;
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel {
- return [NSSet setWithObject:@"camera"];
-}
-
-- (double)zoomLevel {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
- return *_mbglMap->getCameraOptions(padding).zoom;
-}
-
-- (void)setZoomLevel:(double)zoomLevel {
- MGLLogDebug(@"Setting zoomLevel: %f", zoomLevel);
- [self setZoomLevel:zoomLevel animated:NO];
-}
-
-- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated {
- MGLLogDebug(@"Setting zoomLevel: %f animated: %@", zoomLevel, MGLStringFromBOOL(animated));
- [self willChangeValueForKey:@"zoomLevel"];
- _mbglMap->easeTo(mbgl::CameraOptions()
- .withZoom(zoomLevel)
- .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets)),
- MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
- [self didChangeValueForKey:@"zoomLevel"];
-}
-
-- (void)setZoomLevel:(double)zoomLevel atPoint:(NSPoint)point animated:(BOOL)animated {
- [self willChangeValueForKey:@"centerCoordinate"];
- [self willChangeValueForKey:@"zoomLevel"];
- MGLMapCamera *oldCamera = self.camera;
- mbgl::ScreenCoordinate center(point.x, self.bounds.size.height - point.y);
- _mbglMap->easeTo(mbgl::CameraOptions()
- .withZoom(zoomLevel)
- .withAnchor(center),
- MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
- if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- [self didChangeValueForKey:@"zoomLevel"];
- [self didChangeValueForKey:@"centerCoordinate"];
-}
-
-- (void)setMinimumZoomLevel:(double)minimumZoomLevel
-{
- MGLLogDebug(@"Setting minimumZoomLevel: %f", minimumZoomLevel);
- _mbglMap->setBounds(mbgl::BoundOptions().withMinZoom(minimumZoomLevel));
-}
-
-- (void)setMaximumZoomLevel:(double)maximumZoomLevel
-{
- MGLLogDebug(@"Setting maximumZoomLevel: %f", maximumZoomLevel);
- _mbglMap->setBounds(mbgl::BoundOptions().withMaxZoom(maximumZoomLevel));
-}
-
-- (double)maximumZoomLevel {
- return *_mbglMap->getBounds().maxZoom;
-}
-
-- (double)minimumZoomLevel {
- return *_mbglMap->getBounds().minZoom;
-}
-
-/// Respond to a click on the zoom control.
-- (IBAction)zoomInOrOut:(NSSegmentedControl *)sender {
- switch (sender.selectedSegment) {
- case 0:
- // Zoom out.
- [self moveToEndOfParagraph:sender];
- break;
- case 1:
- // Zoom in.
- [self moveToBeginningOfParagraph:sender];
- break;
- default:
- break;
- }
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingDirection {
- return [NSSet setWithObject:@"camera"];
-}
-
-- (CLLocationDirection)direction {
- return mbgl::util::wrap(*_mbglMap->getCameraOptions().bearing, 0., 360.);
-}
-
-- (void)setDirection:(CLLocationDirection)direction {
- MGLLogDebug(@"Setting direction: %f", direction);
- [self setDirection:direction animated:NO];
-}
-
-- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated {
- MGLLogDebug(@"Setting direction: %f animated: %@", direction, MGLStringFromBOOL(animated));
- [self willChangeValueForKey:@"direction"];
- _mbglMap->easeTo(mbgl::CameraOptions()
- .withBearing(direction)
- .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets)),
- MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
- [self didChangeValueForKey:@"direction"];
-}
-
-- (void)offsetDirectionBy:(CLLocationDegrees)delta animated:(BOOL)animated {
- [self setDirection:*_mbglMap->getCameraOptions().bearing + delta animated:animated];
-}
-
-+ (NSSet<NSString *> *)keyPathsForValuesAffectingCamera {
- return [NSSet setWithObjects:@"latitude", @"longitude", @"centerCoordinate", @"zoomLevel", @"direction", nil];
-}
-
-- (MGLMapCamera *)camera {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
- return [self cameraForCameraOptions:_mbglMap->getCameraOptions(padding)];
-}
-
-- (void)setCamera:(MGLMapCamera *)camera {
- MGLLogDebug(@"Setting camera: %@", camera);
- [self setCamera:camera animated:NO];
-}
-
-- (void)setCamera:(MGLMapCamera *)camera animated:(BOOL)animated {
- MGLLogDebug(@"Setting camera: %@ animated: %@", camera, MGLStringFromBOOL(animated));
- [self setCamera:camera withDuration:animated ? MGLAnimationDuration : 0 animationTimingFunction:nil completionHandler:NULL];
-}
-
-- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion {
- MGLLogDebug(@"Setting camera: %@ duration: %f animationTimingFunction: %@", camera, duration, function);
- [self setCamera:camera withDuration:duration animationTimingFunction:function edgePadding:NSEdgeInsetsZero completionHandler:completion];
-}
-
-- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function edgePadding:(NSEdgeInsets)edgePadding completionHandler:(nullable void (^)(void))completion {
- edgePadding = MGLEdgeInsetsInsetEdgeInset(edgePadding, self.contentInsets);
- mbgl::AnimationOptions animationOptions;
- if (duration > 0) {
- animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
- animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
- }
- if (completion) {
- animationOptions.transitionFinishFn = [completion]() {
- // Must run asynchronously after the transition is completely over.
- // Otherwise, a call to -setCamera: within the completion handler
- // would reenter the completion handler’s caller.
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
- };
- }
-
- if ([self.camera isEqualToMapCamera:camera]) {
- if (completion) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- completion();
- });
- }
- return;
- }
-
- [self willChangeValueForKey:@"camera"];
- _mbglMap->cancelTransitions();
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:edgePadding];
- _mbglMap->easeTo(cameraOptions, animationOptions);
- [self didChangeValueForKey:@"camera"];
-}
-
-- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion {
- MGLLogDebug(@"Setting flyToCamera: %@ completionHandler: %@", camera, completion);
- [self flyToCamera:camera withDuration:-1 completionHandler:completion];
-}
-
-- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion {
- MGLLogDebug(@"Setting flyToCamera: %@ withDuration: %f completionHandler: %@", camera, duration, completion);
- [self flyToCamera:camera withDuration:duration peakAltitude:-1 completionHandler:completion];
-}
-
-- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion {
- MGLLogDebug(@"Setting flyToCamera: %@ withDuration: %f peakAltitude: %f completionHandler: %@", camera, duration, peakAltitude, completion);
- mbgl::AnimationOptions animationOptions;
- if (duration >= 0) {
- animationOptions.duration = MGLDurationFromTimeInterval(duration);
- }
- if (peakAltitude >= 0) {
- CLLocationDegrees peakLatitude = (self.centerCoordinate.latitude + camera.centerCoordinate.latitude) / 2;
- CLLocationDegrees peakPitch = (self.camera.pitch + camera.pitch) / 2;
- animationOptions.minZoom = MGLZoomLevelForAltitude(peakAltitude, peakPitch,
- peakLatitude, self.frame.size);
- }
- if (completion) {
- animationOptions.transitionFinishFn = [completion]() {
- // Must run asynchronously after the transition is completely over.
- // Otherwise, a call to -setCamera: within the completion handler
- // would reenter the completion handler’s caller.
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
- };
- }
-
- if ([self.camera isEqualToMapCamera:camera]) {
- if (completion) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- completion();
- });
- }
- return;
- }
-
- [self willChangeValueForKey:@"camera"];
- _mbglMap->cancelTransitions();
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:self.contentInsets];
- _mbglMap->flyTo(cameraOptions, animationOptions);
- [self didChangeValueForKey:@"camera"];
-}
-
-/// Returns a CameraOptions object that specifies parameters for animating to
-/// the given camera.
-- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(NSEdgeInsets) edgePadding {
- mbgl::CameraOptions options;
- options.center = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate);
- options.padding = MGLEdgeInsetsFromNSEdgeInsets(edgePadding);
- options.zoom = MGLZoomLevelForAltitude(camera.altitude, camera.pitch,
- camera.centerCoordinate.latitude,
- self.frame.size);
- if (camera.heading >= 0) {
- options.bearing = camera.heading;
- }
- if (camera.pitch >= 0) {
- options.pitch = camera.pitch;
- }
- return options;
-}
-
-+ (NSSet *)keyPathsForValuesAffectingVisibleCoordinateBounds {
- return [NSSet setWithObjects:@"centerCoordinate", @"zoomLevel", @"direction", @"bounds", nil];
-}
-
-- (MGLCoordinateBounds)visibleCoordinateBounds {
- return [self convertRect:self.bounds toCoordinateBoundsFromView:self];
-}
-
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds {
- MGLLogDebug(@"Setting visibleCoordinateBounds: %@", MGLStringFromCoordinateBounds(bounds));
- [self setVisibleCoordinateBounds:bounds animated:NO];
-}
-
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated {
- MGLLogDebug(@"Setting visibleCoordinateBounds: %@ animated: %@", MGLStringFromCoordinateBounds(bounds), MGLStringFromBOOL(animated));
- [self setVisibleCoordinateBounds:bounds edgePadding:NSEdgeInsetsZero animated:animated];
-}
-
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
- [self setVisibleCoordinateBounds:bounds edgePadding:insets animated:animated completionHandler:nil];
-}
-
-- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion {
- _mbglMap->cancelTransitions();
-
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
- padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding);
- mbgl::AnimationOptions animationOptions;
- if (animated) {
- animationOptions.duration = MGLDurationFromTimeInterval(MGLAnimationDuration);
- }
-
- MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
- if ([self.camera isEqualToMapCamera:camera]) {
- completion();
- return;
- }
-
- [self willChangeValueForKey:@"visibleCoordinateBounds"];
- animationOptions.transitionFinishFn = ^() {
- [self didChangeValueForKey:@"visibleCoordinateBounds"];
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
- }
- };
- _mbglMap->easeTo(cameraOptions, animationOptions);
-}
-
-- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds {
- return [self cameraThatFitsCoordinateBounds:bounds edgePadding:NSEdgeInsetsZero];
-}
-
-- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
- padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding);
- return [self cameraForCameraOptions:cameraOptions];
-}
-
-- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets
-{
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
- padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
-
- MGLMapCamera *currentCamera = self.camera;
- CGFloat pitch = camera.pitch < 0 ? currentCamera.pitch : camera.pitch;
- CLLocationDirection direction = camera.heading < 0 ? currentCamera.heading : camera.heading;
-
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), padding, direction, pitch);
- return [self cameraForCameraOptions:cameraOptions];
-}
-
-- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingShape:(MGLShape *)shape edgePadding:(NSEdgeInsets)insets {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
- padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
-
- MGLMapCamera *currentCamera = self.camera;
- CGFloat pitch = camera.pitch < 0 ? currentCamera.pitch : camera.pitch;
- CLLocationDirection direction = camera.heading < 0 ? currentCamera.heading : camera.heading;
-
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForGeometry([shape geometryObject], padding, direction, pitch);
-
- return [self cameraForCameraOptions: cameraOptions];
-}
-
-- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(NSEdgeInsets)insets {
- mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
- padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
-
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForGeometry([shape geometryObject], padding, direction);
-
- return [self cameraForCameraOptions:cameraOptions];
-}
-
-- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions {
- mbgl::CameraOptions mapCamera = _mbglMap->getCameraOptions();
- CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : *mapCamera.center);
- double zoomLevel = cameraOptions.zoom ? *cameraOptions.zoom : self.zoomLevel;
- CLLocationDirection direction = cameraOptions.bearing ? mbgl::util::wrap(*cameraOptions.bearing, 0., 360.) : self.direction;
- CGFloat pitch = cameraOptions.pitch ? *cameraOptions.pitch : *mapCamera.pitch;
- CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoomLevel, pitch,
- centerCoordinate.latitude,
- self.frame.size);
- return [MGLMapCamera cameraLookingAtCenterCoordinate:centerCoordinate
- altitude:altitude
- pitch:pitch
- heading:direction];
-}
-
-- (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),
- MAX(NSMinX(contentLayoutRect), 0),
- MAX(NSMinY(contentLayoutRect), 0),
- NSWidth(self.bounds) - NSMaxX(contentLayoutRect));
- }
- } else {
- contentInsets = NSEdgeInsetsZero;
- }
-
- self.contentInsets = contentInsets;
-}
-
-- (void)setContentInsets:(NSEdgeInsets)contentInsets {
- [self setContentInsets:contentInsets animated:NO completionHandler:nil];
-}
-
-- (void)setContentInsets:(NSEdgeInsets)contentInsets animated:(BOOL)animated {
- [self setContentInsets:contentInsets animated:animated completionHandler:nil];
-}
-
-- (void)setContentInsets:(NSEdgeInsets)contentInsets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion {
- if (NSEdgeInsetsEqual(contentInsets, self.contentInsets)) {
- if (completion) {
- completion();
- }
- return;
- }
- MGLLogDebug(@"Setting contentInset: %@ animated:", MGLStringFromNSEdgeInsets(contentInsets), MGLStringFromBOOL(animated));
- // 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;
- _contentInsets = contentInsets;
- [self setCenterCoordinate:oldCenter animated:animated completionHandler:completion];
-}
-
-#pragma mark Mouse events and gestures
-
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-/// Drag to pan, plus drag to zoom, rotate, and tilt when a modifier key is held
-/// down.
-- (void)handlePanGesture:(NSPanGestureRecognizer *)gestureRecognizer {
- NSPoint delta = [gestureRecognizer translationInView:self];
- NSPoint endPoint = [gestureRecognizer locationInView:self];
- NSPoint startPoint = NSMakePoint(endPoint.x - delta.x, endPoint.y - delta.y);
-
- NSEventModifierFlags flags = [NSApp currentEvent].modifierFlags;
- if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- [self.window invalidateCursorRectsForView:self];
- _mbglMap->setGestureInProgress(true);
-
- if (![self isPanningWithGesture]) {
- // Hide the cursor except when panning.
- CGDisplayHideCursor(kCGDirectMainDisplay);
- _didHideCursorDuringGesture = YES;
- }
- } else if (gestureRecognizer.state == NSGestureRecognizerStateEnded
- || gestureRecognizer.state == NSGestureRecognizerStateCancelled) {
- _mbglMap->setGestureInProgress(false);
- [self.window invalidateCursorRectsForView:self];
-
- if (_didHideCursorDuringGesture) {
- _didHideCursorDuringGesture = NO;
- // Move the cursor back to the start point and show it again, creating
- // the illusion that it has stayed in place during the entire gesture.
- CGPoint cursorPoint = [self convertPoint:startPoint toView:nil];
- cursorPoint = [self.window convertRectToScreen:{ cursorPoint, NSZeroSize }].origin;
- cursorPoint.y = self.window.screen.frame.size.height - cursorPoint.y;
- CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cursorPoint);
- CGDisplayShowCursor(kCGDirectMainDisplay);
- }
- }
-
- if (flags & NSShiftKeyMask) {
- // Shift-drag to zoom.
- if (!self.zoomEnabled) {
- return;
- }
-
- _mbglMap->cancelTransitions();
-
- if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- _zoomAtBeginningOfGesture = [self zoomLevel];
- } else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- CGFloat newZoomLevel = _zoomAtBeginningOfGesture - delta.y / 75;
- [self setZoomLevel:newZoomLevel atPoint:startPoint animated:NO];
- }
- } else if (flags & NSAlternateKeyMask) {
- // Option-drag to rotate and/or tilt.
- _mbglMap->cancelTransitions();
-
- if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- _directionAtBeginningOfGesture = self.direction;
- _pitchAtBeginningOfGesture = *_mbglMap->getCameraOptions().pitch;
- } else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- MGLMapCamera *oldCamera = self.camera;
- BOOL didChangeCamera = NO;
- mbgl::ScreenCoordinate center(startPoint.x, self.bounds.size.height - startPoint.y);
- if (self.rotateEnabled) {
- CLLocationDirection newDirection = _directionAtBeginningOfGesture - delta.x / 10;
- [self willChangeValueForKey:@"direction"];
- _mbglMap->jumpTo(mbgl::CameraOptions().withBearing(newDirection).withAnchor(center));
- didChangeCamera = YES;
- [self didChangeValueForKey:@"direction"];
- }
- if (self.pitchEnabled) {
- _mbglMap->jumpTo(mbgl::CameraOptions().withPitch(_pitchAtBeginningOfGesture + delta.y / 5).withAnchor(center));
- didChangeCamera = YES;
- }
-
- if (didChangeCamera
- && [self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- }
- } else if (self.scrollEnabled) {
- // Otherwise, drag to pan.
- _mbglMap->cancelTransitions();
-
- if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- delta.y *= -1;
- [self offsetCenterCoordinateBy:delta animated:NO];
- [gestureRecognizer setTranslation:NSZeroPoint inView:nil];
- }
- }
-}
-
-/// Returns whether the user is panning using a gesture.
-- (BOOL)isPanningWithGesture {
- NSGestureRecognizerState state = _panGestureRecognizer.state;
- NSEventModifierFlags flags = [NSApp currentEvent].modifierFlags;
- return ((state == NSGestureRecognizerStateBegan || state == NSGestureRecognizerStateChanged)
- && !(flags & NSShiftKeyMask || flags & NSAlternateKeyMask));
-}
-
-/// Pinch to zoom.
-- (void)handleMagnificationGesture:(NSMagnificationGestureRecognizer *)gestureRecognizer {
- if (!self.zoomEnabled) {
- return;
- }
-
- _mbglMap->cancelTransitions();
-
- if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- _mbglMap->setGestureInProgress(true);
- _zoomAtBeginningOfGesture = [self zoomLevel];
- } else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- NSPoint zoomInPoint = [gestureRecognizer locationInView:self];
- mbgl::ScreenCoordinate center(zoomInPoint.x, self.bounds.size.height - zoomInPoint.y);
- if (gestureRecognizer.magnification > -1) {
- [self willChangeValueForKey:@"zoomLevel"];
- [self willChangeValueForKey:@"centerCoordinate"];
- MGLMapCamera *oldCamera = self.camera;
- _mbglMap->jumpTo(mbgl::CameraOptions()
- .withZoom(_zoomAtBeginningOfGesture + log2(1 + gestureRecognizer.magnification))
- .withAnchor(center));
- if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- [self didChangeValueForKey:@"centerCoordinate"];
- [self didChangeValueForKey:@"zoomLevel"];
- }
- } else if (gestureRecognizer.state == NSGestureRecognizerStateEnded
- || gestureRecognizer.state == NSGestureRecognizerStateCancelled) {
- _mbglMap->setGestureInProgress(false);
- }
-}
-
-/// Click or tap to select an annotation.
-- (void)handleClickGesture:(NSClickGestureRecognizer *)gestureRecognizer {
- if (gestureRecognizer.state != NSGestureRecognizerStateEnded
- || [self subviewContainingGesture:gestureRecognizer]) {
- return;
- }
-
- NSPoint gesturePoint = [gestureRecognizer locationInView:self];
- MGLAnnotationTag hitAnnotationTag = [self annotationTagAtPoint:gesturePoint persistingResults:YES];
- if (hitAnnotationTag != MGLAnnotationTagNotFound) {
- if (hitAnnotationTag != _selectedAnnotationTag) {
- id <MGLAnnotation> annotation = [self annotationWithTag:hitAnnotationTag];
- NSAssert(annotation, @"Cannot select nonexistent annotation with tag %llu", hitAnnotationTag);
- [self selectAnnotation:annotation atPoint:gesturePoint];
- }
- } else {
- [self deselectAnnotation:self.selectedAnnotation];
- }
-}
-
-/// Right-click to show the context menu.
-- (void)handleRightClickGesture:(NSClickGestureRecognizer *)gestureRecognizer {
- NSMenu *menu = [self menuForEvent:[NSApp currentEvent]];
- if (menu) {
- [NSMenu popUpContextMenu:menu withEvent:[NSApp currentEvent] forView:self];
- }
-}
-
-/// Double-click or double-tap to zoom in.
-- (void)handleDoubleClickGesture:(NSClickGestureRecognizer *)gestureRecognizer {
- if (!self.zoomEnabled || gestureRecognizer.state != NSGestureRecognizerStateEnded
- || [self subviewContainingGesture:gestureRecognizer]) {
- return;
- }
-
- _mbglMap->cancelTransitions();
-
- NSPoint gesturePoint = [gestureRecognizer locationInView:self];
- [self setZoomLevel:round(self.zoomLevel) + 1 atPoint:gesturePoint animated:YES];
-}
-
-- (void)smartMagnifyWithEvent:(NSEvent *)event {
- if (!self.zoomEnabled) {
- return;
- }
-
- _mbglMap->cancelTransitions();
-
- // Tap with two fingers (“right-click”) to zoom out on mice but not trackpads.
- NSPoint gesturePoint = [self convertPoint:event.locationInWindow fromView:nil];
- [self setZoomLevel:round(self.zoomLevel) - 1 atPoint:gesturePoint animated:YES];
-}
-
-/// Rotate fingers to rotate.
-- (void)handleRotationGesture:(NSRotationGestureRecognizer *)gestureRecognizer {
- if (!self.rotateEnabled) {
- return;
- }
-
- _mbglMap->cancelTransitions();
-
- if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- _mbglMap->setGestureInProgress(true);
- _directionAtBeginningOfGesture = self.direction;
- } else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- MGLMapCamera *oldCamera = self.camera;
-
- NSPoint rotationPoint = [gestureRecognizer locationInView:self];
- mbgl::ScreenCoordinate anchor(rotationPoint.x, self.bounds.size.height - rotationPoint.y);
- _mbglMap->jumpTo(mbgl::CameraOptions()
- .withBearing(_directionAtBeginningOfGesture + gestureRecognizer.rotationInDegrees)
- .withAnchor(anchor));
-
- if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- } else if (gestureRecognizer.state == NSGestureRecognizerStateEnded
- || gestureRecognizer.state == NSGestureRecognizerStateCancelled) {
- _mbglMap->setGestureInProgress(false);
- }
-}
-
-- (BOOL)wantsScrollEventsForSwipeTrackingOnAxis:(__unused NSEventGestureAxis)axis {
- // Track both horizontal and vertical swipes in -scrollWheel:.
- return YES;
-}
-
-- (void)scrollWheel:(NSEvent *)event {
- // https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#10_7Dragging
- BOOL isScrollWheel = event.phase == NSEventPhaseNone && event.momentumPhase == NSEventPhaseNone && !event.hasPreciseScrollingDeltas;
- if (isScrollWheel || [[NSUserDefaults standardUserDefaults] boolForKey:MGLScrollWheelZoomsMapViewDefaultKey]) {
- // A traditional, vertical scroll wheel zooms instead of panning.
- if (self.zoomEnabled) {
- const double delta =
- event.scrollingDeltaY / ([event hasPreciseScrollingDeltas] ? 100 : 10);
- if (delta != 0) {
- double scale = 2.0 / (1.0 + std::exp(-std::abs(delta)));
-
- // Zooming out.
- if (delta < 0) {
- scale = 1.0 / scale;
- }
-
- NSPoint gesturePoint = [self convertPoint:event.locationInWindow fromView:nil];
- [self setZoomLevel:self.zoomLevel + log2(scale) atPoint:gesturePoint animated:NO];
- }
- }
- } else if (self.scrollEnabled
- && _magnificationGestureRecognizer.state == NSGestureRecognizerStatePossible
- && _rotationGestureRecognizer.state == NSGestureRecognizerStatePossible) {
- // Scroll to pan.
- _mbglMap->cancelTransitions();
-
- CGFloat x = event.scrollingDeltaX;
- CGFloat y = event.scrollingDeltaY;
- if (x || y) {
- [self offsetCenterCoordinateBy:NSMakePoint(x, y) animated:NO];
- }
-
- // Drift pan.
- if (event.momentumPhase != NSEventPhaseNone) {
- [self offsetCenterCoordinateBy:NSMakePoint(x, y) animated:NO];
- }
- }
-}
-
-/// Returns the subview that the gesture is located in.
-- (NSView *)subviewContainingGesture:(NSGestureRecognizer *)gestureRecognizer {
- if (NSPointInRect([gestureRecognizer locationInView:self.compass], self.compass.bounds)) {
- return self.compass;
- }
- if (NSPointInRect([gestureRecognizer locationInView:self.zoomControls], self.zoomControls.bounds)) {
- return self.zoomControls;
- }
- if (NSPointInRect([gestureRecognizer locationInView:self.attributionView], self.attributionView.bounds)) {
- return self.attributionView;
- }
- return nil;
-}
-
-#pragma mark NSGestureRecognizerDelegate methods
-- (BOOL)gestureRecognizer:(NSGestureRecognizer *)gestureRecognizer shouldAttemptToRecognizeWithEvent:(NSEvent *)event {
- if (gestureRecognizer == _singleClickRecognizer) {
- if (!self.selectedAnnotation) {
- NSPoint gesturePoint = [self convertPoint:[event locationInWindow] fromView:nil];
- MGLAnnotationTag hitAnnotationTag = [self annotationTagAtPoint:gesturePoint persistingResults:NO];
- if (hitAnnotationTag == MGLAnnotationTagNotFound) {
- return NO;
- }
- }
- }
- return YES;
-}
-
-#pragma mark Keyboard events
-
-- (void)keyDown:(NSEvent *)event {
- // This is the recommended way to handle arrow key presses, causing
- // methods like -moveUp: and -moveToBeginningOfParagraph: to be called
- // for various standard keybindings.
- [self interpretKeyEvents:@[event]];
-}
-
-// The following action methods are declared in NSResponder.h.
-
-- (void)insertTab:(id)sender {
- if (self.window.firstResponder == self) {
- [self.window selectNextKeyView:self];
- }
-}
-
-- (void)insertBacktab:(id)sender {
- if (self.window.firstResponder == self) {
- [self.window selectPreviousKeyView:self];
- }
-}
-
-- (void)insertText:(NSString *)insertString {
- switch (insertString.length == 1 ? [insertString characterAtIndex:0] : 0) {
- case '-':
- [self moveToEndOfParagraph:nil];
- break;
-
- case '+':
- case '=':
- [self moveToBeginningOfParagraph:nil];
- break;
-
- default:
- [super insertText:insertString];
- break;
- }
-}
-
-- (IBAction)moveUp:(__unused id)sender {
- [self offsetCenterCoordinateBy:NSMakePoint(0, MGLKeyPanningIncrement) animated:YES];
-}
-
-- (IBAction)moveDown:(__unused id)sender {
- [self offsetCenterCoordinateBy:NSMakePoint(0, -MGLKeyPanningIncrement) animated:YES];
-}
-
-- (IBAction)moveLeft:(__unused id)sender {
- [self offsetCenterCoordinateBy:NSMakePoint(MGLKeyPanningIncrement, 0) animated:YES];
-}
-
-- (IBAction)moveRight:(__unused id)sender {
- [self offsetCenterCoordinateBy:NSMakePoint(-MGLKeyPanningIncrement, 0) animated:YES];
-}
-
-- (IBAction)moveToBeginningOfParagraph:(__unused id)sender {
- if (self.zoomEnabled) {
- [self setZoomLevel:round(self.zoomLevel) + 1 animated:YES];
- }
-}
-
-- (IBAction)moveToEndOfParagraph:(__unused id)sender {
- if (self.zoomEnabled) {
- [self setZoomLevel:round(self.zoomLevel) - 1 animated:YES];
- }
-}
-
-- (IBAction)moveWordLeft:(__unused id)sender {
- if (self.rotateEnabled) {
- [self offsetDirectionBy:MGLKeyRotationIncrement animated:YES];
- }
-}
-
-- (IBAction)moveWordRight:(__unused id)sender {
- if (self.rotateEnabled) {
- [self offsetDirectionBy:-MGLKeyRotationIncrement animated:YES];
- }
-}
-
-- (void)setZoomEnabled:(BOOL)zoomEnabled {
- _zoomEnabled = zoomEnabled;
- _zoomControls.enabled = zoomEnabled;
- _zoomControls.hidden = !zoomEnabled;
-}
-
-- (void)setRotateEnabled:(BOOL)rotateEnabled {
- _rotateEnabled = rotateEnabled;
- _compass.enabled = rotateEnabled;
- _compass.hidden = !rotateEnabled;
-}
-
-#pragma mark Ornaments
-
-/// Updates the zoom controls’ enabled state based on the current zoom level.
-- (void)updateZoomControls {
- [_zoomControls setEnabled:self.zoomLevel > self.minimumZoomLevel forSegment:0];
- [_zoomControls setEnabled:self.zoomLevel < self.maximumZoomLevel forSegment:1];
-}
-
-/// Updates the compass to point in the same direction as the map.
-- (void)updateCompass {
- // The circular slider control goes counterclockwise, whereas our map
- // measures its direction clockwise.
- _compass.doubleValue = -self.direction;
-}
-
-- (IBAction)rotate:(NSSlider *)sender {
- [self setDirection:-sender.doubleValue animated:YES];
-}
-
-- (IBAction)giveFeedback:(id)sender {
- MGLMapCamera *camera = self.camera;
- double zoomLevel = self.zoomLevel;
- NSMutableArray *urls = [NSMutableArray array];
- for (MGLAttributionInfo *info in [self.style attributionInfosWithFontSize:0 linkColor:nil]) {
- NSURL *url = [info feedbackURLForStyleURL:self.styleURL
- atCenterCoordinate:camera.centerCoordinate
- zoomLevel:zoomLevel
- direction:camera.heading
- pitch:camera.pitch];
- if (url) {
- [urls addObject:url];
- }
- }
- [[NSWorkspace sharedWorkspace] openURLs:urls
- withAppBundleIdentifier:nil
- options:0
- additionalEventParamDescriptor:nil
- launchIdentifiers:nil];
-}
-
-#pragma mark Annotations
-
-- (nullable NSArray<id <MGLAnnotation>> *)annotations {
- if (_annotationContextsByAnnotationTag.empty()) {
- return nil;
- }
-
- // Map all the annotation tags to the annotations themselves.
- std::vector<id <MGLAnnotation>> annotations;
- std::transform(_annotationContextsByAnnotationTag.begin(),
- _annotationContextsByAnnotationTag.end(),
- std::back_inserter(annotations),
- ^ id <MGLAnnotation> (const std::pair<MGLAnnotationTag, MGLAnnotationContext> &pair) {
- return pair.second.annotation;
- });
- return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()];
-}
-
-- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotations
-{
- return [self visibleAnnotationsInRect:self.bounds];
-}
-
-- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect
-{
- if (_annotationContextsByAnnotationTag.empty())
- {
- return nil;
- }
-
- std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect];
- std::vector<MGLAnnotationTag> shapeAnnotationTags = [self shapeAnnotationTagsInRect:rect];
-
- if (shapeAnnotationTags.size()) {
- annotationTags.insert(annotationTags.end(), shapeAnnotationTags.begin(), shapeAnnotationTags.end());
- }
-
- if (annotationTags.size())
- {
- NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()];
-
- for (auto const& annotationTag: annotationTags)
- {
- if (!_annotationContextsByAnnotationTag.count(annotationTag) ||
- annotationTag == MGLAnnotationTagNotFound)
- {
- continue;
- }
-
- MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
- NSAssert(annotationContext.annotation, @"Missing annotation for tag %llu.", annotationTag);
- if (annotationContext.annotation)
- {
- [annotations addObject:annotationContext.annotation];
- }
- }
-
- return [annotations copy];
- }
-
- return nil;
-}
-
-/// Returns the annotation assigned the given tag. Cheap.
-- (id <MGLAnnotation>)annotationWithTag:(MGLAnnotationTag)tag {
- if ( ! _annotationContextsByAnnotationTag.count(tag) ||
- tag == MGLAnnotationTagNotFound) {
- return nil;
- }
-
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
- return annotationContext.annotation;
-}
-
-/// Returns the annotation tag assigned to the given annotation.
-- (MGLAnnotationTag)annotationTagForAnnotation:(id <MGLAnnotation>)annotation {
- if (!annotation || _annotationTagsByAnnotation.count(annotation) == 0) {
- return MGLAnnotationTagNotFound;
- }
-
- return _annotationTagsByAnnotation.at(annotation);
-}
-
-- (void)addAnnotation:(id <MGLAnnotation>)annotation {
- if (annotation) {
- [self addAnnotations:@[annotation]];
- }
-}
-
-- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
- if (!annotations) {
- return;
- }
-
- [self willChangeValueForKey:@"annotations"];
-
- BOOL delegateHasImagesForAnnotations = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)];
-
- for (id <MGLAnnotation> annotation in annotations) {
- NSAssert([annotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation");
-
- // adding the same annotation object twice is a no-op
- if (_annotationTagsByAnnotation.count(annotation) != 0) {
- continue;
- }
-
- if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
- // The multipoint knows how to style itself (with the map view’s help).
- MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation;
- if (!multiPoint.pointCount) {
- continue;
- }
-
- _isChangingAnnotationLayers = YES;
- MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]);
- MGLAnnotationContext context;
- context.annotation = annotation;
- _annotationContextsByAnnotationTag[annotationTag] = context;
- _annotationTagsByAnnotation[annotation] = annotationTag;
-
- [(NSObject *)annotation addObserver:self forKeyPath:@"coordinates" options:0 context:(void *)(NSUInteger)annotationTag];
- } else if (![annotation isKindOfClass:[MGLMultiPolyline class]]
- && ![annotation isKindOfClass:[MGLMultiPolygon class]]
- && ![annotation isKindOfClass:[MGLShapeCollection class]]
- && ![annotation isKindOfClass:[MGLPointCollection class]]) {
- MGLAnnotationImage *annotationImage = nil;
- if (delegateHasImagesForAnnotations) {
- annotationImage = [self.delegate mapView:self imageForAnnotation:annotation];
- }
- if (!annotationImage) {
- annotationImage = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName];
- }
- if (!annotationImage) {
- annotationImage = self.defaultAnnotationImage;
- }
-
- NSString *symbolName = annotationImage.styleIconIdentifier;
- if (!symbolName) {
- symbolName = [MGLAnnotationSpritePrefix stringByAppendingString:annotationImage.reuseIdentifier];
- annotationImage.styleIconIdentifier = symbolName;
- }
-
- if (!self.annotationImagesByIdentifier[annotationImage.reuseIdentifier]) {
- self.annotationImagesByIdentifier[annotationImage.reuseIdentifier] = annotationImage;
- [self installAnnotationImage:annotationImage];
- }
-
- MGLAnnotationTag annotationTag = _mbglMap->addAnnotation(mbgl::SymbolAnnotation {
- MGLPointFromLocationCoordinate2D(annotation.coordinate),
- symbolName.UTF8String ?: ""
- });
-
- MGLAnnotationContext context;
- context.annotation = annotation;
- context.imageReuseIdentifier = annotationImage.reuseIdentifier;
- _annotationContextsByAnnotationTag[annotationTag] = context;
- _annotationTagsByAnnotation[annotation] = annotationTag;
-
- if ([annotation isKindOfClass:[NSObject class]]) {
- NSAssert(![annotation isKindOfClass:[MGLMultiPoint class]], @"Point annotation should not be MGLMultiPoint.");
- [(NSObject *)annotation addObserver:self forKeyPath:@"coordinate" options:0 context:(void *)(NSUInteger)annotationTag];
- }
-
- // Opt into potentially expensive tooltip tracking areas.
- if ([annotation respondsToSelector:@selector(toolTip)] && annotation.toolTip.length) {
- _wantsToolTipRects = YES;
- }
- }
- }
-
- [self didChangeValueForKey:@"annotations"];
- if (_isChangingAnnotationLayers) {
- [self.style willChangeValueForKey:@"layers"];
- }
-
- [self updateAnnotationTrackingAreas];
-}
-
-/// Initializes and returns a default annotation image that depicts a round pin
-/// rising from the center, with a shadow slightly below center. The alignment
-/// rect therefore excludes the bottom half.
-- (MGLAnnotationImage *)defaultAnnotationImage {
- NSImage *image = MGLDefaultMarkerImage();
- NSRect alignmentRect = image.alignmentRect;
- alignmentRect.origin.y = NSMidY(alignmentRect);
- alignmentRect.size.height /= 2;
- image.alignmentRect = alignmentRect;
- return [MGLAnnotationImage annotationImageWithImage:image
- reuseIdentifier:MGLDefaultStyleMarkerSymbolName];
-}
-
-/// Sends the raw pixel data of the annotation image’s image to mbgl and
-/// calculates state needed for hit testing later.
-- (void)installAnnotationImage:(MGLAnnotationImage *)annotationImage {
- NSString *iconIdentifier = annotationImage.styleIconIdentifier;
- self.annotationImagesByIdentifier[annotationImage.reuseIdentifier] = annotationImage;
-
- NSImage *image = annotationImage.image;
- NSSize size = image.size;
- if (size.width == 0 || size.height == 0 || !image.valid) {
- // Can’t create an empty sprite. An image that hasn’t loaded is also useless.
- return;
- }
-
- _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
-
- // Create a slop area with a “radius” equal to the annotation image’s entire
- // size, allowing the eventual click to be on any point within this image.
- // Union this slop area with any existing slop areas.
- _unionedAnnotationImageSize = NSMakeSize(MAX(_unionedAnnotationImageSize.width, size.width),
- MAX(_unionedAnnotationImageSize.height, size.height));
-
- // Opt into potentially expensive cursor tracking areas.
- if (annotationImage.cursor) {
- _wantsCursorRects = YES;
- }
-}
-
-- (void)removeAnnotation:(id <MGLAnnotation>)annotation {
- if (annotation) {
- [self removeAnnotations:@[annotation]];
- }
-}
-
-- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
- if (!annotations) {
- return;
- }
-
- [self willChangeValueForKey:@"annotations"];
-
- for (id <MGLAnnotation> annotation in annotations) {
- NSAssert([annotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation");
-
- MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation];
- NSAssert(annotationTag != MGLAnnotationTagNotFound, @"No ID for annotation %@", annotation);
-
- if (annotationTag == _selectedAnnotationTag) {
- [self deselectAnnotation:annotation];
- }
- if (annotationTag == _lastSelectedAnnotationTag) {
- _lastSelectedAnnotationTag = MGLAnnotationTagNotFound;
- }
-
- _annotationContextsByAnnotationTag.erase(annotationTag);
- _annotationTagsByAnnotation.erase(annotation);
-
- if ([annotation isKindOfClass:[NSObject class]] &&
- ![annotation isKindOfClass:[MGLMultiPoint class]]) {
- [(NSObject *)annotation removeObserver:self forKeyPath:@"coordinate" context:(void *)(NSUInteger)annotationTag];
- } else if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
- [(NSObject *)annotation removeObserver:self forKeyPath:@"coordinates" context:(void *)(NSUInteger)annotationTag];
- }
-
- _isChangingAnnotationLayers = YES;
- _mbglMap->removeAnnotation(annotationTag);
- }
-
- [self didChangeValueForKey:@"annotations"];
- if (_isChangingAnnotationLayers) {
- [self.style willChangeValueForKey:@"layers"];
- }
-
- [self updateAnnotationTrackingAreas];
-}
-
-- (nullable MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier {
- return self.annotationImagesByIdentifier[identifier];
-}
-
-- (id <MGLAnnotation>)annotationAtPoint:(NSPoint)point {
- return [self annotationWithTag:[self annotationTagAtPoint:point persistingResults:NO]];
-}
-
-/**
- Returns the tag of the annotation at the given point in the view.
-
- This is more involved than it sounds: if multiple point annotations overlap
- near the point, this method cycles through them so that each of them is
- accessible to the user at some point.
-
- @param persist True to remember the cycleable set of annotations, so that a
- different annotation is returned the next time this method is called
- with the same point. Setting this parameter to false is useful for
- asking “what if?”
- */
-- (MGLAnnotationTag)annotationTagAtPoint:(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);
- std::vector<MGLAnnotationTag> nearbyAnnotations = [self annotationTagsInRect:queryRect];
- std::vector<MGLAnnotationTag> nearbyShapeAnnotations = [self shapeAnnotationTagsInRect:queryRect];
-
- if (nearbyShapeAnnotations.size()) {
- nearbyAnnotations.insert(nearbyAnnotations.end(), nearbyShapeAnnotations.begin(), nearbyShapeAnnotations.end());
- }
-
- if (nearbyAnnotations.size()) {
- // Assume that the user is fat-fingering an annotation.
- NSRect hitRect = NSInsetRect({ point, NSZeroSize },
- -MGLAnnotationImagePaddingForHitTest,
- -MGLAnnotationImagePaddingForHitTest);
-
- // Filter out any annotation whose image is unselectable or for which
- // hit testing fails.
- auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) {
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- NSAssert(annotation, @"Unknown annotation found nearby click");
- if (!annotation) {
- return true;
- }
-
- if ([annotation isKindOfClass:[MGLMultiPoint class]])
- {
- if ([self.delegate respondsToSelector:@selector(mapView:shapeAnnotationIsEnabled:)]) {
- return !!(![self.delegate mapView:self shapeAnnotationIsEnabled:(MGLMultiPoint *)annotation]);
- } else {
- return false;
- }
- }
-
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- if (!annotationImage.selectable) {
- return true;
- }
-
- // Filter out the annotation if the fattened finger didn’t land on a
- // translucent or opaque pixel in the image.
- NSRect annotationRect = [self frameOfImage:annotationImage.image
- centeredAtCoordinate:annotation.coordinate];
- return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect
- context:nil hints:nil flipped:NO];
- });
- nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end));
- }
-
- MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound;
- if (nearbyAnnotations.size()) {
- // The first selection in the cycle should be the one nearest to the
- // tap. Also the annotation tags need to be stable in order to compare them with
- // the remembered tags _annotationsNearbyLastClick.
- CLLocationCoordinate2D currentCoordinate = [self convertPoint:point toCoordinateFromView:self];
- std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag tagA, const MGLAnnotationTag tagB) {
- CLLocationCoordinate2D coordinateA = [[self annotationWithTag:tagA] coordinate];
- CLLocationCoordinate2D coordinateB = [[self annotationWithTag:tagB] coordinate];
- CLLocationDegrees deltaA = hypot(coordinateA.latitude - currentCoordinate.latitude,
- coordinateA.longitude - currentCoordinate.longitude);
- CLLocationDegrees deltaB = hypot(coordinateB.latitude - currentCoordinate.latitude,
- coordinateB.longitude - currentCoordinate.longitude);
- return deltaA < deltaB;
- });
-
- if (nearbyAnnotations == _annotationsNearbyLastClick) {
- // The last time we persisted a set of annotations, we had the same
- // set of annotations as we do now. Cycle through them.
- if (_lastSelectedAnnotationTag == MGLAnnotationTagNotFound
- || _lastSelectedAnnotationTag == nearbyAnnotations.back()) {
- // Either no annotation is selected or the last annotation in
- // the set was selected. Wrap around to the first annotation in
- // the set.
- hitAnnotationTag = nearbyAnnotations.front();
- } else {
- auto result = std::find(nearbyAnnotations.begin(),
- nearbyAnnotations.end(),
- _lastSelectedAnnotationTag);
- if (result == nearbyAnnotations.end()) {
- // An annotation from this set hasn’t been selected before.
- // Select the first (nearest) one.
- hitAnnotationTag = nearbyAnnotations.front();
- } else {
- // Step to the next annotation in the set.
- auto distance = std::distance(nearbyAnnotations.begin(), result);
- hitAnnotationTag = nearbyAnnotations[distance + 1];
- }
- }
- } else {
- // Remember the nearby annotations for the next time this method is
- // called.
- if (persist) {
- _annotationsNearbyLastClick = nearbyAnnotations;
- }
-
- // Choose the first nearby annotation.
- if (nearbyAnnotations.size()) {
- hitAnnotationTag = nearbyAnnotations.front();
- }
- }
- }
-
- return hitAnnotationTag;
-}
-
-/// Returns the tags of the annotations coincident with the given rectangle.
-- (std::vector<MGLAnnotationTag>)annotationTagsInRect:(NSRect)rect {
- // Cocoa origin is at the lower-left corner.
- return self.renderer->queryPointAnnotations({
- { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
- { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) },
- });
-}
-
-- (std::vector<MGLAnnotationTag>)shapeAnnotationTagsInRect:(NSRect)rect {
- // Cocoa origin is at the lower-left corner.
- return _rendererFrontend->getRenderer()->queryShapeAnnotations({
- { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
- { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) },
- });
-}
-
-- (id <MGLAnnotation>)selectedAnnotation {
- if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag) ||
- _selectedAnnotationTag == MGLAnnotationTagNotFound) {
- return nil;
- }
-
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag);
- return annotationContext.annotation;
-}
-
-- (void)setSelectedAnnotation:(id <MGLAnnotation>)annotation {
- MGLLogDebug(@"Selecting annotation: %@", annotation);
- [self willChangeValueForKey:@"selectedAnnotations"];
- _selectedAnnotationTag = [self annotationTagForAnnotation:annotation];
- if (_selectedAnnotationTag != MGLAnnotationTagNotFound) {
- _lastSelectedAnnotationTag = _selectedAnnotationTag;
- }
- [self didChangeValueForKey:@"selectedAnnotations"];
-}
-
-- (NSArray<id <MGLAnnotation>> *)selectedAnnotations {
- id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
- return selectedAnnotation ? @[selectedAnnotation] : @[];
-}
-
-- (void)setSelectedAnnotations:(NSArray<id <MGLAnnotation>> *)selectedAnnotations {
- MGLLogDebug(@"Selecting: %lu annotations", selectedAnnotations.count);
- if (!selectedAnnotations.count) {
- return;
- }
-
- id <MGLAnnotation> firstAnnotation = selectedAnnotations[0];
- NSAssert([firstAnnotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation");
- if ([firstAnnotation isKindOfClass:[MGLMultiPoint class]]) {
- return;
- }
-
- [self selectAnnotation:firstAnnotation];
-}
-
-- (BOOL)isMovingAnnotationIntoViewSupportedForAnnotation:(id<MGLAnnotation>)annotation animated:(BOOL)animated {
- // Consider delegating
- return [annotation isKindOfClass:[MGLPointAnnotation class]];
-}
-
-- (void)selectAnnotation:(id <MGLAnnotation>)annotation
-{
- MGLLogDebug(@"Selecting annotation: %@", annotation);
- [self selectAnnotation:annotation atPoint:NSZeroPoint];
-}
-
-- (void)selectAnnotation:(id <MGLAnnotation>)annotation atPoint:(NSPoint)gesturePoint
-{
- MGLLogDebug(@"Selecting annotation: %@ atPoint: %@", annotation, NSStringFromPoint(gesturePoint));
- [self selectAnnotation:annotation atPoint:gesturePoint moveIntoView:YES animateSelection:YES];
-}
-
-- (void)selectAnnotation:(id <MGLAnnotation>)annotation atPoint:(NSPoint)gesturePoint moveIntoView:(BOOL)moveIntoView animateSelection:(BOOL)animateSelection
-{
- MGLLogDebug(@"Selecting annotation: %@ atPoint: %@ moveIntoView: %@ animateSelection: %@", annotation, NSStringFromPoint(gesturePoint), MGLStringFromBOOL(moveIntoView), MGLStringFromBOOL(animateSelection));
- id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
- if (annotation == selectedAnnotation) {
- return;
- }
-
- // Deselect the annotation before reselecting it.
- [self deselectAnnotation:selectedAnnotation];
-
- // Add the annotation to the map if it hasn’t been added yet.
- MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation];
- if (annotationTag == MGLAnnotationTagNotFound) {
- [self addAnnotation:annotation];
- }
-
- if (moveIntoView) {
- moveIntoView = [self isMovingAnnotationIntoViewSupportedForAnnotation:annotation animated:animateSelection];
- }
-
- // The annotation's anchor will bounce to the current click.
- NSRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag];
-
- // Check for invalid (zero) positioning rect
- if (NSEqualRects(positioningRect, NSZeroRect)) {
- CLLocationCoordinate2D origin = annotation.coordinate;
- positioningRect.origin = [self convertCoordinate:origin toPointToView:self];
- }
-
- BOOL shouldShowCallout = ([annotation respondsToSelector:@selector(title)]
- && annotation.title
- && !self.calloutForSelectedAnnotation.shown
- && [self.delegate respondsToSelector:@selector(mapView:annotationCanShowCallout:)]
- && [self.delegate mapView:self annotationCanShowCallout:annotation]);
-
- if (NSIsEmptyRect(NSIntersectionRect(positioningRect, self.bounds))) {
- if (!moveIntoView && !NSEqualPoints(gesturePoint, NSZeroPoint)) {
- positioningRect = CGRectMake(gesturePoint.x, gesturePoint.y, positioningRect.size.width, positioningRect.size.height);
- }
- }
- // Onscreen or partially on-screen
- else if (!shouldShowCallout) {
- moveIntoView = NO;
- }
-
- self.selectedAnnotation = annotation;
-
- // For the callout to be shown, the annotation must have a title, its
- // callout must not already be shown, and the annotation must be able to
- // show a callout according to the delegate.
- if (shouldShowCallout) {
- NSPopover *callout = [self calloutForAnnotation:annotation];
-
- // Hang the callout off the right edge of the annotation image’s
- // alignment rect, or off the left edge in a right-to-left UI.
- callout.delegate = self;
- self.calloutForSelectedAnnotation = callout;
-
- NSRectEdge edge = (self.userInterfaceLayoutDirection == NSUserInterfaceLayoutDirectionRightToLeft
- ? NSMinXEdge
- : NSMaxXEdge);
-
- // The following will do nothing if the positioning rect is not on-screen. See
- // `-[MGLMapView updateAnnotationCallouts]` for presenting the callout when the selected
- // annotation comes back on-screen.
- [callout showRelativeToRect:positioningRect ofView:self preferredEdge:edge];
- }
-
- if (moveIntoView)
- {
- moveIntoView = NO;
-
- NSRect (^edgeInsetsInsetRect)(NSRect, NSEdgeInsets) = ^(NSRect rect, NSEdgeInsets insets) {
- return NSMakeRect(rect.origin.x + insets.left,
- rect.origin.y + insets.bottom,
- rect.size.width - insets.left - insets.right,
- rect.size.height - insets.top - insets.bottom);
- };
-
- // Add padding around the positioning rect (in essence an inset from the edge of the viewport
- NSRect expandedPositioningRect = positioningRect;
-
- if (shouldShowCallout) {
- // If we have a callout, expand this rect to include a buffer
- expandedPositioningRect = edgeInsetsInsetRect(positioningRect, MGLMapViewOffscreenAnnotationPadding);
- }
-
- // Used for callout positioning, and moving offscreen annotations onscreen.
- CGRect constrainedRect = edgeInsetsInsetRect(self.bounds, self.contentInsets);
- CGRect bounds = constrainedRect;
-
- // Any one of these cases should trigger a move onscreen
- CGFloat minX = CGRectGetMinX(expandedPositioningRect);
-
- if (minX < CGRectGetMinX(bounds)) {
- constrainedRect.origin.x = minX;
- moveIntoView = YES;
- }
- else {
- CGFloat maxX = CGRectGetMaxX(expandedPositioningRect);
-
- if (maxX > CGRectGetMaxX(bounds)) {
- constrainedRect.origin.x = maxX - CGRectGetWidth(constrainedRect);
- moveIntoView = YES;
- }
- }
-
- CGFloat minY = CGRectGetMinY(expandedPositioningRect);
-
- if (minY < CGRectGetMinY(bounds)) {
- constrainedRect.origin.y = minY;
- moveIntoView = YES;
- }
- else {
- CGFloat maxY = CGRectGetMaxY(expandedPositioningRect);
-
- if (maxY > CGRectGetMaxY(bounds)) {
- constrainedRect.origin.y = maxY - CGRectGetHeight(constrainedRect);
- moveIntoView = YES;
- }
- }
-
- if (moveIntoView)
- {
- CGPoint center = CGPointMake(CGRectGetMidX(constrainedRect), CGRectGetMidY(constrainedRect));
- CLLocationCoordinate2D centerCoord = [self convertPoint:center toCoordinateFromView:self];
- [self setCenterCoordinate:centerCoord animated:animateSelection];
- }
- }
-}
-
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated {
- MGLLogDebug(@"Showing: %lu annotations animated: %@", annotations.count, MGLStringFromBOOL(animated));
- CGFloat maximumPadding = 100;
- CGFloat yPadding = (NSHeight(self.bounds) / 5 <= maximumPadding) ? (NSHeight(self.bounds) / 5) : maximumPadding;
- CGFloat xPadding = (NSWidth(self.bounds) / 5 <= maximumPadding) ? (NSWidth(self.bounds) / 5) : maximumPadding;
-
- NSEdgeInsets edgeInsets = NSEdgeInsetsMake(yPadding, xPadding, yPadding, xPadding);
-
- [self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
-}
-
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
- [self showAnnotations:annotations edgePadding:insets animated:animated completionHandler:nil];
-}
-
-- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion {
- if (!annotations.count) {
- if (completion) {
- completion();
- }
- return;
- }
-
- mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
-
- for (id <MGLAnnotation> annotation in annotations) {
- if ([annotation conformsToProtocol:@protocol(MGLOverlay)]) {
- bounds.extend(MGLLatLngBoundsFromCoordinateBounds(((id <MGLOverlay>)annotation).overlayBounds));
- } else {
- bounds.extend(MGLLatLngFromLocationCoordinate2D(annotation.coordinate));
- }
- }
-
- [self setVisibleCoordinateBounds:MGLCoordinateBoundsFromLatLngBounds(bounds)
- edgePadding:insets
- animated:animated
- completionHandler:completion];
-}
-
-/// Returns a popover detailing the annotation.
-- (NSPopover *)calloutForAnnotation:(id <MGLAnnotation>)annotation {
- NSPopover *callout = [[NSPopover alloc] init];
- callout.behavior = NSPopoverBehaviorTransient;
-
- NSViewController *viewController;
- if ([self.delegate respondsToSelector:@selector(mapView:calloutViewControllerForAnnotation:)]) {
- NSViewController *viewControllerFromDelegate = [self.delegate mapView:self
- calloutViewControllerForAnnotation:annotation];
- if (viewControllerFromDelegate) {
- viewController = viewControllerFromDelegate;
- }
- }
- if (!viewController) {
- viewController = self.calloutViewController;
- }
- NSAssert(viewController, @"Unable to load MGLAnnotationCallout view controller");
- // The popover’s view controller can bind to KVO-compliant key paths of the
- // annotation.
- viewController.representedObject = annotation;
- callout.contentViewController = viewController;
-
- return callout;
-}
-
-- (NSViewController *)calloutViewController {
- // Lazily load a default view controller.
- if (!_calloutViewController) {
- _calloutViewController = [[NSViewController alloc] initWithNibName:@"MGLAnnotationCallout"
- bundle:[NSBundle mgl_frameworkBundle]];
- }
- return _calloutViewController;
-}
-
-/// Returns the rectangle that represents the annotation image of the annotation
-/// with the given tag. This rectangle is fitted to the image’s alignment rect
-/// and is appropriate for positioning a popover.
-- (NSRect)positioningRectForCalloutForAnnotationWithTag:(MGLAnnotationTag)annotationTag {
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- if (!annotation) {
- return NSZeroRect;
- }
- if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
- CLLocationCoordinate2D origin = annotation.coordinate;
- CGPoint originPoint = [self convertCoordinate:origin toPointToView:self];
- return CGRectMake(originPoint.x, originPoint.y, MGLAnnotationImagePaddingForHitTest, MGLAnnotationImagePaddingForHitTest);
-
- }
-
- NSImage *image = [self imageOfAnnotationWithTag:annotationTag].image;
- if (!image) {
- image = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName].image;
- }
- if (!image) {
- return NSZeroRect;
- }
-
- NSRect positioningRect = [self frameOfImage:image centeredAtCoordinate:annotation.coordinate];
- positioningRect = NSOffsetRect(image.alignmentRect, positioningRect.origin.x, positioningRect.origin.y);
- return NSInsetRect(positioningRect, -MGLAnnotationImagePaddingForCallout,
- -MGLAnnotationImagePaddingForCallout);
-}
-
-/// Returns the rectangle relative to the viewport that represents the given
-/// image centered at the given coordinate.
-- (NSRect)frameOfImage:(NSImage *)image centeredAtCoordinate:(CLLocationCoordinate2D)coordinate {
- NSPoint calloutAnchorPoint = [self convertCoordinate:coordinate toPointToView:self];
- return NSInsetRect({ calloutAnchorPoint, NSZeroSize }, -image.size.width / 2, -image.size.height / 2);
-}
-
-/// Returns the annotation image assigned to the annotation with the given tag.
-- (MGLAnnotationImage *)imageOfAnnotationWithTag:(MGLAnnotationTag)annotationTag {
- if (annotationTag == MGLAnnotationTagNotFound
- || _annotationContextsByAnnotationTag.count(annotationTag) == 0) {
- return nil;
- }
-
- NSString *customSymbol = _annotationContextsByAnnotationTag.at(annotationTag).imageReuseIdentifier;
- NSString *symbolName = customSymbol.length ? customSymbol : MGLDefaultStyleMarkerSymbolName;
-
- return [self dequeueReusableAnnotationImageWithIdentifier:symbolName];
-}
-
-- (void)deselectAnnotation:(id <MGLAnnotation>)annotation {
- if (!annotation || self.selectedAnnotation != annotation) {
- return;
- }
-
- // Close the callout popover gracefully.
- NSPopover *callout = self.calloutForSelectedAnnotation;
- [callout performClose:self];
-
- self.selectedAnnotation = nil;
-}
-
-/// Move the annotation callout to point to the selected annotation at its
-/// current position.
-- (void)updateAnnotationCallouts {
- NSPopover *callout = self.calloutForSelectedAnnotation;
- if (callout) {
- NSRect rect = [self positioningRectForCalloutForAnnotationWithTag:_selectedAnnotationTag];
-
- NSAssert(!NSEqualRects(rect, NSZeroRect), @"Positioning rect should be non-zero");
-
- if (!NSIsEmptyRect(NSIntersectionRect(rect, self.bounds))) {
-
- // It's possible that the current callout hasn't been presented (since the original
- // positioningRect was offscreen). We can check that the callout has a valid window
- // This results in the callout being presented just as the annotation comes on screen
- // which matches MapKit, but (currently) not iOS.
- if (!callout.contentViewController.view.window) {
- NSRectEdge edge = (self.userInterfaceLayoutDirection == NSUserInterfaceLayoutDirectionRightToLeft
- ? NSMinXEdge
- : NSMaxXEdge);
- // Re-present the callout
- [callout showRelativeToRect:rect ofView:self preferredEdge:edge];
- }
- else {
- callout.positioningRect = rect;
- }
- }
- }
-}
-
-#pragma mark MGLMultiPointDelegate methods
-
-- (double)alphaForShapeAnnotation:(MGLShape *)annotation {
- if (_delegateHasAlphasForShapeAnnotations) {
- return [self.delegate mapView:self alphaForShapeAnnotation:annotation];
- }
- return 1.0;
-}
-
-- (mbgl::Color)strokeColorForShapeAnnotation:(MGLShape *)annotation {
- NSColor *color = (_delegateHasStrokeColorsForShapeAnnotations
- ? [self.delegate mapView:self strokeColorForShapeAnnotation:annotation]
- : [NSColor selectedMenuItemColor]);
- return color.mgl_color;
-}
-
-- (mbgl::Color)fillColorForPolygonAnnotation:(MGLPolygon *)annotation {
- NSColor *color = (_delegateHasFillColorsForShapeAnnotations
- ? [self.delegate mapView:self fillColorForPolygonAnnotation:annotation]
- : [NSColor selectedMenuItemColor]);
- return color.mgl_color;
-}
-
-- (CGFloat)lineWidthForPolylineAnnotation:(MGLPolyline *)annotation {
- if (_delegateHasLineWidthsForShapeAnnotations) {
- return [self.delegate mapView:self lineWidthForPolylineAnnotation:(MGLPolyline *)annotation];
- }
- return 3.0;
-}
-
-#pragma mark MGLPopoverDelegate methods
-
-- (void)popoverDidShow:(__unused NSNotification *)notification {
- id <MGLAnnotation> annotation = self.selectedAnnotation;
- if (annotation && [self.delegate respondsToSelector:@selector(mapView:didSelectAnnotation:)]) {
- [self.delegate mapView:self didSelectAnnotation:annotation];
- }
-}
-
-- (void)popoverDidClose:(__unused NSNotification *)notification {
- // Deselect the closed popover, in case the popover was closed due to user
- // action.
- id <MGLAnnotation> annotation = self.calloutForSelectedAnnotation.contentViewController.representedObject;
- self.calloutForSelectedAnnotation = nil;
- self.selectedAnnotation = nil;
-
- if ([self.delegate respondsToSelector:@selector(mapView:didDeselectAnnotation:)]) {
- [self.delegate mapView:self didDeselectAnnotation:annotation];
- }
-}
-
-#pragma mark Overlays
-
-- (nonnull NSArray<id <MGLOverlay>> *)overlays
-{
- if (self.annotations == nil) { return @[]; }
-
- NSMutableArray<id <MGLOverlay>> *mutableOverlays = [NSMutableArray array];
-
- [self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
- if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
- {
- [mutableOverlays addObject:(id<MGLOverlay>)annotation];
- }
- }];
-
- return [NSArray arrayWithArray:mutableOverlays];
-}
-
-- (void)addOverlay:(id <MGLOverlay>)overlay {
- MGLLogDebug(@"Adding overlay: %@", overlay);
- [self addOverlays:@[overlay]];
-}
-
-- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays
-{
- MGLLogDebug(@"Adding: %lu overlays", overlays.count);
-#if DEBUG
- for (id <MGLOverlay> overlay in overlays) {
- NSAssert([overlay conformsToProtocol:@protocol(MGLOverlay)], @"Overlay does not conform to MGLOverlay");
- }
-#endif
- [self addAnnotations:overlays];
-}
-
-- (void)removeOverlay:(id <MGLOverlay>)overlay {
- MGLLogDebug(@"Removing overlay: %@", overlay);
- [self removeOverlays:@[overlay]];
-}
-
-- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays {
- MGLLogDebug(@"Removing: %lu overlays", overlays.count);
-#if DEBUG
- for (id <MGLOverlay> overlay in overlays) {
- NSAssert([overlay conformsToProtocol:@protocol(MGLOverlay)], @"Overlay does not conform to MGLOverlay");
- }
-#endif
- [self removeAnnotations:overlays];
-}
-
-#pragma mark Tooltips and cursors
-
-- (void)updateAnnotationTrackingAreas {
- if (_wantsToolTipRects) {
- [self removeAllToolTips];
- std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:self.bounds];
- for (MGLAnnotationTag annotationTag : annotationTags) {
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- if ([annotation respondsToSelector:@selector(toolTip)] && annotation.toolTip.length) {
- // Add a tooltip tracking area over the annotation image’s
- // frame, accounting for the image’s alignment rect.
- 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)annotationTag];
- }
- }
- // Opt into potentially expensive cursor tracking areas.
- if (annotationImage.cursor) {
- _wantsCursorRects = YES;
- }
- }
- }
-
- // Blow away any cursor tracking areas and rebuild them. That’s the
- // potentially expensive part.
- if (_wantsCursorRects) {
- [self.window invalidateCursorRectsForView:self];
- }
-}
-
-- (NSString *)view:(__unused NSView *)view stringForToolTip:(__unused NSToolTipTag)tag point:(__unused NSPoint)point userData:(void *)data {
- NSAssert((NSUInteger)data < MGLAnnotationTagNotFound, @"Invalid annotation tag in tooltip rect user data.");
- MGLAnnotationTag annotationTag = (MGLAnnotationTag)MIN((NSUInteger)data, MGLAnnotationTagNotFound);
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- return annotation.toolTip;
-}
-
-- (void)resetCursorRects {
- // Drag to pan has a grabbing hand cursor.
- if ([self isPanningWithGesture]) {
- [self addCursorRect:self.bounds cursor:[NSCursor closedHandCursor]];
- return;
- }
-
- // The rest of this method can be expensive, so bail if no annotations have
- // ever had custom cursors.
- if (!_wantsCursorRects) {
- return;
- }
-
- std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:self.bounds];
- for (MGLAnnotationTag annotationTag : annotationTags) {
- id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- if (annotationImage.cursor) {
- // Add a cursor tracking area over the annotation image, respecting
- // the image’s alignment rect.
- 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 Data
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point {
- MGLLogDebug(@"Querying visibleFeaturesAtPoint: %@", NSStringFromPoint(point));
- return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
-}
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
- MGLLogDebug(@"Querying visibleFeaturesAtPoint: %@ inStyleLayersWithIdentifiers: %@", NSStringFromPoint(point), styleLayerIdentifiers);
- return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
-}
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
- MGLLogDebug(@"Querying visibleFeaturesAtPoint: %@ inStyleLayersWithIdentifiers: %@ predicate: %@", NSStringFromPoint(point), styleLayerIdentifiers, predicate);
- // Cocoa origin is at the lower-left corner.
- mbgl::ScreenCoordinate screenCoordinate = { point.x, NSHeight(self.bounds) - point.y };
-
- mbgl::optional<std::vector<std::string>> optionalLayerIDs;
- if (styleLayerIdentifiers) {
- __block std::vector<std::string> layerIDs;
- layerIDs.reserve(styleLayerIdentifiers.count);
- [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
- layerIDs.push_back(identifier.UTF8String);
- }];
- optionalLayerIDs = layerIDs;
- }
-
- mbgl::optional<mbgl::style::Filter> optionalFilter;
- if (predicate) {
- optionalFilter = predicate.mgl_filter;
- }
-
- std::vector<mbgl::Feature> features = _rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate, { optionalLayerIDs, optionalFilter });
- return MGLFeaturesFromMBGLFeatures(features);
-}
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect {
- MGLLogDebug(@"Querying visibleFeaturesInRect: %@", NSStringFromRect(rect));
- return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
-}
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
- MGLLogDebug(@"Querying visibleFeaturesInRect: %@ inStyleLayersWithIdentifiers: %@", NSStringFromRect(rect), styleLayerIdentifiers);
- return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
-}
-
-- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
- MGLLogDebug(@"Querying visibleFeaturesInRect: %@ inStyleLayersWithIdentifiers: %@ predicate: %@", NSStringFromRect(rect), styleLayerIdentifiers, predicate);
- // Cocoa origin is at the lower-left corner.
- mbgl::ScreenBox screenBox = {
- { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
- { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) },
- };
-
- mbgl::optional<std::vector<std::string>> optionalLayerIDs;
- if (styleLayerIdentifiers) {
- __block std::vector<std::string> layerIDs;
- layerIDs.reserve(styleLayerIdentifiers.count);
- [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
- layerIDs.push_back(identifier.UTF8String);
- }];
- optionalLayerIDs = layerIDs;
- }
-
- mbgl::optional<mbgl::style::Filter> optionalFilter;
- if (predicate) {
- optionalFilter = predicate.mgl_filter;
- }
-
- std::vector<mbgl::Feature> features = _rendererFrontend->getRenderer()->queryRenderedFeatures(screenBox, { optionalLayerIDs, optionalFilter });
- return MGLFeaturesFromMBGLFeatures(features);
-}
-
-#pragma mark User interface validation
-
-- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
- if (menuItem.action == @selector(giveFeedback:)) {
- return YES;
- }
- return NO;
-}
-
-#pragma mark Interface Builder methods
-
-- (void)prepareForInterfaceBuilder {
- [super prepareForInterfaceBuilder];
-
- // Color the background a glorious Mapbox teal.
- self.layer.borderColor = [NSColor colorWithRed:59/255.
- green:178/255.
- blue:208/255.
- alpha:0.8].CGColor;
- self.layer.borderWidth = 2;
- self.layer.backgroundColor = [NSColor colorWithRed:59/255.
- green:178/255.
- blue:208/255.
- alpha:0.6].CGColor;
-
- // Place a playful marker right smack dab in the middle.
- self.layer.contents = MGLDefaultMarkerImage();
- self.layer.contentsGravity = kCAGravityCenter;
- self.layer.contentsScale = [NSScreen mainScreen].backingScaleFactor;
-}
-
-#pragma mark Geometric methods
-
-- (NSPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable NSView *)view {
- if (!CLLocationCoordinate2DIsValid(coordinate)) {
- return NSMakePoint(NAN, NAN);
- }
- return [self convertLatLng:MGLLatLngFromLocationCoordinate2D(coordinate) toPointToView:view];
-}
-
-/// Converts a geographic coordinate to a point in the view’s coordinate system.
-- (NSPoint)convertLatLng:(mbgl::LatLng)latLng toPointToView:(nullable NSView *)view {
- mbgl::ScreenCoordinate pixel = _mbglMap->pixelForLatLng(latLng);
- // Cocoa origin is at the lower-left corner.
- pixel.y = NSHeight(self.bounds) - pixel.y;
- return [self convertPoint:NSMakePoint(pixel.x, pixel.y) toView:view];
-}
-
-- (CLLocationCoordinate2D)convertPoint:(NSPoint)point toCoordinateFromView:(nullable NSView *)view {
- return MGLLocationCoordinate2DFromLatLng([self convertPoint:point toLatLngFromView:view]);
-}
-
-/// Converts a point in the view’s coordinate system to a geographic coordinate.
-- (mbgl::LatLng)convertPoint:(NSPoint)point toLatLngFromView:(nullable NSView *)view {
- NSPoint convertedPoint = [self convertPoint:point fromView:view];
- return _mbglMap->latLngForPixel({
- convertedPoint.x,
- // mbgl origin is at the top-left corner.
- NSHeight(self.bounds) - convertedPoint.y,
- }).wrapped();
-}
-
-- (NSRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable NSView *)view {
- return [self convertLatLngBounds:MGLLatLngBoundsFromCoordinateBounds(bounds) toRectToView:view];
-}
-
-/// Converts a geographic bounding box to a rectangle in the view’s coordinate
-/// system.
-- (NSRect)convertLatLngBounds:(mbgl::LatLngBounds)bounds toRectToView:(nullable NSView *)view {
- auto northwest = bounds.northwest();
- auto northeast = bounds.northeast();
- auto southwest = bounds.southwest();
- auto southeast = bounds.southeast();
-
- auto center = [self convertPoint:{ NSMidX(view.bounds), NSMidY(view.bounds) } toLatLngFromView:view];
-
- // Extend bounds to account for the antimeridian
- northwest.unwrapForShortestPath(center);
- northeast.unwrapForShortestPath(center);
- southwest.unwrapForShortestPath(center);
- southeast.unwrapForShortestPath(center);
-
- auto correctedLatLngBounds = mbgl::LatLngBounds::empty();
- correctedLatLngBounds.extend(northwest);
- correctedLatLngBounds.extend(northeast);
- correctedLatLngBounds.extend(southwest);
- correctedLatLngBounds.extend(southeast);
-
- NSRect rect = { [self convertLatLng:correctedLatLngBounds.southwest() toPointToView:view], CGSizeZero };
- rect = MGLExtendRect(rect, [self convertLatLng:correctedLatLngBounds.northeast() toPointToView:view]);
- return rect;
-}
-
-- (MGLCoordinateBounds)convertRect:(NSRect)rect toCoordinateBoundsFromView:(nullable NSView *)view {
- return MGLCoordinateBoundsFromLatLngBounds([self convertRect:rect toLatLngBoundsFromView:view]);
-}
-
-/// Converts a rectangle in the given view’s coordinate system to a geographic
-/// bounding box.
-- (mbgl::LatLngBounds)convertRect:(NSRect)rect toLatLngBoundsFromView:(nullable NSView *)view {
- auto bounds = mbgl::LatLngBounds::empty();
- auto bottomLeft = [self convertPoint:{ NSMinX(rect), NSMinY(rect) } toLatLngFromView:view];
- auto bottomRight = [self convertPoint:{ NSMaxX(rect), NSMinY(rect) } toLatLngFromView:view];
- auto topRight = [self convertPoint:{ NSMaxX(rect), NSMaxY(rect) } toLatLngFromView:view];
- auto topLeft = [self convertPoint:{ NSMinX(rect), NSMaxY(rect) } toLatLngFromView:view];
-
- // If the bounds straddles the antimeridian, unwrap it so that one side
- // extends beyond ±180° longitude.
- auto center = [self convertPoint:{ NSMidX(rect), NSMidY(rect) } toLatLngFromView:view];
- bottomLeft.unwrapForShortestPath(center);
- bottomRight.unwrapForShortestPath(center);
- topRight.unwrapForShortestPath(center);
- topLeft.unwrapForShortestPath(center);
-
- bounds.extend(bottomLeft);
- bounds.extend(bottomRight);
- bounds.extend(topRight);
- bounds.extend(topLeft);
-
- return bounds;
-}
-
-- (CLLocationDistance)metersPerPointAtLatitude:(CLLocationDegrees)latitude {
- return mbgl::Projection::getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
-}
-
-#pragma mark Debugging
-
-- (MGLMapDebugMaskOptions)debugMask {
- mbgl::MapDebugOptions options = _mbglMap->getDebug();
- MGLMapDebugMaskOptions mask = 0;
- if (options & mbgl::MapDebugOptions::TileBorders) {
- mask |= MGLMapDebugTileBoundariesMask;
- }
- if (options & mbgl::MapDebugOptions::ParseStatus) {
- mask |= MGLMapDebugTileInfoMask;
- }
- if (options & mbgl::MapDebugOptions::Timestamps) {
- mask |= MGLMapDebugTimestampsMask;
- }
- if (options & mbgl::MapDebugOptions::Collision) {
- mask |= MGLMapDebugCollisionBoxesMask;
- }
- if (options & mbgl::MapDebugOptions::Overdraw) {
- mask |= MGLMapDebugOverdrawVisualizationMask;
- }
- if (options & mbgl::MapDebugOptions::StencilClip) {
- mask |= MGLMapDebugStencilBufferMask;
- }
- if (options & mbgl::MapDebugOptions::DepthBuffer) {
- mask |= MGLMapDebugDepthBufferMask;
- }
- return mask;
-}
-
-- (void)setDebugMask:(MGLMapDebugMaskOptions)debugMask {
- mbgl::MapDebugOptions options = mbgl::MapDebugOptions::NoDebug;
- if (debugMask & MGLMapDebugTileBoundariesMask) {
- options |= mbgl::MapDebugOptions::TileBorders;
- }
- if (debugMask & MGLMapDebugTileInfoMask) {
- options |= mbgl::MapDebugOptions::ParseStatus;
- }
- if (debugMask & MGLMapDebugTimestampsMask) {
- options |= mbgl::MapDebugOptions::Timestamps;
- }
- if (debugMask & MGLMapDebugCollisionBoxesMask) {
- options |= mbgl::MapDebugOptions::Collision;
- }
- if (debugMask & MGLMapDebugOverdrawVisualizationMask) {
- options |= mbgl::MapDebugOptions::Overdraw;
- }
- if (debugMask & MGLMapDebugStencilBufferMask) {
- options |= mbgl::MapDebugOptions::StencilClip;
- }
- if (debugMask & MGLMapDebugDepthBufferMask) {
- options |= mbgl::MapDebugOptions::DepthBuffer;
- }
- _mbglMap->setDebug(options);
-}
-
-@end
diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h
deleted file mode 100644
index 098164cd75..0000000000
--- a/platform/macos/src/MGLMapViewDelegate.h
+++ /dev/null
@@ -1,352 +0,0 @@
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@class MGLMapView;
-@class MGLAnnotationImage;
-@class MGLPolygon;
-@class MGLPolyline;
-@class MGLShape;
-
-/**
- The `MGLMapViewDelegate` protocol defines a set of optional methods that you
- can use to receive messages from an `MGLMapView` instance. Because many map
- operations require the `MGLMapView` class to load data asynchronously, the map
- view calls these methods to notify your application when specific operations
- complete. The map view also uses these methods to request information about
- annotations displayed on the map, such as the styles and interaction modes to
- apply to individual annotations.
- */
-@protocol MGLMapViewDelegate <NSObject>
-
-@optional
-
-#pragma mark Responding to Map Viewpoint Changes
-
-/**
- Tells the delegate that the viewpoint depicted by the map view is about to
- change.
-
- This method is called whenever the currently displayed map camera will start
- changing for any reason.
-
- @param mapView The map view whose viewpoint will change.
- @param animated Whether the change will cause an animated effect on the map.
- */
-- (void)mapView:(MGLMapView *)mapView cameraWillChangeAnimated:(BOOL)animated;
-
-/**
- Tells the delegate that the viewpoint depicted by the map view is changing.
-
- This method is called as the currently displayed map camera changes as part of
- an animation, whether due to a user gesture or due to a call to a method such
- as `-[MGLMapView setCamera:animated:]`. This method can be called before
- `-mapViewDidFinishLoadingMap:` is called.
-
- During the animation, this method may be called many times to report updates
- to the viewpoint. Therefore, your implementation of this method should be as
- lightweight as possible to avoid affecting performance.
-
- @param mapView The map view whose viewpoint is changing.
- */
-- (void)mapViewCameraIsChanging:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the viewpoint depicted by the map view has finished
- changing.
-
- This method is called whenever the currently displayed map camera has finished
- changing, after any calls to `-mapViewRegionIsChanging:` due to animation.
- This method can be called before `-mapViewDidFinishLoadingMap:` is
- called.
-
- @param mapView The map view whose viewpoint has changed.
- @param animated Whether the change caused an animated effect on the map.
- */
-- (void)mapView:(MGLMapView *)mapView cameraDidChangeAnimated:(BOOL)animated;
-
-/**
- Asks the delegate whether the map view should be allowed to change from the
- existing camera to the new camera in response to a user gesture.
-
- This method is called as soon as the user gesture is recognized. It is not
- called in response to a programmatic camera change, such as by setting the
- `centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
-
- This method is called many times during gesturing, so you should avoid performing
- complex or performance-intensive tasks in your implementation.
-
- @param mapView The map view that the user is manipulating.
- @param oldCamera The camera representing the viewpoint at the moment the
- gesture is recognized. If this method returns `NO`, the map view’s camera
- continues to be this camera.
- @param newCamera The expected camera after the gesture completes. If this
- method returns `YES`, this camera becomes the map view’s camera.
- @return A Boolean value indicating whether the map view should stay at
- `oldCamera` or change to `newCamera`.
- */
-- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera;
-
-#pragma mark Loading the Map
-
-/**
- Tells the delegate that the map view will begin to load.
-
- This method is called whenever the map view starts loading, including when a
- new style has been set and the map must reload.
-
- @param mapView The map view that is starting to load.
- */
-- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map view has finished loading.
-
- This method is called whenever the map view finishes loading, either after the
- initial load or after a style change has forced a reload.
-
- @param mapView The map view that has finished loading.
- */
-- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map view was unable to load data needed for
- displaying the map.
-
- This method may be called for a variety of reasons, including a network
- connection failure or a failure to fetch the style from the server. You can use
- the given error message to notify the user that map data is unavailable.
-
- @param mapView The map view that is unable to load the data.
- @param error The reason the data could not be loaded.
- */
-- (void)mapViewDidFailLoadingMap:(MGLMapView *)mapView withError:(NSError *)error;
-
-- (void)mapViewWillStartRenderingMap:(MGLMapView *)mapView;
-- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
-
-/**
- Tells the delegate that the map view is about to redraw.
-
- This method is called any time the map view needs to redraw due to a change in
- the viewpoint or style property transition. This method may be called very
- frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
- implementation of this method should be as lightweight as possible to avoid
- affecting performance.
-
- @param mapView The map view that is about to redraw.
- */
-- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map view has just redrawn.
-
- This method is called any time the map view needs to redraw due to a change in
- the viewpoint or style property transition. This method may be called very
- frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
- implementation of this method should be as lightweight as possible to avoid
- affecting performance.
-
- @param mapView The map view that has just redrawn.
- */
-- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
-
-/**
- Tells the delegate that the map view is entering an idle state, and no more
- drawing will be necessary until new data is loaded or there is some interaction
- with the map.
-
- - No camera transitions are in progress
- - All currently requested tiles have loaded
- - All fade/transition animations have completed
-
- @param mapView The map view that has just entered the idle state.
- */
-- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map has just finished loading a style.
-
- This method is called during the initialization of the map view and after any
- subsequent loading of a new style. This method is called between the
- `-mapViewWillStartRenderingMap:` and `-mapViewDidFinishRenderingMap:` delegate
- methods. Changes to sources or layers of the current style do not cause this
- method to be called.
-
- This method is the earliest opportunity to modify the layout or appearance of
- the current style before the map view is displayed to the user.
-
- @param mapView The map view that has just loaded a style.
- @param style The style that was loaded.
- */
-- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style;
-
-- (nullable NSImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName;
-
-/**
- Asks the delegate whether the map view should evict cached images.
-
- This method is called in two scenarios: when the cumulative size of unused images
- exceeds the cache size or when the last tile that includes the image is removed from
- memory.
-
- @param mapView The map view that is evicting the image.
- @param imageName The image name that is going to be removed.
- @return A Boolean value indicating whether the map view should evict
- the cached image.
- */
-- (BOOL)mapView:(MGLMapView *)mapView shouldRemoveStyleImage:(NSString *)imageName;
-
-#pragma mark Managing the Appearance of Annotations
-
-/**
- Returns an annotation image object to mark the given point annotation object on
- the map.
-
- @param mapView The map view that requested the annotation image.
- @param annotation The object representing the annotation that is about to be
- displayed.
- @return The image object to display for the given annotation or `nil` if you
- want to display the default marker image.
- */
-- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Returns the alpha value to use when rendering a shape annotation.
-
- A value of 0.0 results in a completely transparent shape. A value of 1.0, the
- default, results in a completely opaque shape.
-
- This method sets the opacity of an entire shape, inclusive of its stroke and
- fill. To independently set the values for stroke or fill, specify an alpha
- component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or
- `-mapView:fillColorForPolygonAnnotation:`.
-
- @param mapView The map view rendering the shape annotation.
- @param annotation The annotation being rendered.
- @return An alpha value between 0 and 1.0.
- */
-- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
-
-/**
- Returns the color to use when rendering the outline of a shape annotation.
-
- The default stroke color is the selected menu item color. If a pattern color is
- specified, the result is undefined.
-
- Opacity may be set by specifying an alpha component. The default alpha value is
- `1.0` and results in a completely opaque stroke.
-
- @param mapView The map view rendering the shape annotation.
- @param annotation The annotation being rendered.
- @return A color to use for the shape outline.
- */
-- (NSColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation;
-
-/**
- Returns the color to use when rendering the fill of a polygon annotation.
-
- The default fill color is the selected menu item color. If a pattern color is
- specified, the result is undefined.
-
- Opacity may be set by specifying an alpha component. The default alpha value is
- `1.0` and results in a completely opaque shape.
-
- @param mapView The map view rendering the polygon annotation.
- @param annotation The annotation being rendered.
- @return The polygon’s interior fill color.
- */
-- (NSColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation;
-
-/**
- Returns the line width in points to use when rendering the outline of a
- polyline annotation.
-
- By default, the polyline is outlined with a line 3.0 points wide.
-
- @param mapView The map view rendering the polygon annotation.
- @param annotation The annotation being rendered.
- @return A line width for the polyline, measured in points.
- */
-- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;
-
-#pragma mark Selecting Annotations
-
-/**
- Returns a Boolean value indicating whether the shape annotation can be selected.
-
- If the return value is `YES`, the user can select the annotation by clicking
- on it. If the delegate does not implement this method, the default value is `YES`.
-
- @param mapView The map view that has selected the annotation.
- @param annotation The object representing the shape annotation.
- @return A Boolean value indicating whether the annotation can be selected.
- */
-- (BOOL)mapView:(MGLMapView *)mapView shapeAnnotationIsEnabled:(MGLShape *)annotation;
-
-/**
- Tells the delegate that one of its annotations has been selected.
-
- You can use this method to track changes to the selection state of annotations.
-
- @param mapView The map view containing the annotation.
- @param annotation The annotation that was selected.
- */
-- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Tells the delegate that one of its annotations has been deselected.
-
- You can use this method to track changes in the selection state of annotations.
-
- @param mapView The map view containing the annotation.
- @param annotation The annotation that was deselected.
- */
-- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation;
-
-#pragma mark Managing Callout Popovers
-
-/**
- Returns a Boolean value indicating whether the annotation is able to display
- extra information in a callout popover.
-
- This method is called after an annotation is selected, before any callout is
- displayed for the annotation.
-
- If the return value is `YES`, a callout popover is shown when the user clicks
- on an annotation, selecting it. The default callout displays the annotation’s
- title and subtitle. You can customize the popover’s contents by implementing
- the `-mapView:calloutViewControllerForAnnotation:` method.
-
- If the return value is `NO`, or if this method is absent from the delegate, or
- if the annotation lacks a title, the annotation will not show a callout even
- when selected.
-
- @param mapView The map view that has selected the annotation.
- @param annotation The object representing the annotation.
- @return A Boolean value indicating whether the annotation should show a
- callout.
- */
-- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation;
-
-/**
- Returns a view controller to manage the callout popover’s content view.
-
- Like any instance of `NSPopover`, an annotation callout manages its contents
- with a view controller. The annotation object is the view controller’s
- represented object. This means that you can bind controls in the view
- controller’s content view to KVO-compliant properties of the annotation object,
- such as `title` and `subtitle`.
-
- If each annotation should have an identical callout, you can set the
- `MGLMapView.calloutViewController` property instead.
-
- @param mapView The map view that is requesting a callout view controller.
- @param annotation The object representing the annotation.
- @return A view controller for the given annotation.
- */
-- (nullable NSViewController *)mapView:(MGLMapView *)mapView calloutViewControllerForAnnotation:(id <MGLAnnotation>)annotation;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/MGLMapView_Private.h b/platform/macos/src/MGLMapView_Private.h
deleted file mode 100644
index 3d9b36c30a..0000000000
--- a/platform/macos/src/MGLMapView_Private.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#import "MGLMapView.h"
-
-#include <mbgl/util/size.hpp>
-
-namespace mbgl {
- class Map;
- class Renderer;
-}
-
-@class MGLSource;
-
-@interface MGLMapView (Private)
-
-/// True if the view or application is in a state where it is not expected to be
-/// actively drawing.
-@property (nonatomic, readonly, getter=isDormant) BOOL dormant;
-
-// These properties exist because initially, both the latitude and longitude are
-// NaN. You have to set both the latitude and longitude simultaneously. If you
-// set the latitude but reuse the current longitude, and the current longitude
-// happens to be NaN, there will be no change because the resulting coordinate
-// pair is invalid.
-
-/// Center latitude set independently of the center longitude in an inspectable.
-@property (nonatomic) CLLocationDegrees pendingLatitude;
-/// Center longitude set independently of the center latitude in an inspectable.
-@property (nonatomic) CLLocationDegrees pendingLongitude;
-
-/// The map view’s OpenGL rendering context, if it is backed by an OpenGL based view.
-@property (readonly, nonatomic, nullable) CGLContextObj context;
-
-- (mbgl::Size)framebufferSize;
-
-/// Map observers
-- (void)cameraWillChangeAnimated:(BOOL)animated;
-- (void)cameraIsChanging;
-- (void)cameraDidChangeAnimated:(BOOL)animated;
-- (void)mapViewWillStartLoadingMap;
-- (void)mapViewDidFinishLoadingMap;
-- (void)mapViewDidFailLoadingMapWithError:(nonnull NSError *)error;
-- (void)mapViewWillStartRenderingFrame;
-- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered;
-- (void)mapViewWillStartRenderingMap;
-- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered;
-- (void)mapViewDidBecomeIdle;
-- (void)mapViewDidFinishLoadingStyle;
-- (void)sourceDidChange:(nonnull MGLSource *)source;
-- (BOOL)shouldRemoveStyleImage:(nonnull NSString *)imageName;
-
-/// Asynchronously render a frame of the map.
-- (void)setNeedsRerender;
-
-/// Synchronously render a frame of the map.
-- (void)renderSync;
-
-- (BOOL)isTargetingInterfaceBuilder;
-
-- (nonnull mbgl::Map *)mbglMap;
-
-- (nonnull mbgl::Renderer *)renderer;
-
-@end
diff --git a/platform/macos/src/MGLOpenGLLayer.h b/platform/macos/src/MGLOpenGLLayer.h
deleted file mode 100644
index 832664f397..0000000000
--- a/platform/macos/src/MGLOpenGLLayer.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-/// A subclass of NSOpenGLLayer that creates the environment mbgl needs to
-/// render good-looking maps.
-@interface MGLOpenGLLayer : NSOpenGLLayer
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/MGLOpenGLLayer.mm b/platform/macos/src/MGLOpenGLLayer.mm
deleted file mode 100644
index fde2b52404..0000000000
--- a/platform/macos/src/MGLOpenGLLayer.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-#import "MGLOpenGLLayer.h"
-
-#import "MGLMapView_Private.h"
-
-@implementation MGLOpenGLLayer {
- NSOpenGLContext *_context;
-}
-
-- (MGLMapView *)mapView {
- return (MGLMapView *)super.view;
-}
-
-// - (BOOL)isAsynchronous {
-// return YES;
-// }
-
-- (BOOL)needsDisplayOnBoundsChange {
- return YES;
-}
-
-- (CGRect)frame {
- return self.view.bounds;
-}
-
-- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat {
- if (!_context) {
- _context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
- }
- return _context;
-}
-
-- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask {
- NSOpenGLPixelFormatAttribute pfas[] = {
- NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFAClosestPolicy,
- NSOpenGLPFAAccumSize, 32,
- NSOpenGLPFAColorSize, 24,
- NSOpenGLPFAAlphaSize, 8,
- NSOpenGLPFADepthSize, 16,
- NSOpenGLPFAStencilSize, 8,
- NSOpenGLPFAScreenMask, mask,
- NSOpenGLPFAAllowOfflineRenderers, // Allows using the integrated GPU
- 0
- };
- return [[NSOpenGLPixelFormat alloc] initWithAttributes:pfas];
-}
-
-- (BOOL)canDrawInOpenGLContext:(__unused NSOpenGLContext *)context pixelFormat:(__unused NSOpenGLPixelFormat *)pixelFormat forLayerTime:(__unused CFTimeInterval)t displayTime:(__unused const CVTimeStamp *)ts {
- return !self.mapView.dormant;
-}
-
-- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat forLayerTime:(CFTimeInterval)t displayTime:(const CVTimeStamp *)ts {
- [self.mapView renderSync];
- [super drawInOpenGLContext:context pixelFormat:pixelFormat forLayerTime:t displayTime:ts];
-}
-
-@end
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
deleted file mode 100644
index 6728992d6b..0000000000
--- a/platform/macos/src/Mapbox.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-#import "MGLFoundation.h"
-
-/// Project version number for Mapbox.
-FOUNDATION_EXPORT MGL_EXPORT double MapboxVersionNumber;
-
-/// Project version string for Mapbox.
-FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
-
-#import "MGLAccountManager.h"
-#import "MGLAnnotation.h"
-#import "MGLAnnotationImage.h"
-#import "MGLClockDirectionFormatter.h"
-#import "MGLCluster.h"
-#import "MGLCompassDirectionFormatter.h"
-#import "MGLCoordinateFormatter.h"
-#import "MGLDistanceFormatter.h"
-#import "MGLFeature.h"
-#import "MGLGeometry.h"
-#import "MGLLight.h"
-#import "MGLMapCamera.h"
-#import "MGLMapView.h"
-#import "MGLMapView+IBAdditions.h"
-#import "MGLMapViewDelegate.h"
-#import "MGLMultiPoint.h"
-#import "MGLOfflinePack.h"
-#import "MGLOfflineRegion.h"
-#import "MGLOfflineStorage.h"
-#import "MGLOverlay.h"
-#import "MGLPointAnnotation.h"
-#import "MGLPointCollection.h"
-#import "MGLPolygon.h"
-#import "MGLPolyline.h"
-#import "MGLShape.h"
-#import "MGLShapeCollection.h"
-#import "MGLStyle.h"
-#import "MGLStyleLayer.h"
-#import "MGLForegroundStyleLayer.h"
-#import "MGLVectorStyleLayer.h"
-#import "MGLFillStyleLayer.h"
-#import "MGLFillExtrusionStyleLayer.h"
-#import "MGLLineStyleLayer.h"
-#import "MGLSymbolStyleLayer.h"
-#import "MGLRasterStyleLayer.h"
-#import "MGLCircleStyleLayer.h"
-#import "MGLBackgroundStyleLayer.h"
-#import "MGLHeatmapStyleLayer.h"
-#import "MGLHillshadeStyleLayer.h"
-#import "MGLOpenGLStyleLayer.h"
-#import "MGLSource.h"
-#import "MGLTileSource.h"
-#import "MGLVectorTileSource.h"
-#import "MGLShapeSource.h"
-#import "MGLComputedShapeSource.h"
-#import "MGLRasterTileSource.h"
-#import "MGLRasterDEMSource.h"
-#import "MGLImageSource.h"
-#import "MGLTilePyramidOfflineRegion.h"
-#import "MGLShapeOfflineRegion.h"
-#import "MGLTypes.h"
-#import "NSValue+MGLAdditions.h"
-#import "MGLStyleValue.h"
-#import "MGLAttributionInfo.h"
-#import "MGLMapSnapshotter.h"
-#import "NSExpression+MGLAdditions.h"
-#import "NSPredicate+MGLAdditions.h"
-#import "MGLLoggingConfiguration.h"
-#import "MGLNetworkConfiguration.h"
-#import "MGLAttributedExpression.h"
-#import "MGLSDKMetricsManager.h"
diff --git a/platform/macos/src/NSColor+MGLAdditions.h b/platform/macos/src/NSColor+MGLAdditions.h
deleted file mode 100644
index a3c5aba63f..0000000000
--- a/platform/macos/src/NSColor+MGLAdditions.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-#include <mbgl/util/color.hpp>
-#include <mbgl/style/property_value.hpp>
-
-@interface NSColor (MGLAdditions)
-
-/**
- Converts the color into an mbgl::Color in sRGB space.
- */
-- (mbgl::Color)mgl_color;
-
-/**
- Instantiates `NSColor` from an `mbgl::Color`
- */
-+ (NSColor *)mgl_colorWithColor:(mbgl::Color)color;
-
-- (mbgl::style::PropertyValue<mbgl::Color>)mgl_colorPropertyValue;
-
-@end
-
-@interface NSExpression (MGLColorAdditions)
-
-+ (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components;
-+ (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components;
-+ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions;
-
-@end
diff --git a/platform/macos/src/NSColor+MGLAdditions.mm b/platform/macos/src/NSColor+MGLAdditions.mm
deleted file mode 100644
index 6df3d750ce..0000000000
--- a/platform/macos/src/NSColor+MGLAdditions.mm
+++ /dev/null
@@ -1,124 +0,0 @@
-#import "NSColor+MGLAdditions.h"
-
-@implementation NSColor (MGLAdditions)
-
-- (mbgl::Color)mgl_color {
- CGFloat r, g, b, a;
-
- // The Mapbox Style Specification does not specify a color space, but it is
- // assumed to be sRGB for consistency with CSS.
- NSColor *srgbColor = self;
- if ([NSColor redColor].colorSpaceName == NSCalibratedRGBColorSpace) {
- srgbColor = [srgbColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
- } else {
- srgbColor = [srgbColor colorUsingColorSpace:[NSColorSpace sRGBColorSpace]];
- }
- [srgbColor getRed:&r green:&g blue:&b alpha:&a];
-
- // NSColor provides non-premultiplied color components, so we have to premultiply each
- // color component with the alpha value to transform it into a valid
- // mbgl::Color which expects premultiplied color components.
- return { static_cast<float>(r*a), static_cast<float>(g*a), static_cast<float>(b*a), static_cast<float>(a) };
-}
-
-+ (NSColor *)mgl_colorWithColor:(mbgl::Color)color {
- // If there is no alpha value, return original color values.
- if (color.a == 0.0f) {
- // macOS 10.12 Sierra and below uses calibrated RGB by default.
- if ([NSColor redColor].colorSpaceName == NSCalibratedRGBColorSpace) {
- return [NSColor colorWithCalibratedRed:color.r green:color.g blue:color.b alpha:color.a];
- } else {
- return [NSColor colorWithRed:color.r green:color.g blue:color.b alpha:color.a];
- }
- }
-
- // mbgl::Color provides premultiplied color components, so we have to convert color
- // components to non-premultiplied values to return a valid NSColor object.
- float red = static_cast<float>((color.r / color.a));
- float green = static_cast<float>((color.g / color.a));
- float blue = static_cast<float>((color.b / color.a));
-
- // macOS 10.12 Sierra and below uses calibrated RGB by default.
- if ([NSColor redColor].colorSpaceName == NSCalibratedRGBColorSpace) {
- return [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:color.a];
- } else {
- return [NSColor colorWithRed:red green:green blue:blue alpha:color.a];
- }
-}
-
-- (mbgl::style::PropertyValue<mbgl::Color>)mgl_colorPropertyValue {
- mbgl::Color color = self.mgl_color;
- return {{ color.r, color.g, color.b, color.a }};
-}
-
-@end
-
-@implementation NSExpression (MGLColorAdditions)
-
-+ (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components {
- if (NSColor *color = [self mgl_colorWithRGBComponents:components]) {
- return [NSExpression expressionForConstantValue:color];
- }
-
- NSExpression *color = [NSExpression expressionForConstantValue:[NSColor class]];
- NSExpression *alpha = [NSExpression expressionForConstantValue:@1.0];
- return [NSExpression expressionForFunction:color
- selectorName:@"colorWithRed:green:blue:alpha:"
- arguments:[components arrayByAddingObject:alpha]];
-}
-
-+ (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components {
- if (NSColor *color = [self mgl_colorWithRGBComponents:components]) {
- return [NSExpression expressionForConstantValue:color];
- }
-
- NSExpression *color = [NSExpression expressionForConstantValue:[NSColor class]];
- return [NSExpression expressionForFunction:color
- selectorName:@"colorWithRed:green:blue:alpha:"
- arguments:components];
-}
-
-/**
- Returns a color object corresponding to the given component expressions.
- */
-+ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions {
- // Map the component expressions to constant components. If any component is
- // a non-constant expression, the components cannot be converted into a
- // constant color value.
- std::vector<CGFloat> components;
- for (NSExpression *componentExpression in componentExpressions) {
- if (componentExpression.expressionType != NSConstantValueExpressionType) {
- return nil;
- }
-
- NSNumber *component = (NSNumber *)componentExpression.constantValue;
- if (![component isKindOfClass:[NSNumber class]]) {
- return nil;
- }
-
- components.push_back(component.doubleValue / 255.0);
- }
-
- if (components.size() < 4) {
- components.push_back(1.0);
- } else {
- // Alpha
- components.back() *= 255.0;
- }
-
-
- // macOS 10.12 Sierra and below uses calibrated RGB by default.
- if ([NSColor redColor].colorSpaceName == NSCalibratedRGBColorSpace) {
- return [NSColor colorWithCalibratedRed:components[0]
- green:components[1]
- blue:components[2]
- alpha:components[3]];
- }
- // The Mapbox Style Specification does not specify a color space, but it is
- // assumed to be sRGB for consistency with CSS.
- return [NSColor colorWithColorSpace:[NSColorSpace sRGBColorSpace]
- components:&components[0]
- count:components.size()];
-}
-
-@end
diff --git a/platform/macos/src/NSImage+MGLAdditions.h b/platform/macos/src/NSImage+MGLAdditions.h
deleted file mode 100644
index c08fc57bea..0000000000
--- a/platform/macos/src/NSImage+MGLAdditions.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#import <Cocoa/Cocoa.h>
-
-#include <mbgl/style/image.hpp>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface NSImage (MGLAdditions)
-
-- (nullable instancetype)initWithMGLPremultipliedImage:(mbgl::PremultipliedImage&&)image;
-
-- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)image;
-
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
-
-- (mbgl::PremultipliedImage) mgl_premultipliedImage;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/macos/src/NSImage+MGLAdditions.mm b/platform/macos/src/NSImage+MGLAdditions.mm
deleted file mode 100644
index 2666dfe790..0000000000
--- a/platform/macos/src/NSImage+MGLAdditions.mm
+++ /dev/null
@@ -1,49 +0,0 @@
-#import "NSImage+MGLAdditions.h"
-
-#include <mbgl/util/image+MGLAdditions.hpp>
-
-@implementation NSImage (MGLAdditions)
-
-- (nullable instancetype)initWithMGLPremultipliedImage:(mbgl::PremultipliedImage&&)src {
- CGImageRef image = CGImageCreateWithMGLPremultipliedImage(std::move(src));
- if (!image) {
- return nil;
- }
-
- self = [self initWithCGImage:image size:NSZeroSize];
- CGImageRelease(image);
- return self;
-}
-
-- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage {
- CGImageRef image = CGImageCreateWithMGLPremultipliedImage(styleImage->getImage().clone());
- if (!image) {
- return nil;
- }
-
- NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:image];
- CGImageRelease(image);
- CGFloat w = styleImage->getImage().size.width / styleImage->getPixelRatio();
- CGFloat h = styleImage->getImage().size.height / styleImage->getPixelRatio();
- if (self = [self initWithSize:NSMakeSize(w, h)]) {
- [self addRepresentation:rep];
- [self setTemplate:styleImage->isSdf()];
- }
- return self;
-}
-
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
- mbgl::PremultipliedImage cPremultipliedImage = self.mgl_premultipliedImage;
- auto imageWidth = cPremultipliedImage.size.width;
- return std::make_unique<mbgl::style::Image>([identifier UTF8String],
- std::move(cPremultipliedImage),
- (float)(imageWidth / self.size.width),
- [self isTemplate]);
-}
-
-- (mbgl::PremultipliedImage)mgl_premultipliedImage {
- CGImageRef ref = [self CGImageForProposedRect:nullptr context:nullptr hints:nullptr];
- return MGLPremultipliedImageFromCGImage(ref);
-}
-
-@end
diff --git a/platform/macos/src/NSProcessInfo+MGLAdditions.h b/platform/macos/src/NSProcessInfo+MGLAdditions.h
deleted file mode 100644
index 1dc1439d53..0000000000
--- a/platform/macos/src/NSProcessInfo+MGLAdditions.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#import <Foundation/Foundation.h>
-
-@interface NSProcessInfo (MGLAdditions)
-
-/**
- Returns YES if the current process is Interface Builder’s helper process for
- rendering designables.
- */
-- (BOOL)mgl_isInterfaceBuilderDesignablesAgent;
-
-@end
diff --git a/platform/macos/src/NSProcessInfo+MGLAdditions.m b/platform/macos/src/NSProcessInfo+MGLAdditions.m
deleted file mode 100644
index 0c287c030b..0000000000
--- a/platform/macos/src/NSProcessInfo+MGLAdditions.m
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "NSProcessInfo+MGLAdditions.h"
-
-@implementation NSProcessInfo (MGLAdditions)
-
-- (BOOL)mgl_isInterfaceBuilderDesignablesAgent {
- NSString *processName = self.processName;
- return [processName hasPrefix:@"IBAgent"] || [processName hasPrefix:@"IBDesignablesAgent"];
-}
-
-@end