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.CachedTransition;
import javafx.animation.Animation.Status;
import javafx.animation.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
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 {
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;
}
}
private StackPane overlayPane = new StackPane();
StackPane sidePane = new StackPane();
private StackPane content = new StackPane();
private Transition drawerTransition;
// private Transition outTransition;
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 BooleanProperty overLayVisible = new SimpleBooleanProperty(true);
private double activeOffset = 20;
private double startMouse = -1;
private double startTranslate = -1;
private double startSize = -1;
private DoubleProperty translateProperty = sidePane.translateXProperty();
private boolean resizable = false;
private boolean openCalled = false;
private boolean closeCalled = true;
private DoubleProperty defaultSizeProperty = new SimpleDoubleProperty();
private ObjectProperty maxSizeProperty =
new SimpleObjectProperty<>(sidePane.maxWidthProperty());
private ObjectProperty minSizeProperty =
new SimpleObjectProperty<>(sidePane.minWidthProperty());
private ObjectProperty prefSizeProperty =
new SimpleObjectProperty<>(sidePane.prefWidthProperty());
private ObjectProperty sizeProperty =
new SimpleObjectProperty<>(sidePane.widthProperty());
private ObjectProperty parentSizeProperty =
new SimpleObjectProperty<>();
private ObjectProperty boundedNode = new SimpleObjectProperty<>();
private SimpleObjectProperty directionProperty = new SimpleObjectProperty<>(
DrawerDirection.LEFT);
/**
* creates empty drawer node
*/
public JFXDrawer() {
initialize();
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);
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);
this.getChildren().add(content);
// add listeners
overlayPane.setOnMouseClicked((e) -> close());
initListeners();
// init size value
setDefaultDrawerSize(100);
}
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((o, oldVal, newVal) -> {
overlayPane.setStyle(!newVal ? "-fx-background-color : transparent;" : "");
overlayPane.setMouseTransparent(!newVal);
overlayPane.setPickOnBounds(newVal);
});
directionProperty.addListener((o, oldVal, newVal) -> updateDirection(newVal));
initTranslate.addListener((o, oldVal, newVal) -> updateDrawerAnimation(newVal.doubleValue()));
// 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) {
holdTimer.play();
e.consume();
}
}
});
// mouse drag handler
translateProperty.addListener((o, oldVal, newVal) -> {
double opValue = 1 - newVal.doubleValue() / initTranslate.doubleValue();
overlayPane.setOpacity(opValue);
});
// add opening/closing action listeners
translateProperty.addListener((o, oldVal, newVal) -> {
if (!openCalled && closeCalled
&& directionProperty.get().doubleValue() * newVal.doubleValue() >
directionProperty.get().doubleValue() * initTranslate.doubleValue() / 2) {
openCalled = true;
closeCalled = false;
onDrawerOpeningProperty.get().handle(new JFXDrawerEvent(JFXDrawerEvent.OPENING));
}
});
translateProperty.addListener((o, oldVal, newVal) -> {
if (openCalled && !closeCalled
&& directionProperty.get().doubleValue() * newVal.doubleValue() <
directionProperty.get().doubleValue() * initTranslate.doubleValue() / 2) {
closeCalled = true;
openCalled = false;
onDrawerClosingProperty.get().handle(new JFXDrawerEvent(JFXDrawerEvent.CLOSING));
}
});
this.sidePane.addEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragHandler);
this.sidePane.addEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedHandler);
this.sidePane.addEventHandler(MouseEvent.MOUSE_PRESSED, mousePressedHandler);
this.content.addEventHandler(MouseEvent.MOUSE_RELEASED, (e) -> {
holdTimer.stop();
this.content.removeEventFilter(MouseEvent.MOUSE_DRAGGED, mouseDragHandler);
});
holdTimer.setOnFinished(e -> {
if (!this.getChildren().contains(overlayPane)) {
this.getChildren().add(overlayPane);
}
if (!this.getChildren().contains(sidePane)) {
this.getChildren().add(sidePane);
}
partialTransition = new DrawerPartialTransition(initTranslate.doubleValue(),
initTranslate.doubleValue() + initOffset * directionProperty
.get()
.doubleValue() + activeOffset * directionProperty.get()
.doubleValue());
partialTransition.setOnFinished((event) -> {
this.content.addEventFilter(MouseEvent.MOUSE_DRAGGED, mouseDragHandler);
this.content.addEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedHandler);
this.content.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler() {
@Override
public void handle(Event event) {
JFXDrawer.this.content.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleasedHandler);
JFXDrawer.this.content.removeEventHandler(MouseEvent.MOUSE_RELEASED, this);
}
});
});
partialTransition.play();
});
}
ChangeListener super Node> widthListener = (o, oldVal, newVal) -> {
if (newVal != null && newVal instanceof Region) {
parentSizeProperty.set(((Region) newVal).widthProperty());
}
};
ChangeListener super Node> heightListener = (o, oldVal, newVal) -> {
if (newVal != null && newVal instanceof Region) {
parentSizeProperty.set(((Region) newVal).heightProperty());
}
};
ChangeListener super Scene> sceneWidthListener = (o, oldVal, newVal) -> {
if (newVal != null && this.getParent() == null) {
parentSizeProperty.set(newVal.widthProperty());
}
};
ChangeListener super Scene> sceneHeightListener = (o, oldVal, newVal) -> {
if (newVal != null && this.getParent() == null) {
parentSizeProperty.set(newVal.heightProperty());
}
};
/**
* this method will change the drawer behavior according to its direction
*
* @param dir
*/
private void updateDirection(DrawerDirection dir) {
maxSizeProperty.get().set(-1);
prefSizeProperty.get().set(-1);
if (dir == DrawerDirection.LEFT) {
// change the pane position
StackPane.setAlignment(sidePane, Pos.CENTER_LEFT);
// reset old translation
translateProperty.set(0);
// set the new translation property
translateProperty = sidePane.translateXProperty();
// change the size property
maxSizeProperty.set(sidePane.maxWidthProperty());
minSizeProperty.set(sidePane.minWidthProperty());
prefSizeProperty.set(sidePane.prefWidthProperty());
sizeProperty.set(sidePane.widthProperty());
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.RIGHT) {
StackPane.setAlignment(sidePane, Pos.CENTER_RIGHT);
translateProperty.set(0);
translateProperty = sidePane.translateXProperty();
maxSizeProperty.set(sidePane.maxWidthProperty());
minSizeProperty.set(sidePane.minWidthProperty());
prefSizeProperty.set(sidePane.prefWidthProperty());
sizeProperty.set(sidePane.widthProperty());
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) {
StackPane.setAlignment(sidePane, Pos.TOP_CENTER);
translateProperty.set(0);
translateProperty = sidePane.translateYProperty();
maxSizeProperty.set(sidePane.maxHeightProperty());
minSizeProperty.set(sidePane.minHeightProperty());
prefSizeProperty.set(sidePane.prefHeightProperty());
sizeProperty.set(sidePane.heightProperty());
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);
} else if (dir == DrawerDirection.BOTTOM) {
StackPane.setAlignment(sidePane, Pos.BOTTOM_CENTER);
translateProperty.set(0);
translateProperty = sidePane.translateYProperty();
maxSizeProperty.set(sidePane.maxHeightProperty());
minSizeProperty.set(sidePane.minHeightProperty());
prefSizeProperty.set(sidePane.prefHeightProperty());
sizeProperty.set(sidePane.heightProperty());
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);
}
setDefaultDrawerSize(defaultSizeProperty.get());
updateDrawerAnimation(initTranslate.doubleValue());
}
private void updateDrawerAnimation(double translation) {
drawerTransition = new DrawerTransition(translation, 0);
translateProperty.set(translation);
}
/***************************************************************************
* *
* 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 super MouseEvent> eventFilter = Event::consume;
final boolean bindSize = prefSizeProperty.get().isBound();
prefSizeProperty.get().unbind();
maxSizeProperty.get().unbind();
// disable mouse events
this.addEventFilter(MouseEvent.ANY, eventFilter);
EventHandler drawerDrawer = (finish) -> {
callback.call(null);
if (isTransitionStopped(this.drawerTransition) && translateProperty.get() != 0) {
drawerTransition.setRate(1);
if (tempDrawerSize > getDefaultDrawerSize()) {
ParallelTransition parallelTransition = new ParallelTransition(
new InDrawerSizeTransition(),
new DrawerTransition(translateProperty.get(), 0));
parallelTransition.setOnFinished((finish1) -> {
if (bindSize) {
prefSizeProperty.get().bind(parentSizeProperty.get());
maxSizeProperty.get().bind(parentSizeProperty.get());
}
});
parallelTransition.play();
} else {
EventHandler oldFinishHandler = this.drawerTransition.getOnFinished();
this.drawerTransition.setOnFinished((finish1) -> {
if (bindSize) {
prefSizeProperty.get().bind(parentSizeProperty.get());
maxSizeProperty.get().bind(parentSizeProperty.get());
}
this.drawerTransition.setOnFinished(oldFinishHandler);
});
this.drawerTransition.play();
}
}
// enable mouse events
this.removeEventFilter(MouseEvent.ANY, eventFilter);
};
if (sizeProperty.get().get() > getDefaultDrawerSize()) {
tempDrawerSize = sizeProperty.get().get();
ParallelTransition parallelTransition = new ParallelTransition(
new OutDrawerSizeTransition(),
new DrawerTransition(translateProperty.get(), initTranslate.doubleValue()));
parallelTransition.setOnFinished(drawerDrawer);
parallelTransition.play();
} else {
if (isTransitionStopped(drawerTransition) && translateProperty.get() == 0) {
drawerTransition.setRate(-1);
drawerTransition.setOnFinished(drawerDrawer);
drawerTransition.play();
}
tempDrawerSize = getDefaultDrawerSize();
}
}
/**
* this method indicates whether the drawer is shown or not
*
* @return true if he drawer is totally visible else false
*/
public boolean isShown() {
return isTransitionStopped(drawerTransition) && translateProperty.get() == 0;
}
public boolean isShowing() {
return (isRunningTransition(drawerTransition) && this.drawerTransition.getRate() > 0)
|| (partialTransition instanceof DrawerPartialTransitionDraw
&& isRunningTransition(partialTransition));
}
private boolean isRunningTransition(Transition transition) {
return transition.getStatus() == Status.RUNNING;
}
public boolean isHiding() {
return (isRunningTransition(drawerTransition) && this.drawerTransition.getRate() < 0)
|| (partialTransition instanceof DrawerPartialTransitionHide
&& isRunningTransition(partialTransition));
}
public boolean isHidden() {
return !this.getChildren().contains(this.overlayPane);
}
/**
* toggle the drawer on
*/
public void open() {
if (partialTransition == null || isTransitionStopped(partialTransition)) {
drawerTransition.setRate(1);
this.drawerTransition.setOnFinished((finish) -> onDrawerOpenedProperty.get()
.handle(new JFXDrawerEvent(
JFXDrawerEvent.OPENED)));
if (isTransitionStopped(drawerTransition)) {
if (isHidden()) {
this.drawerTransition.playFromStart();
} else {
this.drawerTransition.play();
}
}
} else {
partialOpen();
}
}
private boolean isTransitionStopped(Transition transition) {
return transition.getStatus() == Status.STOPPED;
}
/**
* toggle the drawer off
*/
public void close() {
// unbind properties as the drawer size might be bound to stage size
maxSizeProperty.get().unbind();
prefSizeProperty.get().unbind();
if (sizeProperty.get().get() > getDefaultDrawerSize()) {
tempDrawerSize = prefSizeProperty.get().get();
ParallelTransition parallelTransition = new ParallelTransition(
new OutDrawerSizeTransition(),
new DrawerTransition(translateProperty.get(), initTranslate.doubleValue()));
parallelTransition.setOnFinished((finish) -> {
onDrawerClosedProperty.get().handle(new JFXDrawerEvent(JFXDrawerEvent.CLOSED));
});
parallelTransition.play();
} else {
if (partialTransition == null || isTransitionStopped(partialTransition)) {
drawerTransition.setRate(-1);
drawerTransition.setOnFinished((finish) -> onDrawerClosedProperty.get()
.handle(new JFXDrawerEvent(
JFXDrawerEvent.CLOSED)));
if (isTransitionStopped(drawerTransition)) {
if (isShown()) {
this.drawerTransition.playFrom(this.drawerTransition.getCycleDuration());
} else {
this.drawerTransition.play();
}
}
} else {
partialClose();
}
tempDrawerSize = getDefaultDrawerSize();
}
}
/***************************************************************************
* *
* Setters / Getters *
* *
**************************************************************************/
public ObservableList getSidePane() {
return sidePane.getChildren();
}
public void setSidePane(Node... sidePane) {
this.sidePane.getChildren().setAll(sidePane);
}
public ObservableList getContent() {
return content.getChildren();
}
public void setContent(Node... content) {
this.content.getChildren().setAll(content);
}
public double getDefaultDrawerSize() {
return defaultSizeProperty.get();
}
public void setDefaultDrawerSize(double drawerWidth) {
defaultSizeProperty.set(drawerWidth);
maxSizeProperty.get().set(drawerWidth);
prefSizeProperty.get().set(drawerWidth);
}
public DrawerDirection getDirection() {
return directionProperty.get();
}
public SimpleObjectProperty directionProperty() {
return directionProperty;
}
public void setDirection(DrawerDirection direction) {
this.directionProperty.set(direction);
}
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);
}
public boolean isResizableOnDrag() {
return resizable;
}
public void setResizableOnDrag(boolean resizable) {
this.resizable = resizable;
}
public final ObjectProperty boundedNodeProperty() {
return this.boundedNode;
}
public final Node getBoundedNode() {
return this.boundedNodeProperty().get();
}
public final void setBoundedNode(final Node boundedNode) {
this.boundedNodeProperty().unbind();
this.boundedNodeProperty().set(boundedNode);
}
/***************************************************************************
* *
* Custom Events *
* *
**************************************************************************/
private ObjectProperty> onDrawerClosedProperty =
new SimpleObjectProperty<>((closed) -> {
});
public void setOnDrawerClosed(EventHandler super JFXDrawerEvent> handler) {
onDrawerClosedProperty.set(handler);
}
public void getOnDrawerClosed(EventHandler super JFXDrawerEvent> handler) {
onDrawerClosedProperty.get();
}
/**
* Defines a function to be called when the drawer is closing.
*/
private ObjectProperty> onDrawerClosingProperty =
new SimpleObjectProperty<>((closing) -> {
});
public void setOnDrawerClosing(EventHandler super JFXDrawerEvent> handler) {
onDrawerClosingProperty.set(handler);
}
public void getOnDrawerClosing(EventHandler super JFXDrawerEvent> handler) {
onDrawerClosingProperty.get();
}
private ObjectProperty> onDrawerOpenedProperty =
new SimpleObjectProperty<>((opened) -> {
});
public void setOnDrawerOpened(EventHandler super JFXDrawerEvent> handler) {
onDrawerOpenedProperty.set(handler);
}
public void getOnDrawerOpened(EventHandler super JFXDrawerEvent> handler) {
onDrawerOpenedProperty.get();
}
/**
* Defines a function to be called when the drawer is opening.
*/
private ObjectProperty> onDrawerOpeningProperty =
new SimpleObjectProperty<>((opening) -> {
});
public void setOnDrawerOpening(EventHandler super JFXDrawerEvent> handler) {
onDrawerOpeningProperty.set(handler);
}
public void getOnDrawerOpening(EventHandler super JFXDrawerEvent> handler) {
onDrawerOpeningProperty.get();
}
/***************************************************************************
* *
* 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().get();
}
double eventPoint = 0;
if (directionProperty.get() == DrawerDirection.RIGHT
|| directionProperty.get() == DrawerDirection.LEFT) {
eventPoint = mouseEvent.getSceneX();
} else {
eventPoint = mouseEvent.getSceneY();
}
if (((size + (directionProperty.get().doubleValue() * eventPoint)) >= activeOffset)
&& (partialTransition != null)) {
partialTransition = null;
} else if (partialTransition == null) {
double currentTranslate;
if (startMouse < 0) {
currentTranslate = initTranslate.doubleValue()
+ directionProperty.get().doubleValue() * initOffset
+ directionProperty.get().doubleValue()
* (size + directionProperty.get().doubleValue()
* eventPoint);
} else {
currentTranslate = directionProperty.get().doubleValue()
* (startTranslate + directionProperty.get().doubleValue()
* (eventPoint - startMouse));
}
if (directionProperty.get().doubleValue() * currentTranslate <= 0) {
// the drawer is hidden
if (resizable) {
maxSizeProperty.get().unbind();
prefSizeProperty.get().unbind();
if ((startSize - getDefaultDrawerSize())
+ directionProperty.get().doubleValue() * currentTranslate > 0) {
// change the side drawer size if dragging from hidden
maxSizeProperty.get()
.set(startSize + directionProperty.get().doubleValue() * currentTranslate);
prefSizeProperty.get()
.set(startSize + directionProperty.get().doubleValue() * currentTranslate);
} else {
// if the side drawer is not fully shown perform translation to show it , and set its default size
maxSizeProperty.get().set(defaultSizeProperty.get());
maxSizeProperty.get().set(defaultSizeProperty.get());
translateProperty.set(directionProperty.get().doubleValue()
* ((startSize - getDefaultDrawerSize())
+ directionProperty.get().doubleValue()
* currentTranslate));
}
} else {
translateProperty.set(currentTranslate);
}
} else {
// the drawer is already shown
if (resizable) {
if (startSize + directionProperty.get()
.doubleValue() * currentTranslate <= parentSizeProperty.get().get()) {
// change the side drawer size after being shown
maxSizeProperty.get().unbind();
prefSizeProperty.get().unbind();
maxSizeProperty.get()
.set(startSize + directionProperty.get().doubleValue() * currentTranslate);
prefSizeProperty.get()
.set(startSize + directionProperty.get().doubleValue() * currentTranslate);
} else {
// bind the drawer size to its parent
maxSizeProperty.get().bind(parentSizeProperty.get());
prefSizeProperty.get().bind(parentSizeProperty.get());
}
}
translateProperty.set(0);
}
}
}
};
private EventHandler mousePressedHandler = (mouseEvent) -> {
if (directionProperty.get() == DrawerDirection.RIGHT
|| directionProperty.get() == DrawerDirection.LEFT) {
startMouse = mouseEvent.getSceneX();
} else {
startMouse = mouseEvent.getSceneY();
}
startTranslate = translateProperty.get();
startSize = sizeProperty.get().get();
};
private EventHandler mouseReleasedHandler = (mouseEvent) -> {
if (directionProperty.get().doubleValue() * translateProperty.get()
> directionProperty.get().doubleValue() * initTranslate.doubleValue() / 2) {
// show side pane
partialOpen();
} else {
// hide the sidePane
partialClose();
}
// reset drawer animation properties
startMouse = -1;
startTranslate = -1;
startSize = sizeProperty.get().get();
};
private void partialClose() {
if (partialTransition != null) {
partialTransition.stop();
}
partialTransition = new DrawerPartialTransitionHide(translateProperty.get(),
initTranslate.doubleValue());
partialTransition.setOnFinished((event) -> {
this.getChildren().remove(overlayPane);
this.getChildren().remove(sidePane);
translateProperty.set(initTranslate.doubleValue());
onDrawerClosedProperty.get().handle(new JFXDrawerEvent(JFXDrawerEvent.CLOSED));
});
partialTransition.play();
}
private void partialOpen() {
if (partialTransition != null) {
partialTransition.stop();
}
partialTransition = new DrawerPartialTransitionDraw(translateProperty.get(), 0);
partialTransition.setOnFinished((event) -> {
translateProperty.set(0);
onDrawerOpenedProperty.get().handle(new JFXDrawerEvent(JFXDrawerEvent.OPENED));
});
partialTransition.play();
}
/***************************************************************************
* *
* Animations *
* *
**************************************************************************/
private double tempDrawerSize = getDefaultDrawerSize();
private class OutDrawerSizeTransition extends CachedTransition {
public OutDrawerSizeTransition() {
super(sidePane, new Timeline(new KeyFrame(Duration.millis(1000),
new KeyValue(prefSizeProperty.get(),
getDefaultDrawerSize(),
Interpolator.EASE_BOTH),
new KeyValue(maxSizeProperty.get(),
getDefaultDrawerSize(),
Interpolator.EASE_BOTH)))
);
setCycleDuration(Duration.seconds(0.5));
setDelay(Duration.seconds(0));
}
}
private class InDrawerSizeTransition extends CachedTransition {
public InDrawerSizeTransition() {
super(sidePane, new Timeline(
new KeyFrame(Duration.millis(0),
new KeyValue(maxSizeProperty.get(), getDefaultDrawerSize(), Interpolator.EASE_BOTH),
new KeyValue(prefSizeProperty.get(), getDefaultDrawerSize(), Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(1000),
new KeyValue(maxSizeProperty.get(), tempDrawerSize, Interpolator.EASE_BOTH),
new KeyValue(prefSizeProperty.get(), tempDrawerSize, Interpolator.EASE_BOTH)
)));
setCycleDuration(Duration.seconds(0.5));
setDelay(Duration.seconds(0));
}
}
private class DrawerTransition extends CachedTransition {
public DrawerTransition(double start, double end) {
super(sidePane, new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(translateProperty, start, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(1000), new KeyValue(translateProperty, end, Interpolator.EASE_BOTH))
)/*, new CacheMomento(overlayPane)*/);
// TODO: add this in later java version, as currently
// Region is not rendered correctly when node cache is enabled
// and this issue will be fixed later.
setCycleDuration(Duration.seconds(0.5));
setDelay(Duration.seconds(0));
}
@Override
protected void starting() {
super.starting();
if (this.getRate() > 0) {
if (!JFXDrawer.this.getChildren().contains(overlayPane)) {
JFXDrawer.this.getChildren().add(overlayPane);
}
if (!JFXDrawer.this.getChildren().contains(sidePane)) {
JFXDrawer.this.getChildren().add(sidePane);
}
}
}
@Override
protected void stopping() {
super.stopping();
if (this.getRate() < 0) {
JFXDrawer.this.getChildren().remove(overlayPane);
JFXDrawer.this.getChildren().remove(sidePane);
}
}
}
private class DrawerPartialTransition extends CachedTransition {
public DrawerPartialTransition(double start, double end) {
super(sidePane, new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(translateProperty, start, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(600), new KeyValue(translateProperty, end, Interpolator.EASE_BOTH))));
setCycleDuration(Duration.seconds(0.5));
setDelay(Duration.seconds(0));
}
}
private class DrawerPartialTransitionDraw extends DrawerPartialTransition {
public DrawerPartialTransitionDraw(double start, double end) {
super(start, end);
}
}
private class DrawerPartialTransitionHide extends DrawerPartialTransition {
public DrawerPartialTransitionHide(double start, double end) {
super(start, end);
}
}
/***************************************************************************
* *
* 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