Package lighthouse.utils

Source Code of lighthouse.utils.GuiUtils

package lighthouse.utils;

import com.google.common.base.Throwables;
import com.google.common.util.concurrent.Uninterruptibles;
import com.sun.prism.GraphicsPipeline;
import com.sun.prism.sw.SWPipeline;
import javafx.animation.*;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.WritableDoubleValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.CacheHint;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.util.Duration;
import lighthouse.Main;
import lighthouse.protocol.LHUtils;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;

import static com.google.common.base.Preconditions.checkState;
import static lighthouse.protocol.LHUtils.unchecked;

public class GuiUtils {
    public static final Logger log = LoggerFactory.getLogger(GuiUtils.class);

    public static void runAlert(BiConsumer<Stage, AlertWindowController> setup) {
        try {
            // 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.
            Stage dialogStage = new Stage();
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            FXMLLoader loader = new FXMLLoader(GuiUtils.class.getResource("alert.fxml"));
            Pane pane = loader.load();
            AlertWindowController controller = loader.getController();
            setup.accept(dialogStage, controller);
            dialogStage.setScene(new Scene(pane));
            dialogStage.showAndWait();
        } catch (Throwable e) {
            // We crashed whilst trying to show the alert dialog. This can happen if we're being crashed by inbound
            // closures onto the event thread which will execute in the nested event loop. Just give up here: at the
            // moment we have no way to filter them out of the event queue.
            e.printStackTrace();
            Runtime.getRuntime().exit(1);
        }
    }

    public static void crashAlert(Throwable t) {
        Throwable rootCause = Throwables.getRootCause(t);
        log.error("CRASH!", rootCause);
        // Always use runLater to avoid "Nested event loops are allowed only while handling system events" error that
        // can occur if the crash occurs during e.g. an animation.
        Platform.runLater(() -> {
            runAlert((stage, controller) -> controller.crashAlert(stage, rootCause.toString()));
            Platform.exit();
        });
    }

