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();