All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jfoenix.controls.JFXDrawer Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.jfoenix.controls;

import com.jfoenix.controls.events.JFXDrawerEvent;
import com.jfoenix.transitions.JFXAnimationTimer;
import com.jfoenix.transitions.JFXKeyFrame;
import com.jfoenix.transitions.JFXKeyValue;
import javafx.animation.Interpolator;
import javafx.animation.PauseTransition;
import javafx.animation.Transition;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import javafx.util.Duration;

import java.util.ArrayList;

/**
 * JFXDrawer is material design implementation of drawer.
 * the drawer has two main nodes, the content and side pane.
 * 
    *
  • content pane: is a stack pane that holds the nodes inside the drawer
  • *
  • side pane: is a stack pane that holds the nodes inside the drawer side area (Drawable node)
  • *
* * @author Shadi Shaheen * @version 1.0 * @since 2016-03-09 */ public class JFXDrawer extends StackPane { /** * Defines the directions that a {@link JFXDrawer} can originate from. */ public enum DrawerDirection { LEFT(1), RIGHT(-1), TOP(1), BOTTOM(-1); private double numVal; DrawerDirection(double numVal) { this.numVal = numVal; } public double doubleValue() { return numVal; } } // nodes private StackPane overlayPane = new StackPane(); StackPane sidePane = new StackPane(); private StackPane content = new StackPane(); private StackPane contentHolder = new StackPane(); private Region paddingPane = new Region(); // animation private Transition partialTransition; private Duration holdTime = Duration.seconds(0.2); private PauseTransition holdTimer = new PauseTransition(holdTime); private double initOffset = 30; private DoubleProperty initTranslate = new SimpleDoubleProperty(); private double activeOffset = 20; private double startMouse = -1; private double startTranslate = -1; private double startSize = -1; // used to trigger the drawer events private boolean openCalled = false; private boolean closeCalled = true; // side pane size properties private DoubleProperty translateProperty = sidePane.translateXProperty(); private DoubleProperty defaultSizeProperty = new SimpleDoubleProperty(); private DoubleProperty maxSizeProperty = sidePane.maxWidthProperty(); private DoubleProperty prefSizeProperty = sidePane.prefWidthProperty(); private ReadOnlyDoubleProperty sizeProperty = sidePane.widthProperty(); // this property is used to reference the parent width/height property private ReadOnlyDoubleProperty parentSizeProperty = null; // this is used to allow resizing the content of the drawer private DoubleProperty paddingSizeProperty = paddingPane.minWidthProperty(); /*************************************************************************** * * * Animations * * * **************************************************************************/ // used to hold the new translation value during the animation private double translateTo = 0; // used to cache the drawer size private double tempDrawerSize = getDefaultDrawerSize(); private JFXAnimationTimer translateTimer = new JFXAnimationTimer( new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> overlayPane.opacityProperty()) .setEndValueSupplier(() -> 1 - translateTo / initTranslate.get()) .setInterpolator(Interpolator.EASE_BOTH).build()), new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> translateProperty) .setEndValueSupplier(() -> translateTo) .setInterpolator(Interpolator.EASE_BOTH).build()), new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> prefSizeProperty) .setEndValueSupplier(() -> getDefaultDrawerSize()) .setAnimateCondition(() -> translateTo == initTranslate.get()) .setInterpolator(Interpolator.EASE_BOTH).build()), new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> maxSizeProperty) .setEndValueSupplier(() -> getDefaultDrawerSize()) .setAnimateCondition(() -> translateTo == initTranslate.get()) .setInterpolator(Interpolator.EASE_BOTH).build()), new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> prefSizeProperty) .setEndValueSupplier(() -> tempDrawerSize) .setAnimateCondition(() -> translateTo == 0 && tempDrawerSize > getDefaultDrawerSize()) .setInterpolator(Interpolator.EASE_BOTH).build()), new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> maxSizeProperty) .setEndValueSupplier(() -> tempDrawerSize) .setAnimateCondition(() -> translateTo == 0 && tempDrawerSize > getDefaultDrawerSize()) .setInterpolator(Interpolator.EASE_BOTH).build()), // padding animation new JFXKeyFrame(Duration.millis(420), JFXKeyValue.builder() .setTargetSupplier(() -> paddingSizeProperty) .setEndValueSupplier(this::computePaddingSize) .setInterpolator(Interpolator.EASE_BOTH).build()) ); /** * creates empty drawer node */ public JFXDrawer() { initialize(); contentHolder.setPickOnBounds(false); overlayPane.setBackground(new Background(new BackgroundFill(Color.rgb(0, 0, 0, 0.1), CornerRadii.EMPTY, Insets.EMPTY))); overlayPane.getStyleClass().add("jfx-drawer-overlay-pane"); overlayPane.setOpacity(0); overlayPane.setMouseTransparent(true); sidePane.getStyleClass().add("jfx-drawer-side-pane"); sidePane.setBackground(new Background(new BackgroundFill(Color.rgb(255, 255, 255, 1), CornerRadii.EMPTY, Insets.EMPTY))); sidePane.setPickOnBounds(false); translateTimer.setCacheNodes(sidePane); // add listeners initListeners(); // init size value setDefaultDrawerSize(100); getChildren().setAll(contentHolder, overlayPane, sidePane); } private void initialize() { this.getStyleClass().add(DEFAULT_STYLE_CLASS); } private void initListeners() { updateDirection(directionProperty.get()); initTranslate.bind(Bindings.createDoubleBinding(() -> -1 * directionProperty.get().doubleValue() * defaultSizeProperty.getValue() - initOffset * directionProperty.get().doubleValue(), defaultSizeProperty, directionProperty)); // add listeners to update drawer properties overLayVisibleProperty().addListener(observable -> { final boolean overLayVisible = isOverLayVisible(); overlayPane.setStyle(!overLayVisible ? "-fx-background-color : transparent;" : ""); overlayPane.setPickOnBounds(overLayVisible); }); directionProperty.addListener(observable -> updateDirection(directionProperty.get())); initTranslate.addListener(observable -> updateDrawerAnimation(initTranslate.get())); // mouse drag handler // translateProperty.addListener(observable -> overlayPane.setOpacity(1 - translateProperty.doubleValue() / initTranslate.get())); // add opening/closing action listeners translateProperty.addListener((o, oldVal, newVal) -> { if (!openCalled && closeCalled && directionProperty.get().doubleValue() * newVal.doubleValue() > directionProperty.get().doubleValue() * initTranslate.get() / 2) { openCalled = true; closeCalled = false; fireEvent(new JFXDrawerEvent(JFXDrawerEvent.OPENING)); } }); translateProperty.addListener((o, oldVal, newVal) -> { if (openCalled && !closeCalled && directionProperty.get().doubleValue() * newVal.doubleValue() < directionProperty.get().doubleValue() * initTranslate.get() / 2) { closeCalled = true; openCalled = false; fireEvent(new JFXDrawerEvent(JFXDrawerEvent.CLOSING)); } }); overlayPane.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> close()); sidePane.addEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragHandler); sidePane.addEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedHandler); sidePane.addEventHandler(MouseEvent.MOUSE_PRESSED, mousePressedHandler); // content listener for mouse hold on a side this.content.addEventHandler(MouseEvent.MOUSE_PRESSED, (e) -> { if (!e.isConsumed()) { double size = 0; long valid = 0; for (int i = 0; i < callBacks.size(); i++) { if (!callBacks.get(i).call(null)) { valid++; } } if (directionProperty.get() == DrawerDirection.RIGHT) { size = content.getWidth(); } else if (directionProperty.get() == DrawerDirection.BOTTOM) { size = content.getHeight(); } double eventPoint = 0; if (directionProperty.get() == DrawerDirection.RIGHT || directionProperty.get() == DrawerDirection.LEFT) { eventPoint = e.getX(); } else { eventPoint = e.getY(); } if (size + directionProperty.get().doubleValue() * eventPoint < activeOffset && (content.getCursor() == Cursor.DEFAULT || content.getCursor() == null) && valid == 0 && !isShown()) { holdTimer.play(); e.consume(); } } }); this.content.addEventHandler(MouseEvent.MOUSE_RELEASED, (e) -> { holdTimer.stop(); this.content.removeEventFilter(MouseEvent.MOUSE_DRAGGED, mouseDragHandler); }); holdTimer.setOnFinished(e -> { translateTo = initTranslate.get() + initOffset * directionProperty.get().doubleValue() + activeOffset * directionProperty.get().doubleValue(); overlayPane.setMouseTransparent(!isOverLayVisible()); translateTimer.setOnFinished(null); translateTimer.start(); }); } ChangeListener widthListener = (o, oldVal, newVal) -> { if (newVal != null && newVal instanceof Region) { parentSizeProperty = ((Region) newVal).widthProperty(); } }; ChangeListener heightListener = (o, oldVal, newVal) -> { if (newVal != null && newVal instanceof Region) { parentSizeProperty = ((Region) newVal).heightProperty(); } }; ChangeListener sceneWidthListener = (o, oldVal, newVal) -> { if (newVal != null && this.getParent() == null) { parentSizeProperty = newVal.widthProperty(); } }; ChangeListener sceneHeightListener = (o, oldVal, newVal) -> { if (newVal != null && this.getParent() == null) { parentSizeProperty = newVal.heightProperty(); } }; /** * This method will change the drawer behavior according to the argument direction. * * @param dir - The direction that the drawer will enter the screen from. */ private void updateDirection(DrawerDirection dir) { maxSizeProperty.set(-1); prefSizeProperty.set(-1); // reset old translation translateProperty.set(0); // update properties if (dir == DrawerDirection.LEFT || dir == DrawerDirection.RIGHT) { // set the new translation property translateProperty = sidePane.translateXProperty(); // change the size property maxSizeProperty = sidePane.maxWidthProperty(); prefSizeProperty = sidePane.prefWidthProperty(); sizeProperty = sidePane.widthProperty(); paddingSizeProperty = paddingPane.prefWidthProperty(); this.boundedNodeProperty().removeListener(heightListener); this.boundedNodeProperty().addListener(widthListener); if (getBoundedNode() == null) { this.boundedNodeProperty().bind(this.parentProperty()); } this.sceneProperty().removeListener(sceneHeightListener); this.sceneProperty().removeListener(sceneWidthListener); this.sceneProperty().addListener(sceneWidthListener); } else if (dir == DrawerDirection.TOP || dir == DrawerDirection.BOTTOM) { // set the new translation property translateProperty = sidePane.translateYProperty(); // change the size property maxSizeProperty = sidePane.maxHeightProperty(); prefSizeProperty = sidePane.prefHeightProperty(); sizeProperty = sidePane.heightProperty(); paddingSizeProperty = paddingPane.prefHeightProperty(); this.boundedNodeProperty().removeListener(widthListener); this.boundedNodeProperty().addListener(heightListener); if (getBoundedNode() == null) { this.boundedNodeProperty().bind(this.parentProperty()); } this.sceneProperty().removeListener(sceneHeightListener); this.sceneProperty().removeListener(sceneWidthListener); this.sceneProperty().addListener(sceneHeightListener); } // update pane alignment if (dir == DrawerDirection.LEFT) { StackPane.setAlignment(sidePane, Pos.CENTER_LEFT); } else if (dir == DrawerDirection.RIGHT) { StackPane.setAlignment(sidePane, Pos.CENTER_RIGHT); } else if (dir == DrawerDirection.TOP) { StackPane.setAlignment(sidePane, Pos.TOP_CENTER); } else if (dir == DrawerDirection.BOTTOM) { StackPane.setAlignment(sidePane, Pos.BOTTOM_CENTER); } setDefaultDrawerSize(defaultSizeProperty.get()); updateDrawerAnimation(initTranslate.get()); updateContent(); } private void updateDrawerAnimation(double translation) { translateProperty.set(translation); translateTo = translation; } private double computePaddingSize() { if (!isResizeContent()) { return 0; } if (translateTo == 0 && tempDrawerSize > getDefaultDrawerSize()) { return tempDrawerSize; } else if (translateTo == 0) { return getDefaultDrawerSize(); } else if (translateTo == initTranslate.get()) { return 0; } else { return defaultSizeProperty.get() + getDirection().doubleValue() * translateTo; } } /*************************************************************************** * * * Public API * * * **************************************************************************/ private ArrayList> callBacks = new ArrayList<>(); /** * the callbacks are used to add conditions to allow * starting the drawer when holding on the side part of the content */ public void addInitDrawerCallback(Callback callBack) { callBacks.add(callBack); } /** * this method is only used in drawers stack component * * @param callback */ void bringToFront(Callback callback) { EventHandler eventFilter = Event::consume; final boolean bindSize = prefSizeProperty.isBound(); prefSizeProperty.unbind(); maxSizeProperty.unbind(); // disable mouse events this.addEventFilter(MouseEvent.ANY, eventFilter); Runnable onFinished = () -> { callback.call(null); translateTo = 0; translateTimer.setOnFinished(() -> { if (bindSize) { prefSizeProperty.bind(parentSizeProperty); maxSizeProperty.bind(parentSizeProperty); } // enable mouse events this.removeEventFilter(MouseEvent.ANY, eventFilter); }); translateTimer.start(); }; if (sizeProperty.get() > getDefaultDrawerSize()) { tempDrawerSize = sizeProperty.get(); } else { tempDrawerSize = getDefaultDrawerSize(); } translateTo = initTranslate.get(); translateTimer.setOnFinished(onFinished); translateTimer.start(); } /** * This indicates whether or not the drawer is completely shown. * * @return True if the drawer is totally visible and not transitioning, otherwise false. */ public boolean isShown() { return (translateTo == 0 || translateProperty.get() == 0) && !translateTimer.isRunning(); } /** * This indicates whether or not the drawer is in the process of being shown. * * @return True if the drawer is transitioning from closed to open, otherwise false. */ public boolean isShowing() { return translateTo == 0 && translateTimer.isRunning(); } /** * This indicates whether or not the drawer is in the process of being hidden. * * @return True if the drawer is transitioning from open to closed, otherwise false. */ public boolean isHiding() { return translateTo == initTranslate.get() && translateTimer.isRunning(); } /** * This indicates whether or not the drawer is completely hidden. * * @return True if the drawer is hidden and not in the process of transitioning, otherwise false. */ public boolean isHidden() { return translateTo == initTranslate.get() && !translateTimer.isRunning(); } /** * Toggles the drawer between open and closed. The drawer will be closed if it is shown or transitioning between * closed and open. Likewise, it will be opened if it is open or transitioning from open to closed. */ public void toggle() { if (isShown() || isShowing()) { close(); } else { open(); } } /** * Starts the animation to transition this drawer to open. */ public void open() { translateTo = 0; overlayPane.setMouseTransparent(!isOverLayVisible()); translateTimer.setOnFinished(() -> fireEvent(new JFXDrawerEvent(JFXDrawerEvent.OPENED))); translateTimer.reverseAndContinue(); } /** * Starts the animation to transition this drawer to closed. */ public void close() { // unbind properties as the drawer size might be bound to stage size maxSizeProperty.unbind(); prefSizeProperty.unbind(); if (sizeProperty.get() > getDefaultDrawerSize()) { tempDrawerSize = prefSizeProperty.get(); } else { tempDrawerSize = getDefaultDrawerSize(); } if (translateTo != initTranslate.get()) { translateTo = initTranslate.get(); translateTimer.reverseAndContinue(); } translateTimer.setOnFinished(() -> { overlayPane.setMouseTransparent(true); fireEvent(new JFXDrawerEvent(JFXDrawerEvent.CLOSED)); }); } /*************************************************************************** * * * Setters / Getters * * * **************************************************************************/ public ObservableList getSidePane() { return sidePane.getChildren(); } public void setSidePane(Node... sidePane) { this.sidePane.getChildren().setAll(sidePane); } public ObservableList getContent() { if(contentHolder.getChildren().isEmpty()) updateContent(); return content.getChildren(); } public void setContent(Node... content) { this.content.getChildren().setAll(content); if(contentHolder.getChildren().isEmpty()) updateContent(); } private void updateContent() { paddingPane.setPrefSize(0, 0); paddingPane.setMinSize(0, 0); Node contentNode = content; switch (getDirection()) { case TOP: contentNode = new VBox(paddingPane, content); VBox.setVgrow(content, Priority.ALWAYS); break; case BOTTOM: contentNode = new VBox(content, paddingPane); VBox.setVgrow(content, Priority.ALWAYS); break; case LEFT: contentNode = new HBox(paddingPane, content); HBox.setHgrow(content, Priority.ALWAYS); break; case RIGHT: contentNode = new HBox(content, paddingPane); HBox.setHgrow(content, Priority.ALWAYS); break; } contentNode.setPickOnBounds(false); if (isShown()) { paddingSizeProperty.set(computePaddingSize()); } contentHolder.getChildren().setAll(contentNode); } /*************************************************************************** * * * public properties * * * **************************************************************************/ public double getDefaultDrawerSize() { return defaultSizeProperty.get(); } public void setDefaultDrawerSize(double drawerWidth) { defaultSizeProperty.set(drawerWidth); maxSizeProperty.set(drawerWidth); prefSizeProperty.set(drawerWidth); } private SimpleObjectProperty directionProperty = new SimpleObjectProperty<>(DrawerDirection.LEFT); public DrawerDirection getDirection() { return directionProperty.get(); } public SimpleObjectProperty directionProperty() { return directionProperty; } public void setDirection(DrawerDirection direction) { this.directionProperty.set(direction); } private BooleanProperty overLayVisible = new SimpleBooleanProperty(true); public final BooleanProperty overLayVisibleProperty() { return this.overLayVisible; } public final boolean isOverLayVisible() { return this.overLayVisibleProperty().get(); } public final void setOverLayVisible(final boolean overLayVisible) { this.overLayVisibleProperty().set(overLayVisible); } private boolean resizable = false; public boolean isResizableOnDrag() { return resizable; } public void setResizableOnDrag(boolean resizable) { this.resizable = resizable; } private boolean resizeContent = false; public boolean isResizeContent() { return resizeContent; } public void setResizeContent(boolean resizeContent) { this.resizeContent = resizeContent; // animate content size translateTimer.reverseAndContinue(); } private ObjectProperty boundedNode = new SimpleObjectProperty<>(); private final ObjectProperty boundedNodeProperty() { return this.boundedNode; } private final Node getBoundedNode() { return this.boundedNodeProperty().get(); } private final void setBoundedNode(final Node boundedNode) { this.boundedNodeProperty().unbind(); this.boundedNodeProperty().set(boundedNode); } /*************************************************************************** * * * Custom Events * * * **************************************************************************/ public EventHandler getOnDrawerClosed() { return onDrawerClosedProperty().get(); } public ObjectProperty> onDrawerClosedProperty() { return onDrawerClosed; } public void setOnDrawerClosed(EventHandler onDrawerClosed) { onDrawerClosedProperty().set(onDrawerClosed); } private ObjectProperty> onDrawerClosed = new ObjectPropertyBase>() { @Override protected void invalidated() { setEventHandler(JFXDrawerEvent.CLOSED, get()); } @Override public Object getBean() { return JFXDrawer.this; } @Override public String getName() { return "onClosed"; } }; public EventHandler getOnDrawerClosing() { return onDrawerClosing.get(); } public ObjectProperty> onDrawerClosingProperty() { return onDrawerClosing; } public void setOnDrawerClosing(EventHandler onDrawerClosing) { this.onDrawerClosing.set(onDrawerClosing); } private ObjectProperty> onDrawerClosing = new ObjectPropertyBase>() { @Override protected void invalidated() { setEventHandler(JFXDrawerEvent.CLOSING, get()); } @Override public Object getBean() { return JFXDrawer.this; } @Override public String getName() { return "onClosing"; } }; public EventHandler getOnDrawerOpened() { return onDrawerOpened.get(); } public ObjectProperty> onDrawerOpenedProperty() { return onDrawerOpened; } public void setOnDrawerOpened(EventHandler onDrawerOpened) { this.onDrawerOpened.set(onDrawerOpened); } private ObjectProperty> onDrawerOpened = new ObjectPropertyBase>() { @Override protected void invalidated() { setEventHandler(JFXDrawerEvent.OPENED, get()); } @Override public Object getBean() { return JFXDrawer.this; } @Override public String getName() { return "onOpened"; } }; public EventHandler getOnDrawerOpening() { return onDrawerOpening.get(); } public ObjectProperty> onDrawerOpeningProperty() { return onDrawerOpening; } public void setOnDrawerOpening(EventHandler onDrawerOpening) { this.onDrawerOpening.set(onDrawerOpening); } private ObjectProperty> onDrawerOpening = new ObjectPropertyBase>() { @Override protected void invalidated() { setEventHandler(JFXDrawerEvent.OPENING, get()); } @Override public Object getBean() { return JFXDrawer.this; } @Override public String getName() { return "onOpening"; } }; /*************************************************************************** * * * Action Handlers * * * **************************************************************************/ private EventHandler mouseDragHandler = (mouseEvent) -> { if (!mouseEvent.isConsumed()) { mouseEvent.consume(); double size = 0; Bounds sceneBounds = content.localToScene(content.getLayoutBounds()); if (directionProperty.get() == DrawerDirection.RIGHT) { size = sceneBounds.getMinX() + sceneBounds.getWidth(); } else if (directionProperty.get() == DrawerDirection.BOTTOM) { size = sceneBounds.getMinY() + sceneBounds.getHeight(); } if (startSize == -1) { startSize = sizeProperty.get(); } double eventPoint; double directionValue = getDirection().doubleValue(); if (getDirection() == DrawerDirection.RIGHT || getDirection() == DrawerDirection.LEFT) { eventPoint = mouseEvent.getSceneX(); } else { eventPoint = mouseEvent.getSceneY(); } if (size + (directionValue * eventPoint) >= activeOffset && partialTransition != null) { partialTransition = null; } else if (partialTransition == null) { double currentTranslate = startTranslate + eventPoint - startMouse; if (directionValue * currentTranslate <= 0) { // the drawer is hidden if (resizable) { maxSizeProperty.unbind(); prefSizeProperty.unbind(); if (startSize - getDefaultDrawerSize() + directionValue * currentTranslate > 0) { // change the side drawer size if dragging from hidden maxSizeProperty.set(startSize + directionValue * currentTranslate); prefSizeProperty.set(startSize + directionValue * currentTranslate); if (isResizeContent()) { paddingSizeProperty.set(startSize + directionValue * currentTranslate); } } else { // if the side drawer is not fully shown perform translation to show it , and set its default size maxSizeProperty.set(getDefaultDrawerSize()); double translation = directionValue * (startSize - getDefaultDrawerSize()) + currentTranslate; translateProperty.set(translation); overlayPane.setOpacity(1 - translateProperty.get() / initTranslate.get()); if (isResizeContent()) { paddingSizeProperty.set(defaultSizeProperty.get() + directionValue * translation); } } } else { translateProperty.set(currentTranslate); overlayPane.setOpacity(1 - translateProperty.get() / initTranslate.get()); } } else { // the drawer is already shown if (resizable) { if (startSize + directionValue * currentTranslate <= parentSizeProperty.get()) { // change the side drawer size after being shown maxSizeProperty.unbind(); prefSizeProperty.unbind(); maxSizeProperty.set(startSize + directionValue * currentTranslate); prefSizeProperty.set(startSize + directionValue * currentTranslate); if (isResizeContent()) { paddingSizeProperty.set(startSize + directionValue * currentTranslate); } } else { // bind the drawer size to its parent maxSizeProperty.bind(parentSizeProperty); prefSizeProperty.bind(parentSizeProperty); } } translateProperty.set(0); overlayPane.setOpacity(1 - translateProperty.get() / initTranslate.get()); } } } }; private EventHandler mousePressedHandler = (mouseEvent) -> { translateTimer.setOnFinished(null); translateTimer.stop(); if (directionProperty.get() == DrawerDirection.RIGHT || directionProperty.get() == DrawerDirection.LEFT) { startMouse = mouseEvent.getSceneX(); } else { startMouse = mouseEvent.getSceneY(); } startTranslate = translateProperty.get(); startSize = sizeProperty.get(); }; private EventHandler mouseReleasedHandler = (mouseEvent) -> { if (directionProperty.get().doubleValue() * translateProperty.get() > directionProperty.get().doubleValue() * initTranslate.get() / 2) { // show side pane if (translateProperty.get() != 0.0) { partialOpen(); } } else { // hide the sidePane if (translateProperty.get() != initTranslate.get()) { partialClose(); } } if (sizeProperty.get() > getDefaultDrawerSize()) { tempDrawerSize = prefSizeProperty.get(); } else { tempDrawerSize = getDefaultDrawerSize(); } // reset drawer animation properties startMouse = -1; startTranslate = -1; startSize = sizeProperty.get(); }; private void partialClose() { translateTo = initTranslate.get(); translateTimer.setOnFinished(() -> { overlayPane.setMouseTransparent(true); fireEvent(new JFXDrawerEvent(JFXDrawerEvent.CLOSED)); }); translateTimer.start(); } private void partialOpen() { translateTo = 0; overlayPane.setMouseTransparent(!isOverLayVisible()); translateTimer.setOnFinished(() -> fireEvent(new JFXDrawerEvent(JFXDrawerEvent.OPENED))); translateTimer.start(); } /*************************************************************************** * * * Stylesheet Handling * * * **************************************************************************/ /** * Initialize the style class to 'jfx-drawer'. *

* This is the selector class from which CSS can be used to style * this control. */ private static final String DEFAULT_STYLE_CLASS = "jfx-drawer"; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy