/**
* Author: Mike Hearn <mhearn@bitcoinfoundation.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.plan99.payfile.gui.utils;
import com.google.common.base.Throwables;
import javafx.animation.*;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.Pane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.function.BiConsumer;
import static com.google.common.base.Preconditions.checkState;
import static net.plan99.payfile.utils.Exceptions.evalUnchecked;
public class GuiUtils {
public static void runAlert(BiConsumer<Stage, AlertWindowController> setup) {
// JavaFX doesn't actually have a standard alert template. Instead the Scene Builder app will create FXML
// files for an alert window for you, and then you customise it as you see fit. I guess it makes sense in
// an odd sort of way.
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.APPLICATION_MODAL);
FXMLLoader loader = new FXMLLoader(GuiUtils.class.getResource("alert.fxml"));
Pane pane = evalUnchecked(() -> (Pane) loader.load());
AlertWindowController controller = loader.getController();
setup.accept(dialogStage, controller);
dialogStage.setScene(new Scene(pane));
dialogStage.showAndWait();
}
public static void crashAlert(Throwable t) {
t.printStackTrace();
Throwable rootCause = Throwables.getRootCause(t);
Runnable r = () -> {
runAlert((stage, controller) -> controller.crashAlert(stage, rootCause.toString()));
Platform.exit();
};
if (Platform.isFxApplicationThread())
r.run();
else
Platform.runLater(r);
}
/** Show a GUI alert box for any unhandled exceptions that propagate out of this thread. */
public static void handleCrashesOnThisThread() {
Thread.currentThread().setUncaughtExceptionHandler(
(thread, exception) -> GuiUtils.crashAlert(Throwables.getRootCause(exception)));
}
public static void informationalAlert(String message, String details, Object... args) {
String formattedDetails = String.format(details, args);
Runnable r = () -> runAlert((stage, controller) -> controller.informational(stage, message, formattedDetails));
if (Platform.isFxApplicationThread())
r.run();
else
Platform.runLater(r);
}
private static final int UI_ANIMATION_TIME_MSEC = 350;
public static void fadeIn(Node ui) {
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
ft.setFromValue(0.0);
ft.setToValue(1.0);
ft.play();
}
public static Animation fadeOut(Node ui) {
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
ft.setFromValue(ui.getOpacity());
ft.setToValue(0.0);
ft.play();
return ft;
}
public static Animation fadeOutAndRemove(Node ui, Pane parentPane) {
Animation animation = fadeOut(ui);
animation.setOnFinished(actionEvent -> parentPane.getChildren().remove(ui));
return animation;
}
public static void blurOut(Node node) {
GaussianBlur blur = new GaussianBlur(0.0);
node.setEffect(blur);
Timeline timeline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 10.0);
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
}
public static void blurIn(Node node) {
GaussianBlur blur = (GaussianBlur) node.getEffect();
Timeline timeline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
timeline.getKeyFrames().add(kf);
timeline.setOnFinished(actionEvent -> node.setEffect(null));
timeline.play();
}
public static void checkGuiThread() {
checkState(Platform.isFxApplicationThread());
}
}