summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-12-27 11:58:20 -0800
committerMinh Nguyễn <mxn@1ec5.org>2016-12-27 16:19:33 -0800
commitff0c583949e7bb327f322135809bdf431a17e3cb (patch)
tree439bf11b7f3c418fa8039b8e14df8a8509ec8fe8
parentba67c03eba3759bf03d87a28d64ddf9f1e267216 (diff)
downloadqtlocation-mapboxgl-ff0c583949e7bb327f322135809bdf431a17e3cb.tar.gz
[macos] Layer filter editor
Added a Layer Filter panel to the bottom of the macosapp document window that edits the selected layer’s predicate. Subclassed NSPredicateEditorRowTemplate to allow for arbitrary key paths in a single template and also to represent an aggregate value as a token field.
-rw-r--r--platform/macos/app/Base.lproj/MainMenu.xib11
-rw-r--r--platform/macos/app/Base.lproj/MapDocument.xib235
-rw-r--r--platform/macos/app/FeatureAttributePredicateEditorRowTemplate.h5
-rw-r--r--platform/macos/app/FeatureAttributePredicateEditorRowTemplate.m147
-rw-r--r--platform/macos/app/MapDocument.m34
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj6
6 files changed, 413 insertions, 25 deletions
diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib
index 9faf1ba04b..64ed8d09f9 100644
--- a/platform/macos/app/Base.lproj/MainMenu.xib
+++ b/platform/macos/app/Base.lproj/MainMenu.xib
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11191" systemVersion="15G31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1212" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11191"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -434,6 +435,12 @@
<action selector="toggleLayers:" target="-1" id="YdA-Mr-MHi"/>
</connections>
</menuItem>
+ <menuItem title="Show Layer Filter" id="q0e-JO-Xth">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleLayerFilter:" target="-1" id="6FD-mU-yq3"/>
+ </connections>
+ </menuItem>
<menuItem isSeparatorItem="YES" id="8aO-Nm-fxF"/>
<menuItem title="Labels In" id="M7v-B1-vo3">
<modifierMask key="keyEquivalentModifierMask"/>
diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib
index e147ba83d0..fe4762402d 100644
--- a/platform/macos/app/Base.lproj/MapDocument.xib
+++ b/platform/macos/app/Base.lproj/MapDocument.xib
@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1212" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MapDocument">
<connections>
<outlet property="mapView" destination="q4d-kF-8Hi" id="7hI-dS-A5R"/>
<outlet property="mapViewContextMenu" destination="XbX-6a-Mgy" id="YD0-1r-5N2"/>
- <outlet property="splitView" destination="IPR-fm-vk8" id="9xt-ar-uad"/>
+ <outlet property="predicateSplitView" destination="PMo-HJ-OR3" id="WjV-ED-5fD"/>
<outlet property="styleLayersArrayController" destination="GXW-3J-Gff" id="Ygs-7o-juz"/>
+ <outlet property="styleLayersSplitView" destination="IPR-fm-vk8" id="Yf4-cR-W29"/>
<outlet property="styleLayersTableView" destination="Mm4-6F-qEb" id="TB5-ha-JJE"/>
<outlet property="window" destination="cSv-fg-MAQ" id="TBu-Mu-79N"/>
</connections>
@@ -36,6 +38,7 @@
<declaredKeys>
<string>identifier</string>
<string>visible</string>
+ <string>predicate</string>
</declaredKeys>
<connections>
<binding destination="Xji-k6-iQ4" name="contentArray" keyPath="selection.layers" id="X25-Nb-Brf"/>
@@ -55,14 +58,14 @@
<rect key="frame" x="0.0" y="0.0" width="642" height="480"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="sMc-vT-RwH">
- <rect key="frame" x="0.0" y="0.0" width="163" height="480"/>
+ <rect key="frame" x="0.0" y="0.0" width="185" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" id="bSc-hK-bzQ">
- <rect key="frame" x="0.0" y="0.0" width="163" height="480"/>
+ <rect key="frame" x="0.0" y="0.0" width="185" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" id="Mm4-6F-qEb">
- <rect key="frame" x="0.0" y="0.0" width="163" height="480"/>
+ <rect key="frame" x="0.0" y="0.0" width="185" height="480"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -85,7 +88,7 @@
</binding>
</connections>
</tableColumn>
- <tableColumn editable="NO" width="141" minWidth="40" maxWidth="1000" id="BwD-ww-7uw">
+ <tableColumn editable="NO" width="163" minWidth="40" maxWidth="1000" id="BwD-ww-7uw">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
@@ -126,21 +129,223 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="0vt-rI-sHB">
- <rect key="frame" x="147" y="480" width="16" height="0.0"/>
+ <rect key="frame" x="169" y="480" width="16" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
- <customView id="q4d-kF-8Hi" customClass="MGLMapView">
- <rect key="frame" x="164" y="0.0" width="478" height="480"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <splitView autosaveName="MBXFilterSplitView" dividerStyle="thin" id="PMo-HJ-OR3">
+ <rect key="frame" x="186" y="0.0" width="456" height="480"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <subviews>
+ <customView fixedFrame="YES" id="q4d-kF-8Hi" customClass="MGLMapView">
+ <rect key="frame" x="0.0" y="0.0" width="456" height="379"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <connections>
+ <outlet property="delegate" destination="-2" id="dh2-0H-jFZ"/>
+ <outlet property="menu" destination="XbX-6a-Mgy" id="dSu-HR-Kq2"/>
+ </connections>
+ </customView>
+ <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="Kft-Ar-3PQ">
+ <rect key="frame" x="0.0" y="380" width="456" height="100"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <clipView key="contentView" id="BcG-vk-Now">
+ <rect key="frame" x="0.0" y="0.0" width="456" height="100"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <predicateEditor verticalHuggingPriority="750" nestingMode="compound" canRemoveAllRows="YES" rowHeight="25" id="6vE-YI-Rel">
+ <rect key="frame" x="0.0" y="0.0" width="456" height="100"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+ <rowTemplates>
+ <predicateEditorRowTemplate rowType="compound" id="BxM-Fk-fTN">
+ <popUpMenus>
+ <menu id="Xs9-mi-bFL">
+ <items>
+ <menuItem title="Any" state="on" id="Nco-tn-b7s">
+ <integer key="representedObject" value="2"/>
+ </menuItem>
+ <menuItem title="All" id="o2p-g4-agW">
+ <integer key="representedObject" value="1"/>
+ </menuItem>
+ <menuItem title="None" id="BBM-Mi-bFU">
+ <integer key="representedObject" value="0"/>
+ </menuItem>
+ </items>
+ </menu>
+ <menu id="DB6-uo-x9N">
+ <items>
+ <menuItem title="of the following are true" state="on" id="3zs-VD-nVg"/>
+ </items>
+ </menu>
+ </popUpMenus>
+ </predicateEditorRowTemplate>
+ <predicateEditorRowTemplate rowType="simple" id="Wqv-mw-4vY" customClass="FeatureAttributePredicateEditorRowTemplate">
+ <array key="leftExpressionObject">
+ <expression type="keyPath">
+ <string key="keyPath">string</string>
+ </expression>
+ </array>
+ <integer key="rightExpressionObject" value="700"/>
+ <popUpMenus>
+ <menu id="hg7-Gg-kDR">
+ <items>
+ <menuItem title="string" state="on" id="yqb-0B-JIn">
+ <expression key="representedObject" type="keyPath">
+ <string key="keyPath">string</string>
+ </expression>
+ </menuItem>
+ </items>
+ </menu>
+ <menu id="OzK-Yl-gzs">
+ <items>
+ <menuItem title="is" state="on" id="EXt-Ii-58I">
+ <integer key="representedObject" value="4"/>
+ </menuItem>
+ <menuItem title="is at least" id="diA-te-oP7">
+ <integer key="representedObject" value="3"/>
+ </menuItem>
+ <menuItem title="is at most" id="DVP-hh-cti">
+ <integer key="representedObject" value="1"/>
+ </menuItem>
+ <menuItem title="is less than" id="gjD-eE-5Qf">
+ <integer key="representedObject" value="0"/>
+ </menuItem>
+ <menuItem title="is more than" id="BLw-cg-dS8">
+ <integer key="representedObject" value="2"/>
+ </menuItem>
+ <menuItem title="is not" id="fZA-gd-2YX">
+ <integer key="representedObject" value="5"/>
+ </menuItem>
+ <menuItem title="is one of" id="eNT-km-TxV">
+ <integer key="representedObject" value="10"/>
+ </menuItem>
+ </items>
+ </menu>
+ </popUpMenus>
+ </predicateEditorRowTemplate>
+ <predicateEditorRowTemplate rowType="simple" id="wrH-hN-KkV" customClass="FeatureAttributePredicateEditorRowTemplate">
+ <array key="leftExpressionObject">
+ <expression type="keyPath">
+ <string key="keyPath">integer</string>
+ </expression>
+ </array>
+ <integer key="rightExpressionObject" value="300"/>
+ <popUpMenus>
+ <menu id="mxx-PF-Uk1">
+ <items>
+ <menuItem title="integer" state="on" id="zjg-iH-ldw">
+ <expression key="representedObject" type="keyPath">
+ <string key="keyPath">integer</string>
+ </expression>
+ </menuItem>
+ </items>
+ </menu>
+ <menu id="t3G-Iv-PWh">
+ <items>
+ <menuItem title="is" state="on" id="W2j-4q-nL1">
+ <integer key="representedObject" value="4"/>
+ </menuItem>
+ <menuItem title="is at least" id="Uau-vm-9w4">
+ <integer key="representedObject" value="3"/>
+ </menuItem>
+ <menuItem title="is at most" id="IwP-IA-Eoa">
+ <integer key="representedObject" value="1"/>
+ </menuItem>
+ <menuItem title="is less than" id="lYG-3r-SnX">
+ <integer key="representedObject" value="0"/>
+ </menuItem>
+ <menuItem title="is more than" id="9Gl-9d-mz9">
+ <integer key="representedObject" value="2"/>
+ </menuItem>
+ <menuItem title="is not" id="fEN-ap-aE2">
+ <integer key="representedObject" value="5"/>
+ </menuItem>
+ <menuItem title="is one of" id="AXf-Fk-T65">
+ <integer key="representedObject" value="10"/>
+ </menuItem>
+ </items>
+ </menu>
+ </popUpMenus>
+ </predicateEditorRowTemplate>
+ <predicateEditorRowTemplate rowType="simple" id="CmU-AF-UCD" customClass="FeatureAttributePredicateEditorRowTemplate">
+ <array key="leftExpressionObject">
+ <expression type="keyPath">
+ <string key="keyPath">float</string>
+ </expression>
+ </array>
+ <integer key="rightExpressionObject" value="500"/>
+ <popUpMenus>
+ <menu id="0DE-A3-bYf">
+ <items>
+ <menuItem title="float" state="on" id="Bx4-8s-246">
+ <expression key="representedObject" type="keyPath">
+ <string key="keyPath">float</string>
+ </expression>
+ </menuItem>
+ </items>
+ </menu>
+ <menu id="Isc-aI-S9W">
+ <items>
+ <menuItem title="is" state="on" id="z20-CG-WD6">
+ <integer key="representedObject" value="4"/>
+ </menuItem>
+ <menuItem title="is at least" id="e0a-Hk-IlW">
+ <integer key="representedObject" value="3"/>
+ </menuItem>
+ <menuItem title="is at most" id="Glf-GN-6we">
+ <integer key="representedObject" value="1"/>
+ </menuItem>
+ <menuItem title="is less than" id="9DD-gB-6AB">
+ <integer key="representedObject" value="0"/>
+ </menuItem>
+ <menuItem title="is more than" id="N0b-pS-QEU">
+ <integer key="representedObject" value="2"/>
+ </menuItem>
+ <menuItem title="is not" id="J6J-f0-hll">
+ <integer key="representedObject" value="5"/>
+ </menuItem>
+ <menuItem title="is one of" id="5G0-1Q-S2B">
+ <integer key="representedObject" value="10"/>
+ </menuItem>
+ </items>
+ </menu>
+ </popUpMenus>
+ </predicateEditorRowTemplate>
+ </rowTemplates>
+ <connections>
+ <binding destination="GXW-3J-Gff" name="value" keyPath="selection.predicate" id="xc2-AY-P22">
+ <dictionary key="options">
+ <bool key="NSRaisesForNotApplicableKeys" value="NO"/>
+ </dictionary>
+ </binding>
+ </connections>
+ </predicateEditor>
+ </subviews>
+ <color key="backgroundColor" white="0.91000002619999998" alpha="1" colorSpace="calibratedWhite"/>
+ </clipView>
+ <constraints>
+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="hGB-sT-MZ9"/>
+ </constraints>
+ <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="svL-nO-cey">
+ <rect key="frame" x="-100" y="-100" width="360" height="15"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="Die-wi-C47">
+ <rect key="frame" x="440" y="130" width="16" height="0.0"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
+ </subviews>
<constraints>
- <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="kg3-4h-7Hl"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="afd-SL-SjN"/>
</constraints>
+ <holdingPriorities>
+ <real value="250"/>
+ <real value="250"/>
+ </holdingPriorities>
<connections>
- <outlet property="delegate" destination="-2" id="dh2-0H-jFZ"/>
- <outlet property="menu" destination="XbX-6a-Mgy" id="dSu-HR-Kq2"/>
+ <outlet property="delegate" destination="-2" id="HeW-CX-0V0"/>
</connections>
- </customView>
+ </splitView>
</subviews>
<holdingPriorities>
<real value="250"/>
diff --git a/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.h b/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.h
new file mode 100644
index 0000000000..6fe6b1b911
--- /dev/null
+++ b/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.h
@@ -0,0 +1,5 @@
+#import <Cocoa/Cocoa.h>
+
+@interface FeatureAttributePredicateEditorRowTemplate : NSPredicateEditorRowTemplate
+
+@end
diff --git a/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.m b/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.m
new file mode 100644
index 0000000000..0d19bd1635
--- /dev/null
+++ b/platform/macos/app/FeatureAttributePredicateEditorRowTemplate.m
@@ -0,0 +1,147 @@
+#import "FeatureAttributePredicateEditorRowTemplate.h"
+
+#import <Mapbox/Mapbox.h>
+
+@implementation MGLStyleLayer (MBXAdditions)
+
+- (NSPredicate *)predicate {
+ return nil;
+}
+
+- (void)setPredicate:(NSPredicate *)predicate {
+}
+
+@end
+
+@implementation FeatureAttributePredicateEditorRowTemplate {
+ NSTextField *_keyPathTextField;
+ NSPopUpButton *_operatorPopUpButton;
+ NSTextField *_valueTextField;
+ NSTokenField *_valueTokenField;
+}
+
+- (double)matchForPredicate:(NSComparisonPredicate *)predicate {
+ if (![predicate isKindOfClass:[NSComparisonPredicate class]]) {
+ return 0;
+ }
+
+ id constantValue = predicate.rightExpression.constantValue;
+ if ([constantValue isKindOfClass:[NSArray class]]) {
+ constantValue = [[constantValue firstObject] constantValue];
+ }
+ switch (self.rightExpressionAttributeType) {
+ case NSBooleanAttributeType:
+ return ([constantValue isKindOfClass:[NSNumber class]]
+ && (strcmp([constantValue objCType], @encode(char)) == 0
+ || strcmp([constantValue objCType], @encode(BOOL)) == 0)) ? 1 : 0;
+
+ case NSDoubleAttributeType:
+ case NSFloatAttributeType:
+ return ([constantValue isKindOfClass:[NSNumber class]]
+ && (strcmp([constantValue objCType], @encode(double)) == 0
+ || strcmp([constantValue objCType], @encode(float)) == 0)) ? 1 : 0;
+
+ case NSInteger16AttributeType:
+ case NSInteger32AttributeType:
+ case NSInteger64AttributeType:
+ return ([constantValue isKindOfClass:[NSNumber class]]
+ && strcmp([constantValue objCType], @encode(double)) != 0
+ && strcmp([constantValue objCType], @encode(float)) != 0
+ && strcmp([constantValue objCType], @encode(char)) != 0
+ && strcmp([constantValue objCType], @encode(BOOL)) != 0) ? 1 : 0;
+
+ case NSStringAttributeType:
+ return [constantValue isKindOfClass:[NSString class]] ? 0.8 : 0;
+
+ default:
+ return [super matchForPredicate:predicate];
+ }
+}
+
+- (NS_ARRAY_OF(NSView *) *)templateViews {
+ NSMutableArray *views = super.templateViews.mutableCopy;
+ views[0] = self.keyPathTextField;
+ _operatorPopUpButton = views[1];
+ _valueTextField = views[2];
+
+ BOOL isInPredicate = [_operatorPopUpButton.selectedItem.representedObject unsignedIntegerValue] == NSInPredicateOperatorType;
+ if (isInPredicate) {
+ [views insertObject:self.valueTokenField atIndex:2];
+ } else {
+ [views addObject:self.valueTokenField];
+ }
+ [views[2] setHidden:NO];
+ [views[3] setHidden:YES];
+
+ return views;
+}
+
+- (NSTextField *)keyPathTextField {
+ if (!_keyPathTextField) {
+ _keyPathTextField = [[NSTextField alloc] initWithFrame:NSZeroRect];
+ _keyPathTextField.editable = NO;
+ _keyPathTextField.bordered = NO;
+ _keyPathTextField.backgroundColor = nil;
+ _keyPathTextField.font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ }
+ [_keyPathTextField sizeToFit];
+ return _keyPathTextField;
+}
+
+- (NSTokenField *)valueTokenField {
+ if (!_valueTokenField) {
+ _valueTokenField = [[NSTokenField alloc] initWithFrame:NSZeroRect];
+ _valueTokenField.font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ }
+ [_valueTokenField sizeToFit];
+ NSRect frame = _valueTokenField.frame;
+ frame.size.width = _valueTextField.frame.size.width;
+ _valueTokenField.frame = frame;
+ return _valueTokenField;
+}
+
+- (NSPredicate *)predicateWithSubpredicates:(NS_ARRAY_OF(NSPredicate *) *)subpredicates {
+ NSComparisonPredicate *predicate = (NSComparisonPredicate *)[super predicateWithSubpredicates:subpredicates];
+ NSAssert([predicate isKindOfClass:[NSComparisonPredicate class]], @"FeatureAttributePredicateEditorRowTemplate only works with comparison predicates.");
+
+ NSExpression *leftExpression = [NSExpression expressionForKeyPath:self.keyPathTextField.stringValue];
+ NSExpression *rightExpression = predicate.rightExpression;
+ if (predicate.predicateOperatorType == NSInPredicateOperatorType) {
+ rightExpression = [NSExpression expressionForAggregate:
+ [_valueTokenField.stringValue componentsSeparatedByString:@","]];
+ }
+ return [NSComparisonPredicate predicateWithLeftExpression:leftExpression
+ rightExpression:rightExpression
+ modifier:predicate.comparisonPredicateModifier
+ type:predicate.predicateOperatorType
+ options:predicate.options];
+}
+
+- (void)setPredicate:(NSComparisonPredicate *)predicate {
+ NSAssert([predicate isKindOfClass:[NSComparisonPredicate class]], @"FeatureAttributePredicateEditorRowTemplate only works with comparison predicates.");
+
+ self.keyPathTextField.stringValue = predicate.leftExpression.keyPath;
+ [self.keyPathTextField sizeToFit];
+
+ BOOL isInPredicate = predicate.predicateOperatorType == NSInPredicateOperatorType;
+ _operatorPopUpButton.enabled = !isInPredicate;
+ _valueTextField.hidden = isInPredicate;
+ self.valueTokenField.hidden = !isInPredicate;
+ NSExpression *rightExpression = predicate.rightExpression;
+ if (isInPredicate) {
+ NSArray *values = [rightExpression.constantValue valueForKeyPath:@"constantValue"];
+ self.valueTokenField.stringValue = [values componentsJoinedByString:@","];
+ rightExpression = [NSExpression expressionForConstantValue:nil];
+ } else {
+ self.valueTokenField.stringValue = @"";
+ }
+
+ predicate = [NSComparisonPredicate predicateWithLeftExpression:self.leftExpressions.firstObject
+ rightExpression:rightExpression
+ modifier:predicate.comparisonPredicateModifier
+ type:predicate.predicateOperatorType
+ options:predicate.options];
+ [super setPredicate:predicate];
+}
+
+@end
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 705ebb8a45..0a8883c473 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -54,7 +54,8 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
@property (weak) IBOutlet NSArrayController *styleLayersArrayController;
@property (weak) IBOutlet NSTableView *styleLayersTableView;
@property (weak) IBOutlet NSMenu *mapViewContextMenu;
-@property (weak) IBOutlet NSSplitView *splitView;
+@property (weak) IBOutlet NSSplitView *styleLayersSplitView;
+@property (weak) IBOutlet NSSplitView *predicateSplitView;
@end
@@ -105,7 +106,8 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)];
[self.mapView addGestureRecognizer:pressGestureRecognizer];
- [self.splitView setPosition:0 ofDividerAtIndex:0];
+ [self.styleLayersSplitView setPosition:0 ofDividerAtIndex:0];
+ [self.predicateSplitView setPosition:DBL_MAX ofDividerAtIndex:0];
[self applyPendingState];
}
@@ -235,10 +237,10 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
Show or hide the Layers sidebar.
*/
- (IBAction)toggleLayers:(id)sender {
- BOOL isShown = ![self.splitView isSubviewCollapsed:self.splitView.arrangedSubviews.firstObject];
+ BOOL isShown = ![self.styleLayersSplitView isSubviewCollapsed:self.styleLayersSplitView.arrangedSubviews.firstObject];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
context.allowsImplicitAnimation = YES;
- [self.splitView setPosition:isShown ? 0 : 100 ofDividerAtIndex:0];
+ [self.styleLayersSplitView setPosition:isShown ? 0 : 100 ofDividerAtIndex:0];
[self.window.toolbar validateVisibleItems];
} completionHandler:nil];
}
@@ -331,6 +333,17 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.styleLayersArrayController removeObjectsAtArrangedObjectIndexes:indices];
}
+/**
+ Show or hide the Layer Filter pane.
+ */
+- (IBAction)toggleLayerFilter:(id)sender {
+ BOOL isShown = ![self.predicateSplitView isSubviewCollapsed:self.predicateSplitView.arrangedSubviews.lastObject];
+ [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
+ context.allowsImplicitAnimation = YES;
+ [self.predicateSplitView setPosition:isShown ? DBL_MAX : self.mapView.frame.size.height - 100 ofDividerAtIndex:0];
+ } completionHandler:nil];
+}
+
- (IBAction)setLabelLanguage:(NSMenuItem *)sender {
_isLocalizingLabels = sender.tag;
[self reload:sender];
@@ -813,7 +826,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
return YES;
}
if (menuItem.action == @selector(toggleLayers:)) {
- BOOL isShown = ![self.splitView isSubviewCollapsed:self.splitView.arrangedSubviews.firstObject];
+ BOOL isShown = ![self.styleLayersSplitView isSubviewCollapsed:self.styleLayersSplitView.arrangedSubviews.firstObject];
menuItem.title = isShown ? @"Hide Layers" : @"Show Layers";
return YES;
}
@@ -833,6 +846,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.action == @selector(deleteStyleLayers:)) {
return self.styleLayersTableView.clickedRow >= 0 || self.styleLayersTableView.selectedRow >= 0;
}
+ if (menuItem.action == @selector(toggleLayerFilter:)) {
+ BOOL isShown = ![self.predicateSplitView isSubviewCollapsed:self.predicateSplitView.arrangedSubviews.lastObject];
+ menuItem.title = isShown ? @"Hide Layer Filter" : @"Show Layer Filter";
+ return YES;
+ }
if (menuItem.action == @selector(setLabelLanguage:)) {
menuItem.state = menuItem.tag == _isLocalizingLabels ? NSOnState: NSOffState;
if (menuItem.tag) {
@@ -984,7 +1002,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
if (action == @selector(toggleLayers:)) {
- BOOL isShown = ![self.splitView isSubviewCollapsed:self.splitView.arrangedSubviews.firstObject];
+ BOOL isShown = ![self.styleLayersSplitView isSubviewCollapsed:self.styleLayersSplitView.arrangedSubviews.firstObject];
[(NSButton *)toolbarItem.view setState:isShown ? NSOnState : NSOffState];
}
return NO;
@@ -1074,14 +1092,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
- DroppedPinAnnotation *droppedPin = annotation;
+ DroppedPinAnnotation *droppedPin = (DroppedPinAnnotation *)annotation;
[droppedPin resume];
}
}
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
- DroppedPinAnnotation *droppedPin = annotation;
+ DroppedPinAnnotation *droppedPin = (DroppedPinAnnotation *)annotation;
[droppedPin pause];
}
}
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 56872a1b19..7a1cd80305 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -127,6 +127,7 @@
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8F25A61D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h */; };
DA8F25B31D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25A71D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm */; };
DAA48EFD1D6A4731006A7E36 /* StyleLayerIconTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */; };
+ DAA578331E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA578321E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.m */; };
DAB2CCE51DF632ED001B2FE1 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */; };
DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; };
DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22121CF3D3E200D220D9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -388,6 +389,8 @@
DA8F25B71D51D2240010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleLayerIconTransformer.h; sourceTree = "<group>"; };
DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleLayerIconTransformer.m; sourceTree = "<group>"; };
+ DAA578311E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeatureAttributePredicateEditorRowTemplate.h; sourceTree = "<group>"; };
+ DAA578321E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FeatureAttributePredicateEditorRowTemplate.m; sourceTree = "<group>"; };
DAB2CCE31DF632ED001B2FE1 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LimeGreenStyleLayer.h; sourceTree = "<group>"; };
DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LimeGreenStyleLayer.m; sourceTree = "<group>"; };
DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; };
@@ -625,6 +628,8 @@
DA839E961CC2E3400062CAFB /* AppDelegate.m */,
DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */,
DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */,
+ DAA578311E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.h */,
+ DAA578321E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.m */,
DAB2CCE31DF632ED001B2FE1 /* LimeGreenStyleLayer.h */,
DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */,
DAE6C2E51CC3050F00DB3429 /* LocationCoordinate2DTransformer.h */,
@@ -1234,6 +1239,7 @@
DAE6C2F11CC3050F00DB3429 /* TimeIntervalTransformer.m in Sources */,
DA839E9A1CC2E3400062CAFB /* main.m in Sources */,
DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */,
+ DAA578331E11FD46009B2566 /* FeatureAttributePredicateEditorRowTemplate.m in Sources */,
DAF0D81C1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m in Sources */,
DAE6C2F01CC3050F00DB3429 /* OfflinePackNameValueTransformer.m in Sources */,
);