/* * Copyright 2013 eWidgetFX. * * Licensed 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 org.ewidgetfx.applauncher.apptrayfx.iconswipelist; import javafx.animation.Interpolator; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.value.ChangeListener; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.util.Duration; /** * * @author Carl Dea <carl.dea@gmail.com> * @since 1.0 */ public final class IconSwipeListPane extends Group { public static enum SwipeAxis { VERTICAL, HORIZONTAL }; protected DoubleProperty scroll = new SimpleDoubleProperty(0.0); protected DoubleProperty clickPos = new SimpleDoubleProperty(); protected DoubleProperty scrollOrigin = new SimpleDoubleProperty(); protected BooleanProperty buttonDown = new SimpleBooleanProperty(false); protected DoubleProperty dragDelta = new SimpleDoubleProperty(); protected Timeline dragTimeLine = null; protected BooleanProperty noScroll = new SimpleBooleanProperty(); protected Pane iconList; private SwipeAxis swipeAxis = SwipeAxis.HORIZONTAL; /* mouse swipe events */ protected EventHandler<MouseEvent> filterMousePressed; protected EventHandler<MouseEvent> filterMouseDragged; protected EventHandler<MouseEvent> filterMouseReleased; private final IconSwipeListInfo iconSwipeListInfo; public IconSwipeListPane(IconSwipeListInfo iconSwipeListInfo, Pane iconList, SwipeAxis swipeAxis) { this.iconSwipeListInfo = iconSwipeListInfo; this.iconList = iconList; this.swipeAxis = swipeAxis; init(); } protected void init() { // when user mouse pressed the app icon. filterMousePressed = (mouseEvent) -> { animStop(); if (swipeAxis == SwipeAxis.HORIZONTAL) { clickPos.set(mouseEvent.getSceneX()); } else { clickPos.set(mouseEvent.getSceneY()); } scrollOrigin.set(scroll.get()); buttonDown.set(true); }; // when user drags the app icons vertically up or down filterMouseDragged = (mouseEvent) -> { if (swipeAxis == SwipeAxis.HORIZONTAL) { if (iconList.getWidth() > (iconSwipeListInfo.getWidth() - 40)) { double prevX = scroll.get(); updateScrollAxis(mouseEvent.getX()); dragDelta.set(scroll.subtract(prevX).doubleValue()); } } else { if (iconList.getHeight() > (iconSwipeListInfo.getHeight() - 40)) { double prevY = scroll.get(); updateScrollAxis(mouseEvent.getY()); dragDelta.set(scroll.subtract(prevY).doubleValue()); } } }; // when the user finishes dragging and releases (inertia) filterMouseReleased = (mouseEvent) -> { if (swipeAxis == SwipeAxis.HORIZONTAL) { if (iconList.getWidth() > (iconSwipeListInfo.getWidth() - 40)) { updateScrollAxis(mouseEvent.getX()); animStart(dragDelta.doubleValue()); } } else { if (iconList.getHeight() > (iconSwipeListInfo.getHeight() - 40)) { updateScrollAxis(mouseEvent.getY()); animStart(dragDelta.doubleValue()); } } dragDelta.set(0); buttonDown.set(false); }; // bind scrollY property final Node iconList = this.iconList; ChangeListener<Number> scrollListener = null; if (swipeAxis == SwipeAxis.HORIZONTAL) { scrollListener = (observableValue, number, number2) -> { if (iconList != null) { iconList.setTranslateX(0 - number2.doubleValue()); } }; } else { scrollListener = (observableValue, number, number2) -> { if (iconList != null) { iconList.setTranslateY(0 - number2.doubleValue()); } }; scroll.addListener((observableValue, number, number2) -> { if (iconList != null) { iconList.setTranslateY(0 - number2.doubleValue()); } }); } scroll.addListener(scrollListener); noScroll.set(false); // Build tray area // add icon list getChildren().add(iconList); // add icon list addEventHandler(MouseEvent.MOUSE_PRESSED, filterMousePressed); addEventHandler(MouseEvent.MOUSE_DRAGGED, filterMouseDragged); addEventHandler(MouseEvent.MOUSE_RELEASED, filterMouseReleased); setClip(iconSwipeListInfo.getScrollViewPort()); } protected void updateScrollAxis(double axisPoint) { if (noScroll.get()) { return; } scroll.set(restrainScrolling(scrollOrigin.doubleValue() - (axisPoint - clickPos.doubleValue()))); } protected double restrainScrolling(double yOrXAxisCoord) { double dist = 0; if (swipeAxis == SwipeAxis.HORIZONTAL) { dist = getLayoutBounds().getWidth() - iconSwipeListInfo.getWidth() + 10; } else { dist = getLayoutBounds().getHeight() - iconSwipeListInfo.getHeight() + 10; } if (yOrXAxisCoord < 0) // upper coordinate bound { return 0; } else if (yOrXAxisCoord > dist) { return dist + 10; } else { return yOrXAxisCoord; } } protected void animStart(double delta) { if (dragDelta.doubleValue() > 5 && dragDelta.doubleValue() < -5) { return; } if (noScroll.get()) { return; } DoubleProperty endScrollValue = new SimpleDoubleProperty(); endScrollValue.set(restrainScrolling(scroll.doubleValue() + delta * 15)); if (dragTimeLine != null) { dragTimeLine.stop(); } dragTimeLine = new Timeline( new KeyFrame(Duration.millis(800), new KeyValue(scroll, endScrollValue.get(), Interpolator.EASE_OUT))); dragTimeLine.playFromStart(); } protected void animStop() { if (dragTimeLine != null) { dragTimeLine.stop(); } } }