mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-17 15:57:18 -04:00
alt: transparent title bar
This commit is contained in:
parent
d29a198f7f
commit
c360a4abb0
@ -110,7 +110,7 @@ public final class Controllers {
|
|||||||
|
|
||||||
Task.runAsync(JavaVersion::initialize).start();
|
Task.runAsync(JavaVersion::initialize).start();
|
||||||
|
|
||||||
scene = new Scene(decorator.getDecorator(), 800, 519);
|
scene = new Scene(decorator.getDecorator(), 800, 480);
|
||||||
decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty());
|
decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty());
|
||||||
decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty());
|
decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty());
|
||||||
scene.getStylesheets().setAll(config().getTheme().getStylesheets());
|
scene.getStylesheets().setAll(config().getTheme().getStylesheets());
|
||||||
|
@ -18,16 +18,14 @@
|
|||||||
package org.jackhuang.hmcl.ui;
|
package org.jackhuang.hmcl.ui;
|
||||||
|
|
||||||
import com.jfoenix.controls.*;
|
import com.jfoenix.controls.*;
|
||||||
import javafx.animation.Animation;
|
import javafx.animation.*;
|
||||||
import javafx.animation.Interpolator;
|
|
||||||
import javafx.animation.KeyFrame;
|
|
||||||
import javafx.animation.Timeline;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.beans.value.WeakChangeListener;
|
import javafx.beans.value.WeakChangeListener;
|
||||||
|
import javafx.beans.value.WritableValue;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
@ -62,6 +60,7 @@ import java.lang.reflect.Constructor;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
@ -304,6 +303,27 @@ public final class FXUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void playAnimation(Node node, String animationKey, Timeline timeline) {
|
||||||
|
animationKey = "FXUTILS.ANIMATION." + animationKey;
|
||||||
|
Object oldTimeline = node.getProperties().get(animationKey);
|
||||||
|
if (oldTimeline instanceof Timeline) ((Timeline) oldTimeline).stop();
|
||||||
|
if (timeline != null) timeline.play();
|
||||||
|
node.getProperties().put(animationKey, timeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void playAnimation(Node node, String animationKey, Duration duration, WritableValue<T> property, T from, T to, Interpolator interpolator) {
|
||||||
|
if (from == null) from = property.getValue();
|
||||||
|
if (duration == null || Objects.equals(duration, Duration.ZERO) || Objects.equals(from, to)) {
|
||||||
|
playAnimation(node, animationKey, null);
|
||||||
|
property.setValue(to);
|
||||||
|
} else {
|
||||||
|
playAnimation(node, animationKey, new Timeline(
|
||||||
|
new KeyFrame(Duration.ZERO, new KeyValue(property, from, interpolator)),
|
||||||
|
new KeyFrame(duration, new KeyValue(property, to, interpolator))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void openFolder(File file) {
|
public static void openFolder(File file) {
|
||||||
if (!FileUtils.makeDirectory(file)) {
|
if (!FileUtils.makeDirectory(file)) {
|
||||||
Logging.LOG.log(Level.SEVERE, "Unable to make directory " + file);
|
Logging.LOG.log(Level.SEVERE, "Unable to make directory " + file);
|
||||||
|
@ -26,7 +26,6 @@ import javafx.util.Duration;
|
|||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
|
||||||
public class TransitionPane extends StackPane implements AnimationHandler {
|
public class TransitionPane extends StackPane implements AnimationHandler {
|
||||||
private Timeline animation;
|
|
||||||
private Duration duration;
|
private Duration duration;
|
||||||
private Node previousNode, currentNode;
|
private Node previousNode, currentNode;
|
||||||
|
|
||||||
@ -62,24 +61,19 @@ public class TransitionPane extends StackPane implements AnimationHandler {
|
|||||||
public void setContent(Node newView, AnimationProducer transition, Duration duration) {
|
public void setContent(Node newView, AnimationProducer transition, Duration duration) {
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
|
|
||||||
Timeline prev = animation;
|
|
||||||
if (prev != null)
|
|
||||||
prev.stop();
|
|
||||||
|
|
||||||
updateContent(newView);
|
updateContent(newView);
|
||||||
|
|
||||||
transition.init(this);
|
transition.init(this);
|
||||||
|
|
||||||
// runLater or "init" will not work
|
// runLater or "init" will not work
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Timeline nowAnimation = new Timeline();
|
Timeline newAnimation = new Timeline();
|
||||||
nowAnimation.getKeyFrames().addAll(transition.animate(this));
|
newAnimation.getKeyFrames().addAll(transition.animate(this));
|
||||||
nowAnimation.getKeyFrames().add(new KeyFrame(duration, e -> {
|
newAnimation.getKeyFrames().add(new KeyFrame(duration, e -> {
|
||||||
setMouseTransparent(false);
|
setMouseTransparent(false);
|
||||||
getChildren().remove(previousNode);
|
getChildren().remove(previousNode);
|
||||||
}));
|
}));
|
||||||
nowAnimation.play();
|
FXUtils.playAnimation(this, "transition_pane", newAnimation);
|
||||||
animation = nowAnimation;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +50,21 @@ public interface DecoratorPage extends Refreshable {
|
|||||||
private final boolean backable;
|
private final boolean backable;
|
||||||
private final boolean refreshable;
|
private final boolean refreshable;
|
||||||
private final boolean animate;
|
private final boolean animate;
|
||||||
|
private final boolean titleBarTransparent;
|
||||||
|
private final double leftPaneWidth;
|
||||||
|
|
||||||
public State(String title, Node titleNode, boolean backable, boolean refreshable, boolean animate) {
|
public State(String title, Node titleNode, boolean backable, boolean refreshable, boolean animate) {
|
||||||
|
this(title, titleNode, backable, refreshable, animate, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public State(String title, Node titleNode, boolean backable, boolean refreshable, boolean animate, boolean titleBarTransparent, double leftPaneWidth) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.titleNode = titleNode;
|
this.titleNode = titleNode;
|
||||||
this.backable = backable;
|
this.backable = backable;
|
||||||
this.refreshable = refreshable;
|
this.refreshable = refreshable;
|
||||||
this.animate = animate;
|
this.animate = animate;
|
||||||
|
this.titleBarTransparent = titleBarTransparent;
|
||||||
|
this.leftPaneWidth = leftPaneWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static State fromTitle(String title) {
|
public static State fromTitle(String title) {
|
||||||
@ -86,5 +94,13 @@ public interface DecoratorPage extends Refreshable {
|
|||||||
public boolean isAnimate() {
|
public boolean isAnimate() {
|
||||||
return animate;
|
return animate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTitleBarTransparent() {
|
||||||
|
return titleBarTransparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLeftPaneWidth() {
|
||||||
|
return leftPaneWidth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import com.jfoenix.controls.JFXButton;
|
|||||||
import com.jfoenix.svg.SVGGlyph;
|
import com.jfoenix.svg.SVGGlyph;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.css.PseudoClass;
|
||||||
import javafx.geometry.Bounds;
|
import javafx.geometry.Bounds;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@ -31,11 +32,11 @@ import javafx.scene.control.SkinBase;
|
|||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Region;
|
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import javafx.util.Duration;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.setting.Theme;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@ -44,16 +45,19 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
|||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
|
||||||
public class DecoratorSkin extends SkinBase<Decorator> {
|
public class DecoratorSkin extends SkinBase<Decorator> {
|
||||||
|
private static final PseudoClass TRANSPARENT = PseudoClass.getPseudoClass("transparent");
|
||||||
private static final SVGGlyph minus = Lang.apply(new SVGGlyph(0, "MINUS", "M804.571 420.571v109.714q0 22.857-16 38.857t-38.857 16h-694.857q-22.857 0-38.857-16t-16-38.857v-109.714q0-22.857 16-38.857t38.857-16h694.857q22.857 0 38.857 16t16 38.857z", Color.WHITE),
|
private static final SVGGlyph minus = Lang.apply(new SVGGlyph(0, "MINUS", "M804.571 420.571v109.714q0 22.857-16 38.857t-38.857 16h-694.857q-22.857 0-38.857-16t-16-38.857v-109.714q0-22.857 16-38.857t38.857-16h694.857q22.857 0 38.857 16t16 38.857z", Color.WHITE),
|
||||||
glyph -> { glyph.setSize(12, 2); glyph.setTranslateY(4); });
|
glyph -> { glyph.setSize(12, 2); glyph.setTranslateY(4); });
|
||||||
|
|
||||||
private final BorderPane root;
|
private final BorderPane root;
|
||||||
private final BorderPane titleContainer;
|
private final StackPane titleContainer;
|
||||||
private final Stage primaryStage;
|
private final Stage primaryStage;
|
||||||
private final TransitionPane navBarPane;
|
private final TransitionPane navBarPane;
|
||||||
|
private final StackPane leftPane;
|
||||||
|
|
||||||
private double xOffset, yOffset, newX, newY, initX, initY;
|
private double xOffset, yOffset, newX, newY, initX, initY;
|
||||||
private boolean allowMove, isDragging;
|
private boolean allowMove, isDragging;
|
||||||
|
private boolean titleBarTransparent = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for all SkinBase instances.
|
* Constructor for all SkinBase instances.
|
||||||
@ -68,23 +72,32 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
minus.fillProperty().bind(Theme.foregroundFillBinding());
|
minus.fillProperty().bind(Theme.foregroundFillBinding());
|
||||||
|
|
||||||
Decorator skinnable = getSkinnable();
|
Decorator skinnable = getSkinnable();
|
||||||
|
StackPane parent = new StackPane();
|
||||||
|
parent.backgroundProperty().bind(skinnable.backgroundProperty());
|
||||||
|
parent.setPickOnBounds(false);
|
||||||
|
parent.prefHeightProperty().bind(control.prefHeightProperty());
|
||||||
|
parent.prefWidthProperty().bind(control.prefWidthProperty());
|
||||||
|
|
||||||
root = new BorderPane();
|
root = new BorderPane();
|
||||||
root.getStyleClass().addAll("jfx-decorator", "resize-border");
|
root.getStyleClass().addAll("jfx-decorator", "resize-border");
|
||||||
root.prefHeightProperty().bind(control.prefHeightProperty());
|
|
||||||
root.prefWidthProperty().bind(control.prefWidthProperty());
|
|
||||||
root.setMaxHeight(Region.USE_PREF_SIZE);
|
|
||||||
root.setMinHeight(Region.USE_PREF_SIZE);
|
|
||||||
root.setMaxWidth(Region.USE_PREF_SIZE);
|
|
||||||
root.setMinWidth(Region.USE_PREF_SIZE);
|
|
||||||
|
|
||||||
// center node with a container node in bottom layer and a "welcome" layer at the top layer.
|
// animation layer at bottom
|
||||||
|
{
|
||||||
|
HBox layer = new HBox();
|
||||||
|
leftPane = new StackPane();
|
||||||
|
leftPane.setPrefWidth(0);
|
||||||
|
leftPane.getStyleClass().add("jfx-decorator-drawer");
|
||||||
|
layer.getChildren().setAll(leftPane);
|
||||||
|
parent.getChildren().add(layer);
|
||||||
|
parent.getChildren().add(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// center node with a animation layer at bottom, a container layer at middle and a "welcome" layer at top.
|
||||||
StackPane container = new StackPane();
|
StackPane container = new StackPane();
|
||||||
skinnable.setDrawerWrapper(container);
|
skinnable.setDrawerWrapper(container);
|
||||||
container.getStyleClass().add("jfx-decorator-drawer");
|
|
||||||
container.backgroundProperty().bind(skinnable.backgroundProperty());
|
|
||||||
FXUtils.setOverflowHidden(container);
|
FXUtils.setOverflowHidden(container);
|
||||||
// bottom layer
|
|
||||||
|
// content layer at middle
|
||||||
{
|
{
|
||||||
StackPane contentPlaceHolder = new StackPane();
|
StackPane contentPlaceHolder = new StackPane();
|
||||||
contentPlaceHolder.getStyleClass().add("jfx-decorator-content-container");
|
contentPlaceHolder.getStyleClass().add("jfx-decorator-content-container");
|
||||||
@ -93,7 +106,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
container.getChildren().add(contentPlaceHolder);
|
container.getChildren().add(contentPlaceHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// top layer for welcome and hint
|
// welcome and hint layer at top
|
||||||
{
|
{
|
||||||
StackPane floatLayer = new StackPane();
|
StackPane floatLayer = new StackPane();
|
||||||
Bindings.bindContent(floatLayer.getChildren(), skinnable.containerProperty());
|
Bindings.bindContent(floatLayer.getChildren(), skinnable.containerProperty());
|
||||||
@ -114,18 +127,26 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
|
|
||||||
root.setCenter(container);
|
root.setCenter(container);
|
||||||
|
|
||||||
titleContainer = new BorderPane();
|
titleContainer = new StackPane();
|
||||||
root.setOnMouseReleased(this::onMouseReleased);
|
root.setOnMouseReleased(this::onMouseReleased);
|
||||||
root.setOnMouseDragged(this::onMouseDragged);
|
root.setOnMouseDragged(this::onMouseDragged);
|
||||||
root.setOnMouseMoved(this::onMouseMoved);
|
root.setOnMouseMoved(this::onMouseMoved);
|
||||||
titleContainer.setPickOnBounds(false);
|
titleContainer.setPickOnBounds(false);
|
||||||
titleContainer.setMinHeight(40);
|
titleContainer.setMinHeight(40);
|
||||||
titleContainer.getStyleClass().addAll("jfx-tool-bar", "window-title-bar");
|
titleContainer.getStyleClass().addAll("jfx-tool-bar");
|
||||||
titleContainer.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> allowMove = true);
|
titleContainer.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> allowMove = true);
|
||||||
titleContainer.addEventHandler(MouseEvent.MOUSE_EXITED, e -> {
|
titleContainer.addEventHandler(MouseEvent.MOUSE_EXITED, e -> {
|
||||||
if (!isDragging) allowMove = false;
|
if (!isDragging) allowMove = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
StackPane titleBarBackground = new StackPane();
|
||||||
|
titleBarBackground.getStyleClass().add("background");
|
||||||
|
titleContainer.getChildren().add(titleBarBackground);
|
||||||
|
|
||||||
|
BorderPane titleBar = new BorderPane();
|
||||||
|
titleBar.setPickOnBounds(false);
|
||||||
|
titleContainer.getChildren().add(titleBar);
|
||||||
|
|
||||||
Rectangle rectangle = new Rectangle(0, 0, 0, 0);
|
Rectangle rectangle = new Rectangle(0, 0, 0, 0);
|
||||||
rectangle.widthProperty().bind(titleContainer.widthProperty());
|
rectangle.widthProperty().bind(titleContainer.widthProperty());
|
||||||
rectangle.heightProperty().bind(titleContainer.heightProperty().add(100));
|
rectangle.heightProperty().bind(titleContainer.heightProperty().add(100));
|
||||||
@ -134,14 +155,21 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
navBarPane = new TransitionPane();
|
navBarPane = new TransitionPane();
|
||||||
FXUtils.onChangeAndOperate(skinnable.stateProperty(), s -> {
|
FXUtils.onChangeAndOperate(skinnable.stateProperty(), s -> {
|
||||||
if (s == null) return;
|
if (s == null) return;
|
||||||
Node node = createNavBar(skinnable, s.isBackable(), skinnable.canCloseProperty().get(), skinnable.showCloseAsHomeProperty().get(), s.isRefreshable(), s.getTitle(), s.getTitleNode());
|
Node node = createNavBar(skinnable, s.isTitleBarTransparent(), s.getLeftPaneWidth(), s.isBackable(), skinnable.canCloseProperty().get(), skinnable.showCloseAsHomeProperty().get(), s.isRefreshable(), s.getTitle(), s.getTitleNode());
|
||||||
|
double targetOpacity = s.isTitleBarTransparent() ? 0 : 1;
|
||||||
if (s.isAnimate()) {
|
if (s.isAnimate()) {
|
||||||
navBarPane.setContent(node, ContainerAnimations.FADE.getAnimationProducer());
|
navBarPane.setContent(node, ContainerAnimations.FADE.getAnimationProducer());
|
||||||
} else {
|
} else {
|
||||||
navBarPane.getChildren().setAll(node);
|
navBarPane.getChildren().setAll(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FXUtils.playAnimation(titleBarBackground, "animation",
|
||||||
|
s.isAnimate() ? Duration.millis(160) : null, titleBarBackground.opacityProperty(), null, targetOpacity, FXUtils.SINE);
|
||||||
|
titleBarTransparent = s.isTitleBarTransparent();
|
||||||
|
FXUtils.playAnimation(leftPane, "animation",
|
||||||
|
s.isAnimate() ? Duration.millis(160) : null, leftPane.prefWidthProperty(), null, s.getLeftPaneWidth(), FXUtils.SINE);
|
||||||
});
|
});
|
||||||
titleContainer.setCenter(navBarPane);
|
titleBar.setCenter(navBarPane);
|
||||||
|
|
||||||
HBox buttonsContainer = new HBox();
|
HBox buttonsContainer = new HBox();
|
||||||
buttonsContainer.setStyle("-fx-background-color: transparent;");
|
buttonsContainer.setStyle("-fx-background-color: transparent;");
|
||||||
@ -162,14 +190,14 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
|
|
||||||
buttonsContainer.getChildren().setAll(btnMin, btnClose);
|
buttonsContainer.getChildren().setAll(btnMin, btnClose);
|
||||||
}
|
}
|
||||||
titleContainer.setRight(buttonsContainer);
|
titleBar.setRight(buttonsContainer);
|
||||||
}
|
}
|
||||||
root.setTop(titleContainer);
|
root.setTop(titleContainer);
|
||||||
|
|
||||||
getChildren().setAll(root);
|
getChildren().add(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node createNavBar(Decorator skinnable, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) {
|
private Node createNavBar(Decorator skinnable, boolean titleBarTransparent, double leftPaneWidth, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) {
|
||||||
BorderPane navBar = new BorderPane();
|
BorderPane navBar = new BorderPane();
|
||||||
{
|
{
|
||||||
HBox navLeft = new HBox();
|
HBox navLeft = new HBox();
|
||||||
@ -202,6 +230,13 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
if (title != null) {
|
if (title != null) {
|
||||||
Label titleLabel = new Label();
|
Label titleLabel = new Label();
|
||||||
titleLabel.getStyleClass().add("jfx-decorator-title");
|
titleLabel.getStyleClass().add("jfx-decorator-title");
|
||||||
|
if (titleBarTransparent) titleLabel.pseudoClassStateChanged(TRANSPARENT, true);
|
||||||
|
if (!canClose && !canBack) {
|
||||||
|
titleLabel.setAlignment(Pos.CENTER);
|
||||||
|
// 20: in this case width of navLeft is 10, so to make the text center aligned,
|
||||||
|
// we should have width 2 * 10 reduced
|
||||||
|
titleLabel.setPrefWidth(leftPaneWidth - 20);
|
||||||
|
}
|
||||||
titleLabel.setText(title);
|
titleLabel.setText(title);
|
||||||
center.setLeft(titleLabel);
|
center.setLeft(titleLabel);
|
||||||
BorderPane.setAlignment(titleLabel, Pos.CENTER_LEFT);
|
BorderPane.setAlignment(titleLabel, Pos.CENTER_LEFT);
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.ui.decorator;
|
package org.jackhuang.hmcl.ui.decorator;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Control;
|
import javafx.scene.control.Control;
|
||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
@ -31,10 +28,10 @@ import org.jackhuang.hmcl.ui.animation.AnimationProducer;
|
|||||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||||
import org.jackhuang.hmcl.ui.wizard.Refreshable;
|
import org.jackhuang.hmcl.ui.wizard.Refreshable;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|
||||||
|
|
||||||
public abstract class DecoratorTransitionPage extends Control implements DecoratorPage {
|
public abstract class DecoratorTransitionPage extends Control implements DecoratorPage {
|
||||||
protected final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(""));
|
protected final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(""));
|
||||||
|
private final DoubleProperty leftPaneWidth = new SimpleDoubleProperty();
|
||||||
|
private final BooleanProperty titleBarTransparent = new SimpleBooleanProperty(false);
|
||||||
private final BooleanProperty backable = new SimpleBooleanProperty(false);
|
private final BooleanProperty backable = new SimpleBooleanProperty(false);
|
||||||
private final BooleanProperty refreshable = new SimpleBooleanProperty(false);
|
private final BooleanProperty refreshable = new SimpleBooleanProperty(false);
|
||||||
private Node currentPage;
|
private Node currentPage;
|
||||||
@ -60,11 +57,11 @@ public abstract class DecoratorTransitionPage extends Control implements Decorat
|
|||||||
if (to instanceof DecoratorPage) {
|
if (to instanceof DecoratorPage) {
|
||||||
state.bind(Bindings.createObjectBinding(() -> {
|
state.bind(Bindings.createObjectBinding(() -> {
|
||||||
State state = ((DecoratorPage) to).stateProperty().get();
|
State state = ((DecoratorPage) to).stateProperty().get();
|
||||||
return new State(state.getTitle(), state.getTitleNode(), backable.get(), state.isRefreshable(), true);
|
return new State(state.getTitle(), state.getTitleNode(), backable.get(), state.isRefreshable(), true, titleBarTransparent.get(), leftPaneWidth.get());
|
||||||
}, ((DecoratorPage) to).stateProperty()));
|
}, ((DecoratorPage) to).stateProperty()));
|
||||||
} else {
|
} else {
|
||||||
state.unbind();
|
state.unbind();
|
||||||
state.set(new State("", null, backable.get(), false, true));
|
state.set(new State("", null, backable.get(), false, true, titleBarTransparent.get(), leftPaneWidth.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to instanceof Region) {
|
if (to instanceof Region) {
|
||||||
@ -112,4 +109,28 @@ public abstract class DecoratorTransitionPage extends Control implements Decorat
|
|||||||
public ReadOnlyObjectProperty<State> stateProperty() {
|
public ReadOnlyObjectProperty<State> stateProperty() {
|
||||||
return state.getReadOnlyProperty();
|
return state.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getLeftPaneWidth() {
|
||||||
|
return leftPaneWidth.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleProperty leftPaneWidthProperty() {
|
||||||
|
return leftPaneWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeftPaneWidth(double leftPaneWidth) {
|
||||||
|
this.leftPaneWidth.set(leftPaneWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTitleBarTransparent() {
|
||||||
|
return titleBarTransparent.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty titleBarTransparentProperty() {
|
||||||
|
return titleBarTransparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitleBarTransparent(boolean titleBarTransparent) {
|
||||||
|
this.titleBarTransparent.set(titleBarTransparent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.SINE;
|
|||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class MainPage extends StackPane implements DecoratorPage {
|
public final class MainPage extends StackPane implements DecoratorPage {
|
||||||
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle("Hello Minecraft! Launcher " + Metadata.VERSION));
|
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle("HMCL " + Metadata.VERSION));
|
||||||
|
|
||||||
private final PopupMenu menu = new PopupMenu();
|
private final PopupMenu menu = new PopupMenu();
|
||||||
private final JFXPopup popup = new JFXPopup(menu);
|
private final JFXPopup popup = new JFXPopup(menu);
|
||||||
|
@ -78,6 +78,8 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
private final TabHeader.Tab profileTab = new TabHeader.Tab("profile");
|
private final TabHeader.Tab profileTab = new TabHeader.Tab("profile");
|
||||||
|
|
||||||
public RootPage() {
|
public RootPage() {
|
||||||
|
setLeftPaneWidth(200);
|
||||||
|
|
||||||
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource()));
|
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource()));
|
||||||
|
|
||||||
Profile profile = Profiles.getSelectedProfile();
|
Profile profile = Profiles.getSelectedProfile();
|
||||||
@ -104,6 +106,7 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
@Override
|
@Override
|
||||||
protected void onNavigated(Node to) {
|
protected void onNavigated(Node to) {
|
||||||
backableProperty().set(!(to instanceof MainPage));
|
backableProperty().set(!(to instanceof MainPage));
|
||||||
|
setTitleBarTransparent(to instanceof MainPage);
|
||||||
|
|
||||||
super.onNavigated(to);
|
super.onNavigated(to);
|
||||||
}
|
}
|
||||||
@ -237,18 +240,8 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
|
|
||||||
// the root page, with the sidebar in left, navigator in center.
|
// the root page, with the sidebar in left, navigator in center.
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
|
sideBar.setPrefWidth(200);
|
||||||
{
|
root.setLeft(sideBar);
|
||||||
StackPane drawerContainer = new StackPane();
|
|
||||||
FXUtils.setLimitWidth(drawerContainer, 200);
|
|
||||||
drawerContainer.getStyleClass().add("gray-background");
|
|
||||||
drawerContainer.getChildren().setAll(sideBar);
|
|
||||||
FXUtils.setOverflowHidden(drawerContainer, 8);
|
|
||||||
|
|
||||||
StackPane wrapper = new StackPane(drawerContainer);
|
|
||||||
wrapper.setPadding(new Insets(4, 0, 4, 4));
|
|
||||||
root.setLeft(wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
control.transitionPane.getStyleClass().add("jfx-decorator-content-container");
|
control.transitionPane.getStyleClass().add("jfx-decorator-content-container");
|
||||||
|
@ -134,7 +134,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.two-line-list-item > .title {
|
.two-line-list-item > .title {
|
||||||
-fx-text-fill: black;
|
-fx-text-fill: #292929;
|
||||||
-fx-font-size: 15px;
|
-fx-font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,10 +153,6 @@
|
|||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-title-bar .separator {
|
|
||||||
-fx-fill: -fx-base-darker-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.darker-fill {
|
.darker-fill {
|
||||||
-fx-fill: -fx-base-darker-color;
|
-fx-fill: -fx-base-darker-color;
|
||||||
}
|
}
|
||||||
@ -373,11 +369,14 @@
|
|||||||
.jfx-tool-bar {
|
.jfx-tool-bar {
|
||||||
-fx-font-size: 13.0;
|
-fx-font-size: 13.0;
|
||||||
-fx-font-weight: BOLD;
|
-fx-font-weight: BOLD;
|
||||||
-fx-background-color: -fx-base-color;
|
|
||||||
-fx-pref-width: 100.0%;
|
-fx-pref-width: 100.0%;
|
||||||
-fx-pref-height: 32.0px;
|
-fx-pref-height: 32.0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jfx-tool-bar .background {
|
||||||
|
-fx-background-color: -fx-base-color;
|
||||||
|
}
|
||||||
|
|
||||||
.jfx-tool-bar HBox {
|
.jfx-tool-bar HBox {
|
||||||
-fx-alignment: center-left;
|
-fx-alignment: center-left;
|
||||||
-fx-padding: 0.0 5.0;
|
-fx-padding: 0.0 5.0;
|
||||||
@ -1098,6 +1097,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.jfx-decorator-drawer {
|
.jfx-decorator-drawer {
|
||||||
|
-fx-background-color: rgba(244, 244, 244, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
.jfx-decorator-title {
|
.jfx-decorator-title {
|
||||||
@ -1105,6 +1105,10 @@
|
|||||||
-fx-font-size: 14;
|
-fx-font-size: 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jfx-decorator-title:transparent {
|
||||||
|
-fx-text-fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
.jfx-decorator-tab .tab-container .tab-label {
|
.jfx-decorator-tab .tab-container .tab-label {
|
||||||
-fx-text-fill: -fx-base-disabled-text-fill;
|
-fx-text-fill: -fx-base-disabled-text-fill;
|
||||||
-fx-font-size: 14;
|
-fx-font-size: 14;
|
||||||
@ -1116,7 +1120,7 @@
|
|||||||
|
|
||||||
.resize-border {
|
.resize-border {
|
||||||
-fx-border-color: -fx-base-color;
|
-fx-border-color: -fx-base-color;
|
||||||
-fx-border-width: 0 2 2 2;
|
-fx-border-width: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.debug-border {
|
.debug-border {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user