WIP, getting swing "stage" implemented with animations and rendering order
This commit is contained in:
parent
7fda42c508
commit
3707b1f4cd
|
@ -39,7 +39,7 @@ class JavaFxUtil {
|
||||||
.getBounds().x);
|
.getBounds().x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runAndWait(Runnable runnable) {
|
public static void invokeAndWait(Runnable runnable) {
|
||||||
// run synchronously on JavaFX thread
|
// run synchronously on JavaFX thread
|
||||||
if (Platform.isFxApplicationThread()) {
|
if (Platform.isFxApplicationThread()) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
@ -57,7 +57,7 @@ class JavaFxUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T runAndWait(Callable callable) {
|
public static <T> T invokeAndWait(Callable callable) {
|
||||||
// run synchronously on JavaFX thread
|
// run synchronously on JavaFX thread
|
||||||
if (Platform.isFxApplicationThread()) {
|
if (Platform.isFxApplicationThread()) {
|
||||||
try {
|
try {
|
||||||
|
@ -79,7 +79,11 @@ class JavaFxUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runLater(Runnable runnable) {
|
public static void invokeLater(Runnable runnable) {
|
||||||
Platform.runLater(runnable);
|
if (Platform.isFxApplicationThread()) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
Platform.runLater(runnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,23 +47,29 @@ class StageAsSwingWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method method;
|
private static Method method;
|
||||||
|
static {
|
||||||
private
|
|
||||||
StageAsSwingWrapper() {
|
|
||||||
frame = new JFrame();
|
|
||||||
panel = new JFXPanel();
|
|
||||||
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
|
||||||
|
|
||||||
frame.setUndecorated(true);
|
|
||||||
frame.add(panel);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
method = Scene.class.getDeclaredMethod("preferredSize");
|
method = Scene.class.getDeclaredMethod("preferredSize");
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
StageAsSwingWrapper() {
|
||||||
|
frame = new JFrame() {
|
||||||
|
|
||||||
|
};
|
||||||
|
panel = new JFXPanel();
|
||||||
|
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||||
|
|
||||||
|
frame.setUndecorated(true);
|
||||||
|
frame.add(panel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
opacityProperty = new WritableValue<Float>() {
|
opacityProperty = new WritableValue<Float>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,6 +174,7 @@ class StageAsSwingWrapper {
|
||||||
public
|
public
|
||||||
void close() {
|
void close() {
|
||||||
frame.dispose();
|
frame.dispose();
|
||||||
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -197,12 +204,10 @@ class StageAsSwingWrapper {
|
||||||
frame.setVisible(false);
|
frame.setVisible(false);
|
||||||
frame.setLocation(Short.MIN_VALUE, Short.MIN_VALUE);
|
frame.setLocation(Short.MIN_VALUE, Short.MIN_VALUE);
|
||||||
|
|
||||||
frame.pack();
|
|
||||||
panel.validate();
|
|
||||||
|
|
||||||
// Figure out the size of everything. Because JFXPanel DOES NOT do this.
|
// Figure out the size of everything. Because JFXPanel DOES NOT do this.
|
||||||
sizeToScene();
|
frame.pack();
|
||||||
|
|
||||||
|
sizeToScene();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -221,7 +226,7 @@ class StageAsSwingWrapper {
|
||||||
public
|
public
|
||||||
void initModality(final Dialog.ModalExclusionType modal) {
|
void initModality(final Dialog.ModalExclusionType modal) {
|
||||||
// we take in the javaFX modality, and pass it on to the correct swing version
|
// we take in the javaFX modality, and pass it on to the correct swing version
|
||||||
JavaFxUtil.runAndWait(() -> frame.setModalExclusionType(modal));
|
JavaFxUtil.invokeAndWait(() -> frame.setModalExclusionType(modal));
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -231,9 +236,15 @@ class StageAsSwingWrapper {
|
||||||
|
|
||||||
public
|
public
|
||||||
void sizeToScene() {
|
void sizeToScene() {
|
||||||
|
SwingUtil.invokeAndWait(() -> {
|
||||||
|
frame.invalidate();
|
||||||
|
frame.validate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Figure out the size of everything. Because JFXPanel DOES NOT do this.
|
// Figure out the size of everything. Because JFXPanel DOES NOT do this.
|
||||||
// must be on the FX app thread
|
// must be on the FX app thread
|
||||||
JavaFxUtil.runAndWait(() -> {
|
JavaFxUtil.invokeAndWait(() -> {
|
||||||
final Scene scene = panel.getScene();
|
final Scene scene = panel.getScene();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -250,4 +261,9 @@ class StageAsSwingWrapper {
|
||||||
void setScene(final Scene scene) {
|
void setScene(final Scene scene) {
|
||||||
panel.setScene(scene);
|
panel.setScene(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
WritableValue<Float> getOpacityProperty() {
|
||||||
|
return opacityProperty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
package dorkbox.util.javafx;
|
package dorkbox.util.javafx;
|
||||||
|
|
||||||
import dorkbox.util.JavaFxUtil;
|
import dorkbox.util.JavaFxUtil;
|
||||||
|
import dorkbox.util.SwingUtil;
|
||||||
import impl.org.controlsfx.ImplUtils;
|
import impl.org.controlsfx.ImplUtils;
|
||||||
|
import javafx.animation.*;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -50,6 +52,7 @@ import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.util.Duration;
|
||||||
import org.controlsfx.control.PopOver;
|
import org.controlsfx.control.PopOver;
|
||||||
import org.controlsfx.tools.ValueExtractor;
|
import org.controlsfx.tools.ValueExtractor;
|
||||||
import org.controlsfx.validation.ValidationSupport;
|
import org.controlsfx.validation.ValidationSupport;
|
||||||
|
@ -247,7 +250,7 @@ public class Wizard {
|
||||||
public
|
public
|
||||||
void accept(final WizardPage currentPage) {
|
void accept(final WizardPage currentPage) {
|
||||||
if (currentPage.autoFocusNext) {
|
if (currentPage.autoFocusNext) {
|
||||||
JavaFxUtil.runLater(BUTTON_NEXT::requestFocus);
|
JavaFxUtil.invokeLater(BUTTON_NEXT::requestFocus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -292,7 +295,7 @@ public class Wizard {
|
||||||
borderPane.setTop(region);
|
borderPane.setTop(region);
|
||||||
|
|
||||||
center = new VBox();
|
center = new VBox();
|
||||||
center.setMinSize(0, 0);
|
center.setMinSize(10, 10);
|
||||||
center.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
center.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||||
// center.setStyle("-fx-background-color: #2046ff;");
|
// center.setStyle("-fx-background-color: #2046ff;");
|
||||||
borderPane.setCenter(center);
|
borderPane.setCenter(center);
|
||||||
|
@ -315,7 +318,7 @@ public class Wizard {
|
||||||
private
|
private
|
||||||
void validatePopover(final String newValue) {
|
void validatePopover(final String newValue) {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
currentPage.ifPresent(currentPage -> JavaFxUtil.runLater(() -> {
|
currentPage.ifPresent(currentPage -> JavaFxUtil.invokeLater(() -> {
|
||||||
final PopOver popOver = this.popOver;
|
final PopOver popOver = this.popOver;
|
||||||
|
|
||||||
this.popOverErrorText.setText(newValue);
|
this.popOverErrorText.setText(newValue);
|
||||||
|
@ -388,7 +391,7 @@ public class Wizard {
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
void goNext() {
|
void goNext() {
|
||||||
JavaFxUtil.runLater(() -> {
|
JavaFxUtil.invokeLater(() -> {
|
||||||
currentPage.ifPresent(pageHistory::push);
|
currentPage.ifPresent(pageHistory::push);
|
||||||
currentPage = getFlow().advance(currentPage.orElse(null));
|
currentPage = getFlow().advance(currentPage.orElse(null));
|
||||||
updatePage(stage, true);
|
updatePage(stage, true);
|
||||||
|
@ -400,7 +403,7 @@ public class Wizard {
|
||||||
private
|
private
|
||||||
void goPrev() {
|
void goPrev() {
|
||||||
currentPage = Optional.ofNullable(pageHistory.isEmpty() ? null : pageHistory.pop());
|
currentPage = Optional.ofNullable(pageHistory.isEmpty() ? null : pageHistory.pop());
|
||||||
JavaFxUtil.runLater(() -> updatePage(stage, false));
|
JavaFxUtil.invokeLater(() -> updatePage(stage, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -476,7 +479,7 @@ public class Wizard {
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
void setFlow(Flow flow) {
|
void setFlow(Flow flow) {
|
||||||
JavaFxUtil.runAndWait(() -> this.flow.set(flow));
|
JavaFxUtil.invokeAndWait(() -> this.flow.set(flow));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -624,6 +627,9 @@ public class Wizard {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SequentialTransition sequentialTransition = new SequentialTransition();
|
||||||
|
sequentialTransition.setCycleCount(1);
|
||||||
|
|
||||||
Optional<WizardPage> prevPage = Optional.ofNullable(pageHistory.isEmpty() ? null : pageHistory.peek());
|
Optional<WizardPage> prevPage = Optional.ofNullable(pageHistory.isEmpty() ? null : pageHistory.peek());
|
||||||
prevPage.ifPresent(page -> {
|
prevPage.ifPresent(page -> {
|
||||||
// if we are going forward in the wizard, we read in the settings
|
// if we are going forward in the wizard, we read in the settings
|
||||||
|
@ -643,83 +649,114 @@ public class Wizard {
|
||||||
|
|
||||||
invalidProperty.set(false);
|
invalidProperty.set(false);
|
||||||
popOver.hide();
|
popOver.hide();
|
||||||
|
|
||||||
|
Timeline timeline = new Timeline();
|
||||||
|
timeline.setCycleCount(1);
|
||||||
|
timeline.getKeyFrames()
|
||||||
|
.addAll(new KeyFrame(Duration.millis(200),
|
||||||
|
new KeyValue(stage.getOpacityProperty(), 0F, Interpolator.EASE_OUT)));
|
||||||
|
|
||||||
|
timeline.setOnFinished(event -> {
|
||||||
|
currentPage.ifPresent(currentPage -> {
|
||||||
|
refreshCurrentPage(stage, currentPage);
|
||||||
|
|
||||||
|
SwingUtil.invokeAndWait(() -> SwingUtil.showOnSameScreenAsMouseCenter(stage.frame));
|
||||||
|
|
||||||
|
Timeline timeline2 = new Timeline();
|
||||||
|
timeline2.setCycleCount(1);
|
||||||
|
timeline2.getKeyFrames()
|
||||||
|
.addAll(new KeyFrame(Duration.millis(500),
|
||||||
|
new KeyValue(stage.getOpacityProperty(), 1F, Interpolator.EASE_OUT)));
|
||||||
|
timeline2.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
sequentialTransition.getChildren().add(timeline);
|
||||||
});
|
});
|
||||||
|
|
||||||
currentPage.ifPresent(currentPage -> {
|
// only run this if we don't have a prev page, otherwise, we run this at the end of our animation
|
||||||
// put in default actions
|
if (!prevPage.isPresent()) {
|
||||||
if (!BUTTON_PREV_INIT) {
|
currentPage.ifPresent(currentPage -> {
|
||||||
BUTTON_PREV_INIT = true;
|
refreshCurrentPage(stage, currentPage);
|
||||||
BUTTON_PREVIOUS.setDisable(false);
|
});
|
||||||
}
|
}
|
||||||
if (!BUTTON_NEXT_INIT) {
|
|
||||||
BUTTON_NEXT_INIT = true;
|
|
||||||
BUTTON_NEXT.setDisable(false);
|
|
||||||
|
|
||||||
BUTTON_NEXT.addEventFilter(ActionEvent.ACTION, BUTTON_NEXT_EVENT_HANDLER);
|
sequentialTransition.play();
|
||||||
BUTTON_NEXT.addEventFilter(KeyEvent.KEY_PRESSED, BUTTON_NEXT_EVENT_HANDLER);
|
validateActionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// then give user a chance to modify the default actions
|
private
|
||||||
currentPage.onEnteringPage(this);
|
void refreshCurrentPage(final StageAsSwingWrapper stage, final WizardPage currentPage) {
|
||||||
|
// put in default actions
|
||||||
|
if (!BUTTON_PREV_INIT) {
|
||||||
|
BUTTON_PREV_INIT = true;
|
||||||
|
BUTTON_PREVIOUS.setDisable(false);
|
||||||
|
}
|
||||||
|
if (!BUTTON_NEXT_INIT) {
|
||||||
|
BUTTON_NEXT_INIT = true;
|
||||||
|
BUTTON_NEXT.setDisable(false);
|
||||||
|
|
||||||
invalidProperty.bind(currentPage.invalidProperty);
|
BUTTON_NEXT.addEventFilter(ActionEvent.ACTION, BUTTON_NEXT_EVENT_HANDLER);
|
||||||
invalidPropertyStrings.bind(currentPage.invalidPropertyStrings);
|
BUTTON_NEXT.addEventFilter(KeyEvent.KEY_PRESSED, BUTTON_NEXT_EVENT_HANDLER);
|
||||||
|
}
|
||||||
|
|
||||||
final Node firstFocusElement = currentPage.firstFocusElement;
|
// then give user a chance to modify the default actions
|
||||||
if (firstFocusElement != null) {
|
currentPage.onEnteringPage(this);
|
||||||
JavaFxUtil.runLater(() -> {
|
|
||||||
if (isInvalid()) {
|
invalidProperty.bind(currentPage.invalidProperty);
|
||||||
firstFocusElement.requestFocus();
|
invalidPropertyStrings.bind(currentPage.invalidPropertyStrings);
|
||||||
}
|
|
||||||
else {
|
final Node firstFocusElement = currentPage.firstFocusElement;
|
||||||
JavaFxUtil.runLater(BUTTON_NEXT::requestFocus);
|
if (firstFocusElement != null) {
|
||||||
}
|
JavaFxUtil.invokeLater(() -> {
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isInvalid()) {
|
if (isInvalid()) {
|
||||||
JavaFxUtil.runLater(BUTTON_PREVIOUS::requestFocus);
|
firstFocusElement.requestFocus();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JavaFxUtil.runLater(BUTTON_NEXT::requestFocus);
|
JavaFxUtil.invokeLater(BUTTON_NEXT::requestFocus);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and then switch to the new pane
|
|
||||||
if (currentPage.headerFont != null) {
|
|
||||||
headerText.setFont(currentPage.headerFont);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
headerText.setFont(defaultHeaderFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentPage.headerGraphic != null) {
|
|
||||||
graphicRegion.getChildren().setAll(currentPage.headerGraphic);
|
|
||||||
} else {
|
|
||||||
graphicRegion.getChildren().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
headerText.setText(currentPage.headerText);
|
|
||||||
ObservableList<Node> children = center.getChildren();
|
|
||||||
children.clear();
|
|
||||||
children.add(currentPage.anchorPane);
|
|
||||||
|
|
||||||
|
|
||||||
if (!useSpecifiedSize) {
|
|
||||||
currentPage.anchorPane.autosize();
|
|
||||||
stage.sizeToScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
JavaFxUtil.runLater(() -> {
|
|
||||||
if (isInvalid()) {
|
|
||||||
validatePopover(currentPage.invalidPropertyStrings.get());
|
|
||||||
} else {
|
|
||||||
popOver.hide();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
else {
|
||||||
|
if (isInvalid()) {
|
||||||
|
JavaFxUtil.invokeLater(BUTTON_PREVIOUS::requestFocus);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JavaFxUtil.invokeLater(BUTTON_NEXT::requestFocus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validateActionState();
|
// and then switch to the new pane
|
||||||
|
if (currentPage.headerFont != null) {
|
||||||
|
headerText.setFont(currentPage.headerFont);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
headerText.setFont(defaultHeaderFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPage.headerGraphic != null) {
|
||||||
|
graphicRegion.getChildren().setAll(currentPage.headerGraphic);
|
||||||
|
} else {
|
||||||
|
graphicRegion.getChildren().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
headerText.setText(currentPage.headerText);
|
||||||
|
ObservableList<Node> children = center.getChildren();
|
||||||
|
children.clear();
|
||||||
|
children.add(currentPage.anchorPane);
|
||||||
|
|
||||||
|
if (!useSpecifiedSize) {
|
||||||
|
currentPage.anchorPane.autosize();
|
||||||
|
stage.sizeToScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaFxUtil.invokeAndWait(() -> {
|
||||||
|
if (isInvalid()) {
|
||||||
|
validatePopover(currentPage.invalidPropertyStrings.get());
|
||||||
|
} else {
|
||||||
|
popOver.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
Loading…
Reference in New Issue
Block a user