-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Per-attribute transition properties on MGLStyleLayer #8225
Per-attribute transition properties on MGLStyleLayer #8225
Conversation
@fabian-guerra, thanks for your PR! By analyzing this pull request, we identified @1ec5, @boundsj and @incanus to be potential reviewers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this PR be based against the 3.5.0 release branch since it builds upon data-driven styling?
platform/darwin/src/MGLTypes.h
Outdated
@@ -85,6 +85,21 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) { | |||
#endif | |||
}; | |||
|
|||
/** | |||
A structure containing information about a transition values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove values
.
platform/darwin/src/MGLTypes.h
Outdated
NSTimeInterval duration; | ||
|
||
/** | ||
The delay in seconds to before applying any changes to the style URL or to layout and paint attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove to
in to before
.
{ | ||
NSString *camelCaseKey; | ||
if ([key length] > 1) { | ||
camelCaseKey = [NSString stringWithFormat:@"%@%@",[[key substringToIndex:1] uppercaseString],[key substringFromIndex:1]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style: spaces after ,
.
@@ -14,6 +14,8 @@ | |||
#import "MGLStyleValue_Private.h" | |||
#import "MGL<%- camelize(type) %>StyleLayer.h" | |||
|
|||
#import "NSDate+MGLAdditions.h" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this further up with the others, next to #import "NSPredicate+MGLAdditions.h"
, a similar category use.
platform/darwin/src/MGLStyle.h
Outdated
@@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN | |||
*/ | |||
static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 9; | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extraneous whitespace.
platform/darwin/src/MGLStyle.h
Outdated
@@ -194,6 +195,11 @@ MGL_EXPORT | |||
@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources; | |||
|
|||
/** | |||
Transition values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should describe it a bit more here, maybe:
Values describing animated transitions to styling changes, either to the style URL or to individual properties.
platform/darwin/src/MGLStyle.mm
Outdated
- (void)setTransition:(MGLTransition)transition | ||
{ | ||
[self setTransitionDuration:transition.duration]; | ||
[self setTransitionDelay:transition.delay]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably get rid of the separate internal -setTransitionDuration:
and -setTransitionDelay:
since externally we only set full transition structures containing both values.
|
||
[setPropertyInvocation setArgument:&transition atIndex:2]; | ||
|
||
[setPropertyInvocation performSelector:@selector(invoke)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't this be simply -[NSObject performSelector:withObject:]
since it's only one argument, passing the transition
wrapped in NSValue
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@incanus using an NSValue
I will have to wrap it then unwrap in set***Transition:
, also I will have to add pragma marks to avoid the "PerformSelect may cause a leak because...".
I think this approach is more straightforward, what are your thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you continue with this PR, please also add appropriate tests (generated with MGLStyleLayerTests.mm.ejs) and the obligatory changelog entry 😄
NSString *setPropertyTransitionString = [NSString stringWithFormat:@"mbx_set%@Transition:", camelCaseKey]; | ||
SEL setPropertyTransitionSelector = NSSelectorFromString(setPropertyTransitionString); | ||
|
||
if ([self respondsToSelector:setPropertyTransitionSelector]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the main motivation to introduce dynamic method invocation for transitions?
Most of the complexity here is about parsing the string and forming the private method name to match the actual implementation and that introduces new types of edge cases that we did not previously need to handle. For example, what if the client app passes in a nonsensical string at runtime? So far, I think this implementation would fail silently. Should it log a warning, raise an exception, etc.? Do we expect to offer a string parameter based getter for each transition, too?
Since the style layer implementation is generated and in the spirit of consistency with the existing API and its per property getters and setters, I suggest that we consider making the mbx_
methods in this implementation public and avoid the dynamic invocation altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was pointed to the original post in #8010 (comment) so this makes sense now. Thanks!
I still vote for explicit getters and setters. However, if we do go with the CALayer influenced API, it would be nice to try a refactor so that some or all of this string parsing and method invocation logic goes into the base MGLStyleLayer class.
@@ -1204,6 +1206,15 @@ MGL_EXPORT | |||
* `MGLCameraStyleFunction` with an interpolation mode of: | |||
* `MGLInterpolationModeExponential` | |||
* `MGLInterpolationModeInterval` | |||
* `MGLSourceStyleFunction` with an interpolation mode of: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a byproduct of the style spec / gl native mismatch. All of these comments should be manually removed in this PR (or work against a style spec gitsha that does not cause this to happen to avoid the inconvenience)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it is likely that #7939 will land before this PR and, I think, this problem will go away then once this branch is rebased on top of that change set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if you rebase this PR on top of master as of now, f901e77 will fix this problem 👍
The |
bbdb9f4
to
27b6f8d
Compare
platform/darwin/src/MGLStyleLayer.mm
Outdated
- (NSArray *)transitionKeys | ||
{ | ||
// This is overridden by subclasses | ||
return nil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Raise an MGLAbstractClassException. Search for that string for an example to follow.
[transitionKeys addObject:@"backgroundOpacity"]; | ||
[transitionKeys addObject:@"backgroundPattern"]; | ||
|
||
return transitionKeys; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more efficient to return an array literal.
@@ -84,13 +85,33 @@ - (void)removeFromMapView:(MGLMapView *)mapView | |||
|
|||
#pragma mark - Accessing the Paint Attributes | |||
|
|||
- (NSArray *)transitionKeys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this method doesn’t have any dependencies on other instance methods, you can make this a class method. But I’m unclear on this method’s purpose. It appears to be unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method returns the keys which you can add a transition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, looking more closely, this method appears to be used only in tests (but is exposed publicly). As an alternative to this method, could we move the array of keys into the tests themselves?
Since this PR is scheduled for iOS SDK v3.5.0, please rebase and retarget it at the release-ios-v3.5.0-android-v5.0.0 branch. Thanks! |
27b6f8d
to
f0adb64
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also seeing extraneous commits like 33f1982 in the mix. Is this because you've brought over some changes from master
as well @fabian-guerra?
|
||
return transitionKeys; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, per https://github.com/mapbox/mapbox-gl-native/pull/8225/files#r104082076, you could do like this:
+ (NSArray *)transitionKeys
{
return @[
<% for ...
@"<%- camelizeWithLeadingLowercase(property.name) %>",
<% } -%>
];
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@incanus I was using master but retarget to rebase release-ios-v3.5.0-android-v5.0.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future, do git rebase -i newBranchName
and remove things you don't want as part of the PR. Then force-push and finally retarget the PR.
ba516bc
to
95c452e
Compare
@@ -43,7 +43,7 @@ public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull | |||
return INSTANCE; | |||
} | |||
|
|||
private Mapbox(@NonNull Context context, @NonNull String accessToken) { | |||
Mapbox(@NonNull Context context, @NonNull String accessToken) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR seems to have picked up additional, unrelated commits along the way when it was rebased like this one from #8228
95c452e
to
7cedbff
Compare
Fixed #8225 (review) manually with a rebase dropping these oddball non-@fabian-guerra commits and force-pushed to fix 👍 |
a324ae8
to
2e51b1e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to the comments below, please add an entry to the iOS and macOS changelogs about this enhancement. Thanks!
platform/darwin/src/MGLStyleLayer.h
Outdated
/** | ||
Returns an array of strings that identify transition keys attached to the layer. | ||
*/ | ||
+ (NSArray *)transitionKeys; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we expose this method publicly? If so, let's call it transitionableAttributes
and also make the return type a set of strings instead of an unqualified array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Method is intended to explicitly return which layer attributes are transitionable, we can as well add a note on each property, but I think this is a better way to let know devs about what they can change, also this can be used as helper to set the same transition property to all transitionable attributes
platform/darwin/src/MGLStyleLayer.h
Outdated
@@ -69,6 +69,17 @@ MGL_EXPORT | |||
*/ | |||
@property (nonatomic, assign) float minimumZoomLevel; | |||
|
|||
#pragma mark Layer Transitions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jazzy uses these marks to produce section headings in the generated documentation. For consistency with Apple's documentation, we label each mark according to a task. Here, we can say "Timing Changes to Attributes".
platform/darwin/src/MGLStyleLayer.h
Outdated
@@ -69,6 +69,17 @@ MGL_EXPORT | |||
*/ | |||
@property (nonatomic, assign) float minimumZoomLevel; | |||
|
|||
#pragma mark Layer Transitions | |||
|
|||
- (void)setTransition:(MGLTransition)transition forKey:(NSString *)key; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public methods need documentation comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking we might want to call it -setTransition:forAttribute:
to be more specific about the kind of key that's being transitioned.
platform/darwin/src/MGLStyleLayer.mm
Outdated
return transition; | ||
} | ||
|
||
- (SEL)mbx_selectorForKey:(NSString *)key type:(NSString *)type hasParams:(BOOL)params |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to prefix private methods with a class prefix the way we prefix category methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method would be a bit simpler if we had two methods: one for getters and one for setters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since all the valid setter method names form a closed set, we should generate a lookup table mapping attributes to the corresponding setter name, then look up the passed-in attribute in that table to decide what to call. That way, we can raise an exception when the developer passes in an untransitionable attribute or a bogus attribute. Currently, doing that leads to a nasty crash with no useful information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now not positive that the getter use of -Warc-performSelector-leaks
is safe, since we are creating a new NSValue
inside of mbx_getFooTransition
and we aren't telling ARC how to dispose of it (the use in setters is fine since they return void
). So I think the overridden leak warning is a valid one.
i.e. What happens to the NSValue
at https://github.com/mapbox/mapbox-gl-native/pull/8225/files#diff-24c0d8cf4ae8bed8e0bc00616e9aae68R89 after we return the wrapped transition
?
Additionally, per NSValue
docs:
This method has the same effect as
valueWithBytes:objCType:
and may be deprecated in a future release. You should usevalueWithBytes:objCType:
instead.
2e51b1e
to
1ffc2e6
Compare
@@ -69,6 +69,11 @@ MGL_EXPORT | |||
#endif | |||
|
|||
/** | |||
`backgroundColor` transition attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The transition affecting any changes to this layer’s
backgroundColor
property.This property corresponds to the
background-color-transition
property in the style JSON file format.
(We can't quite say "in the Mapbox Style Specification", as we do elsewhere, because of mapbox/mapbox-gl-js#4081.)
@@ -59,6 +62,11 @@ - (void)testProperties { | |||
XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); | |||
functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; | |||
XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); | |||
// Transition property test | |||
layer.backgroundColorTransition = transitionTest; | |||
MGLTransition backgroundColorTransition = layer.backgroundColorTransition; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By setting and getting before asserting, we're verifying that the transition value round-trips. That's good, but it doesn't rule out the possibility that both the getter and setter are buggy. To rule that out, we'd need to assert after setting that the underlying mbgl::style::BackgroundLayer::getBackgroundColorTransition()
is correct.
@@ -1753,6 +1814,7 @@ MGL_EXPORT | |||
*/ | |||
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslationAnchor; | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: stray line.
platform/darwin/src/MGLTypes.h
Outdated
*/ | ||
NSTimeInterval delay; | ||
} MGLTransition; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should provide a factory method MGLTransitionMake(). We might also want to add transition-related methods to NSValue(MGLAdditions) to make it easier to work with MGLTransition instances when an object is needed.
platform/darwin/src/MGLTypes.h
Outdated
*/ | ||
typedef struct MGLTransition { | ||
/** | ||
The duration in seconds to animate any changes to the style URL or to layout and paint attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit of a nonsequitur to talk about style URLs and attributes here. This structure is generic enough that its documentation should be more self-contained. For example:
The amount of time the animation should take, not including the
delay
.
(It doesn't include the delay, does it?)
platform/darwin/src/MGLTypes.h
Outdated
NSTimeInterval duration; | ||
|
||
/** | ||
The delay in seconds before applying any changes to the style URL or to layout and paint attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The amount of time in seconds to wait before beginning the animation.
d85657b
to
77dea62
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there!
@@ -69,6 +69,13 @@ MGL_EXPORT | |||
#endif | |||
|
|||
/** | |||
The transition affecting any changes to this layer’s `backgroundColor` property. | |||
|
|||
This property corresponds to the background-color-transition property in the style JSON file format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surround background-color-transition
in backticks.
options.delay = MGLTimeIntervalFromDuration(toptions.delay.value_or(mbgl::Duration::zero())); | ||
options.duration = MGLTimeIntervalFromDuration(toptions.duration.value_or(mbgl::Duration::zero())); | ||
XCTAssertEqual(options.delay, transitionTest.delay); | ||
XCTAssertEqual(options.duration, transitionTest.duration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would structure this a little differently:
- Set
fillColorTransition
totransitionTest
. - Call
getFillColorTransition()
. - Assert
toptions.delay && *toptions.delay == transitionTest.delay
.
platform/darwin/src/MGLTypes.h
Outdated
|
||
/** | ||
Creates a new `MGLTransition` from the given duration and delay. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document each @param
and the @return
value.
@@ -70,6 +71,22 @@ NS_ASSUME_NONNULL_BEGIN | |||
*/ | |||
@property (readonly) MGLOfflinePackProgress MGLOfflinePackProgressValue; | |||
|
|||
#pragma mark Working with Transition values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: s/values/Values/
77dea62
to
a63be28
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great.
|
||
@return Returns a `MGLTransition` struct containing the transition attributes. | ||
*/ | ||
NS_INLINE MGLTransition MGLTransitionMake(NSTimeInterval duration, NSTimeInterval delay) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure, but you may also need to MGL_EXPORT this function. Generally we have to export public, top-level symbols, but this one is inlined. @kkaefer would know for sure.
… methods to NSValue(MGLAdditions)
a63be28
to
09f6f9f
Compare
[self getValue:&transition]; | ||
return transition; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have these utilities anymore? We don't use them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been pointed at #8225 (comment). 👍🏻
🎉 |
Fixes #8010