summaryrefslogtreecommitdiff
path: root/platform/macos/app
diff options
context:
space:
mode:
Diffstat (limited to 'platform/macos/app')
-rw-r--r--platform/macos/app/Base.lproj/MapDocument.xib3
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.h7
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.m42
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.h15
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.m49
-rw-r--r--platform/macos/app/MapDocument.m96
6 files changed, 165 insertions, 47 deletions
diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib
index e147ba83d0..4ba8f0a3ad 100644
--- a/platform/macos/app/Base.lproj/MapDocument.xib
+++ b/platform/macos/app/Base.lproj/MapDocument.xib
@@ -27,6 +27,7 @@
<declaredKeys>
<string>layers</string>
<string>name</string>
+ <string>reversedLayers</string>
</declaredKeys>
<connections>
<binding destination="jxx-uM-ZTC" name="contentObject" keyPath="selection.style" id="60N-aU-tgJ"/>
@@ -38,7 +39,7 @@
<string>visible</string>
</declaredKeys>
<connections>
- <binding destination="Xji-k6-iQ4" name="contentArray" keyPath="selection.layers" id="X25-Nb-Brf"/>
+ <binding destination="Xji-k6-iQ4" name="contentArray" keyPath="selection.reversedLayers" id="wtL-d8-GNd"/>
</connections>
</arrayController>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.h b/platform/macos/app/MGLStyle+MBXAdditions.h
new file mode 100644
index 0000000000..dcaf42af28
--- /dev/null
+++ b/platform/macos/app/MGLStyle+MBXAdditions.h
@@ -0,0 +1,7 @@
+#import <Mapbox/Mapbox.h>
+
+@interface MGLStyle (MBXAdditions)
+
+@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *reversedLayers;
+
+@end
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.m b/platform/macos/app/MGLStyle+MBXAdditions.m
new file mode 100644
index 0000000000..be571d8b30
--- /dev/null
+++ b/platform/macos/app/MGLStyle+MBXAdditions.m
@@ -0,0 +1,42 @@
+#import "MGLStyle+MBXAdditions.h"
+
+@implementation MGLStyle (MBXAdditions)
+
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingReversedLayers {
+ return [NSSet setWithObject:@"layers"];
+}
+
+- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+ return self.layers.reverseObjectEnumerator.allObjects;
+}
+
+- (void)setReversedLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+ self.layers = reversedLayers.reverseObjectEnumerator.allObjects;
+}
+
+- (NSUInteger)countOfReversedLayers {
+ return self.layers.count;
+}
+
+- (id)objectInReversedLayersAtIndex:(NSUInteger)index {
+ NSArray *layers = self.layers;
+ return layers[layers.count - 1 - index];
+}
+
+- (void)getReversedLayers:(__kindof MGLStyleLayer **)buffer range:(NSRange)inRange {
+ NSArray *layers = self.layers;
+ for (NSUInteger i = inRange.location; i < NSMaxRange(inRange); i++) {
+ MGLStyleLayer *styleLayer = layers[layers.count - 1 - i];
+ buffer[i] = styleLayer;
+ }
+}
+
+- (void)insertObject:(__kindof MGLStyleLayer *)object inReversedLayersAtIndex:(NSUInteger)index {
+ [self insertLayer:object atIndex:self.layers.count - index];
+}
+
+- (void)removeObjectFromReversedLayersAtIndex:(NSUInteger)index {
+ [self removeLayer:[self objectInReversedLayersAtIndex:index]];
+}
+
+@end
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.h b/platform/macos/app/MGLVectorSource+MBXAdditions.h
new file mode 100644
index 0000000000..312081ec51
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.h
@@ -0,0 +1,15 @@
+#import <Mapbox/Mapbox.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLVectorSource (MBXAdditions)
+
++ (nullable NSString *)preferredMapboxStreetsLanguage;
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
+
+@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.m b/platform/macos/app/MGLVectorSource+MBXAdditions.m
new file mode 100644
index 0000000000..f59b72aa9f
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.m
@@ -0,0 +1,49 @@
+#import "MGLVectorSource+MBXAdditions.h"
+
+@implementation MGLVectorSource (MBXAdditions)
+
++ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ static dispatch_once_t onceToken;
+ static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ dispatch_once(&onceToken, ^{
+ mapboxStreetsLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
+ });
+ return mapboxStreetsLanguages;
+}
+
++ (nullable NSString *)preferredMapboxStreetsLanguage {
+ for (NSString *language in [NSLocale preferredLanguages]) {
+ NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
+ if ([[MGLVectorSource mapboxStreetsLanguages] containsObject:languageCode]) {
+ return languageCode;
+ }
+ }
+ return nil;
+}
+
+- (BOOL)isMapboxStreets {
+ NSURL *url = self.configurationURL;
+ if (![url.scheme isEqualToString:@"mapbox"]) {
+ return NO;
+ }
+ NSArray *identifiers = [url.host componentsSeparatedByString:@","];
+ return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
+}
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
+ if (!self.mapboxStreets) {
+ return @{};
+ }
+
+ // Replace {name} and {name_*} with the matching localized name tag.
+ NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
+ NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
+ for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) {
+ NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
+ localizedKeysByKey[key] = localizedKey;
+ }
+ return localizedKeysByKey;
+}
+
+@end
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 2c31610779..64833a8560 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -4,6 +4,9 @@
#import "LimeGreenStyleLayer.h"
#import "DroppedPinAnnotation.h"
+#import "MGLStyle+MBXAdditions.h"
+#import "MGLVectorSource+MBXAdditions.h"
+
#import <Mapbox/Mapbox.h>
static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped";
@@ -143,11 +146,12 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (NSURL *)shareURL {
NSArray *components = self.mapView.styleURL.pathComponents;
- CLLocationCoordinate2D centerCoordinate = self.mapView.centerCoordinate;
+ MGLMapCamera *camera = self.mapView.camera;
return [NSURL URLWithString:
- [NSString stringWithFormat:@"https://api.mapbox.com/styles/v1/%@/%@.html?access_token=%@#%.2f/%.5f/%.5f/%.f",
+ [NSString stringWithFormat:@"https://api.mapbox.com/styles/v1/%@/%@.html?access_token=%@#%.2f/%.5f/%.5f/%.f/%.f",
components[1], components[2], [MGLAccountManager accessToken],
- self.mapView.zoomLevel, centerCoordinate.latitude, centerCoordinate.longitude, self.mapView.direction]];
+ self.mapView.zoomLevel, camera.centerCoordinate.latitude, camera.centerCoordinate.longitude,
+ camera.heading, camera.pitch]];
}
#pragma mark View methods
@@ -254,7 +258,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)toggleStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.layers objectsAtIndexes:indices];
+ NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
BOOL isVisible = layers.firstObject.visible;
[self.undoManager registerUndoWithTarget:self handler:^(MapDocument * _Nonnull target) {
[target toggleStyleLayersAtArrangedObjectIndexes:indices];
@@ -310,7 +314,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)deleteStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.layers objectsAtIndexes:indices];
+ NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertStyleLayers:layers atArrangedObjectIndexes:indices];
}];
@@ -331,56 +335,55 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)setLabelLanguage:(NSMenuItem *)sender {
_isLocalizingLabels = sender.tag;
- [self updateLabels];
+ [self reload:sender];
}
- (void)updateLabels {
- NSString *preferredLanguageCode = self.preferredLanguageCode;
- NSString *preferredNameToken = _isLocalizingLabels ? [NSString stringWithFormat:@"{name_%@}", preferredLanguageCode] : @"{name}";
- NSRegularExpression *nameTokenExpression = [NSRegularExpression regularExpressionWithPattern:@"\\{name(?:_\\w{2})?\\}" options:0 error:NULL];
-
- for (MGLSymbolStyleLayer *layer in self.mapView.style.layers) {
+ MGLStyle *style = self.mapView.style;
+ NSString *preferredLanguage = _isLocalizingLabels ? ([MGLVectorSource preferredMapboxStreetsLanguage] ?: @"en") : nil;
+ NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
+ for (MGLSymbolStyleLayer *layer in style.layers) {
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
continue;
}
- if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) {
- NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.textField rawValue];
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- layer.textField = [MGLStyleValue<NSString *> valueWithRawValue:textField];
- } else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.textField;
+ MGLVectorSource *source = (MGLVectorSource *)[style sourceWithIdentifier:layer.sourceIdentifier];
+ if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
+ continue;
+ }
+
+ NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
+ if (!localizedKeysByKey) {
+ localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
+ }
+
+ NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
+ NSMutableString *localizedString = string.mutableCopy;
+ [localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
+ NSAssert([key isKindOfClass:[NSString class]], @"key is not a string");
+ NSAssert([localizedKey isKindOfClass:[NSString class]], @"localizedKey is not a string");
+ [localizedString replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key]
+ withString:[NSString stringWithFormat:@"{%@}", localizedKey]
+ options:0
+ range:NSMakeRange(0, localizedString.length)];
+ }];
+ return localizedString;
+ };
+
+ if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) {
+ NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.text rawValue];
+ layer.text = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
+ } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) {
+ MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.text;
NSMutableDictionary *stops = function.stops.mutableCopy;
[stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue<NSString *> *stop, BOOL *done) {
NSString *textField = stop.rawValue;
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:textField];
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
}];
function.stops = stops;
- layer.textField = function;
- }
- }
-}
-
-- (NSString *)preferredLanguageCode {
- // Languages supported by Mapbox Streets v10.
- NSSet *supportedLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
- NSArray *preferredLanguages = [NSLocale preferredLanguages];
-
- for (NSString *language in preferredLanguages) {
- NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
- if ([supportedLanguages containsObject:languageCode]) {
- return languageCode;
+ layer.text = function;
}
}
-
- return @"en";
}
- (void)applyPendingState {
@@ -824,7 +827,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (row == -1) {
menuItem.title = @"Show";
} else {
- BOOL isVisible = self.mapView.style.layers[row].visible;
+ BOOL isVisible = self.mapView.style.reversedLayers[row].visible;
menuItem.title = isVisible ? @"Hide" : @"Show";
}
return row != -1;
@@ -836,7 +839,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
menuItem.state = menuItem.tag == _isLocalizingLabels ? NSOnState: NSOffState;
if (menuItem.tag) {
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:[NSBundle mainBundle].developmentLocalization];
- menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:self.preferredLanguageCode];
+ NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
+ menuItem.enabled = !!preferredLanguage;
+ menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:preferredLanguage ?: @"Preferred Language"];
}
return YES;
}
@@ -1083,9 +1088,8 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
-- (NSColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation {
- NSColor *color = [[NSColor selectedMenuItemColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
- return [color colorWithAlphaComponent:0.8];
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation {
+ return 0.8;
}
@end