mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-22 06:41:41 +01:00
Merge pull request #3287 from battleofwizards/remove-controlsfx
Remove controlsfx dependency
This commit is contained in:
commit
bd1f19c030
11 changed files with 1534 additions and 13 deletions
|
@ -33,7 +33,6 @@ configure(subprojects) {
|
||||||
bitcoinjVersion = 'a88d36d'
|
bitcoinjVersion = 'a88d36d'
|
||||||
btcdCli4jVersion = '975ff5d4'
|
btcdCli4jVersion = '975ff5d4'
|
||||||
codecVersion = '1.9'
|
codecVersion = '1.9'
|
||||||
controlsfxVersion = '8.0.6_20'
|
|
||||||
easybindVersion = '1.0.3'
|
easybindVersion = '1.0.3'
|
||||||
easyVersion = '4.0.1'
|
easyVersion = '4.0.1'
|
||||||
findbugsVersion = '3.0.2'
|
findbugsVersion = '3.0.2'
|
||||||
|
@ -288,7 +287,6 @@ configure(project(':desktop')) {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':core')
|
compile project(':core')
|
||||||
compile "org.controlsfx:controlsfx:$controlsfxVersion"
|
|
||||||
compile "net.glxn:qrgen:$qrgenVersion"
|
compile "net.glxn:qrgen:$qrgenVersion"
|
||||||
compile "de.jensd:fontawesomefx:$fontawesomefxVersion"
|
compile "de.jensd:fontawesomefx:$fontawesomefxVersion"
|
||||||
compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion"
|
compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion"
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
package bisq.desktop.components;
|
package bisq.desktop.components;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
import org.controlsfx.control.PopOver;
|
|
||||||
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
package bisq.desktop.components;
|
package bisq.desktop.components;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
import de.jensd.fx.glyphs.GlyphIcons;
|
import de.jensd.fx.glyphs.GlyphIcons;
|
||||||
|
|
||||||
import org.controlsfx.control.PopOver;
|
|
||||||
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ContentDisplay;
|
import javafx.scene.control.ContentDisplay;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
|
|
@ -18,11 +18,10 @@
|
||||||
package bisq.desktop.components;
|
package bisq.desktop.components;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
import org.controlsfx.control.PopOver;
|
|
||||||
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
|
|
@ -18,13 +18,12 @@
|
||||||
package bisq.desktop.components;
|
package bisq.desktop.components;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
|
|
||||||
import org.controlsfx.control.PopOver;
|
|
||||||
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
|
|
@ -40,8 +40,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||||
* There can be only 1 errorMessageDisplays at a time we use static field for it.
|
* There can be only 1 errorMessageDisplays at a time we use static field for it.
|
||||||
* The position is derived from the position of the textField itself or if set from the layoutReference node.
|
* The position is derived from the position of the textField itself or if set from the layoutReference node.
|
||||||
*/
|
*/
|
||||||
//TODO There are some rare situation where it behaves buggy. Needs further investigation and improvements. Also
|
//TODO There are some rare situation where it behaves buggy. Needs further investigation and improvements.
|
||||||
// consider replacement with controlsFX components.
|
|
||||||
public class InputTextField extends JFXTextField {
|
public class InputTextField extends JFXTextField {
|
||||||
|
|
||||||
private final ObjectProperty<InputValidator.ValidationResult> validationResult = new SimpleObjectProperty<>
|
private final ObjectProperty<InputValidator.ValidationResult> validationResult = new SimpleObjectProperty<>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
This package is a very minimal subset of the external library `controlsfx`.
|
||||||
|
|
||||||
|
Three files were embedded into the project to avoid having `controlsfx` as dependency.
|
||||||
|
|
||||||
|
This is based on version `8.0.6_20` tagged in commit 6a52afec3ef16094cda281abc80b4daa3d3bf1fd:
|
||||||
|
|
||||||
|
[https://github.com/controlsfx/controlsfx/commit/6a52afec3ef16094cda281abc80b4daa3d3bf1fd]
|
||||||
|
|
||||||
|
These specific files got raw copied (with package name adjustment):
|
||||||
|
|
||||||
|
[https://github.com/controlsfx/controlsfx/blob/6a52afec3ef16094cda281abc80b4daa3d3bf1fd/controlsfx/src/main/java/org/controlsfx/control/PopOver.java]
|
||||||
|
[https://github.com/controlsfx/controlsfx/blob/6a52afec3ef16094cda281abc80b4daa3d3bf1fd/controlsfx/src/main/java/impl/org/controlsfx/skin/PopOverSkin.java]
|
||||||
|
[https://github.com/controlsfx/controlsfx/blob/6a52afec3ef16094cda281abc80b4daa3d3bf1fd/controlsfx/src/main/resources/org/controlsfx/control/popover.css]
|
|
@ -0,0 +1,787 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013, ControlsFX
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of ControlsFX, any associated website, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package bisq.desktop.components.controlsfx.control;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static javafx.scene.input.MouseEvent.MOUSE_CLICKED;
|
||||||
|
import bisq.desktop.components.controlsfx.skin.PopOverSkin;
|
||||||
|
import javafx.animation.FadeTransition;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.WeakInvalidationListener;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.beans.value.WeakChangeListener;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.geometry.Bounds;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.PopupControl;
|
||||||
|
import javafx.scene.control.Skin;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.stage.Window;
|
||||||
|
import javafx.stage.WindowEvent;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PopOver control provides detailed information about an owning node in a
|
||||||
|
* popup window. The popup window has a very lightweight appearance (no default
|
||||||
|
* window decorations) and an arrow pointing at the owner. Due to the nature of
|
||||||
|
* popup windows the PopOver will move around with the parent window when the
|
||||||
|
* user drags it. <br>
|
||||||
|
* <center> <img src="popover.png"/> </center> <br>
|
||||||
|
* The PopOver can be detached from the owning node by dragging it away from the
|
||||||
|
* owner. It stops displaying an arrow and starts displaying a title and a close
|
||||||
|
* icon. <br>
|
||||||
|
* <br>
|
||||||
|
* <center> <img src="popover-detached.png"/> </center> <br>
|
||||||
|
* The following image shows a popover with an accordion content node. PopOver
|
||||||
|
* controls are automatically resizing themselves when the content node changes
|
||||||
|
* its size.<br>
|
||||||
|
* <br>
|
||||||
|
* <center> <img src="popover-accordion.png"/> </center> <br>
|
||||||
|
*/
|
||||||
|
public class PopOver extends PopupControl {
|
||||||
|
|
||||||
|
private static final String DEFAULT_STYLE_CLASS = "popover"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private static final Duration DEFAULT_FADE_DURATION = Duration.seconds(.2);
|
||||||
|
|
||||||
|
private double targetX;
|
||||||
|
|
||||||
|
private double targetY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a pop over with a label as the content node.
|
||||||
|
*/
|
||||||
|
public PopOver() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
getStyleClass().add(DEFAULT_STYLE_CLASS);
|
||||||
|
|
||||||
|
setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT);
|
||||||
|
setOnHiding(new EventHandler<WindowEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(WindowEvent evt) {
|
||||||
|
setDetached(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create some initial content.
|
||||||
|
*/
|
||||||
|
Label label = new Label("<No Content>"); //$NON-NLS-1$
|
||||||
|
label.setPrefSize(200, 200);
|
||||||
|
label.setPadding(new Insets(4));
|
||||||
|
setContentNode(label);
|
||||||
|
|
||||||
|
ChangeListener<Object> repositionListener = new ChangeListener<Object>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Object> value,
|
||||||
|
Object oldObject, Object newObject) {
|
||||||
|
if (isShowing() && !isDetached()) {
|
||||||
|
show(getOwnerNode(), targetX, targetY);
|
||||||
|
adjustWindowLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
arrowSize.addListener(repositionListener);
|
||||||
|
cornerRadius.addListener(repositionListener);
|
||||||
|
arrowLocation.addListener(repositionListener);
|
||||||
|
arrowIndent.addListener(repositionListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a pop over with the given node as the content node.
|
||||||
|
*
|
||||||
|
* @param content The content shown by the pop over
|
||||||
|
*/
|
||||||
|
public PopOver(Node content) {
|
||||||
|
this();
|
||||||
|
|
||||||
|
setContentNode(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Skin<?> createDefaultSkin() {
|
||||||
|
return new PopOverSkin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content support.
|
||||||
|
|
||||||
|
private final ObjectProperty<Node> contentNode = new SimpleObjectProperty<Node>(
|
||||||
|
this, "contentNode") { //$NON-NLS-1$
|
||||||
|
@Override
|
||||||
|
public void setValue(Node node) {
|
||||||
|
if (node == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"content node can not be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content shown by the pop over.
|
||||||
|
*
|
||||||
|
* @return the content node property
|
||||||
|
*/
|
||||||
|
public final ObjectProperty<Node> contentNodeProperty() {
|
||||||
|
return contentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the content property
|
||||||
|
*
|
||||||
|
* @return the content node
|
||||||
|
*
|
||||||
|
* @see #contentNodeProperty()
|
||||||
|
*/
|
||||||
|
public final Node getContentNode() {
|
||||||
|
return contentNodeProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the content property.
|
||||||
|
*
|
||||||
|
* @param content
|
||||||
|
* the new content node value
|
||||||
|
*
|
||||||
|
* @see #contentNodeProperty()
|
||||||
|
*/
|
||||||
|
public final void setContentNode(Node content) {
|
||||||
|
contentNodeProperty().set(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InvalidationListener hideListener = new InvalidationListener() {
|
||||||
|
@Override
|
||||||
|
public void invalidated(Observable observable) {
|
||||||
|
if (!isDetached()) {
|
||||||
|
hide(Duration.ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private WeakInvalidationListener weakHideListener = new WeakInvalidationListener(
|
||||||
|
hideListener);
|
||||||
|
|
||||||
|
private ChangeListener<Number> xListener = new ChangeListener<Number>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Number> value,
|
||||||
|
Number oldX, Number newX) {
|
||||||
|
setX(getX() + (newX.doubleValue() - oldX.doubleValue()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private WeakChangeListener<Number> weakXListener = new WeakChangeListener<>(
|
||||||
|
xListener);
|
||||||
|
|
||||||
|
private ChangeListener<Number> yListener = new ChangeListener<Number>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Number> value,
|
||||||
|
Number oldY, Number newY) {
|
||||||
|
setY(getY() + (newY.doubleValue() - oldY.doubleValue()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private WeakChangeListener<Number> weakYListener = new WeakChangeListener<>(
|
||||||
|
yListener);
|
||||||
|
|
||||||
|
private Window ownerWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the pop over in a position relative to the edges of the given owner
|
||||||
|
* node. The position is dependent on the arrow location. If the arrow is
|
||||||
|
* pointing to the right then the pop over will be placed to the left of the
|
||||||
|
* given owner. If the arrow points up then the pop over will be placed
|
||||||
|
* below the given owner node. The arrow will slightly overlap with the
|
||||||
|
* owner node.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the owner of the pop over
|
||||||
|
*/
|
||||||
|
public final void show(Node owner) {
|
||||||
|
show(owner, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the pop over in a position relative to the edges of the given owner
|
||||||
|
* node. The position is dependent on the arrow location. If the arrow is
|
||||||
|
* pointing to the right then the pop over will be placed to the left of the
|
||||||
|
* given owner. If the arrow points up then the pop over will be placed
|
||||||
|
* below the given owner node.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the owner of the pop over
|
||||||
|
* @param offset
|
||||||
|
* if negative specifies the distance to the owner node or when
|
||||||
|
* positive specifies the number of pixels that the arrow will
|
||||||
|
* overlap with the owner node (positive values are recommended)
|
||||||
|
*/
|
||||||
|
public final void show(Node owner, double offset) {
|
||||||
|
requireNonNull(owner);
|
||||||
|
|
||||||
|
Bounds bounds = owner.localToScreen(owner.getBoundsInLocal());
|
||||||
|
|
||||||
|
switch (getArrowLocation()) {
|
||||||
|
case BOTTOM_CENTER:
|
||||||
|
case BOTTOM_LEFT:
|
||||||
|
case BOTTOM_RIGHT:
|
||||||
|
show(owner, bounds.getMinX() + bounds.getWidth() / 2,
|
||||||
|
bounds.getMinY() + offset);
|
||||||
|
break;
|
||||||
|
case LEFT_BOTTOM:
|
||||||
|
case LEFT_CENTER:
|
||||||
|
case LEFT_TOP:
|
||||||
|
show(owner, bounds.getMaxX() - offset,
|
||||||
|
bounds.getMinY() + bounds.getHeight() / 2);
|
||||||
|
break;
|
||||||
|
case RIGHT_BOTTOM:
|
||||||
|
case RIGHT_CENTER:
|
||||||
|
case RIGHT_TOP:
|
||||||
|
show(owner, bounds.getMinX() + offset,
|
||||||
|
bounds.getMinY() + bounds.getHeight() / 2);
|
||||||
|
break;
|
||||||
|
case TOP_CENTER:
|
||||||
|
case TOP_LEFT:
|
||||||
|
case TOP_RIGHT:
|
||||||
|
show(owner, bounds.getMinX() + bounds.getWidth() / 2,
|
||||||
|
bounds.getMinY() + bounds.getHeight() - offset);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the pop over visible at the give location and associates it with
|
||||||
|
* the given owner node. The x and y coordinate will be the target location
|
||||||
|
* of the arrow of the pop over and not the location of the window.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the owning node
|
||||||
|
* @param x
|
||||||
|
* the x coordinate for the pop over arrow tip
|
||||||
|
* @param y
|
||||||
|
* the y coordinate for the pop over arrow tip
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void show(Node owner, double x, double y) {
|
||||||
|
show(owner, x, y, DEFAULT_FADE_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the pop over visible at the give location and associates it with
|
||||||
|
* the given owner node. The x and y coordinate will be the target location
|
||||||
|
* of the arrow of the pop over and not the location of the window.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the owning node
|
||||||
|
* @param x
|
||||||
|
* the x coordinate for the pop over arrow tip
|
||||||
|
* @param y
|
||||||
|
* the y coordinate for the pop over arrow tip
|
||||||
|
* @param fadeInDuration
|
||||||
|
* the time it takes for the pop over to be fully visible
|
||||||
|
*/
|
||||||
|
public final void show(Node owner, double x, double y,
|
||||||
|
Duration fadeInDuration) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calling show() a second time without first closing the
|
||||||
|
* pop over causes it to be placed at the wrong location.
|
||||||
|
*/
|
||||||
|
if (ownerWindow != null && isShowing()) {
|
||||||
|
super.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
targetX = x;
|
||||||
|
targetY = y;
|
||||||
|
|
||||||
|
if (owner == null) {
|
||||||
|
throw new IllegalArgumentException("owner can not be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fadeInDuration == null) {
|
||||||
|
fadeInDuration = DEFAULT_FADE_DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is all needed because children windows do not get their x and y
|
||||||
|
* coordinate updated when the owning window gets moved by the user.
|
||||||
|
*/
|
||||||
|
if (ownerWindow != null) {
|
||||||
|
ownerWindow.xProperty().removeListener(weakXListener);
|
||||||
|
ownerWindow.yProperty().removeListener(weakYListener);
|
||||||
|
ownerWindow.widthProperty().removeListener(weakHideListener);
|
||||||
|
ownerWindow.heightProperty().removeListener(weakHideListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
ownerWindow = owner.getScene().getWindow();
|
||||||
|
ownerWindow.xProperty().addListener(weakXListener);
|
||||||
|
ownerWindow.yProperty().addListener(weakYListener);
|
||||||
|
ownerWindow.widthProperty().addListener(weakHideListener);
|
||||||
|
ownerWindow.heightProperty().addListener(weakHideListener);
|
||||||
|
|
||||||
|
setOnShown(evt -> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The user clicked somewhere into the transparent background. If
|
||||||
|
* this is the case the hide the window (when attached).
|
||||||
|
*/
|
||||||
|
getScene().addEventHandler(MOUSE_CLICKED,
|
||||||
|
new EventHandler<MouseEvent>() {
|
||||||
|
public void handle(MouseEvent evt) {
|
||||||
|
if (evt.getTarget().equals(getScene().getRoot())) {
|
||||||
|
if (!isDetached()) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move the window so that the arrow will end up pointing at the
|
||||||
|
* target coordinates.
|
||||||
|
*/
|
||||||
|
adjustWindowLocation();
|
||||||
|
});
|
||||||
|
|
||||||
|
super.show(owner, x, y);
|
||||||
|
|
||||||
|
// Fade In
|
||||||
|
Node skinNode = getSkin().getNode();
|
||||||
|
skinNode.setOpacity(0);
|
||||||
|
|
||||||
|
FadeTransition fadeIn = new FadeTransition(fadeInDuration, skinNode);
|
||||||
|
fadeIn.setFromValue(0);
|
||||||
|
fadeIn.setToValue(1);
|
||||||
|
fadeIn.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the pop over by quickly changing its opacity to 0.
|
||||||
|
*
|
||||||
|
* @see #hide(Duration)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void hide() {
|
||||||
|
hide(DEFAULT_FADE_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the pop over by quickly changing its opacity to 0.
|
||||||
|
*
|
||||||
|
* @param fadeOutDuration
|
||||||
|
* the duration of the fade transition that is being used to
|
||||||
|
* change the opacity of the pop over
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public final void hide(Duration fadeOutDuration) {
|
||||||
|
if (fadeOutDuration == null) {
|
||||||
|
fadeOutDuration = DEFAULT_FADE_DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isShowing()) {
|
||||||
|
// Fade Out
|
||||||
|
Node skinNode = getSkin().getNode();
|
||||||
|
skinNode.setOpacity(0);
|
||||||
|
|
||||||
|
FadeTransition fadeOut = new FadeTransition(fadeOutDuration,
|
||||||
|
skinNode);
|
||||||
|
fadeOut.setFromValue(1);
|
||||||
|
fadeOut.setToValue(0);
|
||||||
|
fadeOut.setOnFinished(evt -> super.hide());
|
||||||
|
fadeOut.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustWindowLocation() {
|
||||||
|
Bounds bounds = PopOver.this.getSkin().getNode().getBoundsInParent();
|
||||||
|
|
||||||
|
switch (getArrowLocation()) {
|
||||||
|
case TOP_CENTER:
|
||||||
|
case TOP_LEFT:
|
||||||
|
case TOP_RIGHT:
|
||||||
|
setX(getX() + bounds.getMinX() - computeXOffset());
|
||||||
|
setY(getY() + bounds.getMinY() + getArrowSize());
|
||||||
|
break;
|
||||||
|
case LEFT_TOP:
|
||||||
|
case LEFT_CENTER:
|
||||||
|
case LEFT_BOTTOM:
|
||||||
|
setX(getX() + bounds.getMinX() + getArrowSize());
|
||||||
|
setY(getY() + bounds.getMinY() - computeYOffset());
|
||||||
|
break;
|
||||||
|
case BOTTOM_CENTER:
|
||||||
|
case BOTTOM_LEFT:
|
||||||
|
case BOTTOM_RIGHT:
|
||||||
|
setX(getX() + bounds.getMinX() - computeXOffset());
|
||||||
|
setY(getY() - bounds.getMinY() - bounds.getMaxY() - 1);
|
||||||
|
break;
|
||||||
|
case RIGHT_TOP:
|
||||||
|
case RIGHT_BOTTOM:
|
||||||
|
case RIGHT_CENTER:
|
||||||
|
setX(getX() - bounds.getMinX() - bounds.getMaxX() - 1);
|
||||||
|
setY(getY() + bounds.getMinY() - computeYOffset());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeXOffset() {
|
||||||
|
switch (getArrowLocation()) {
|
||||||
|
case TOP_LEFT:
|
||||||
|
case BOTTOM_LEFT:
|
||||||
|
return getCornerRadius() + getArrowIndent() + getArrowSize();
|
||||||
|
case TOP_CENTER:
|
||||||
|
case BOTTOM_CENTER:
|
||||||
|
return getContentNode().prefWidth(-1) / 2;
|
||||||
|
case TOP_RIGHT:
|
||||||
|
case BOTTOM_RIGHT:
|
||||||
|
return getContentNode().prefWidth(-1) - getArrowIndent()
|
||||||
|
- getCornerRadius() - getArrowSize();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeYOffset() {
|
||||||
|
double prefContentHeight = getContentNode().prefHeight(-1);
|
||||||
|
|
||||||
|
switch (getArrowLocation()) {
|
||||||
|
case LEFT_TOP:
|
||||||
|
case RIGHT_TOP:
|
||||||
|
return getCornerRadius() + getArrowIndent() + getArrowSize();
|
||||||
|
case LEFT_CENTER:
|
||||||
|
case RIGHT_CENTER:
|
||||||
|
return Math.max(prefContentHeight, 2 * (getCornerRadius()
|
||||||
|
+ getArrowIndent() + getArrowSize())) / 2;
|
||||||
|
case LEFT_BOTTOM:
|
||||||
|
case RIGHT_BOTTOM:
|
||||||
|
return Math.max(prefContentHeight - getCornerRadius()
|
||||||
|
- getArrowIndent() - getArrowSize(), getCornerRadius()
|
||||||
|
+ getArrowIndent() + getArrowSize());
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches the pop over from the owning node. The pop over will no longer
|
||||||
|
* display an arrow pointing at the owner node.
|
||||||
|
*/
|
||||||
|
public final void detach() {
|
||||||
|
if (isDetachable()) {
|
||||||
|
setDetached(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// detach support
|
||||||
|
|
||||||
|
private final BooleanProperty detachable = new SimpleBooleanProperty(this,
|
||||||
|
"detachable", true); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the pop over is detachable at all.
|
||||||
|
*/
|
||||||
|
public final BooleanProperty detachableProperty() {
|
||||||
|
return detachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the detachable property.
|
||||||
|
*
|
||||||
|
* @param detachable
|
||||||
|
* if true then the user can detach / tear off the pop over
|
||||||
|
*
|
||||||
|
* @see #detachableProperty()
|
||||||
|
*/
|
||||||
|
public final void setDetachable(boolean detachable) {
|
||||||
|
detachableProperty().set(detachable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the detachable property.
|
||||||
|
*
|
||||||
|
* @return true if the user is allowed to detach / tear off the pop over
|
||||||
|
*
|
||||||
|
* @see #detachableProperty()
|
||||||
|
*/
|
||||||
|
public final boolean isDetachable() {
|
||||||
|
return detachableProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final BooleanProperty detached = new SimpleBooleanProperty(this,
|
||||||
|
"detached", false); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the pop over is detached from the owning node or not.
|
||||||
|
* A detached pop over no longer shows an arrow pointing at the owner and
|
||||||
|
* features its own title bar.
|
||||||
|
*
|
||||||
|
* @return the detached property
|
||||||
|
*/
|
||||||
|
public final BooleanProperty detachedProperty() {
|
||||||
|
return detached;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the detached property.
|
||||||
|
*
|
||||||
|
* @param detached
|
||||||
|
* if true the pop over will change its apperance to "detached"
|
||||||
|
* mode
|
||||||
|
*
|
||||||
|
* @see #detachedProperty()
|
||||||
|
*/
|
||||||
|
public final void setDetached(boolean detached) {
|
||||||
|
detachedProperty().set(detached);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the detached property.
|
||||||
|
*
|
||||||
|
* @return true if the pop over is currently detached.
|
||||||
|
*
|
||||||
|
* @see #detachedProperty()
|
||||||
|
*/
|
||||||
|
public final boolean isDetached() {
|
||||||
|
return detachedProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// arrow size support
|
||||||
|
|
||||||
|
// TODO: make styleable
|
||||||
|
|
||||||
|
private final DoubleProperty arrowSize = new SimpleDoubleProperty(this,
|
||||||
|
"arrowSize", 12); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the size of the arrow. Default value is 12.
|
||||||
|
*
|
||||||
|
* @return the arrow size property
|
||||||
|
*/
|
||||||
|
public final DoubleProperty arrowSizeProperty() {
|
||||||
|
return arrowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the arrow size property.
|
||||||
|
*
|
||||||
|
* @return the arrow size property value
|
||||||
|
*
|
||||||
|
* @see #arrowSizeProperty()
|
||||||
|
*/
|
||||||
|
public final double getArrowSize() {
|
||||||
|
return arrowSizeProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the arrow size property.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* the new value of the arrow size property
|
||||||
|
*
|
||||||
|
* @see #arrowSizeProperty()
|
||||||
|
*/
|
||||||
|
public final void setArrowSize(double size) {
|
||||||
|
arrowSizeProperty().set(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// arrow indent support
|
||||||
|
|
||||||
|
// TODO: make styleable
|
||||||
|
|
||||||
|
private final DoubleProperty arrowIndent = new SimpleDoubleProperty(this,
|
||||||
|
"arrowIndent", 12); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the distance between the arrow and the corners of the pop over.
|
||||||
|
* The default value is 12.
|
||||||
|
*
|
||||||
|
* @return the arrow indent property
|
||||||
|
*/
|
||||||
|
public final DoubleProperty arrowIndentProperty() {
|
||||||
|
return arrowIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the arrow indent property.
|
||||||
|
*
|
||||||
|
* @return the arrow indent value
|
||||||
|
*
|
||||||
|
* @see #arrowIndentProperty()
|
||||||
|
*/
|
||||||
|
public final double getArrowIndent() {
|
||||||
|
return arrowIndentProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the arrow indent property.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* the arrow indent value
|
||||||
|
*
|
||||||
|
* @see #arrowIndentProperty()
|
||||||
|
*/
|
||||||
|
public final void setArrowIndent(double size) {
|
||||||
|
arrowIndentProperty().set(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// radius support
|
||||||
|
|
||||||
|
// TODO: make styleable
|
||||||
|
|
||||||
|
private final DoubleProperty cornerRadius = new SimpleDoubleProperty(this,
|
||||||
|
"cornerRadius", 6); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the corner radius property for the pop over.
|
||||||
|
*
|
||||||
|
* @return the corner radius property (default is 6)
|
||||||
|
*/
|
||||||
|
public final DoubleProperty cornerRadiusProperty() {
|
||||||
|
return cornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the corner radius property.
|
||||||
|
*
|
||||||
|
* @return the corner radius
|
||||||
|
*
|
||||||
|
* @see #cornerRadiusProperty()
|
||||||
|
*/
|
||||||
|
public final double getCornerRadius() {
|
||||||
|
return cornerRadiusProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the corner radius property.
|
||||||
|
*
|
||||||
|
* @param radius
|
||||||
|
* the corner radius
|
||||||
|
*
|
||||||
|
* @see #cornerRadiusProperty()
|
||||||
|
*/
|
||||||
|
public final void setCornerRadius(double radius) {
|
||||||
|
cornerRadiusProperty().set(radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detached stage title
|
||||||
|
|
||||||
|
private final StringProperty detachedTitle = new SimpleStringProperty(this,
|
||||||
|
"detachedTitle", "Info"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the title to display when the pop over becomes detached.
|
||||||
|
*
|
||||||
|
* @return the detached title property
|
||||||
|
*/
|
||||||
|
public final StringProperty detachedTitleProperty() {
|
||||||
|
return detachedTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the detached title property.
|
||||||
|
*
|
||||||
|
* @return the detached title
|
||||||
|
*
|
||||||
|
* @see #detachedTitleProperty()
|
||||||
|
*/
|
||||||
|
public final String getDetachedTitle() {
|
||||||
|
return detachedTitleProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the detached title property.
|
||||||
|
*
|
||||||
|
* @param title
|
||||||
|
* the title to use when detached
|
||||||
|
*
|
||||||
|
* @see #detachedTitleProperty()
|
||||||
|
*/
|
||||||
|
public final void setDetachedTitle(String title) {
|
||||||
|
if (title == null) {
|
||||||
|
throw new IllegalArgumentException("title can not be null"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
detachedTitleProperty().set(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ObjectProperty<ArrowLocation> arrowLocation = new SimpleObjectProperty<PopOver.ArrowLocation>(
|
||||||
|
this, "arrowLocation", ArrowLocation.LEFT_TOP); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the preferred arrow location. This might not be the actual
|
||||||
|
* location of the arrow if auto fix is enabled.
|
||||||
|
*
|
||||||
|
* @see #setAutoFix(boolean)
|
||||||
|
*
|
||||||
|
* @return the arrow location property
|
||||||
|
*/
|
||||||
|
public final ObjectProperty<ArrowLocation> arrowLocationProperty() {
|
||||||
|
return arrowLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the arrow location property.
|
||||||
|
*
|
||||||
|
* @see #arrowLocationProperty()
|
||||||
|
*
|
||||||
|
* @param location
|
||||||
|
* the requested location
|
||||||
|
*/
|
||||||
|
public final void setArrowLocation(ArrowLocation location) {
|
||||||
|
arrowLocationProperty().set(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the arrow location property.
|
||||||
|
*
|
||||||
|
* @see #arrowLocationProperty()
|
||||||
|
*
|
||||||
|
* @return the preferred arrow location
|
||||||
|
*/
|
||||||
|
public final ArrowLocation getArrowLocation() {
|
||||||
|
return arrowLocationProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible arrow locations.
|
||||||
|
*/
|
||||||
|
public enum ArrowLocation {
|
||||||
|
LEFT_TOP, LEFT_CENTER, LEFT_BOTTOM, RIGHT_TOP, RIGHT_CENTER, RIGHT_BOTTOM, TOP_LEFT, TOP_CENTER, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
.popover {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .border {
|
||||||
|
-fx-stroke: linear-gradient(to bottom, rgba(0,0,0, .3), rgba(0, 0, 0, .7)) ;
|
||||||
|
-fx-stroke-width: 0.5;
|
||||||
|
-fx-fill: rgba(255.0,255.0,255.0, .95);
|
||||||
|
-fx-effect: dropshadow(gaussian, rgba(0,0,0,.2), 10.0, 0.5, 2.0, 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .content {
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .detached {
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .content > .title > .text {
|
||||||
|
-fx-padding: 6.0 6.0 0.0 6.0;
|
||||||
|
-fx-text-fill: rgba(120, 120, 120, .8);
|
||||||
|
-fx-font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .content > .title > .icon {
|
||||||
|
-fx-padding: 6.0 0.0 0.0 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .content > .title > .icon > .graphics > .circle {
|
||||||
|
-fx-fill: gray ;
|
||||||
|
-fx-effect: innershadow(gaussian, rgba(0,0,0,.2), 3, 0.5, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover > .content > .title > .icon > .graphics > .line {
|
||||||
|
-fx-stroke: white ;
|
||||||
|
-fx-stroke-width: 2;
|
||||||
|
}
|
|
@ -0,0 +1,693 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013 - 2015, ControlsFX
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of ControlsFX, any associated website, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package bisq.desktop.components.controlsfx.skin;
|
||||||
|
|
||||||
|
import static java.lang.Double.MAX_VALUE;
|
||||||
|
import static javafx.geometry.Pos.CENTER_LEFT;
|
||||||
|
import static javafx.scene.control.ContentDisplay.GRAPHIC_ONLY;
|
||||||
|
import static bisq.desktop.components.controlsfx.control.PopOver.ArrowLocation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
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.control.Label;
|
||||||
|
import javafx.scene.control.Skin;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.scene.shape.HLineTo;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
|
import javafx.scene.shape.LineTo;
|
||||||
|
import javafx.scene.shape.MoveTo;
|
||||||
|
import javafx.scene.shape.Path;
|
||||||
|
import javafx.scene.shape.PathElement;
|
||||||
|
import javafx.scene.shape.QuadCurveTo;
|
||||||
|
import javafx.scene.shape.VLineTo;
|
||||||
|
import javafx.stage.Window;
|
||||||
|
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||||
|
import bisq.desktop.components.controlsfx.control.PopOver.ArrowLocation;
|
||||||
|
|
||||||
|
public class PopOverSkin implements Skin<PopOver> {
|
||||||
|
|
||||||
|
private static final String DETACHED_STYLE_CLASS = "detached"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private double xOffset;
|
||||||
|
private double yOffset;
|
||||||
|
|
||||||
|
private boolean tornOff;
|
||||||
|
|
||||||
|
private Label title;
|
||||||
|
private Label closeIcon;
|
||||||
|
|
||||||
|
private Path path;
|
||||||
|
private BorderPane content;
|
||||||
|
private StackPane titlePane;
|
||||||
|
private StackPane stackPane;
|
||||||
|
|
||||||
|
private Point2D dragStartLocation;
|
||||||
|
|
||||||
|
private PopOver popOver;
|
||||||
|
|
||||||
|
public PopOverSkin(final PopOver popOver) {
|
||||||
|
|
||||||
|
this.popOver = popOver;
|
||||||
|
|
||||||
|
stackPane = new StackPane();
|
||||||
|
stackPane.getStylesheets().add(
|
||||||
|
PopOver.class.getResource("popover.css").toExternalForm()); //$NON-NLS-1$
|
||||||
|
stackPane.setPickOnBounds(false);
|
||||||
|
stackPane.getStyleClass().add("popover"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The min width and height equal 2 * corner radius + 2 * arrow indent +
|
||||||
|
* 2 * arrow size.
|
||||||
|
*/
|
||||||
|
stackPane.minWidthProperty().bind(
|
||||||
|
Bindings.add(Bindings.multiply(2, popOver.arrowSizeProperty()),
|
||||||
|
Bindings.add(
|
||||||
|
Bindings.multiply(2,
|
||||||
|
popOver.cornerRadiusProperty()),
|
||||||
|
Bindings.multiply(2,
|
||||||
|
popOver.arrowIndentProperty()))));
|
||||||
|
|
||||||
|
stackPane.minHeightProperty().bind(stackPane.minWidthProperty());
|
||||||
|
|
||||||
|
title = new Label();
|
||||||
|
title.textProperty().bind(popOver.detachedTitleProperty());
|
||||||
|
title.setMaxSize(MAX_VALUE, MAX_VALUE);
|
||||||
|
title.setAlignment(Pos.CENTER);
|
||||||
|
title.getStyleClass().add("text"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
closeIcon = new Label();
|
||||||
|
closeIcon.setGraphic(createCloseIcon());
|
||||||
|
closeIcon.setMaxSize(MAX_VALUE, MAX_VALUE);
|
||||||
|
closeIcon.setContentDisplay(GRAPHIC_ONLY);
|
||||||
|
closeIcon.visibleProperty().bind(popOver.detachedProperty());
|
||||||
|
closeIcon.getStyleClass().add("icon"); //$NON-NLS-1$
|
||||||
|
closeIcon.setAlignment(CENTER_LEFT);
|
||||||
|
closeIcon.getGraphic().setOnMouseClicked(
|
||||||
|
new EventHandler<MouseEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(MouseEvent evt) {
|
||||||
|
popOver.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
titlePane = new StackPane();
|
||||||
|
titlePane.getChildren().add(title);
|
||||||
|
titlePane.getChildren().add(closeIcon);
|
||||||
|
titlePane.getStyleClass().add("title"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
content = new BorderPane();
|
||||||
|
content.setCenter(popOver.getContentNode());
|
||||||
|
content.getStyleClass().add("content"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
if (popOver.isDetached()) {
|
||||||
|
content.setTop(titlePane);
|
||||||
|
popOver.getStyleClass().add(DETACHED_STYLE_CLASS);
|
||||||
|
content.getStyleClass().add(DETACHED_STYLE_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidationListener updatePathListener = new InvalidationListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidated(Observable observable) {
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getPopupWindow().xProperty().addListener(updatePathListener);
|
||||||
|
getPopupWindow().yProperty().addListener(updatePathListener);
|
||||||
|
|
||||||
|
popOver.arrowLocationProperty().addListener(updatePathListener);
|
||||||
|
|
||||||
|
popOver.contentNodeProperty().addListener(new ChangeListener<Node>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Node> value,
|
||||||
|
Node oldContent, Node newContent) {
|
||||||
|
content.setCenter(newContent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
popOver.detachedProperty().addListener(new ChangeListener<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Boolean> value,
|
||||||
|
Boolean oldDetached, Boolean newDetached) {
|
||||||
|
|
||||||
|
updatePath();
|
||||||
|
|
||||||
|
if (newDetached) {
|
||||||
|
popOver.getStyleClass().add(DETACHED_STYLE_CLASS);
|
||||||
|
content.getStyleClass().add(DETACHED_STYLE_CLASS);
|
||||||
|
content.setTop(titlePane);
|
||||||
|
} else {
|
||||||
|
popOver.getStyleClass().remove(DETACHED_STYLE_CLASS);
|
||||||
|
content.getStyleClass().remove(DETACHED_STYLE_CLASS);
|
||||||
|
content.setTop(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
path = new Path();
|
||||||
|
path.getStyleClass().add("border"); //$NON-NLS-1$
|
||||||
|
path.setManaged(false);
|
||||||
|
|
||||||
|
createPathElements();
|
||||||
|
updatePath();
|
||||||
|
|
||||||
|
final EventHandler<MouseEvent> mousePressedHandler = new EventHandler<MouseEvent>() {
|
||||||
|
public void handle(MouseEvent evt) {
|
||||||
|
if (popOver.isDetachable() || popOver.isDetached()) {
|
||||||
|
tornOff = false;
|
||||||
|
|
||||||
|
xOffset = evt.getScreenX();
|
||||||
|
yOffset = evt.getScreenY();
|
||||||
|
|
||||||
|
dragStartLocation = new Point2D(xOffset, yOffset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
final EventHandler<MouseEvent> mouseReleasedHandler = new EventHandler<MouseEvent>() {
|
||||||
|
public void handle(MouseEvent evt) {
|
||||||
|
if (tornOff && !getSkinnable().isDetached()) {
|
||||||
|
tornOff = false;
|
||||||
|
getSkinnable().detach();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
final EventHandler<MouseEvent> mouseDragHandler = new EventHandler<MouseEvent>() {
|
||||||
|
|
||||||
|
public void handle(MouseEvent evt) {
|
||||||
|
if (popOver.isDetachable() || popOver.isDetached()) {
|
||||||
|
double deltaX = evt.getScreenX() - xOffset;
|
||||||
|
double deltaY = evt.getScreenY() - yOffset;
|
||||||
|
|
||||||
|
Window window = getSkinnable().getScene().getWindow();
|
||||||
|
|
||||||
|
window.setX(window.getX() + deltaX);
|
||||||
|
window.setY(window.getY() + deltaY);
|
||||||
|
|
||||||
|
xOffset = evt.getScreenX();
|
||||||
|
yOffset = evt.getScreenY();
|
||||||
|
|
||||||
|
if (dragStartLocation.distance(xOffset, yOffset) > 20) {
|
||||||
|
tornOff = true;
|
||||||
|
updatePath();
|
||||||
|
} else if (tornOff) {
|
||||||
|
tornOff = false;
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
stackPane.setOnMousePressed(mousePressedHandler);
|
||||||
|
stackPane.setOnMouseDragged(mouseDragHandler);
|
||||||
|
stackPane.setOnMouseReleased(mouseReleasedHandler);
|
||||||
|
|
||||||
|
stackPane.getChildren().add(path);
|
||||||
|
stackPane.getChildren().add(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getNode() {
|
||||||
|
return stackPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PopOver getSkinnable() {
|
||||||
|
return popOver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createCloseIcon() {
|
||||||
|
Group group = new Group();
|
||||||
|
group.getStyleClass().add("graphics"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
Circle circle = new Circle();
|
||||||
|
circle.getStyleClass().add("circle"); //$NON-NLS-1$
|
||||||
|
circle.setRadius(6);
|
||||||
|
circle.setCenterX(6);
|
||||||
|
circle.setCenterY(6);
|
||||||
|
group.getChildren().add(circle);
|
||||||
|
|
||||||
|
Line line1 = new Line();
|
||||||
|
line1.getStyleClass().add("line"); //$NON-NLS-1$
|
||||||
|
line1.setStartX(4);
|
||||||
|
line1.setStartY(4);
|
||||||
|
line1.setEndX(8);
|
||||||
|
line1.setEndY(8);
|
||||||
|
group.getChildren().add(line1);
|
||||||
|
|
||||||
|
Line line2 = new Line();
|
||||||
|
line2.getStyleClass().add("line"); //$NON-NLS-1$
|
||||||
|
line2.setStartX(8);
|
||||||
|
line2.setStartY(4);
|
||||||
|
line2.setEndX(4);
|
||||||
|
line2.setEndY(8);
|
||||||
|
group.getChildren().add(line2);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoveTo moveTo;
|
||||||
|
|
||||||
|
private QuadCurveTo topCurveTo, rightCurveTo, bottomCurveTo, leftCurveTo;
|
||||||
|
|
||||||
|
private HLineTo lineBTop, lineETop, lineHTop, lineKTop;
|
||||||
|
private LineTo lineCTop, lineDTop, lineFTop, lineGTop, lineITop, lineJTop;
|
||||||
|
|
||||||
|
private VLineTo lineBRight, lineERight, lineHRight, lineKRight;
|
||||||
|
private LineTo lineCRight, lineDRight, lineFRight, lineGRight, lineIRight,
|
||||||
|
lineJRight;
|
||||||
|
|
||||||
|
private HLineTo lineBBottom, lineEBottom, lineHBottom, lineKBottom;
|
||||||
|
private LineTo lineCBottom, lineDBottom, lineFBottom, lineGBottom,
|
||||||
|
lineIBottom, lineJBottom;
|
||||||
|
|
||||||
|
private VLineTo lineBLeft, lineELeft, lineHLeft, lineKLeft;
|
||||||
|
private LineTo lineCLeft, lineDLeft, lineFLeft, lineGLeft, lineILeft,
|
||||||
|
lineJLeft;
|
||||||
|
|
||||||
|
private void createPathElements() {
|
||||||
|
DoubleProperty centerYProperty = new SimpleDoubleProperty();
|
||||||
|
DoubleProperty centerXProperty = new SimpleDoubleProperty();
|
||||||
|
|
||||||
|
DoubleProperty leftEdgeProperty = new SimpleDoubleProperty();
|
||||||
|
DoubleProperty leftEdgePlusRadiusProperty = new SimpleDoubleProperty();
|
||||||
|
|
||||||
|
DoubleProperty topEdgeProperty = new SimpleDoubleProperty();
|
||||||
|
DoubleProperty topEdgePlusRadiusProperty = new SimpleDoubleProperty();
|
||||||
|
|
||||||
|
DoubleProperty rightEdgeProperty = new SimpleDoubleProperty();
|
||||||
|
DoubleProperty rightEdgeMinusRadiusProperty = new SimpleDoubleProperty();
|
||||||
|
|
||||||
|
DoubleProperty bottomEdgeProperty = new SimpleDoubleProperty();
|
||||||
|
DoubleProperty bottomEdgeMinusRadiusProperty = new SimpleDoubleProperty();
|
||||||
|
|
||||||
|
DoubleProperty cornerProperty = getSkinnable().cornerRadiusProperty();
|
||||||
|
|
||||||
|
DoubleProperty arrowSizeProperty = getSkinnable().arrowSizeProperty();
|
||||||
|
DoubleProperty arrowIndentProperty = getSkinnable()
|
||||||
|
.arrowIndentProperty();
|
||||||
|
|
||||||
|
centerYProperty.bind(Bindings.divide(stackPane.heightProperty(), 2));
|
||||||
|
centerXProperty.bind(Bindings.divide(stackPane.widthProperty(), 2));
|
||||||
|
|
||||||
|
leftEdgePlusRadiusProperty.bind(Bindings.add(leftEdgeProperty,
|
||||||
|
getSkinnable().cornerRadiusProperty()));
|
||||||
|
|
||||||
|
topEdgePlusRadiusProperty.bind(Bindings.add(topEdgeProperty,
|
||||||
|
getSkinnable().cornerRadiusProperty()));
|
||||||
|
|
||||||
|
rightEdgeProperty.bind(stackPane.widthProperty());
|
||||||
|
rightEdgeMinusRadiusProperty.bind(Bindings.subtract(rightEdgeProperty,
|
||||||
|
getSkinnable().cornerRadiusProperty()));
|
||||||
|
|
||||||
|
bottomEdgeProperty.bind(stackPane.heightProperty());
|
||||||
|
bottomEdgeMinusRadiusProperty.bind(Bindings.subtract(
|
||||||
|
bottomEdgeProperty, getSkinnable().cornerRadiusProperty()));
|
||||||
|
|
||||||
|
// INIT
|
||||||
|
moveTo = new MoveTo();
|
||||||
|
moveTo.xProperty().bind(leftEdgePlusRadiusProperty);
|
||||||
|
moveTo.yProperty().bind(topEdgeProperty);
|
||||||
|
|
||||||
|
//
|
||||||
|
// TOP EDGE
|
||||||
|
//
|
||||||
|
lineBTop = new HLineTo();
|
||||||
|
lineBTop.xProperty().bind(
|
||||||
|
Bindings.add(leftEdgePlusRadiusProperty, arrowIndentProperty));
|
||||||
|
|
||||||
|
lineCTop = new LineTo();
|
||||||
|
lineCTop.xProperty().bind(
|
||||||
|
Bindings.add(lineBTop.xProperty(), arrowSizeProperty));
|
||||||
|
lineCTop.yProperty().bind(
|
||||||
|
Bindings.subtract(topEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineDTop = new LineTo();
|
||||||
|
lineDTop.xProperty().bind(
|
||||||
|
Bindings.add(lineCTop.xProperty(), arrowSizeProperty));
|
||||||
|
lineDTop.yProperty().bind(topEdgeProperty);
|
||||||
|
|
||||||
|
lineETop = new HLineTo();
|
||||||
|
lineETop.xProperty().bind(
|
||||||
|
Bindings.subtract(centerXProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineFTop = new LineTo();
|
||||||
|
lineFTop.xProperty().bind(centerXProperty);
|
||||||
|
lineFTop.yProperty().bind(
|
||||||
|
Bindings.subtract(topEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineGTop = new LineTo();
|
||||||
|
lineGTop.xProperty().bind(
|
||||||
|
Bindings.add(centerXProperty, arrowSizeProperty));
|
||||||
|
lineGTop.yProperty().bind(topEdgeProperty);
|
||||||
|
|
||||||
|
lineHTop = new HLineTo();
|
||||||
|
lineHTop.xProperty().bind(
|
||||||
|
Bindings.subtract(Bindings.subtract(
|
||||||
|
rightEdgeMinusRadiusProperty, arrowIndentProperty),
|
||||||
|
Bindings.multiply(arrowSizeProperty, 2)));
|
||||||
|
|
||||||
|
lineITop = new LineTo();
|
||||||
|
lineITop.xProperty().bind(
|
||||||
|
Bindings.subtract(Bindings.subtract(
|
||||||
|
rightEdgeMinusRadiusProperty, arrowIndentProperty),
|
||||||
|
arrowSizeProperty));
|
||||||
|
lineITop.yProperty().bind(
|
||||||
|
Bindings.subtract(topEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineJTop = new LineTo();
|
||||||
|
lineJTop.xProperty().bind(
|
||||||
|
Bindings.subtract(rightEdgeMinusRadiusProperty,
|
||||||
|
arrowIndentProperty));
|
||||||
|
lineJTop.yProperty().bind(topEdgeProperty);
|
||||||
|
|
||||||
|
lineKTop = new HLineTo();
|
||||||
|
lineKTop.xProperty().bind(rightEdgeMinusRadiusProperty);
|
||||||
|
|
||||||
|
//
|
||||||
|
// RIGHT EDGE
|
||||||
|
//
|
||||||
|
rightCurveTo = new QuadCurveTo();
|
||||||
|
rightCurveTo.xProperty().bind(rightEdgeProperty);
|
||||||
|
rightCurveTo.yProperty().bind(
|
||||||
|
Bindings.add(topEdgeProperty, cornerProperty));
|
||||||
|
rightCurveTo.controlXProperty().bind(rightEdgeProperty);
|
||||||
|
rightCurveTo.controlYProperty().bind(topEdgeProperty);
|
||||||
|
|
||||||
|
lineBRight = new VLineTo();
|
||||||
|
lineBRight.yProperty().bind(
|
||||||
|
Bindings.add(topEdgePlusRadiusProperty, arrowIndentProperty));
|
||||||
|
|
||||||
|
lineCRight = new LineTo();
|
||||||
|
lineCRight.xProperty().bind(
|
||||||
|
Bindings.add(rightEdgeProperty, arrowSizeProperty));
|
||||||
|
lineCRight.yProperty().bind(
|
||||||
|
Bindings.add(lineBRight.yProperty(), arrowSizeProperty));
|
||||||
|
|
||||||
|
lineDRight = new LineTo();
|
||||||
|
lineDRight.xProperty().bind(rightEdgeProperty);
|
||||||
|
lineDRight.yProperty().bind(
|
||||||
|
Bindings.add(lineCRight.yProperty(), arrowSizeProperty));
|
||||||
|
|
||||||
|
lineERight = new VLineTo();
|
||||||
|
lineERight.yProperty().bind(
|
||||||
|
Bindings.subtract(centerYProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineFRight = new LineTo();
|
||||||
|
lineFRight.xProperty().bind(
|
||||||
|
Bindings.add(rightEdgeProperty, arrowSizeProperty));
|
||||||
|
lineFRight.yProperty().bind(centerYProperty);
|
||||||
|
|
||||||
|
lineGRight = new LineTo();
|
||||||
|
lineGRight.xProperty().bind(rightEdgeProperty);
|
||||||
|
lineGRight.yProperty().bind(
|
||||||
|
Bindings.add(centerYProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineHRight = new VLineTo();
|
||||||
|
lineHRight.yProperty().bind(
|
||||||
|
Bindings.subtract(Bindings.subtract(
|
||||||
|
bottomEdgeMinusRadiusProperty, arrowIndentProperty),
|
||||||
|
Bindings.multiply(arrowSizeProperty, 2)));
|
||||||
|
|
||||||
|
lineIRight = new LineTo();
|
||||||
|
lineIRight.xProperty().bind(
|
||||||
|
Bindings.add(rightEdgeProperty, arrowSizeProperty));
|
||||||
|
lineIRight.yProperty().bind(
|
||||||
|
Bindings.subtract(Bindings.subtract(
|
||||||
|
bottomEdgeMinusRadiusProperty, arrowIndentProperty),
|
||||||
|
arrowSizeProperty));
|
||||||
|
|
||||||
|
lineJRight = new LineTo();
|
||||||
|
lineJRight.xProperty().bind(rightEdgeProperty);
|
||||||
|
lineJRight.yProperty().bind(
|
||||||
|
Bindings.subtract(bottomEdgeMinusRadiusProperty,
|
||||||
|
arrowIndentProperty));
|
||||||
|
|
||||||
|
lineKRight = new VLineTo();
|
||||||
|
lineKRight.yProperty().bind(bottomEdgeMinusRadiusProperty);
|
||||||
|
|
||||||
|
//
|
||||||
|
// BOTTOM EDGE
|
||||||
|
//
|
||||||
|
|
||||||
|
bottomCurveTo = new QuadCurveTo();
|
||||||
|
bottomCurveTo.xProperty().bind(rightEdgeMinusRadiusProperty);
|
||||||
|
bottomCurveTo.yProperty().bind(bottomEdgeProperty);
|
||||||
|
bottomCurveTo.controlXProperty().bind(rightEdgeProperty);
|
||||||
|
bottomCurveTo.controlYProperty().bind(bottomEdgeProperty);
|
||||||
|
|
||||||
|
lineBBottom = new HLineTo();
|
||||||
|
lineBBottom.xProperty().bind(
|
||||||
|
Bindings.subtract(rightEdgeMinusRadiusProperty,
|
||||||
|
arrowIndentProperty));
|
||||||
|
|
||||||
|
lineCBottom = new LineTo();
|
||||||
|
lineCBottom.xProperty().bind(
|
||||||
|
Bindings.subtract(lineBBottom.xProperty(), arrowSizeProperty));
|
||||||
|
lineCBottom.yProperty().bind(
|
||||||
|
Bindings.add(bottomEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineDBottom = new LineTo();
|
||||||
|
lineDBottom.xProperty().bind(
|
||||||
|
Bindings.subtract(lineCBottom.xProperty(), arrowSizeProperty));
|
||||||
|
lineDBottom.yProperty().bind(bottomEdgeProperty);
|
||||||
|
|
||||||
|
lineEBottom = new HLineTo();
|
||||||
|
lineEBottom.xProperty().bind(
|
||||||
|
Bindings.add(centerXProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineFBottom = new LineTo();
|
||||||
|
lineFBottom.xProperty().bind(centerXProperty);
|
||||||
|
lineFBottom.yProperty().bind(
|
||||||
|
Bindings.add(bottomEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineGBottom = new LineTo();
|
||||||
|
lineGBottom.xProperty().bind(
|
||||||
|
Bindings.subtract(centerXProperty, arrowSizeProperty));
|
||||||
|
lineGBottom.yProperty().bind(bottomEdgeProperty);
|
||||||
|
|
||||||
|
lineHBottom = new HLineTo();
|
||||||
|
lineHBottom.xProperty().bind(
|
||||||
|
Bindings.add(Bindings.add(leftEdgePlusRadiusProperty,
|
||||||
|
arrowIndentProperty), Bindings.multiply(
|
||||||
|
arrowSizeProperty, 2)));
|
||||||
|
|
||||||
|
lineIBottom = new LineTo();
|
||||||
|
lineIBottom.xProperty().bind(
|
||||||
|
Bindings.add(Bindings.add(leftEdgePlusRadiusProperty,
|
||||||
|
arrowIndentProperty), arrowSizeProperty));
|
||||||
|
lineIBottom.yProperty().bind(
|
||||||
|
Bindings.add(bottomEdgeProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineJBottom = new LineTo();
|
||||||
|
lineJBottom.xProperty().bind(
|
||||||
|
Bindings.add(leftEdgePlusRadiusProperty, arrowIndentProperty));
|
||||||
|
lineJBottom.yProperty().bind(bottomEdgeProperty);
|
||||||
|
|
||||||
|
lineKBottom = new HLineTo();
|
||||||
|
lineKBottom.xProperty().bind(leftEdgePlusRadiusProperty);
|
||||||
|
|
||||||
|
//
|
||||||
|
// LEFT EDGE
|
||||||
|
//
|
||||||
|
leftCurveTo = new QuadCurveTo();
|
||||||
|
leftCurveTo.xProperty().bind(leftEdgeProperty);
|
||||||
|
leftCurveTo.yProperty().bind(
|
||||||
|
Bindings.subtract(bottomEdgeProperty, cornerProperty));
|
||||||
|
leftCurveTo.controlXProperty().bind(leftEdgeProperty);
|
||||||
|
leftCurveTo.controlYProperty().bind(bottomEdgeProperty);
|
||||||
|
|
||||||
|
lineBLeft = new VLineTo();
|
||||||
|
lineBLeft.yProperty().bind(
|
||||||
|
Bindings.subtract(bottomEdgeMinusRadiusProperty,
|
||||||
|
arrowIndentProperty));
|
||||||
|
|
||||||
|
lineCLeft = new LineTo();
|
||||||
|
lineCLeft.xProperty().bind(
|
||||||
|
Bindings.subtract(leftEdgeProperty, arrowSizeProperty));
|
||||||
|
lineCLeft.yProperty().bind(
|
||||||
|
Bindings.subtract(lineBLeft.yProperty(), arrowSizeProperty));
|
||||||
|
|
||||||
|
lineDLeft = new LineTo();
|
||||||
|
lineDLeft.xProperty().bind(leftEdgeProperty);
|
||||||
|
lineDLeft.yProperty().bind(
|
||||||
|
Bindings.subtract(lineCLeft.yProperty(), arrowSizeProperty));
|
||||||
|
|
||||||
|
lineELeft = new VLineTo();
|
||||||
|
lineELeft.yProperty().bind(
|
||||||
|
Bindings.add(centerYProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineFLeft = new LineTo();
|
||||||
|
lineFLeft.xProperty().bind(
|
||||||
|
Bindings.subtract(leftEdgeProperty, arrowSizeProperty));
|
||||||
|
lineFLeft.yProperty().bind(centerYProperty);
|
||||||
|
|
||||||
|
lineGLeft = new LineTo();
|
||||||
|
lineGLeft.xProperty().bind(leftEdgeProperty);
|
||||||
|
lineGLeft.yProperty().bind(
|
||||||
|
Bindings.subtract(centerYProperty, arrowSizeProperty));
|
||||||
|
|
||||||
|
lineHLeft = new VLineTo();
|
||||||
|
lineHLeft.yProperty().bind(
|
||||||
|
Bindings.add(Bindings.add(topEdgePlusRadiusProperty,
|
||||||
|
arrowIndentProperty), Bindings.multiply(
|
||||||
|
arrowSizeProperty, 2)));
|
||||||
|
|
||||||
|
lineILeft = new LineTo();
|
||||||
|
lineILeft.xProperty().bind(
|
||||||
|
Bindings.subtract(leftEdgeProperty, arrowSizeProperty));
|
||||||
|
lineILeft.yProperty().bind(
|
||||||
|
Bindings.add(Bindings.add(topEdgePlusRadiusProperty,
|
||||||
|
arrowIndentProperty), arrowSizeProperty));
|
||||||
|
|
||||||
|
lineJLeft = new LineTo();
|
||||||
|
lineJLeft.xProperty().bind(leftEdgeProperty);
|
||||||
|
lineJLeft.yProperty().bind(
|
||||||
|
Bindings.add(topEdgePlusRadiusProperty, arrowIndentProperty));
|
||||||
|
|
||||||
|
lineKLeft = new VLineTo();
|
||||||
|
lineKLeft.yProperty().bind(topEdgePlusRadiusProperty);
|
||||||
|
|
||||||
|
topCurveTo = new QuadCurveTo();
|
||||||
|
topCurveTo.xProperty().bind(leftEdgePlusRadiusProperty);
|
||||||
|
topCurveTo.yProperty().bind(topEdgeProperty);
|
||||||
|
topCurveTo.controlXProperty().bind(leftEdgeProperty);
|
||||||
|
topCurveTo.controlYProperty().bind(topEdgeProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Window getPopupWindow() {
|
||||||
|
return getSkinnable().getScene().getWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean showArrow(ArrowLocation location) {
|
||||||
|
ArrowLocation arrowLocation = getSkinnable().getArrowLocation();
|
||||||
|
return location.equals(arrowLocation) && !getSkinnable().isDetached()
|
||||||
|
&& !tornOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePath() {
|
||||||
|
List<PathElement> elements = new ArrayList<>();
|
||||||
|
elements.add(moveTo);
|
||||||
|
|
||||||
|
if (showArrow(TOP_LEFT)) {
|
||||||
|
elements.add(lineBTop);
|
||||||
|
elements.add(lineCTop);
|
||||||
|
elements.add(lineDTop);
|
||||||
|
}
|
||||||
|
if (showArrow(TOP_CENTER)) {
|
||||||
|
elements.add(lineETop);
|
||||||
|
elements.add(lineFTop);
|
||||||
|
elements.add(lineGTop);
|
||||||
|
}
|
||||||
|
if (showArrow(TOP_RIGHT)) {
|
||||||
|
elements.add(lineHTop);
|
||||||
|
elements.add(lineITop);
|
||||||
|
elements.add(lineJTop);
|
||||||
|
}
|
||||||
|
elements.add(lineKTop);
|
||||||
|
elements.add(rightCurveTo);
|
||||||
|
|
||||||
|
if (showArrow(RIGHT_TOP)) {
|
||||||
|
elements.add(lineBRight);
|
||||||
|
elements.add(lineCRight);
|
||||||
|
elements.add(lineDRight);
|
||||||
|
}
|
||||||
|
if (showArrow(RIGHT_CENTER)) {
|
||||||
|
elements.add(lineERight);
|
||||||
|
elements.add(lineFRight);
|
||||||
|
elements.add(lineGRight);
|
||||||
|
}
|
||||||
|
if (showArrow(RIGHT_BOTTOM)) {
|
||||||
|
elements.add(lineHRight);
|
||||||
|
elements.add(lineIRight);
|
||||||
|
elements.add(lineJRight);
|
||||||
|
}
|
||||||
|
elements.add(lineKRight);
|
||||||
|
elements.add(bottomCurveTo);
|
||||||
|
|
||||||
|
if (showArrow(BOTTOM_RIGHT)) {
|
||||||
|
elements.add(lineBBottom);
|
||||||
|
elements.add(lineCBottom);
|
||||||
|
elements.add(lineDBottom);
|
||||||
|
}
|
||||||
|
if (showArrow(BOTTOM_CENTER)) {
|
||||||
|
elements.add(lineEBottom);
|
||||||
|
elements.add(lineFBottom);
|
||||||
|
elements.add(lineGBottom);
|
||||||
|
}
|
||||||
|
if (showArrow(BOTTOM_LEFT)) {
|
||||||
|
elements.add(lineHBottom);
|
||||||
|
elements.add(lineIBottom);
|
||||||
|
elements.add(lineJBottom);
|
||||||
|
}
|
||||||
|
elements.add(lineKBottom);
|
||||||
|
elements.add(leftCurveTo);
|
||||||
|
|
||||||
|
if (showArrow(LEFT_BOTTOM)) {
|
||||||
|
elements.add(lineBLeft);
|
||||||
|
elements.add(lineCLeft);
|
||||||
|
elements.add(lineDLeft);
|
||||||
|
}
|
||||||
|
if (showArrow(LEFT_CENTER)) {
|
||||||
|
elements.add(lineELeft);
|
||||||
|
elements.add(lineFLeft);
|
||||||
|
elements.add(lineGLeft);
|
||||||
|
}
|
||||||
|
if (showArrow(LEFT_TOP)) {
|
||||||
|
elements.add(lineHLeft);
|
||||||
|
elements.add(lineILeft);
|
||||||
|
elements.add(lineJLeft);
|
||||||
|
}
|
||||||
|
elements.add(lineKLeft);
|
||||||
|
elements.add(topCurveTo);
|
||||||
|
|
||||||
|
path.getElements().setAll(elements);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'org.controlsfx:controlsfx:b98f1c9507c05600f80323674b33d15674926c71b0116f70085b62bdacf1e573',
|
|
||||||
'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882',
|
'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882',
|
||||||
'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b',
|
'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b',
|
||||||
'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752',
|
'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752',
|
||||||
|
|
Loading…
Add table
Reference in a new issue