modules/controls/src/main/java/javafx/scene/control/skin/TitledPaneSkin.java
Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
*** 21,33 ****
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! package com.sun.javafx.scene.control.skin;
import com.sun.javafx.PlatformUtil;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
--- 21,35 ----
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
! package javafx.scene.control.skin;
import com.sun.javafx.PlatformUtil;
+ import com.sun.javafx.scene.control.behavior.BehaviorBase;
+ import com.sun.javafx.scene.control.skin.Utils;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
*** 36,46 ****
--- 38,50 ----
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Cursor;
import javafx.scene.Node;
+ import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
+ import javafx.scene.control.Control;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
*** 51,81 ****
import javafx.scene.control.Labeled;
import javafx.scene.control.ContextMenu;
import javafx.scene.input.MouseButton;
import javafx.scene.text.Font;
! public class TitledPaneSkin extends LabeledSkinBase<TitledPane, TitledPaneBehavior> {
! public static final Duration TRANSITION_DURATION = new Duration(350.0);
// caching results in poorer looking text (it is blurry), so we don't do it
// unless on a low powered device (admittedly the test below isn't a great
// indicator of power, but it'll do for now).
private static final boolean CACHE_ANIMATION = PlatformUtil.isEmbedded();
private final TitleRegion titleRegion;
private final StackPane contentContainer;
private Node content;
private Timeline timeline;
private double transitionStartValue;
private Rectangle clipRect;
private Pos pos;
private HPos hpos;
private VPos vpos;
! public TitledPaneSkin(final TitledPane titledPane) {
! super(titledPane, new TitledPaneBehavior(titledPane));
clipRect = new Rectangle();
transitionStartValue = 0;
titleRegion = new TitleRegion();
--- 55,126 ----
import javafx.scene.control.Labeled;
import javafx.scene.control.ContextMenu;
import javafx.scene.input.MouseButton;
import javafx.scene.text.Font;
! /**
! * Default skin implementation for the {@link TitledPane} control.
! *
! * @see TitledPane
! * @since 9
! */
! public class TitledPaneSkin extends LabeledSkinBase<TitledPane> {
!
! /***************************************************************************
! * *
! * Static fields *
! * *
! **************************************************************************/
! private static final Duration TRANSITION_DURATION = new Duration(350.0);
// caching results in poorer looking text (it is blurry), so we don't do it
// unless on a low powered device (admittedly the test below isn't a great
// indicator of power, but it'll do for now).
private static final boolean CACHE_ANIMATION = PlatformUtil.isEmbedded();
+
+
+ /***************************************************************************
+ * *
+ * Private fields *
+ * *
+ **************************************************************************/
+
+ private final TitledPaneBehavior behavior;
+
private final TitleRegion titleRegion;
private final StackPane contentContainer;
private Node content;
private Timeline timeline;
private double transitionStartValue;
private Rectangle clipRect;
private Pos pos;
private HPos hpos;
private VPos vpos;
!
!
! /***************************************************************************
! * *
! * Constructors *
! * *
! **************************************************************************/
!
! /**
! * Creates a new TitledPaneSkin instance, installing the necessary child
! * nodes into the Control {@link Control#getChildren() children} list, as
! * well as the necessary input mappings for handling key, mouse, etc events.
! *
! * @param control The control that this skin should be installed onto.
! */
! public TitledPaneSkin(final TitledPane control) {
! super(control);
!
! // install default input map for the TitledPane control
! this.behavior = new TitledPaneBehavior(control);
! // control.setInputMap(behavior.getInputMap());
clipRect = new Rectangle();
transitionStartValue = 0;
titleRegion = new TitleRegion();
*** 90,209 ****
}
}
};
contentContainer.setClip(clipRect);
! if (titledPane.isExpanded()) {
setTransition(1.0f);
! setExpanded(titledPane.isExpanded());
} else {
setTransition(0.0f);
if (content != null) {
content.setVisible(false);
}
}
getChildren().setAll(contentContainer, titleRegion);
! registerChangeListener(titledPane.contentProperty(), "CONTENT");
! registerChangeListener(titledPane.expandedProperty(), "EXPANDED");
! registerChangeListener(titledPane.collapsibleProperty(), "COLLAPSIBLE");
! registerChangeListener(titledPane.alignmentProperty(), "ALIGNMENT");
! registerChangeListener(titledPane.widthProperty(), "WIDTH");
! registerChangeListener(titledPane.heightProperty(), "HEIGHT");
! registerChangeListener(titleRegion.alignmentProperty(), "TITLE_REGION_ALIGNMENT");
!
! pos = titledPane.getAlignment();
! hpos = pos == null ? HPos.LEFT : pos.getHpos();
! vpos = pos == null ? VPos.CENTER : pos.getVpos();
! }
!
! public StackPane getContentContainer() {
! return contentContainer;
! }
!
! @Override
! protected void handleControlPropertyChanged(String property) {
! super.handleControlPropertyChanged(property);
! if ("CONTENT".equals(property)) {
content = getSkinnable().getContent();
if (content == null) {
contentContainer.getChildren().clear();
} else {
contentContainer.getChildren().setAll(content);
}
! } else if ("EXPANDED".equals(property)) {
! setExpanded(getSkinnable().isExpanded());
! } else if ("COLLAPSIBLE".equals(property)) {
! titleRegion.update();
! } else if ("ALIGNMENT".equals(property)) {
pos = getSkinnable().getAlignment();
hpos = pos.getHpos();
vpos = pos.getVpos();
! } else if ("TITLE_REGION_ALIGNMENT".equals(property)) {
pos = titleRegion.getAlignment();
hpos = pos.getHpos();
vpos = pos.getVpos();
! } else if ("WIDTH".equals(property)) {
! clipRect.setWidth(getSkinnable().getWidth());
! } else if ("HEIGHT".equals(property)) {
! clipRect.setHeight(contentContainer.getHeight());
! } else if ("GRAPHIC_TEXT_GAP".equals(property)) {
! titleRegion.requestLayout();
! }
! }
! // Override LabeledSkinBase updateChildren because
! // it removes all the children. The update() in TitleRegion
! // will replace this method.
! @Override protected void updateChildren() {
! if (titleRegion != null) {
! titleRegion.update();
! }
}
- private void setExpanded(boolean expanded) {
- if (! getSkinnable().isCollapsible()) {
- setTransition(1.0f);
- return;
- }
! // we need to perform the transition between expanded / hidden
! if (getSkinnable().isAnimated()) {
! transitionStartValue = getTransition();
! doAnimationTransition();
! } else {
! if (expanded) {
! setTransition(1.0f);
! } else {
! setTransition(0.0f);
! }
! if (content != null) {
! content.setVisible(expanded);
! }
! getSkinnable().requestLayout();
! }
! }
private DoubleProperty transition;
! private void setTransition(double value) { transitionProperty().set(value); }
! private double getTransition() { return transition == null ? 0.0 : transition.get(); }
! private DoubleProperty transitionProperty() {
if (transition == null) {
transition = new SimpleDoubleProperty(this, "transition", 0.0) {
@Override protected void invalidated() {
contentContainer.requestLayout();
}
};
}
return transition;
}
! private boolean isInsideAccordion() {
! return getSkinnable().getParent() != null && getSkinnable().getParent() instanceof Accordion;
}
@Override protected void layoutChildren(final double x, double y,
final double w, final double h) {
// header
double headerHeight = snapSize(titleRegion.prefHeight(-1));
--- 135,234 ----
}
}
};
contentContainer.setClip(clipRect);
! if (control.isExpanded()) {
setTransition(1.0f);
! setExpanded(control.isExpanded());
} else {
setTransition(0.0f);
if (content != null) {
content.setVisible(false);
}
}
getChildren().setAll(contentContainer, titleRegion);
! registerChangeListener(control.contentProperty(), e -> {
content = getSkinnable().getContent();
if (content == null) {
contentContainer.getChildren().clear();
} else {
contentContainer.getChildren().setAll(content);
}
! });
! registerChangeListener(control.expandedProperty(), e -> setExpanded(getSkinnable().isExpanded()));
! registerChangeListener(control.collapsibleProperty(), e -> titleRegion.update());
! registerChangeListener(control.alignmentProperty(), e -> {
pos = getSkinnable().getAlignment();
hpos = pos.getHpos();
vpos = pos.getVpos();
! });
! registerChangeListener(control.widthProperty(), e -> clipRect.setWidth(getSkinnable().getWidth()));
! registerChangeListener(control.heightProperty(), e -> clipRect.setHeight(contentContainer.getHeight()));
! registerChangeListener(titleRegion.alignmentProperty(), e -> {
pos = titleRegion.getAlignment();
hpos = pos.getHpos();
vpos = pos.getVpos();
! });
! pos = control.getAlignment();
! hpos = pos == null ? HPos.LEFT : pos.getHpos();
! vpos = pos == null ? VPos.CENTER : pos.getVpos();
}
!
! /***************************************************************************
! * *
! * Properties *
! * *
! **************************************************************************/
private DoubleProperty transition;
! private final void setTransition(double value) { transitionProperty().set(value); }
! private final double getTransition() { return transition == null ? 0.0 : transition.get(); }
! private final DoubleProperty transitionProperty() {
if (transition == null) {
transition = new SimpleDoubleProperty(this, "transition", 0.0) {
@Override protected void invalidated() {
contentContainer.requestLayout();
}
};
}
return transition;
}
!
!
! /***************************************************************************
! * *
! * Public API *
! * *
! **************************************************************************/
!
! /** {@inheritDoc} */
! @Override public void dispose() {
! super.dispose();
!
! if (behavior != null) {
! behavior.dispose();
! }
! }
!
! // Override LabeledSkinBase updateChildren because
! // it removes all the children. The update() in TitleRegion
! // will replace this method.
! /** {@inheritDoc} */
! @Override protected void updateChildren() {
! if (titleRegion != null) {
! titleRegion.update();
! }
}
+ /** {@inheritDoc} */
@Override protected void layoutChildren(final double x, double y,
final double w, final double h) {
// header
double headerHeight = snapSize(titleRegion.prefHeight(-1));
*** 226,263 ****
--- 251,328 ----
clipRect.setHeight(contentHeight);
positionInArea(contentContainer, x, y,
w, contentHeight, /*baseline ignored*/0, HPos.CENTER, VPos.CENTER);
}
+ /** {@inheritDoc} */
@Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
double titleWidth = snapSize(titleRegion.prefWidth(height));
double contentWidth = snapSize(contentContainer.minWidth(height));
return Math.max(titleWidth, contentWidth) + leftInset + rightInset;
}
+ /** {@inheritDoc} */
@Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
double headerHeight = snapSize(titleRegion.prefHeight(width));
double contentHeight = contentContainer.minHeight(width) * getTransition();
return headerHeight + snapSize(contentHeight) + topInset + bottomInset;
}
+ /** {@inheritDoc} */
@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
double titleWidth = snapSize(titleRegion.prefWidth(height));
double contentWidth = snapSize(contentContainer.prefWidth(height));
return Math.max(titleWidth, contentWidth) + leftInset + rightInset;
}
+ /** {@inheritDoc} */
@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
double headerHeight = snapSize(titleRegion.prefHeight(width));
double contentHeight = contentContainer.prefHeight(width) * getTransition();
return headerHeight + snapSize(contentHeight) + topInset + bottomInset;
}
+ /** {@inheritDoc} */
@Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return Double.MAX_VALUE;
}
+
+
+ /***************************************************************************
+ * *
+ * Private implementation *
+ * *
+ **************************************************************************/
+
+ private void setExpanded(boolean expanded) {
+ if (! getSkinnable().isCollapsible()) {
+ setTransition(1.0f);
+ return;
+ }
+
+ // we need to perform the transition between expanded / hidden
+ if (getSkinnable().isAnimated()) {
+ transitionStartValue = getTransition();
+ doAnimationTransition();
+ } else {
+ if (expanded) {
+ setTransition(1.0f);
+ } else {
+ setTransition(0.0f);
+ }
+ if (content != null) {
+ content.setVisible(expanded);
+ }
+ getSkinnable().requestLayout();
+ }
+ }
+
+ private boolean isInsideAccordion() {
+ return getSkinnable().getParent() != null && getSkinnable().getParent() instanceof Accordion;
+ }
+
double getTitleRegionSize(double width) {
return snapSize(titleRegion.prefHeight(width)) + snappedTopInset() + snappedBottomInset();
}
private double prefHeightFromAccordion = 0;
*** 332,341 ****
--- 397,414 ----
timeline.getKeyFrames().setAll(k1, k2);
timeline.play();
}
+
+
+ /***************************************************************************
+ * *
+ * Support classes *
+ * *
+ **************************************************************************/
+
class TitleRegion extends StackPane {
private final StackPane arrowRegion;
public TitleRegion() {
getStyleClass().setAll("title");
*** 364,374 ****
ContextMenu contextMenu = getSkinnable().getContextMenu() ;
if (contextMenu != null) {
contextMenu.hide() ;
}
if (getSkinnable().isCollapsible() && getSkinnable().isFocused()) {
! getBehavior().toggle();
}
});
// title region consists of the title and the arrow regions
update();
--- 437,447 ----
ContextMenu contextMenu = getSkinnable().getContextMenu() ;
if (contextMenu != null) {
contextMenu.hide() ;
}
if (getSkinnable().isCollapsible() && getSkinnable().isFocused()) {
! behavior.toggle();
}
});
// title region consists of the title and the arrow regions
update();