mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-21 14:24:06 +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'
|
||||
btcdCli4jVersion = '975ff5d4'
|
||||
codecVersion = '1.9'
|
||||
controlsfxVersion = '8.0.6_20'
|
||||
easybindVersion = '1.0.3'
|
||||
easyVersion = '4.0.1'
|
||||
findbugsVersion = '3.0.2'
|
||||
|
@ -288,7 +287,6 @@ configure(project(':desktop')) {
|
|||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile "org.controlsfx:controlsfx:$controlsfxVersion"
|
||||
compile "net.glxn:qrgen:$qrgenVersion"
|
||||
compile "de.jensd:fontawesomefx:$fontawesomefxVersion"
|
||||
compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion"
|
||||
|
|
|
@ -18,12 +18,11 @@
|
|||
package bisq.desktop.components;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import org.controlsfx.control.PopOver;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
|
|
@ -18,12 +18,11 @@
|
|||
package bisq.desktop.components;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import de.jensd.fx.glyphs.GlyphIcons;
|
||||
|
||||
import org.controlsfx.control.PopOver;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.scene.control.Label;
|
||||
|
|
|
@ -18,11 +18,10 @@
|
|||
package bisq.desktop.components;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import org.controlsfx.control.PopOver;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
|
|
@ -18,13 +18,12 @@
|
|||
package bisq.desktop.components;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.desktop.components.controlsfx.control.PopOver;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
|
||||
import org.controlsfx.control.PopOver;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
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.
|
||||
* 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
|
||||
// consider replacement with controlsFX components.
|
||||
//TODO There are some rare situation where it behaves buggy. Needs further investigation and improvements.
|
||||
public class InputTextField extends JFXTextField {
|
||||
|
||||
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 {
|
||||
verify = [
|
||||
'org.controlsfx:controlsfx:b98f1c9507c05600f80323674b33d15674926c71b0116f70085b62bdacf1e573',
|
||||
'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882',
|
||||
'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b',
|
||||
'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752',
|
||||
|
|
Loading…
Add table
Reference in a new issue