WIP, getting swing "stage" implemented with animations and rendering order

This commit is contained in:
nathan 2015-08-18 01:02:10 +02:00
parent 7fda42c508
commit 3707b1f4cd
3 changed files with 149 additions and 92 deletions

View File

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

View File

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

View File

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