diff options
Diffstat (limited to 'platform/macos')
-rw-r--r-- | platform/macos/CHANGELOG.md | 1 | ||||
-rw-r--r-- | platform/macos/INSTALL.md | 1 | ||||
-rw-r--r-- | platform/macos/app/MapDocument.m | 9 | ||||
-rw-r--r-- | platform/macos/macos.xcodeproj/project.pbxproj | 32 | ||||
-rw-r--r-- | platform/macos/sdk/Base.lproj/Localizable.strings | 15 | ||||
-rw-r--r-- | platform/macos/src/MGLAttributionButton.h | 16 | ||||
-rw-r--r-- | platform/macos/src/MGLAttributionButton.m | 50 | ||||
-rw-r--r-- | platform/macos/src/MGLAttributionButton.mm | 55 | ||||
-rw-r--r-- | platform/macos/src/MGLMapView.h | 19 | ||||
-rw-r--r-- | platform/macos/src/MGLMapView.mm | 119 | ||||
-rw-r--r-- | platform/macos/test/MGLAttributionButtonTests.m | 31 |
11 files changed, 224 insertions, 124 deletions
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 1d5aa93638..ab85890edb 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -20,6 +20,7 @@ * Fixed an issue where the style zoom levels were not respected when deciding when to render a layer. ([#5811](https://github.com/mapbox/mapbox-gl-native/issues/5811)) * Fixed an issue where feature querying sometimes failed to return the expected features when the map was tilted. ([#6773](https://github.com/mapbox/mapbox-gl-native/pull/6773)) * MGLFeature’s `attributes` and `identifier` properties are now writable. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728)) +* Attribution views now display the correct attribution for the current style. ([#5999](https://github.com/mapbox/mapbox-gl-native/pull/5999)) * If MGLMapView is unable to obtain or parse a style, it now calls its delegate’s `-mapViewDidFailLoadingMap:withError:` method. ([#6145](https://github.com/mapbox/mapbox-gl-native/pull/6145)) * Added the `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` delegate method, which offers the earliest opportunity to modify the layout or appearance of the current style before the map view is displayed to the user. ([#6636](https://github.com/mapbox/mapbox-gl-native/pull/6636)) * Fixed an issue causing stepwise zoom functions to be misinterpreted. ([#6328](https://github.com/mapbox/mapbox-gl-native/pull/6328)) diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md index 665af128c5..a4b944611d 100644 --- a/platform/macos/INSTALL.md +++ b/platform/macos/INSTALL.md @@ -28,6 +28,7 @@ In a storyboard or XIB: 3. MGLMapView needs to be layer-backed: * You can make the window layer-backed by selecting the window and checking Full Size Content View in the Attributes inspector. This allows the map view to underlap the title bar and toolbar. * Alternatively, if you don’t want the entire window to be layer-backed, you can make just the map view layer-backed by selecting it and checking its entry under the View Effects inspector’s Core Animation Layer section. +4. Add a map feedback item to your Help menu. (Drag Menu Item from the Object library into Main Menu ‣ Help ‣ Menu.) Title it “Improve This Map” or similar, and connect it to the `giveFeedback:` action of First Responder. If you need to manipulate the map view programmatically: diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index 6c36d00d73..c742440e84 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -666,15 +666,6 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio }]; } -#pragma mark Help methods - -- (IBAction)giveFeedback:(id)sender { - CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate; - NSURL *feedbackURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.mapbox.com/map-feedback/#/%.5f/%.5f/%.0f", - centerCoordinate.longitude, centerCoordinate.latitude, round(self.mapView.zoomLevel + 1)]]; - [[NSWorkspace sharedWorkspace] openURL:feedbackURL]; -} - #pragma mark Mouse events - (void)handlePressGesture:(NSPressGestureRecognizer *)gestureRecognizer { diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 9a264f0bb7..2f7ef1c2df 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -60,6 +60,8 @@ 5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; 558F18221D0B13B100123F46 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 558F18211D0B13B000123F46 /* libmbgl-loop.a */; }; 55D9B4B11D005D3900C1CCE2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; }; + DA00FC8A1D5EEAC3009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */; }; + DA00FC8B1D5EEAC3009AABC8 /* MGLAttributionInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */; }; DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */; }; DA2207BC1DC076940002F84D /* MGLStyleValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */; }; DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA2784FD1DF03060001D5B8D /* Media.xcassets */; }; @@ -83,6 +85,8 @@ DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */; }; DA7262071DEEDD460043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA7262081DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA7262061DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm */; }; + DA7DC9811DED5F5C0027472F /* MGLVectorSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */; }; + DA7DC9831DED647F0027472F /* MGLRasterSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7DC9821DED647F0027472F /* MGLRasterSource_Private.h */; }; DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E961CC2E3400062CAFB /* AppDelegate.m */; }; DA839E9A1CC2E3400062CAFB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E991CC2E3400062CAFB /* main.m */; }; DA839E9D1CC2E3400062CAFB /* MapDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E9C1CC2E3400062CAFB /* MapDocument.m */; }; @@ -184,7 +188,7 @@ DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */; }; DAE6C3B21CC31EF300DB3429 /* MGLAttributionButton.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */; }; - DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */; }; + DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.mm */; }; DAE6C3B41CC31EF300DB3429 /* MGLCompassCell.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */; }; DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */; }; DAE6C3B61CC31EF300DB3429 /* MGLMapView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */; }; @@ -203,6 +207,8 @@ DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */; }; DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */; }; DAED38601D62CED700D7640F /* NSURL+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAED385E1D62CED700D7640F /* NSURL+MGLAdditions.m */; }; + DAEDC4321D6033F1000224FF /* MGLAttributionInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */; }; + DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */; }; DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */; }; DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */; }; DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */; }; @@ -300,6 +306,8 @@ 558F18211D0B13B000123F46 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/osx/Debug/libmbgl-loop.a"; sourceTree = "<group>"; }; 55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 55FE0E8D1D100A0900FD240B /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/macos/config.xcconfig; sourceTree = "<group>"; }; + DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; }; + DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; }; DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; }; DA2207BA1DC076930002F84D /* test-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Bridging-Header.h"; sourceTree = "<group>"; }; DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLStyleValueTests.swift; sourceTree = "<group>"; }; @@ -324,6 +332,8 @@ DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; }; DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; }; DA7262061DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; }; + DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorSource_Private.h; sourceTree = "<group>"; }; + DA7DC9821DED647F0027472F /* MGLRasterSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource_Private.h; sourceTree = "<group>"; }; DA839E921CC2E3400062CAFB /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DA839E951CC2E3400062CAFB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; DA839E961CC2E3400062CAFB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; @@ -440,7 +450,7 @@ DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapViewDelegate.h; sourceTree = "<group>"; }; DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationImage.m; sourceTree = "<group>"; }; DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionButton.h; sourceTree = "<group>"; }; - DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButton.m; sourceTree = "<group>"; }; + DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionButton.mm; sourceTree = "<group>"; }; DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCompassCell.h; sourceTree = "<group>"; }; DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCompassCell.m; sourceTree = "<group>"; }; DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Private.h; sourceTree = "<group>"; }; @@ -459,6 +469,8 @@ DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; }; DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; }; DAED385E1D62CED700D7640F /* NSURL+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MGLAdditions.m"; sourceTree = "<group>"; }; + DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAttributionInfoTests.m; path = ../../darwin/test/MGLAttributionInfoTests.m; sourceTree = "<group>"; }; + DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButtonTests.m; sourceTree = "<group>"; }; DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; }; DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; }; DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLExpressionTests.mm; path = ../../darwin/test/MGLExpressionTests.mm; sourceTree = "<group>"; }; @@ -543,11 +555,13 @@ DA8F25991D51CAD00010E6B5 /* MGLSource_Private.h */, 352742801D4C243B00A1ECE6 /* MGLSource.mm */, DA8F25951D51CAC70010E6B5 /* MGLVectorSource.h */, + DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */, DA8F25961D51CAC70010E6B5 /* MGLVectorSource.mm */, 352742871D4C245800A1ECE6 /* MGLGeoJSONSource.h */, DA87A99B1DC9D8DD00810D09 /* MGLGeoJSONSource_Private.h */, 352742881D4C245800A1ECE6 /* MGLGeoJSONSource.mm */, 352742831D4C244700A1ECE6 /* MGLRasterSource.h */, + DA7DC9821DED647F0027472F /* MGLRasterSource_Private.h */, 352742841D4C244700A1ECE6 /* MGLRasterSource.mm */, DA551B7F1DB496AC0009AFAF /* MGLTileSet.h */, DA551B801DB496AC0009AFAF /* MGLTileSet_Private.h */, @@ -849,6 +863,8 @@ isa = PBXGroup; children = ( DA8F257D1D51C5F40010E6B5 /* Styling */, + DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */, + DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */, DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */, DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */, DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */, @@ -879,6 +895,8 @@ DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */, DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */, DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */, + DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */, + DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */, DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */, DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */, DAE6C3571CC31E0400DB3429 /* MGLStyle.h */, @@ -900,7 +918,7 @@ DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */, DAE6C3A71CC31EF300DB3429 /* MGLAnnotationImage.m */, DAE6C3A81CC31EF300DB3429 /* MGLAttributionButton.h */, - DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.m */, + DAE6C3A91CC31EF300DB3429 /* MGLAttributionButton.mm */, DAE6C3AA1CC31EF300DB3429 /* MGLCompassCell.h */, DAE6C3AB1CC31EF300DB3429 /* MGLCompassCell.m */, DAE6C3A01CC31E9400DB3429 /* MGLMapView.h */, @@ -934,11 +952,13 @@ DA8F258F1D51CA600010E6B5 /* MGLRasterStyleLayer.h in Headers */, 3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */, DAE6C38D1CC31E2A00DB3429 /* MGLOfflineRegion_Private.h in Headers */, + DA7DC9831DED647F0027472F /* MGLRasterSource_Private.h in Headers */, 408AA8651DAEEE3400022900 /* MGLPolygon+MGLAdditions.h in Headers */, DA8F259C1D51CB000010E6B5 /* MGLStyleValue_Private.h in Headers */, DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */, DAE6C3B61CC31EF300DB3429 /* MGLMapView_Private.h in Headers */, 3527428D1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.h in Headers */, + DA00FC8A1D5EEAC3009AABC8 /* MGLAttributionInfo.h in Headers */, DAE6C3B21CC31EF300DB3429 /* MGLAttributionButton.h in Headers */, 40B77E451DB11BC9003DA2FE /* NSArray+MGLAdditions.h in Headers */, 35C5D8471D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h in Headers */, @@ -959,6 +979,7 @@ DAE6C39C1CC31E2A00DB3429 /* NSString+MGLAdditions.h in Headers */, 3529039B1D6C63B80002C7DF /* NSPredicate+MGLAdditions.h in Headers */, DA8F25971D51CAC70010E6B5 /* MGLVectorSource.h in Headers */, + DA7DC9811DED5F5C0027472F /* MGLVectorSource_Private.h in Headers */, DAE6C3861CC31E2A00DB3429 /* MGLGeometry_Private.h in Headers */, DAE6C3841CC31E2A00DB3429 /* MGLAccountManager_Private.h in Headers */, DAE6C3691CC31E0400DB3429 /* MGLTypes.h in Headers */, @@ -1211,7 +1232,7 @@ DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */, DA7262081DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm in Sources */, 355BA4EE1D41633E00CCC6D5 /* NSColor+MGLAdditions.mm in Sources */, - DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */, + DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.mm in Sources */, 35602BFB1D3EA99F0050646F /* MGLFillStyleLayer.mm in Sources */, DAE6C3931CC31E2A00DB3429 /* MGLShape.mm in Sources */, 352742861D4C244700A1ECE6 /* MGLRasterSource.mm in Sources */, @@ -1245,6 +1266,7 @@ 408AA8681DAEEE5200022900 /* MGLPolygon+MGLAdditions.m in Sources */, DAE6C3951CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm in Sources */, DAE6C3851CC31E2A00DB3429 /* MGLAccountManager.m in Sources */, + DA00FC8B1D5EEAC3009AABC8 /* MGLAttributionInfo.mm in Sources */, DAE6C3921CC31E2A00DB3429 /* MGLPolyline.mm in Sources */, 3527428A1D4C245800A1ECE6 /* MGLGeoJSONSource.mm in Sources */, DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */, @@ -1269,6 +1291,7 @@ DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */, DA87A9A11DC9DCB400810D09 /* MGLRuntimeStylingHelper.m in Sources */, DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */, + DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */, DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */, DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */, DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.m in Sources */, @@ -1286,6 +1309,7 @@ DA87A9981DC9D88400810D09 /* MGLGeoJSONSourceTests.mm in Sources */, DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.m in Sources */, 3599A3E81DF70E2000E77FB2 /* MGLStyleValueTests.m in Sources */, + DAEDC4321D6033F1000224FF /* MGLAttributionInfoTests.m in Sources */, DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */, DA2207BC1DC076940002F84D /* MGLStyleValueTests.swift in Sources */, ); diff --git a/platform/macos/sdk/Base.lproj/Localizable.strings b/platform/macos/sdk/Base.lproj/Localizable.strings index 818c82b2ec..b7a4a21173 100644 --- a/platform/macos/sdk/Base.lproj/Localizable.strings +++ b/platform/macos/sdk/Base.lproj/Localizable.strings @@ -1,18 +1,3 @@ -/* Linked part of copyright notice */ -"COPYRIGHT_MAPBOX" = "Mapbox"; - -/* Copyright notice link */ -"COPYRIGHT_MAPBOX_LINK" = "https://www.mapbox.com/about/maps/"; - -/* Linked part of copyright notice */ -"COPYRIGHT_OSM" = "OpenStreetMap"; - -/* Copyright notice link */ -"COPYRIGHT_OSM_LINK" = "http://www.openstreetmap.org/about/"; - -/* Copyright notice prefix */ -"COPYRIGHT_PREFIX" = "© "; - /* Accessibility title */ "MAP_A11Y_TITLE" = "Mapbox"; diff --git a/platform/macos/src/MGLAttributionButton.h b/platform/macos/src/MGLAttributionButton.h index 9ff3137849..88fcdadf78 100644 --- a/platform/macos/src/MGLAttributionButton.h +++ b/platform/macos/src/MGLAttributionButton.h @@ -1,15 +1,23 @@ #import <Cocoa/Cocoa.h> +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLAttributionInfo; + /// Button that looks like a hyperlink and opens a URL. @interface MGLAttributionButton : NSButton -/// Returns an `MGLAttributionButton` instance with the given title and URL. -- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url; +/// Returns an `MGLAttributionButton` instance with the given info. +- (instancetype)initWithAttributionInfo:(MGLAttributionInfo *)info; /// The URL to open and display as a tooltip. -@property (nonatomic) NSURL *URL; +@property (nonatomic, readonly, nullable) NSURL *URL; /// Opens the URL. -- (IBAction)openURL:(id)sender; +- (IBAction)openURL:(nullable id)sender; @end + +NS_ASSUME_NONNULL_END diff --git a/platform/macos/src/MGLAttributionButton.m b/platform/macos/src/MGLAttributionButton.m deleted file mode 100644 index e21b860794..0000000000 --- a/platform/macos/src/MGLAttributionButton.m +++ /dev/null @@ -1,50 +0,0 @@ -#import "MGLAttributionButton.h" - -#import "NSBundle+MGLAdditions.h" - -@implementation MGLAttributionButton { - NSTrackingRectTag _trackingAreaTag; -} - -- (instancetype)initWithTitle:(NSString *)title URL:(NSURL *)url { - if (self = [super initWithFrame:NSZeroRect]) { - self.bordered = NO; - self.bezelStyle = NSRegularSquareBezelStyle; - - // Start with a copyright symbol. The whole string will be mini. - NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:NSLocalizedStringWithDefaultValue(@"COPYRIGHT_PREFIX", nil, nil, @"© ", @"Copyright notice prefix") attributes:@{ - NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]], - }]; - // Append the specified title, underlining it like a hyperlink. - [attributedTitle appendAttributedString: - [[NSAttributedString alloc] initWithString:title - attributes:@{ - NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]], - NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), - }]]; - self.attributedTitle = attributedTitle; - [self sizeToFit]; - - _URL = url; - self.toolTip = _URL.absoluteString; - - self.target = self; - self.action = @selector(openURL:); - } - return self; -} - -- (BOOL)wantsLayer { - return YES; -} - -- (void)resetCursorRects { - // The whole button gets a pointing hand cursor, just like a hyperlink. - [self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]]; -} - -- (IBAction)openURL:(__unused id)sender { - [[NSWorkspace sharedWorkspace] openURL:self.URL]; -} - -@end diff --git a/platform/macos/src/MGLAttributionButton.mm b/platform/macos/src/MGLAttributionButton.mm new file mode 100644 index 0000000000..ed8bb18a66 --- /dev/null +++ b/platform/macos/src/MGLAttributionButton.mm @@ -0,0 +1,55 @@ +#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/MGLMapView.h b/platform/macos/src/MGLMapView.h index 88745db212..ea87f3b338 100644 --- a/platform/macos/src/MGLMapView.h +++ b/platform/macos/src/MGLMapView.h @@ -950,6 +950,25 @@ IB_DESIGNABLE */ - (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><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 /** diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index a2fe7acbda..bf31daffad 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1,6 +1,7 @@ #import "MGLMapView_Private.h" #import "MGLAnnotationImage_Private.h" #import "MGLAttributionButton.h" +#import "MGLAttributionInfo.h" #import "MGLCompassCell.h" #import "MGLOpenGLLayer.h" #import "MGLStyle.h" @@ -84,23 +85,6 @@ const CGFloat MGLAnnotationImagePaddingForHitTest = 4; /// Distance from the callout’s anchor point to the annotation it points to. const CGFloat MGLAnnotationImagePaddingForCallout = 4; -/// Copyright notices displayed in the attribution view. -struct MGLAttribution { - /// Attribution button label text. A copyright symbol is prepended to this string. - NSString *title; - /// URL to open when the attribution button is clicked. - NSString *urlString; -} MGLAttributions[] = { - { - .title = NSLocalizedStringWithDefaultValue(@"COPYRIGHT_MAPBOX", nil, nil, @"Mapbox", @"Linked part of copyright notice"), - .urlString = NSLocalizedStringWithDefaultValue(@"COPYRIGHT_MAPBOX_LINK", nil, nil, @"https://www.mapbox.com/about/maps/", @"Copyright notice link"), - }, - { - .title = NSLocalizedStringWithDefaultValue(@"COPYRIGHT_OSM", nil, nil, @"OpenStreetMap", @"Linked part of copyright notice"), - .urlString = NSLocalizedStringWithDefaultValue(@"COPYRIGHT_OSM_LINK", nil, nil, @"http://www.openstreetmap.org/about/", @"Copyright notice link"), - }, -}; - /// Unique identifier representing a single annotation in mbgl. typedef uint32_t MGLAnnotationTag; @@ -371,6 +355,7 @@ public: /// Adds legally required map attribution to the lower-left corner. - (void)installAttributionView { + [_attributionView removeFromSuperview]; _attributionView = [[NSView alloc] initWithFrame:NSZeroRect]; _attributionView.wantsLayer = YES; @@ -433,37 +418,69 @@ public: /// Updates the attribution view to reflect the sources used. For now, this is /// hard-coded to the standard Mapbox and OpenStreetMap attribution. - (void)updateAttributionView { - self.attributionView.subviews = @[]; - - for (NSUInteger i = 0; i < sizeof(MGLAttributions) / sizeof(MGLAttributions[0]); i++) { + 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. - NSURL *url = [NSURL URLWithString:MGLAttributions[i].urlString]; - NSButton *button = [[MGLAttributionButton alloc] initWithTitle:MGLAttributions[i].title URL:url]; + 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 = self.attributionView.subviews.lastObject; - [self.attributionView addSubview:button]; - [_attributionView addConstraint: + NSView *previousView = attributionView.subviews.lastObject; + [attributionView addSubview:button]; + [attributionView addConstraint: [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual - toItem:_attributionView + toItem:attributionView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; - [_attributionView addConstraint: + [attributionView addConstraint: [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual - toItem:previousView ? previousView : _attributionView + 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]]; } } @@ -732,20 +749,6 @@ public: attribute:NSLayoutAttributeTrailing multiplier:1 constant:8]]; - [self addConstraint:[NSLayoutConstraint constraintWithItem:_attributionView.subviews.firstObject - attribute:NSLayoutAttributeTop - relatedBy:NSLayoutRelationEqual - toItem:_attributionView - attribute:NSLayoutAttributeTop - multiplier:1 - constant:0]]; - [self addConstraint:[NSLayoutConstraint constraintWithItem:_attributionView - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:_attributionView.subviews.lastObject - attribute:NSLayoutAttributeTrailing - multiplier:1 - constant:8]]; [super updateConstraints]; } @@ -924,6 +927,12 @@ public: } break; } + case mbgl::MapChangeSourceDidChange: + { + [self installAttributionView]; + self.needsUpdateConstraints = YES; + break; + } } } @@ -1640,6 +1649,23 @@ public: [self setDirection:-sender.doubleValue animated:YES]; } +- (IBAction)giveFeedback:(id)sender { + CLLocationCoordinate2D centerCoordinate = self.centerCoordinate; + double zoomLevel = self.zoomLevel; + NSMutableArray *urls = [NSMutableArray array]; + for (MGLAttributionInfo *info in [self.style attributionInfosWithFontSize:0 linkColor:nil]) { + NSURL *url = [info feedbackURLAtCenterCoordinate:centerCoordinate zoomLevel:zoomLevel]; + if (url) { + [urls addObject:url]; + } + } + [[NSWorkspace sharedWorkspace] openURLs:urls + withAppBundleIdentifier:nil + options:0 + additionalEventParamDescriptor:nil + launchIdentifiers:nil]; +} + #pragma mark Annotations - (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)annotations { @@ -2454,6 +2480,15 @@ public: return MGLFeaturesFromMBGLFeatures(features); } +#pragma mark User interface validation + +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + if (menuItem.action == @selector(giveFeedback:)) { + return YES; + } + return [super validateMenuItem:menuItem]; +} + #pragma mark Interface Builder methods - (void)prepareForInterfaceBuilder { diff --git a/platform/macos/test/MGLAttributionButtonTests.m b/platform/macos/test/MGLAttributionButtonTests.m new file mode 100644 index 0000000000..f5c0aac856 --- /dev/null +++ b/platform/macos/test/MGLAttributionButtonTests.m @@ -0,0 +1,31 @@ +#import <Mapbox/Mapbox.h> +#import <XCTest/XCTest.h> + +#import "MGLAttributionButton.h" +#import "MGLAttributionInfo.h" + +@interface MGLAttributionButtonTests : XCTestCase + +@end + +@implementation MGLAttributionButtonTests + +- (void)testPlainSymbol { + NSAttributedString *title = [[NSAttributedString alloc] initWithString:@"® & ™ Mapbox" attributes:@{ + NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), + }]; + MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:nil]; + MGLAttributionButton *button = [[MGLAttributionButton alloc] initWithAttributionInfo:info]; + + NSRange symbolUnderlineRange; + NSNumber *symbolUnderline = [button.attributedTitle attribute:NSUnderlineStyleAttributeName atIndex:0 effectiveRange:&symbolUnderlineRange]; + XCTAssertNil(symbolUnderline); + XCTAssertEqual(symbolUnderlineRange.length, 6); + + NSRange wordUnderlineRange; + NSNumber *wordUnderline = [button.attributedTitle attribute:NSUnderlineStyleAttributeName atIndex:6 effectiveRange:&wordUnderlineRange]; + XCTAssertEqualObjects(wordUnderline, @(NSUnderlineStyleSingle)); + XCTAssertEqual(wordUnderlineRange.length, 6); +} + +@end |