Merge pull request #3287 from battleofwizards/remove-controlsfx

Remove controlsfx dependency
This commit is contained in:
sqrrm 2019-09-19 12:25:03 +02:00 committed by GitHub
commit bd1f19c030
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1534 additions and 13 deletions

View file

@ -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"

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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<>

View file

@ -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]

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -14,7 +14,6 @@
dependencyVerification {
verify = [
'org.controlsfx:controlsfx:b98f1c9507c05600f80323674b33d15674926c71b0116f70085b62bdacf1e573',
'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882',
'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b',
'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752',