/* * Copyright 2015 Bekwam, Inc * * 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 com.bekwam.examples.javafx.overlay1; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.fxml.FXML; import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.scene.paint.CycleMethod; import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Stop; import javafx.scene.shape.Line; import javafx.scene.shape.Polyline; import javafx.util.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Main JavaFX Controller for Overlay1App * * @author carl_000 */ public class Overlay1Controller { private Logger logger = LoggerFactory.getLogger(Overlay1Controller.class); @FXML StackPane sp; @FXML VBox mainContent; @FXML VBox overlayContent; @FXML VBox overlayBottom; @FXML Line overlayBottomLineFlat; private Polyline overlayBottomLineUp; private boolean overlayShowing = false; private Border topHighlightBorder; private Border topEmptyBorder; private double lastYPress = 0.0d; public void initialize() { createTopHighlightBorder(); createTopEmptyBorder(); createOverlayBottomLineUp(); double screenHeight = sp.getPrefHeight(); overlayContent.setTranslateY(-1 * screenHeight); /** * Record lastYPress to determine whether or not the drag is allowed. * Drag down is only allowed at the top of the screen. */ sp.addEventFilter(MouseEvent.MOUSE_PRESSED, (evt) -> lastYPress = evt.getY()); /** * If at the top of the screen, provide a white border visual cue that a * drag down is available. */ sp.addEventFilter(MouseEvent.MOUSE_MOVED, (evt) -> { if( evt.getY() <= 20.0d && !overlayShowing ) { if( mainContent.getBorder() != topHighlightBorder ) { mainContent.setBorder(topHighlightBorder); } } else { if( mainContent.getBorder() != topEmptyBorder ) { mainContent.setBorder(topEmptyBorder); } } }); /** * Until the end of the screen -- and if the drag down is within bounds -- * keep moving the overlay down on top of the main. */ sp.addEventFilter(MouseEvent.MOUSE_DRAGGED, (evt) -> { if( lastYPress > 20.0d && !overlayShowing ) return; if (evt.getY() <= sp.getPrefHeight()) { // don't run off the screen double h = -1 * (sp.getPrefHeight() - evt.getY()); overlayContent.setTranslateY(h); } }); /** * If the mouse is released (and a drag is in effect), decide whether or not * to show the whole overlay or hide it again. The criteria is if the drag * the midpoint passes of the screen. */ sp.addEventFilter(MouseEvent.MOUSE_RELEASED, (evt) -> { if( lastYPress > 20.0d && !overlayShowing ) return; if (evt.getY() > sp.getPrefHeight() / 2) { switchToOverlayBottomLineUp(); if (logger.isDebugEnabled()) { logger.debug("[RELEASED] filling full screen; mouse.y={}", evt.getY()); } double startTranslateY = -1 * (screenHeight - evt.getY()); double endTranslateY = 0.0d; if (evt.getY() <= sp.getPrefHeight()) { // not off the screen animateOverlayContent(startTranslateY, endTranslateY); } else { // off screen - just do a simple set overlayContent.setTranslateY(endTranslateY); } overlayShowing = true; } else { if (logger.isDebugEnabled()) { logger.debug("[RELEASED] resetting to 0; mouse.y={}", evt.getY()); } switchToOverlayBottomFlat(); double startTranslateY = -1 * (screenHeight - evt.getY()); double endTranslateY = -1 * screenHeight; if (logger.isDebugEnabled()) { logger.debug("[RELEASED] animating from {} to {}", startTranslateY, endTranslateY); } animateOverlayContent(startTranslateY, endTranslateY); overlayShowing = false; } }); } private void createTopHighlightBorder() { Stop[] stops = new Stop[] { new Stop(0, Color.WHITE), new Stop(.3, Color.LIGHTGRAY), new Stop(1, Color.TRANSPARENT) }; LinearGradient lg1 = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops); topHighlightBorder = new Border(new BorderStroke( lg1, null, null, null, BorderStrokeStyle.SOLID, BorderStrokeStyle.NONE, BorderStrokeStyle.NONE, BorderStrokeStyle.NONE, CornerRadii.EMPTY, new BorderWidths( 8.0d ), null )); } private void createOverlayBottomLineUp() { overlayBottomLineUp = new Polyline(); overlayBottomLineUp.getPoints().addAll( new Double[]{ -10.0d, 4.0d, 0.0d, 0.0d, 10.0d, 4.0d} ); } private void createTopEmptyBorder() { topEmptyBorder = new Border(new BorderStroke( null, null, null, null, BorderStrokeStyle.NONE, BorderStrokeStyle.NONE, BorderStrokeStyle.NONE, BorderStrokeStyle.NONE, CornerRadii.EMPTY, null, null )); } private void switchToOverlayBottomLineUp() { if( !overlayBottom.getChildren().contains(overlayBottomLineUp)) { overlayBottom.getChildren().remove(overlayBottomLineFlat); overlayBottom.getChildren().add(overlayBottomLineUp); } } private void switchToOverlayBottomFlat() { if( !overlayBottom.getChildren().contains(overlayBottomLineFlat)) { overlayBottom.getChildren().remove(overlayBottomLineUp); overlayBottom.getChildren().add(overlayBottomLineFlat); } } private void animateOverlayContent(double startTranslateY, double endTranslateY) { Timeline timeline = new Timeline(); timeline.getKeyFrames().addAll( new KeyFrame(Duration.ZERO, new KeyValue(overlayContent.translateYProperty(), startTranslateY) ), new KeyFrame(Duration.millis(300.0d), new KeyValue(overlayContent.translateYProperty(), endTranslateY) ) ); timeline.play(); } }