On Mon, 31 Jul 2023 00:09:38 GMT, Michael Strauß <mstra...@openjdk.org> wrote:
>> Implementation of [CSS >> Transitions](https://gist.github.com/mstr2/c72f8c9faa87de14926978f517a6018a). >> >> ### Example >> >> .button { >> -fx-background-color: dodgerblue; >> } >> >> .button:hover { >> -fx-background-color: red; >> -fx-scale-x: 1.1; >> -fx-scale-y: 1.1; >> >> transition: -fx-background-color 0.5s ease, >> -fx-scale-x 0.5s ease, >> -fx-scale-y 0.5s ease; >> } >> >> <img >> src="https://user-images.githubusercontent.com/43553916/184781143-0520fbfe-54bf-4b8d-93ac-834708e46500.gif" >> width="200"/> >> >> ### Limitations >> This implementation supports both shorthand and longhand notations for the >> `transition` property. However, due to limitations of JavaFX CSS, mixing >> both notations doesn't work: >> >> .button { >> transition: -fx-background-color 1s; >> transition-easing-function: linear; >> } >> >> This issue should be addressed in a follow-up enhancement. > > Michael Strauß has updated the pull request incrementally with one additional > commit since the last revision: > > Make TransitionEvent final Some early feedback, it's a lot of code :) modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html line 1719: > 1717: <tr> > 1718: <td style="width: 120px; vertical-align: top"><span > class="grammar">jump-start</span></td> > 1719: <td>the interval starts with a rise point when the input > progress value is 0</span></td> This has a span closing tag without an opening one modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html line 1723: > 1721: <tr> > 1722: <td style="width: 120px; vertical-align: top"><span > class="grammar">jump-end</span></td> > 1723: <td>the interval ends with a rise point when the input > progress value is 1</span></td> This has a span closing tag without an opening one modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html line 1727: > 1725: <tr> > 1726: <td style="width: 120px; vertical-align: top"><span > class="grammar">jump-none</span></td> > 1727: <td>all rise points are within the open interval > (0..1)</span></td> This has a span closing tag without an opening one modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html line 1732: > 1730: <td style="width: 120px; vertical-align: top"><span > class="grammar">jump-both</span></td> > 1731: <td>the interval starts with a rise point when the input > progress value is 0, > 1732: and ends with a rise point when the input progress > value is 1</span></td> This has a span closing tag without an opening one modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinition.java line 29: > 27: > 28: import javafx.animation.Interpolator; > 29: import javafx.css.StyleableProperty; minor: this is only imported for the Javadoc, but not actually used by code; you could consider using a fully qualified name in the javadoc modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinition.java line 45: > 43: */ > 44: public record TransitionDefinition(String propertyName, Duration duration, > 45: Duration delay, Interpolator > interpolator) { I see this is an internal class that makes use of `javafx.util.Duration`. I think it's not further exposed. I see a lot of calls getting the duration/delay which almost instantly converts the value to nano seconds. It might be an idea to use nanos here immediately (ie. use `long` in the constructor) and have the converter supply longs. modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinition.java line 54: > 52: */ > 53: public TransitionDefinition(String propertyName, Duration duration, > 54: Duration delay, Interpolator > interpolator) { I think you should not repeat the parameters here, just use: Suggestion: public TransitionDefinition { I would also move the "@throws" documentation tags to the record class definition modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinitionConverter.java line 77: > 75: } else { > 76: propertyName = "all"; > 77: } minor: could consider: Suggestion: String propertyName = parsedProperty != null ? parsedProperty.convert(null) : "all"; Same for the other variable initializer block below this one. modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinitionConverter.java line 111: > 109: Duration[] durations = null; > 110: Duration[] delays = null; > 111: Interpolator[] timingFunctions = null; minor: you could consider initializing these with empty arrays, which would make the checks later in the code simpler; however, if the `convertedValues` can hold `null`s for values, this won't work (I don't think it does though). This would also make initializing the variables short enough to be perhaps be done immediately: Duration delay = delays.length == 0 ? Duration.ZERO : delays[i % delays.length]; modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinitionCssMetaData.java line 63: > 61: private static final Duration[] DURATION_ZERO = new Duration[] { > Duration.ZERO }; > 62: > 63: private static final Interpolator[] INTERPOLATOR_EASE = new > Interpolator[] { InterpolatorConverter.CSS_EASE }; Careful, the array contents could still be modified modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionDefinitionCssMetaData.java line 89: > 87: } > 88: }, > 89: new CssMetaData<S, Duration[]>( "transition-duration", minor: Inconsistent spacing used for these properties Suggestion: new CssMetaData<S, Duration[]>("transition-duration", modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 49: > 47: private final P property; > 48: private Interpolator interpolator; > 49: private long startTime, endTime, delay, duration; minor: If these are not in the standard unit (seconds), it might be good to clarify the unit used. It seems to be nano seconds. modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 66: > 64: */ > 65: @SuppressWarnings("unchecked") > 66: public static <T, P extends Property<T> & StyleableProperty<T>> > TransitionTimer<T, P> run( minor: this should either be a comment, or a complete javadoc modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 126: > 124: * @param forceStop if {@code true}, the timer is stopped > unconditionally > 125: * @return {@code true} if the timer was cancelled or {@code timer} > is {@code null}, > 126: * {@code false} otherwise minor: Suggestion: * @return {@code true} if the timer was cancelled, or {@code timer} is {@code null}, * otherwise {@code false} modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 157: > 155: */ > 156: private static void adjustReversingTimer(TransitionTimer<?, ?> > existingTimer, TransitionTimer<?, ?> newTimer, > 157: TransitionDefinition > transition, long now) { minor: This should either be a comment or a full javadoc (all tags present) modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 179: > 177: * The elapsed time is computed according to the CSS Transitions > specification. > 178: */ > 179: private static <T, P extends Property<T> & StyleableProperty<T>> > void fireTransitionEvent( minor: incomplete javadoc, change to comment? modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 206: > 204: * Gets the styleable property targeted by this {@code > TransitionTimer}. > 205: */ > 206: public final P getProperty() { minor: incomplete javadoc, missing return tag modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 263: > 261: * when the transition is interrupted by another transition, or when > it ends normally. > 262: */ > 263: public final void stop(EventType<TransitionEvent> eventType) { minor: Incomplete javadoc modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 302: > 300: * After this method is called, the {@link #updating} flag is {@code > false}. > 301: */ > 302: private boolean pollUpdating() { minor: Incomplete javadoc, missing return tag modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 311: > 309: * Gets the progress of this timer along the input progress axis, > ranging from 0 to 1. > 310: */ > 311: private double getProgress() { minor: missing return tag modules/javafx.graphics/src/main/java/com/sun/javafx/css/TransitionTimer.java line 345: > 343: * > 344: * @param timer the other timer > 345: * @return {@code true} if the target values are equal, {@code > false} otherwise minor: I think this is more common: Suggestion: * @return {@code true} if the target values are equal, otherwise {@code false} modules/javafx.graphics/src/main/java/com/sun/scenario/animation/StepInterpolator.java line 73: > 71: } > 72: > 73: if (t >= 0 && step < 0) { `t >= 0` always holds, perhaps the original `t` was meant here? The `t` parameter is re-assigned, which may be confusing. modules/javafx.graphics/src/main/java/com/sun/scenario/animation/StepInterpolator.java line 83: > 81: }; > 82: > 83: if (t <= 1 && step > jumps) { `t <= 1` is always true, perhaps the original `t` was intended here? See other comment. modules/javafx.graphics/src/main/java/com/sun/scenario/animation/StepInterpolator.java line 97: > 95: @Override > 96: public boolean equals(Object obj) { > 97: return obj instanceof StepInterpolator other minor: Perhaps make `StepInterpolator` `final` modules/javafx.graphics/src/main/java/javafx/animation/Interpolator.java line 305: > 303: * @since 22 > 304: */ > 305: public static Interpolator STEP_START = STEPS(1, StepPosition.START); Suggestion: public static final Interpolator STEP_START = STEPS(1, StepPosition.START); modules/javafx.graphics/src/main/java/javafx/animation/Interpolator.java line 312: > 310: * @since 22 > 311: */ > 312: public static Interpolator STEP_END = STEPS(1, StepPosition.END); Suggestion: public static final Interpolator STEP_END = STEPS(1, StepPosition.END); modules/javafx.graphics/src/main/java/javafx/animation/Interpolator.java line 319: > 317: * The output time value is determined by the {@link StepPosition}. > 318: * > 319: * @param intervals the number of intervals in the step interpolator minor: When I see a plural like `intervals` (or `employees`) I think of a list of objects. Perhaps `intervalCount` would be better? modules/javafx.graphics/src/main/java/javafx/animation/Interpolator.java line 325: > 323: * @since 22 > 324: */ > 325: public static Interpolator STEPS(int intervals, StepPosition > position) { This doesn't specify what happens when `position` is `null`, and is also missing the restrictions on `intervals`. modules/javafx.graphics/src/main/java/javafx/css/CssParser.java line 678: > 676: LOGGER.finest("Expected \'<duration>\'"); > 677: } > 678: ParseException re = new ParseException("Expected > \'<duration>\'",token, this); Suggestion: ParseException re = new ParseException("Expected '<duration>'", token, this); modules/javafx.graphics/src/main/java/javafx/css/CssParser.java line 1022: > 1020: default -> new ParsedValueImpl<>(key, null, true); > 1021: }; > 1022: } minor: No need for `else` (saves nesting) modules/javafx.graphics/src/main/java/javafx/css/CssParser.java line 3949: > 3947: > 3948: private ParsedValueImpl<ParsedValue[], TransitionDefinition> > parseTransition(Term term) > 3949: throws ParseException{ Suggestion: throws ParseException { modules/javafx.graphics/src/main/java/javafx/css/CssParser.java line 3958: > 3956: if (term == null) { > 3957: break; > 3958: } else if (isEasingFunction(term.token)) { minor: No need for `else` Suggestion: } if (isEasingFunction(term.token)) { modules/javafx.graphics/src/main/java/javafx/css/StyleableBooleanProperty.java line 80: > 78: setValue(v); > 79: } > 80: I'm not sure how I feel about this; the changes made don't really seem to belong here. The `StyleableXXXProperty` classes are convenient helpers, but all that matters is that they are `StyleableProperty` implementations. There is no requirement to use the helpers. So what happens when a property defines their own helper, or implements `StyleableProperty` directly? Or if classes are refactored at some point and they decide to stop using these helpers? modules/javafx.graphics/src/main/java/javafx/css/TransitionEvent.java line 43: > 41: public final class TransitionEvent extends Event { > 42: > 43: private static final long serialVersionUID = 20220820L; minor: may I suggest `1L` as in version 1? It's not an existing class that needs to be compatible with older implementations for which a version was derived by the compiler. modules/javafx.graphics/src/main/java/javafx/css/TransitionEvent.java line 88: > 86: * @param eventType the event type > 87: * @param property the {@code StyleableProperty} that is targeted by > the transition > 88: * @param elapsedTime the time that has elapsed since the transition > has entered its active period Can property be `null`? Any restrictions on `elapsedTime`? modules/javafx.graphics/src/main/java/javafx/css/TransitionEvent.java line 111: > 109: * not including the time spent in the delay phase. > 110: * > 111: * @return the elapsed time Any guarantees here? Can it be `null`, negative, zero, infinite? modules/javafx.graphics/src/main/java/javafx/scene/Node.java line 8937: > 8935: * a running {@link TransitionTimer} with this {@code Node}. This > allows the node > 8936: * to keep track of running timers that are targeting its > properties. > 8937: */ minor: incomplete javadoc modules/javafx.graphics/src/main/java/javafx/scene/Node.java line 8951: > 8949: * when their {@link TransitionTimer} has completed. > 8950: */ > 8951: private void removeTransitionTimer(TransitionTimer<?, ?> timer) { minor: incomplete javadoc modules/javafx.graphics/src/main/java/javafx/scene/Node.java line 8960: > 8958: * Finds the transition timer that targets the specified {@code > property}. > 8959: * > 8960: * @return the transition timer, or {@code null} minor: missing @param tag modules/javafx.graphics/src/main/java/javafx/scene/Node.java line 8968: > 8966: > 8967: for (TransitionTimer<?, ?> timer : transitionTimers) { > 8968: if (timer.getProperty() == property) { minor: this probably works, but I'd still use `equals` here ------------- PR Review: https://git.openjdk.org/jfx/pull/870#pullrequestreview-1554590248 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279184581 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279185366 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279185442 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279185777 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279195463 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279235400 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279197467 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279199846 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279204340 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279208647 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279209361 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279217008 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279222846 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279225319 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279226794 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279236379 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279237951 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279241079 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279242702 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279249222 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279251667 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279256926 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279258025 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279263450 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279266478 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279266767 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279271364 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279268169 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279273159 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279275071 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279276790 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279277822 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279295992 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279300672 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279303855 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279302999 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279308190 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279308636 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279309244 PR Review Comment: https://git.openjdk.org/jfx/pull/870#discussion_r1279310798