    /** Show a GUI alert box for any unhandled exceptions that propagate out of this thread. */
    public static void handleCrashesOnThisThread() {
        Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> {
            Platform.runLater(() -> {
                Main.instance.mainStage.hide();
                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);
    }

    public static final int UI_ANIMATION_TIME_MSEC = 300;
    public static final Duration UI_ANIMATION_TIME = Duration.millis(UI_ANIMATION_TIME_MSEC);

    public static Animation fadeIn(Node ui) {
        return fadeIn(ui, 0, 1.0);
    }

    public static Animation fadeIn(Node ui, int delayMillis, double targetValue) {
        ui.setCache(true);
        ui.setCacheHint(CacheHint.SPEED);
        FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
        ft.setFromValue(ui.getOpacity());
        ft.setToValue(targetValue);
        ft.setOnFinished(ev -> ui.setCache(false));
        ft.setDelay(Duration.millis(delayMillis));
        ft.play();
        return ft;
    }

    public static Animation fadeOut(Node ui) {
        ui.setCache(true);
        ui.setCacheHint(CacheHint.SPEED);
        FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
        ft.setFromValue(ui.getOpacity());
        ft.setToValue(0.0);
        ft.setOnFinished(ev -> ui.setCache(false));
        ft.play();
        return ft;
    }

    public static Animation fadeOutAndRemove(Pane parentPane, Node... nodes) {
        Animation animation = fadeOut(nodes[0]);
        animation.setOnFinished(actionEvent -> parentPane.getChildren().removeAll(nodes));
        for (int i = 1; i < nodes.length; i++) {
            fadeOut(nodes[i]);
        }
        return animation;
    }

    public static Animation fadeOutAndRemove(Duration duration, Pane parentPane, Node... nodes) {
        nodes[0].setCache(true);
        FadeTransition ft = new FadeTransition(duration, nodes[0]);
        ft.setFromValue(nodes[0].getOpacity());
        ft.setToValue(0.0);
        ft.setOnFinished(ev -> parentPane.getChildren().removeAll(nodes));
        ft.play();
        return ft;
    }

    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(UI_ANIMATION_TIME, kv);
        timeline.getKeyFrames().add(kf);
        timeline.play();
    }

    public static void blurIn(Node node, Duration duration) {
        GaussianBlur blur = (GaussianBlur) node.getEffect();
        if (blur == null) {
            Main.log.error("BUG: Attempted to cancel non-existent blur.");
            return;
        }
        Timeline timeline = new Timeline();
        KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
        KeyFrame kf = new KeyFrame(duration, kv);
        timeline.getKeyFrames().add(kf);
        timeline.setOnFinished(actionEvent -> node.setEffect(null));
        timeline.play();
    }

    /*
    public static void blurOut(Node node) {
        BoxBlur blur = new BoxBlur();
        blur.setIterations(1);
        blur.setWidth(0.0);
        blur.setHeight(0.0);
        Timeline timeline = new Timeline();
        KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC),
                new KeyValue(blur.widthProperty(), 8.0),
                new KeyValue(blur.heightProperty(), 8.0));
        timeline.getKeyFrames().add(kf);
        timeline.play();
        node.setEffect(blur);
    }

    public static void blurIn(Node node) {
        BoxBlur blur = (BoxBlur) node.getEffect();
        Timeline timeline = new Timeline();
        KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC),
                new KeyValue(blur.widthProperty(), 0.0),
                new KeyValue(blur.heightProperty(), 0.0));
        timeline.getKeyFrames().add(kf);
        timeline.setOnFinished(actionEvent -> node.setEffect(null));
        timeline.play();
    }
    */

    public static ScaleTransition zoomIn(Node node) {
        return zoomIn(node, 0);
    }

    public static ScaleTransition zoomIn(Node node, int delayMillis) {
        return scaleFromTo(node, 0.95, 1.0, delayMillis);
    }

    public static ScaleTransition explodeOut(Node node) {
        return scaleFromTo(node, 1.0, 1.05, 0);
    }

    private static ScaleTransition scaleFromTo(Node node, double from, double to, int delayMillis) {
        //node.setCache(true);
        //node.setCacheHint(CacheHint.SPEED);
        ScaleTransition scale = new ScaleTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), node);
        scale.setFromX(from);
        scale.setFromY(from);
        scale.setToX(to);
        scale.setToY(to);
        scale.setDelay(Duration.millis(delayMillis));
        //scale.setOnFinished(ev -> node.setCache(false));
        scale.play();
        return scale;
    }

    public static void dropShadowOn(Node node) {
        DropShadow dropShadow = node.getEffect() != null ? (DropShadow) node.getEffect() : new DropShadow(BlurType.THREE_PASS_BOX, Color.BLACK, 0.0, 0.0, 0, 0);
        node.setEffect(dropShadow);
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC / 3),
                        new KeyValue(dropShadow.radiusProperty(), 3.0))
        );
        timeline.play();
    }

    public static void dropShadowOff(Node node) {
        DropShadow dropShadow = (DropShadow) node.getEffect();
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC / 3),
                        new KeyValue(dropShadow.radiusProperty(), 0.0))
        );
        timeline.setOnFinished((ev) -> node.setEffect(null));
        timeline.play();
    }

    public static void brightnessAdjust(Node node, double adjustment) {
        node.setCache(true);
        node.setCacheHint(CacheHint.SPEED);
        ColorAdjust adjust = new ColorAdjust();
        adjust.setBrightness(0.0);
        node.setEffect(adjust);
        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC * 0.7),
                new KeyValue(adjust.brightnessProperty(), adjustment)));
        timeline.play();
    }

    public static void brightnessUnadjust(Node node) {
        ColorAdjust effect = (ColorAdjust) node.getEffect();
        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC * 0.7),
                new KeyValue(effect.brightnessProperty(), 0.0)));
        timeline.setOnFinished(ev -> node.setCache(false));
        timeline.play();
    }

    public static void checkGuiThread() {
        checkState(Platform.isFxApplicationThread());
    }

    public static BooleanBinding conjunction(List<BooleanProperty> list) {
        BooleanBinding accumulator = new SimpleBooleanProperty(true).and(list.get(0));
        for (int i = 1; i < list.size(); i++) {
            accumulator = accumulator.and(list.get(i));
        }
        return accumulator;
    }

    public static Path resourceOverrideDirectory;

    public static URL getResource(String name) {
        if (resourceOverrideDirectory != null)
            return unchecked(() -> new URL("file://" + resourceOverrideDirectory.resolve(name).toAbsolutePath()));
        else
            return Main.class.getResource(name);
    }

    @Nullable
    public static Coin valueOrNull(String str) {
        try {
            return valueOrThrow(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    public static Coin valueOrThrow(String str) throws NumberFormatException {
        long value = BitcoinValue.userInputToSatoshis(str);
        if (value > 0)
            return Coin.valueOf(value);
        throw new NumberFormatException();
    }

    public static void runOnGuiThreadAfter(long millis, Runnable runnable) {
        new Thread(() -> {
            Uninterruptibles.sleepUninterruptibly(millis, TimeUnit.MILLISECONDS);
            Platform.runLater(runnable);
        }).start();
    }

    public static void runAfterFrame(Runnable runnable) {
        AnimationTimer frameWaiter = new AnimationTimer() {
            private int frames;

            @Override
            public void handle(long l) {
                frames++;
                if (frames > 2) {
                    stop();
                    runnable.run();
                }
            }
        };
        frameWaiter.start();
    }

    public static void platformFiddleChooser(FileChooser chooser) {
        // Work around FileChooser bugs.
        if (LHUtils.isUnix()) {
            chooser.setInitialDirectory(new File(System.getProperty("user.home")));
        }
    }

    public static void platformFiddleChooser(DirectoryChooser chooser) {
        // Work around DirectoryChooser bugs.
        if (LHUtils.isUnix()) {
            chooser.setInitialDirectory(new File(System.getProperty("user.home")));
        }
    }

    public static void roundCorners(ImageView view, double amount) {
        // This should be easier to do just with CSS.
        Rectangle clipRect = new Rectangle(view.getFitWidth(), view.getFitHeight());
        clipRect.setArcWidth(amount);
        clipRect.setArcHeight(amount);
        view.setClip(clipRect);
    }

    public static class AnimatedBindInfo {
        @Nullable public Timeline timeline;
        public NumberBinding bindFrom;
        public Runnable onAnimFinish;
    }

    public static AnimatedBindInfo animatedBind(Node node, WritableDoubleValue bindTo, NumberBinding bindFrom) {
        return animatedBind(node, bindTo, bindFrom, null);
    }

    public static AnimatedBindInfo animatedBind(Node node, WritableDoubleValue bindTo, NumberBinding bindFrom, @Nullable Interpolator interpolator) {
        bindTo.set(bindFrom.doubleValue());   // Initialise.
        bindFrom.addListener((o, prev, cur) -> {
            AnimatedBindInfo info = (AnimatedBindInfo) node.getUserData();
            if (info.timeline != null)
                info.timeline.stop();
            info.timeline = new Timeline(new KeyFrame(UI_ANIMATION_TIME,
                    interpolator != null ? new KeyValue(bindTo, cur, interpolator) : new KeyValue(bindTo, cur)));
            info.timeline.setOnFinished(ev -> {
                ((AnimatedBindInfo) node.getUserData()).timeline = null;
                if (info.onAnimFinish != null)
                    info.onAnimFinish.run();
            });
            info.timeline.play();
        });
        // We must pin bindFrom into the object graph, otherwise something like:
        //    animatedBind(node, node.opacityProperty(), when(a).then(1).otherwise(2))
        // will mysteriously stop working when the result of when() gets garbage collected and the listener with it.
        AnimatedBindInfo info = new AnimatedBindInfo();
        info.bindFrom = bindFrom;
        node.setUserData(info);
        return info;
    }

    public static boolean isSoftwarePipeline() {
        return GraphicsPipeline.getPipeline() instanceof SWPipeline;
    }
}
TOP

Related Classes of lighthouse.utils.GuiUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.