/* * 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.core; import javafx.animation.FadeTransition; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; import javafx.geometry.Point2D; import javafx.geometry.Pos; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.SVGPath; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.stage.WindowEvent; import javafx.util.Duration; import org.ewidgetfx.util.DragStagePane; /** * * @author Carl Dea <carl.dea@gmail.com> * @since 1.0 */ public final class WidgetStage extends Stage { private Point2D anchorPt; private Point2D previousLocation; private boolean dragging; private Widget widget; private Parent root; private boolean hover = false; public WidgetStage(Stage owner, Widget widget) { if (widget.getDecoration() != Widget.DECORATION.STAGED_OS_TITLE_BAR) { initStyle(StageStyle.TRANSPARENT); } // Possible bug, On MacOSX dragging the widget will drag the parent at the same time. // This doesn't happen on Windows 7 //initOwner(owner); //initModality(Modality.NONE); this.widget = widget; widget.setParentStage(this); Widget.DECORATION decoration = widget.getDecoration(); Group group = new Group(); root = group; Node titleNode = null; switch (decoration) { case STAGED_CONFIG_CLOSE: VBox vBox1 = new VBox(); titleNode = createTitleConfigClose(); vBox1.getChildren().add(titleNode); vBox1.getChildren().add(widget.getAsNode()); group.getChildren().add(vBox1); break; case STAGED_CLOSE: VBox vBox = new VBox(); titleNode = createTitleClose(); vBox.getChildren().add(titleNode); vBox.getChildren().add(widget.getAsNode()); group.getChildren().add(vBox); break; case STAGED_UNDECORATED: group.getChildren().add(widget.getAsNode()); root = group; break; } // drag start root.setOnMousePressed(me -> { anchorPt = new Point2D(me.getScreenX(), me.getScreenY()); }); // dragging root.setOnMouseDragged(me -> { dragging = true; if (anchorPt != null && previousLocation != null) { setX(previousLocation.getX() + me.getScreenX() - anchorPt.getX()); setY(previousLocation.getY() + me.getScreenY() - anchorPt.getY()); } }); // drag stopped root.setOnMouseReleased(me -> { dragging = false; previousLocation = new Point2D(getX(), getY()); }); if (titleNode != null) { final Node finalTitleNode = titleNode; FadeTransition fadeInTransition = new FadeTransition(); fadeInTransition.setDuration(Duration.millis(250)); fadeInTransition.setFromValue(0); fadeInTransition.setToValue(1); fadeInTransition.setNode(titleNode); FadeTransition fadeOutTransition = new FadeTransition(); fadeOutTransition.setDelay(Duration.millis(2000)); fadeOutTransition.setDuration(Duration.millis(250)); fadeOutTransition.setFromValue(1); fadeOutTransition.setToValue(0); fadeOutTransition.setNode(titleNode); EventHandler mouseEntered = me -> { //if (!hover) { if (me.getSource() == finalTitleNode) { fadeOutTransition.stop(); System.out.println("title is detected"); } else { System.out.println("root is detected"); } fadeInTransition.stop(); fadeInTransition.play(); //hover = true; //} }; EventHandler mouseExited = me -> { //if (hover) { fadeOutTransition.stop(); fadeOutTransition.play(); //hover = false; //} }; titleNode.setOnMouseEntered(mouseEntered); titleNode.setOnMouseExited(mouseExited); root.setOnMouseEntered(mouseEntered); root.setOnMouseExited(mouseExited); } // close the widget root.setOnMouseClicked(me -> { if (me.getClickCount() == 3) { close(); } }); xProperty().addListener((ObservableValue<? extends Number> observableValue, Number number, Number number2) -> { if (!dragging) { previousLocation = new Point2D(getX(), getY()); } }); yProperty().addListener((ObservableValue<? extends Number> observableValue, Number number, Number number2) -> { if (!dragging) { previousLocation = new Point2D(getX(), getY()); } }); final Scene scene = new Scene(root, widget.getAsNode().getPrefWidth(), widget.getAsNode().getPrefHeight(), null); setScene(scene); // initialize for initial drag of region addEventHandler(WindowEvent.WINDOW_SHOWN, (e) -> { previousLocation = new Point2D(getX(), getY()); }); addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, (e) -> { close(); }); } public Node createTitleClose() { // basic design // +----------------------+---+ // | / / // /// //// | X | // +----------------------+---+ // 1) black translucent background color // 2) // 3) white X in the 2nd column // 4) 1st column is draggable Node title = null; DragStagePane dragStagePane = new DragStagePane(this); ReadOnlyDoubleProperty widgetWidth = widget.getAsNode().prefWidthProperty(); HBox closeContainer = createCloseButton(); HBox hBox = new HBox(); String bgStyling = "-fx-background-color: rgba(0,0,0,.70); " + "-fx-background-radius: 2.0;" + "-fx-border-color: rgba(255,255,255,.70);" + "-fx-background-insets: 3;" + //"-fx-border-insets: 3;" + "-fx-border-width: 1;" + "-fx-border-radius: 2;" + ""; // String styling = "-fx-background-color: linear (0%,0%) to (100%,100%) stops (0.0, rgba(0,0,0,.70)) (1.0,rgba(255,255,255,.70)); " + // "-fx-background-radius: 4.0;" + // "-fx-border-color: rgba(255,255,255,.70);" + // "-fx-background-insets: 3;" // ; double insetOffset = hBox.getInsets().getLeft() + hBox.getInsets().getRight(); dragStagePane.setPrefWidth(widget.getAsNode().getPrefWidth() + insetOffset - 20); hBox.setMinHeight(20); hBox.setMaxHeight(20); hBox.setStyle(bgStyling); hBox.setAlignment(Pos.CENTER_RIGHT); hBox.getChildren().addAll(dragStagePane, closeContainer); return hBox; } public Node createTitleConfigClose() { // basic design // +----------------------+---+ // | / / // /// //// | X | // +----------------------+---+ // 1) black translucent background color // 2) // 3) white X in the 2nd column // 4) 1st column is draggable Node title = null; DragStagePane dragStagePane = new DragStagePane(this); ReadOnlyDoubleProperty widgetWidth = widget.getAsNode().prefWidthProperty(); HBox closeContainer = createCloseButton(); HBox configContainer = createConfigButton(); HBox hBox = new HBox(); String bgStyling = "-fx-background-color: rgba(0,0,0,.70); " + "-fx-background-radius: 2.0;" + "-fx-border-color: rgba(255,255,255,.70);" + "-fx-background-insets: 3;" + //"-fx-border-insets: 3;" + "-fx-border-width: 1;" + "-fx-border-radius: 2;" + ""; // String styling = "-fx-background-color: linear (0%,0%) to (100%,100%) stops (0.0, rgba(0,0,0,.70)) (1.0,rgba(255,255,255,.70)); " + // "-fx-background-radius: 4.0;" + // "-fx-border-color: rgba(255,255,255,.70);" + // "-fx-background-insets: 3;" // ; double insetOffset = hBox.getInsets().getLeft() + hBox.getInsets().getRight(); dragStagePane.setPrefWidth(widget.getAsNode().getPrefWidth() + insetOffset - 20); hBox.setMinHeight(20); hBox.setMaxHeight(20); hBox.setStyle(bgStyling); hBox.setAlignment(Pos.CENTER_RIGHT); hBox.getChildren().addAll(dragStagePane, configContainer, closeContainer); return hBox; } private HBox createCloseButton() { SVGPath closeButton = new SVGPath(); closeButton.setContent("M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z"); closeButton.setFill(Color.WHITE); Group closeButtonBackground = new Group(); closeButtonBackground.getChildren().add(closeButton); closeButton.setScaleX(closeButtonBackground.getScaleX() * .4); closeButton.setScaleY(closeButtonBackground.getScaleY() * .4); HBox closeContainer = new HBox(3); String closeContainerStyle = "-fx-background-color: rgba(0,0,0,.70); " + "-fx-background-radius: 1.0;" + "-fx-border-color: rgba(255,255,255,.70);" + "-fx-background-insets: 1;" + //"-fx-border-insets: 3;" + "-fx-border-width: 1;" + "-fx-border-radius: 1;" + ""; closeContainer.setStyle(closeContainerStyle); closeContainer.setMinWidth(20); closeContainer.setMaxWidth(20); closeContainer.setAlignment(Pos.CENTER); closeContainer.getChildren().add(closeButtonBackground); closeContainer.setOnMousePressed(mouseEvent -> { close(); }); return closeContainer; } private HBox createConfigButton() { SVGPath configButton = new SVGPath(); configButton.setContent("M31.229,17.736c0.064-0.571,0.104-1.148,0.104-1.736s-0.04-1.166-0.104-1.737l-4.377-1.557c-0.218-0.716-0.504-1.401-0.851-2.05l1.993-4.192c-0.725-0.91-1.549-1.734-2.458-2.459l-4.193,1.994c-0.647-0.347-1.334-0.632-2.049-0.849l-1.558-4.378C17.165,0.708,16.588,0.667,16,0.667s-1.166,0.041-1.737,0.105L12.707,5.15c-0.716,0.217-1.401,0.502-2.05,0.849L6.464,4.005C5.554,4.73,4.73,5.554,4.005,6.464l1.994,4.192c-0.347,0.648-0.632,1.334-0.849,2.05l-4.378,1.557C0.708,14.834,0.667,15.412,0.667,16s0.041,1.165,0.105,1.736l4.378,1.558c0.217,0.715,0.502,1.401,0.849,2.049l-1.994,4.193c0.725,0.909,1.549,1.733,2.459,2.458l4.192-1.993c0.648,0.347,1.334,0.633,2.05,0.851l1.557,4.377c0.571,0.064,1.148,0.104,1.737,0.104c0.588,0,1.165-0.04,1.736-0.104l1.558-4.377c0.715-0.218,1.399-0.504,2.049-0.851l4.193,1.993c0.909-0.725,1.733-1.549,2.458-2.458l-1.993-4.193c0.347-0.647,0.633-1.334,0.851-2.049L31.229,17.736zM16,20.871c-2.69,0-4.872-2.182-4.872-4.871c0-2.69,2.182-4.872,4.872-4.872c2.689,0,4.871,2.182,4.871,4.872C20.871,18.689,18.689,20.871,16,20.871z"); configButton.setFill(Color.WHITE); Group closeButtonBackground = new Group(); closeButtonBackground.getChildren().add(configButton); configButton.setScaleX(closeButtonBackground.getScaleX() * .4); configButton.setScaleY(closeButtonBackground.getScaleY() * .4); HBox container = new HBox(3); String closeContainerStyle = "-fx-background-color: rgba(0,0,0,.70); " + "-fx-background-radius: 1.0;" + "-fx-border-color: rgba(255,255,255,.70);" + "-fx-background-insets: 1;" + //"-fx-border-insets: 3;" + "-fx-border-width: 1;" + "-fx-border-radius: 1;" + ""; container.setStyle(closeContainerStyle); container.setMinWidth(20); container.setMaxWidth(20); container.setAlignment(Pos.CENTER); container.getChildren().add(closeButtonBackground); container.setOnMousePressed(mouseEvent -> { }); return container; } public Widget getWidget() { return widget; } public void setWidget(Widget widget) { this.widget = widget; } @Override public void close() { super.close(); widget.stop(); widget.setParentStage(null); Widget.DECORATION decoration = widget.getDecoration(); Group group = (Group) root; group.getChildren().clear(); // switch (decoration) { // case STAGED_CLOSE: // // group.getChildren().clear(); // break; // case STAGED_UNDECORATED: // // group.getChildren().clear(); // break; // } widget.getAsNode().getChildren().clear(); this.widget = null; } }