更新至 Material Design 3 颜色系统 (#4835)
This commit is contained in:
@@ -58,6 +58,7 @@ dependencies {
|
|||||||
implementation("libs:JFoenix")
|
implementation("libs:JFoenix")
|
||||||
implementation(libs.twelvemonkeys.imageio.webp)
|
implementation(libs.twelvemonkeys.imageio.webp)
|
||||||
implementation(libs.java.info)
|
implementation(libs.java.info)
|
||||||
|
implementation(libs.monet.fx)
|
||||||
|
|
||||||
if (launcherExe.isBlank()) {
|
if (launcherExe.isBlank()) {
|
||||||
implementation(libs.hmclauncher)
|
implementation(libs.hmclauncher)
|
||||||
|
|||||||
373
HMCL/src/main/java/com/jfoenix/controls/JFXToggleButton.java
Normal file
373
HMCL/src/main/java/com/jfoenix/controls/JFXToggleButton.java
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.controls;
|
||||||
|
|
||||||
|
import com.jfoenix.skins.JFXToggleButtonSkin;
|
||||||
|
import javafx.css.*;
|
||||||
|
import javafx.css.converter.BooleanConverter;
|
||||||
|
import javafx.css.converter.PaintConverter;
|
||||||
|
import javafx.scene.control.Skin;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JFXToggleButton is the material design implementation of a toggle button.
|
||||||
|
* important CSS Selectors:
|
||||||
|
* <p>
|
||||||
|
* .jfx-toggle-button{
|
||||||
|
* -fx-toggle-color: color-value;
|
||||||
|
* -fx-untoggle-color: color-value;
|
||||||
|
* -fx-toggle-line-color: color-value;
|
||||||
|
* -fx-untoggle-line-color: color-value;
|
||||||
|
* }
|
||||||
|
* <p>
|
||||||
|
* To change the rippler color when toggled:
|
||||||
|
* <p>
|
||||||
|
* .jfx-toggle-button .jfx-rippler{
|
||||||
|
* -fx-rippler-fill: color-value;
|
||||||
|
* }
|
||||||
|
* <p>
|
||||||
|
* .jfx-toggle-button:selected .jfx-rippler{
|
||||||
|
* -fx-rippler-fill: color-value;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @author Shadi Shaheen
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2016-03-09
|
||||||
|
*/
|
||||||
|
public class JFXToggleButton extends ToggleButton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public JFXToggleButton() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Skin<?> createDefaultSkin() {
|
||||||
|
return new JFXToggleButtonSkin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
this.getStyleClass().add(DEFAULT_STYLE_CLASS);
|
||||||
|
// it's up for the user to add this behavior
|
||||||
|
// toggleColor.addListener((o, oldVal, newVal) -> {
|
||||||
|
// // update line color in case not set by the user
|
||||||
|
// if(newVal instanceof Color)
|
||||||
|
// toggleLineColor.set(((Color)newVal).desaturate().desaturate().brighter());
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* styleable Properties *
|
||||||
|
* *
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the style class to 'jfx-toggle-button'.
|
||||||
|
* <p>
|
||||||
|
* This is the selector class from which CSS can be used to style
|
||||||
|
* this control.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_STYLE_CLASS = "jfx-toggle-button";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default color used when the button is toggled
|
||||||
|
*/
|
||||||
|
private final StyleableObjectProperty<Paint> toggleColor = new SimpleStyleableObjectProperty<>(StyleableProperties.TOGGLE_COLOR,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"toggleColor",
|
||||||
|
Color.valueOf(
|
||||||
|
"#009688"));
|
||||||
|
|
||||||
|
public Paint getToggleColor() {
|
||||||
|
return toggleColor == null ? Color.valueOf("#009688") : toggleColor.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleableObjectProperty<Paint> toggleColorProperty() {
|
||||||
|
return this.toggleColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToggleColor(Paint color) {
|
||||||
|
this.toggleColor.set(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default color used when the button is not toggled
|
||||||
|
*/
|
||||||
|
private StyleableObjectProperty<Paint> untoggleColor = new SimpleStyleableObjectProperty<>(StyleableProperties.UNTOGGLE_COLOR,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"unToggleColor",
|
||||||
|
Color.valueOf(
|
||||||
|
"#FAFAFA"));
|
||||||
|
|
||||||
|
public Paint getUnToggleColor() {
|
||||||
|
return untoggleColor == null ? Color.valueOf("#FAFAFA") : untoggleColor.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleableObjectProperty<Paint> unToggleColorProperty() {
|
||||||
|
return this.untoggleColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnToggleColor(Paint color) {
|
||||||
|
this.untoggleColor.set(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default line color used when the button is toggled
|
||||||
|
*/
|
||||||
|
private final StyleableObjectProperty<Paint> toggleLineColor = new SimpleStyleableObjectProperty<>(
|
||||||
|
StyleableProperties.TOGGLE_LINE_COLOR,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"toggleLineColor",
|
||||||
|
Color.valueOf("#77C2BB"));
|
||||||
|
|
||||||
|
public Paint getToggleLineColor() {
|
||||||
|
return toggleLineColor == null ? Color.valueOf("#77C2BB") : toggleLineColor.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleableObjectProperty<Paint> toggleLineColorProperty() {
|
||||||
|
return this.toggleLineColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToggleLineColor(Paint color) {
|
||||||
|
this.toggleLineColor.set(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default line color used when the button is not toggled
|
||||||
|
*/
|
||||||
|
private final StyleableObjectProperty<Paint> untoggleLineColor = new SimpleStyleableObjectProperty<>(
|
||||||
|
StyleableProperties.UNTOGGLE_LINE_COLOR,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"unToggleLineColor",
|
||||||
|
Color.valueOf("#999999"));
|
||||||
|
|
||||||
|
public Paint getUnToggleLineColor() {
|
||||||
|
return untoggleLineColor == null ? Color.valueOf("#999999") : untoggleLineColor.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleableObjectProperty<Paint> unToggleLineColorProperty() {
|
||||||
|
return this.untoggleLineColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnToggleLineColor(Paint color) {
|
||||||
|
this.untoggleLineColor.set(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default size of the toggle button.
|
||||||
|
*/
|
||||||
|
private final StyleableDoubleProperty size = new SimpleStyleableDoubleProperty(
|
||||||
|
StyleableProperties.SIZE,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"size",
|
||||||
|
10.0);
|
||||||
|
|
||||||
|
public double getSize() {
|
||||||
|
return size.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleableDoubleProperty sizeProperty() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(double size) {
|
||||||
|
this.size.set(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the visual indicator for focus
|
||||||
|
*/
|
||||||
|
private final StyleableBooleanProperty disableVisualFocus = new SimpleStyleableBooleanProperty(StyleableProperties.DISABLE_VISUAL_FOCUS,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"disableVisualFocus",
|
||||||
|
false);
|
||||||
|
|
||||||
|
public final StyleableBooleanProperty disableVisualFocusProperty() {
|
||||||
|
return this.disableVisualFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Boolean isDisableVisualFocus() {
|
||||||
|
return disableVisualFocus != null && this.disableVisualFocusProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setDisableVisualFocus(final Boolean disabled) {
|
||||||
|
this.disableVisualFocusProperty().set(disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disable animation on button action
|
||||||
|
*/
|
||||||
|
private final StyleableBooleanProperty disableAnimation = new SimpleStyleableBooleanProperty(StyleableProperties.DISABLE_ANIMATION,
|
||||||
|
JFXToggleButton.this,
|
||||||
|
"disableAnimation",
|
||||||
|
!AnimationUtils.isAnimationEnabled());
|
||||||
|
|
||||||
|
public final StyleableBooleanProperty disableAnimationProperty() {
|
||||||
|
return this.disableAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Boolean isDisableAnimation() {
|
||||||
|
return disableAnimation != null && this.disableAnimationProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setDisableAnimation(final Boolean disabled) {
|
||||||
|
this.disableAnimationProperty().set(disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class StyleableProperties {
|
||||||
|
private static final CssMetaData<JFXToggleButton, Paint> TOGGLE_COLOR =
|
||||||
|
new CssMetaData<>("-jfx-toggle-color",
|
||||||
|
PaintConverter.getInstance(), Color.valueOf("#009688")) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.toggleColor == null || !control.toggleColor.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableProperty<Paint> getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.toggleColorProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final CssMetaData<JFXToggleButton, Paint> UNTOGGLE_COLOR =
|
||||||
|
new CssMetaData<>("-jfx-untoggle-color",
|
||||||
|
PaintConverter.getInstance(), Color.valueOf("#FAFAFA")) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.untoggleColor == null || !control.untoggleColor.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableProperty<Paint> getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.unToggleColorProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final CssMetaData<JFXToggleButton, Paint> TOGGLE_LINE_COLOR =
|
||||||
|
new CssMetaData<>("-jfx-toggle-line-color",
|
||||||
|
PaintConverter.getInstance(), Color.valueOf("#77C2BB")) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.toggleLineColor == null || !control.toggleLineColor.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableProperty<Paint> getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.toggleLineColorProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final CssMetaData<JFXToggleButton, Paint> UNTOGGLE_LINE_COLOR =
|
||||||
|
new CssMetaData<>("-jfx-untoggle-line-color",
|
||||||
|
PaintConverter.getInstance(), Color.valueOf("#999999")) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.untoggleLineColor == null || !control.untoggleLineColor.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableProperty<Paint> getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.unToggleLineColorProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final CssMetaData<JFXToggleButton, Number> SIZE =
|
||||||
|
new CssMetaData<>("-jfx-size",
|
||||||
|
StyleConverter.getSizeConverter(), 10.0) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return !control.size.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableProperty<Number> getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.sizeProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final CssMetaData<JFXToggleButton, Boolean> DISABLE_VISUAL_FOCUS =
|
||||||
|
new CssMetaData<>("-jfx-disable-visual-focus",
|
||||||
|
BooleanConverter.getInstance(), false) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.disableVisualFocus == null || !control.disableVisualFocus.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableBooleanProperty getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.disableVisualFocusProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final CssMetaData<JFXToggleButton, Boolean> DISABLE_ANIMATION =
|
||||||
|
new CssMetaData<>("-jfx-disable-animation",
|
||||||
|
BooleanConverter.getInstance(), false) {
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(JFXToggleButton control) {
|
||||||
|
return control.disableAnimation == null || !control.disableAnimation.isBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyleableBooleanProperty getStyleableProperty(JFXToggleButton control) {
|
||||||
|
return control.disableAnimationProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final List<CssMetaData<? extends Styleable, ?>> CHILD_STYLEABLES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final List<CssMetaData<? extends Styleable, ?>> styleables =
|
||||||
|
new ArrayList<>(ToggleButton.getClassCssMetaData());
|
||||||
|
Collections.addAll(styleables,
|
||||||
|
SIZE,
|
||||||
|
TOGGLE_COLOR,
|
||||||
|
UNTOGGLE_COLOR,
|
||||||
|
TOGGLE_LINE_COLOR,
|
||||||
|
UNTOGGLE_LINE_COLOR,
|
||||||
|
DISABLE_VISUAL_FOCUS,
|
||||||
|
DISABLE_ANIMATION
|
||||||
|
);
|
||||||
|
CHILD_STYLEABLES = Collections.unmodifiableList(styleables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
|
||||||
|
return getClassCssMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
|
||||||
|
return StyleableProperties.CHILD_STYLEABLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,9 +32,9 @@ import javafx.scene.layout.BorderWidths;
|
|||||||
import javafx.scene.layout.CornerRadii;
|
import javafx.scene.layout.CornerRadii;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.shape.SVGPath;
|
import javafx.scene.shape.SVGPath;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
|
|
||||||
public class JFXCheckBoxSkin extends CheckBoxSkin {
|
public class JFXCheckBoxSkin extends CheckBoxSkin {
|
||||||
private final StackPane box = new StackPane();
|
private final StackPane box = new StackPane();
|
||||||
@@ -54,7 +54,7 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
|
|||||||
this.box.setPrefSize(18.0, 18.0);
|
this.box.setPrefSize(18.0, 18.0);
|
||||||
this.box.setMaxSize(18.0, 18.0);
|
this.box.setMaxSize(18.0, 18.0);
|
||||||
this.box.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, new CornerRadii(2.0), Insets.EMPTY)));
|
this.box.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, new CornerRadii(2.0), Insets.EMPTY)));
|
||||||
this.box.setBorder(new Border(new BorderStroke(control.getUnCheckedColor(), BorderStrokeStyle.SOLID, new CornerRadii(2.0), new BorderWidths(this.lineThick))));
|
this.box.setBorder(new Border(new BorderStroke(Themes.getColorScheme().getOnSurfaceVariant(), BorderStrokeStyle.SOLID, new CornerRadii(2.0), new BorderWidths(this.lineThick))));
|
||||||
StackPane boxContainer = new StackPane();
|
StackPane boxContainer = new StackPane();
|
||||||
boxContainer.getChildren().add(this.box);
|
boxContainer.getChildren().add(this.box);
|
||||||
boxContainer.setPadding(new Insets(this.padding));
|
boxContainer.setPadding(new Insets(this.padding));
|
||||||
@@ -64,7 +64,7 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
|
|||||||
shape.setContent("M384 690l452-452 60 60-512 512-238-238 60-60z");
|
shape.setContent("M384 690l452-452 60 60-512 512-238-238 60-60z");
|
||||||
this.mark.setShape(shape);
|
this.mark.setShape(shape);
|
||||||
this.mark.setMaxSize(15.0, 12.0);
|
this.mark.setMaxSize(15.0, 12.0);
|
||||||
this.mark.setStyle("-fx-background-color:WHITE; -fx-border-color:WHITE; -fx-border-width:2px;");
|
this.mark.setStyle("-fx-background-color:-monet-on-primary; -fx-border-color:-monet-on-primary; -fx-border-width:2px;");
|
||||||
this.mark.setVisible(false);
|
this.mark.setVisible(false);
|
||||||
this.mark.setScaleX(0.0);
|
this.mark.setScaleX(0.0);
|
||||||
this.mark.setScaleY(0.0);
|
this.mark.setScaleY(0.0);
|
||||||
@@ -107,13 +107,12 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
|
|||||||
|
|
||||||
private void updateColors() {
|
private void updateColors() {
|
||||||
var control = (JFXCheckBox) getSkinnable();
|
var control = (JFXCheckBox) getSkinnable();
|
||||||
final Paint color = control.isSelected()
|
boolean isSelected = control.isSelected();
|
||||||
? control.getCheckedColor()
|
JFXNodeUtils.updateBackground(box.getBackground(), box, isSelected ? control.getCheckedColor() : Color.TRANSPARENT);
|
||||||
: control.getUnCheckedColor();
|
rippler.setRipplerFill(isSelected ? control.getCheckedColor() : control.getUnCheckedColor());
|
||||||
JFXNodeUtils.updateBackground(box.getBackground(), box, control.isSelected() ? control.getCheckedColor() : Color.TRANSPARENT);
|
|
||||||
rippler.setRipplerFill(color);
|
|
||||||
final BorderStroke borderStroke = box.getBorder().getStrokes().get(0);
|
final BorderStroke borderStroke = box.getBorder().getStrokes().get(0);
|
||||||
box.setBorder(new Border(new BorderStroke(color,
|
box.setBorder(new Border(new BorderStroke(
|
||||||
|
isSelected ? control.getCheckedColor() : Themes.getColorScheme().getOnSurfaceVariant(),
|
||||||
borderStroke.getTopStyle(),
|
borderStroke.getTopStyle(),
|
||||||
borderStroke.getRadii(),
|
borderStroke.getRadii(),
|
||||||
borderStroke.getWidths())));
|
borderStroke.getWidths())));
|
||||||
@@ -185,7 +184,11 @@ public class JFXCheckBoxSkin extends CheckBoxSkin {
|
|||||||
this.select.setRate(selection ? 1.0 : -1.0);
|
this.select.setRate(selection ? 1.0 : -1.0);
|
||||||
this.transition.play();
|
this.transition.play();
|
||||||
this.select.play();
|
this.select.play();
|
||||||
this.box.setBorder(new Border(new BorderStroke(selection ? control.getCheckedColor() : control.getUnCheckedColor(), BorderStrokeStyle.SOLID, new CornerRadii(2.0), new BorderWidths(this.lineThick))));
|
this.box.setBorder(new Border(new BorderStroke(
|
||||||
|
selection ? control.getCheckedColor() : Themes.getColorScheme().getOnSurfaceVariant(),
|
||||||
|
BorderStrokeStyle.SOLID,
|
||||||
|
new CornerRadii(2.0),
|
||||||
|
new BorderWidths(this.lineThick))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createFillTransition() {
|
private void createFillTransition() {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javafx.collections.ObservableList;
|
|||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.Event;
|
import javafx.event.Event;
|
||||||
import javafx.geometry.Bounds;
|
import javafx.geometry.Bounds;
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.NodeOrientation;
|
import javafx.geometry.NodeOrientation;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@@ -116,11 +115,6 @@ final class JFXColorPalette extends Region {
|
|||||||
colorPicker.getCustomColors().addListener((Change<? extends Color> change) -> buildCustomColors());
|
colorPicker.getCustomColors().addListener((Change<? extends Color> change) -> buildCustomColors());
|
||||||
VBox paletteBox = new VBox();
|
VBox paletteBox = new VBox();
|
||||||
paletteBox.getStyleClass().add("color-palette");
|
paletteBox.getStyleClass().add("color-palette");
|
||||||
paletteBox.setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY)));
|
|
||||||
paletteBox.setBorder(new Border(new BorderStroke(Color.valueOf("#9E9E9E"),
|
|
||||||
BorderStrokeStyle.SOLID,
|
|
||||||
CornerRadii.EMPTY,
|
|
||||||
BorderWidths.DEFAULT)));
|
|
||||||
paletteBox.getChildren().addAll(colorPickerGrid);
|
paletteBox.getChildren().addAll(colorPickerGrid);
|
||||||
if (colorPicker.getPreDefinedColors() == null) {
|
if (colorPicker.getPreDefinedColors() == null) {
|
||||||
paletteBox.getChildren().addAll(customColorLabel, customColorGrid, customColorLink);
|
paletteBox.getChildren().addAll(customColorLabel, customColorGrid, customColorLink);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import javafx.scene.layout.*;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.*;
|
import javafx.stage.*;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.jackhuang.hmcl.setting.StyleSheets;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@@ -48,8 +49,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
* @author Shadi Shaheen
|
* @author Shadi Shaheen
|
||||||
*/
|
*/
|
||||||
public class JFXCustomColorPickerDialog extends StackPane {
|
public class JFXCustomColorPickerDialog extends StackPane {
|
||||||
|
|
||||||
public static final String rgbFieldStyle = "-fx-background-color:TRANSPARENT;-fx-font-weight: BOLD;-fx-prompt-text-fill: #808080; -fx-alignment: top-left ; -fx-max-width: 300;";
|
|
||||||
private final Stage dialog = new Stage();
|
private final Stage dialog = new Stage();
|
||||||
// used for concurrency control and preventing FX-thread over use
|
// used for concurrency control and preventing FX-thread over use
|
||||||
private final AtomicInteger concurrencyController = new AtomicInteger(-1);
|
private final AtomicInteger concurrencyController = new AtomicInteger(-1);
|
||||||
@@ -81,15 +80,7 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
|||||||
pickerDecorator.setOnCloseButtonAction(this::updateColor);
|
pickerDecorator.setOnCloseButtonAction(this::updateColor);
|
||||||
pickerDecorator.setPickOnBounds(false);
|
pickerDecorator.setPickOnBounds(false);
|
||||||
customScene = new Scene(pickerDecorator, Color.TRANSPARENT);
|
customScene = new Scene(pickerDecorator, Color.TRANSPARENT);
|
||||||
if (owner != null) {
|
StyleSheets.init(customScene);
|
||||||
final Scene ownerScene = owner.getScene();
|
|
||||||
if (ownerScene != null) {
|
|
||||||
if (ownerScene.getUserAgentStylesheet() != null) {
|
|
||||||
customScene.setUserAgentStylesheet(ownerScene.getUserAgentStylesheet());
|
|
||||||
}
|
|
||||||
customScene.getStylesheets().addAll(ownerScene.getStylesheets());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
curvedColorPicker = new JFXCustomColorPicker();
|
curvedColorPicker = new JFXCustomColorPicker();
|
||||||
|
|
||||||
StackPane pane = new StackPane(curvedColorPicker);
|
StackPane pane = new StackPane(curvedColorPicker);
|
||||||
@@ -104,17 +95,15 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
|||||||
JFXTextField hsbField = new JFXTextField();
|
JFXTextField hsbField = new JFXTextField();
|
||||||
JFXTextField hexField = new JFXTextField();
|
JFXTextField hexField = new JFXTextField();
|
||||||
|
|
||||||
rgbField.setStyle(rgbFieldStyle);
|
rgbField.getStyleClass().add("custom-color-field");
|
||||||
rgbField.setPromptText("RGB Color");
|
rgbField.setPromptText("RGB Color");
|
||||||
rgbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
rgbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
hsbField.setStyle(
|
hsbField.getStyleClass().add("custom-color-field");
|
||||||
"-fx-background-color:TRANSPARENT;-fx-font-weight: BOLD;-fx-prompt-text-fill: #808080; -fx-alignment: top-left ; -fx-max-width: 300;");
|
|
||||||
hsbField.setPromptText("HSB Color");
|
hsbField.setPromptText("HSB Color");
|
||||||
hsbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
hsbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
hexField.setStyle(
|
hexField.getStyleClass().add("custom-color-field");
|
||||||
"-fx-background-color:TRANSPARENT;-fx-font-weight: BOLD;-fx-prompt-text-fill: #808080; -fx-alignment: top-left ; -fx-max-width: 300;");
|
|
||||||
hexField.setPromptText("#HEX Color");
|
hexField.setPromptText("#HEX Color");
|
||||||
hexField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
hexField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import javafx.scene.paint.Color;
|
|||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||||
|
|
||||||
public class JFXRadioButtonSkin extends RadioButtonSkin {
|
public class JFXRadioButtonSkin extends RadioButtonSkin {
|
||||||
private static final double PADDING = 15.0;
|
private static final double PADDING = 15.0;
|
||||||
@@ -68,37 +69,10 @@ public class JFXRadioButtonSkin extends RadioButtonSkin {
|
|||||||
|
|
||||||
});
|
});
|
||||||
control.pressedProperty().addListener((o, oldVal, newVal) -> this.rippler.hideOverlay());
|
control.pressedProperty().addListener((o, oldVal, newVal) -> this.rippler.hideOverlay());
|
||||||
this.registerChangeListener(control.selectedColorProperty(), ignored -> {
|
this.registerChangeListener(control.selectedColorProperty(), ignored -> updateColors());
|
||||||
this.updateAnimation();
|
this.registerChangeListener(control.unSelectedColorProperty(), ignored -> updateColors());
|
||||||
boolean isSelected = this.getSkinnable().isSelected();
|
|
||||||
Color unSelectedColor = ((JFXRadioButton) this.getSkinnable()).getUnSelectedColor();
|
|
||||||
Color selectedColor = ((JFXRadioButton) this.getSkinnable()).getSelectedColor();
|
|
||||||
this.rippler.setRipplerFill(isSelected ? selectedColor : unSelectedColor);
|
|
||||||
if (isSelected) {
|
|
||||||
this.radio.strokeProperty().set(selectedColor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.registerChangeListener(control.unSelectedColorProperty(), ignored -> {
|
|
||||||
this.updateAnimation();
|
|
||||||
boolean isSelected = this.getSkinnable().isSelected();
|
|
||||||
Color unSelectedColor = ((JFXRadioButton) this.getSkinnable()).getUnSelectedColor();
|
|
||||||
Color selectedColor = ((JFXRadioButton) this.getSkinnable()).getSelectedColor();
|
|
||||||
this.rippler.setRipplerFill(isSelected ? selectedColor : unSelectedColor);
|
|
||||||
if (!isSelected) {
|
|
||||||
this.radio.strokeProperty().set(unSelectedColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
this.registerChangeListener(control.selectedProperty(), ignored -> {
|
this.registerChangeListener(control.selectedProperty(), ignored -> {
|
||||||
boolean isSelected = this.getSkinnable().isSelected();
|
updateColors();
|
||||||
Color unSelectedColor = ((JFXRadioButton) this.getSkinnable()).getUnSelectedColor();
|
|
||||||
Color selectedColor = ((JFXRadioButton) this.getSkinnable()).getSelectedColor();
|
|
||||||
this.rippler.setRipplerFill(isSelected ? selectedColor : unSelectedColor);
|
|
||||||
if (this.timeline == null) {
|
|
||||||
this.updateAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.playAnimation();
|
this.playAnimation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -133,38 +107,46 @@ public class JFXRadioButtonSkin extends RadioButtonSkin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeComponents() {
|
private void initializeComponents() {
|
||||||
Color unSelectedColor = ((JFXRadioButton) this.getSkinnable()).getUnSelectedColor();
|
this.updateColors();
|
||||||
Color selectedColor = ((JFXRadioButton) this.getSkinnable()).getSelectedColor();
|
|
||||||
this.radio.setStroke(unSelectedColor);
|
|
||||||
this.rippler.setRipplerFill(this.getSkinnable().isSelected() ? selectedColor : unSelectedColor);
|
|
||||||
this.updateAnimation();
|
|
||||||
this.playAnimation();
|
this.playAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playAnimation() {
|
private void playAnimation() {
|
||||||
this.timeline.setRate(this.getSkinnable().isSelected() ? 1.0 : -1.0);
|
if (AnimationUtils.isAnimationEnabled()) {
|
||||||
this.timeline.play();
|
if (this.timeline == null) {
|
||||||
}
|
this.timeline = new Timeline(
|
||||||
|
new KeyFrame(Duration.ZERO,
|
||||||
private void updateAnimation() {
|
new KeyValue(this.dot.scaleXProperty(), 0, Interpolator.EASE_BOTH),
|
||||||
Color unSelectedColor = ((JFXRadioButton) this.getSkinnable()).getUnSelectedColor();
|
new KeyValue(this.dot.scaleYProperty(), 0, Interpolator.EASE_BOTH)),
|
||||||
Color selectedColor = ((JFXRadioButton) this.getSkinnable()).getSelectedColor();
|
new KeyFrame(Duration.millis(200.0),
|
||||||
this.timeline = new Timeline(
|
new KeyValue(this.dot.scaleXProperty(), 1, Interpolator.EASE_BOTH),
|
||||||
new KeyFrame(Duration.ZERO,
|
new KeyValue(this.dot.scaleYProperty(), 1, Interpolator.EASE_BOTH))
|
||||||
new KeyValue(this.dot.scaleXProperty(), 0, Interpolator.EASE_BOTH),
|
);
|
||||||
new KeyValue(this.dot.scaleYProperty(), 0, Interpolator.EASE_BOTH),
|
} else {
|
||||||
new KeyValue(this.radio.strokeProperty(), unSelectedColor, Interpolator.EASE_BOTH)),
|
this.timeline.stop();
|
||||||
new KeyFrame(Duration.millis(200.0),
|
}
|
||||||
new KeyValue(this.dot.scaleXProperty(), 1, Interpolator.EASE_BOTH),
|
this.timeline.setRate(this.getSkinnable().isSelected() ? 1.0 : -1.0);
|
||||||
new KeyValue(this.dot.scaleYProperty(), 1, Interpolator.EASE_BOTH),
|
this.timeline.play();
|
||||||
new KeyValue(this.radio.strokeProperty(), selectedColor, Interpolator.EASE_BOTH))
|
} else {
|
||||||
);
|
double endScale = this.getSkinnable().isSelected() ? 1.0 : 0.0;
|
||||||
|
this.dot.setScaleX(endScale);
|
||||||
|
this.dot.setScaleY(endScale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRadio() {
|
private void removeRadio() {
|
||||||
this.getChildren().removeIf(node -> "radio".equals(node.getStyleClass().get(0)));
|
this.getChildren().removeIf(node -> "radio".equals(node.getStyleClass().get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateColors() {
|
||||||
|
var control = (JFXRadioButton) getSkinnable();
|
||||||
|
boolean isSelected = control.isSelected();
|
||||||
|
Color unSelectedColor = control.getUnSelectedColor();
|
||||||
|
Color selectedColor = control.getSelectedColor();
|
||||||
|
rippler.setRipplerFill(isSelected ? selectedColor : unSelectedColor);
|
||||||
|
radio.setStroke(isSelected ? selectedColor : unSelectedColor);
|
||||||
|
}
|
||||||
|
|
||||||
protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
|
protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
|
||||||
return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset) + this.snapSizeX(this.radio.minWidth(-1.0)) + this.labelOffset + 2.0 * PADDING;
|
return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset) + this.snapSizeX(this.radio.minWidth(-1.0)) + this.labelOffset + 2.0 * PADDING;
|
||||||
}
|
}
|
||||||
|
|||||||
186
HMCL/src/main/java/com/jfoenix/skins/JFXToggleButtonSkin.java
Normal file
186
HMCL/src/main/java/com/jfoenix/skins/JFXToggleButtonSkin.java
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.skins;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXRippler;
|
||||||
|
import com.jfoenix.controls.JFXRippler.RipplerMask;
|
||||||
|
import com.jfoenix.controls.JFXRippler.RipplerPos;
|
||||||
|
import com.jfoenix.controls.JFXToggleButton;
|
||||||
|
import com.jfoenix.effects.JFXDepthManager;
|
||||||
|
import com.jfoenix.transitions.JFXAnimationTimer;
|
||||||
|
import com.jfoenix.transitions.JFXKeyFrame;
|
||||||
|
import com.jfoenix.transitions.JFXKeyValue;
|
||||||
|
import javafx.animation.Interpolator;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.control.skin.ToggleButtonSkin;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
|
import javafx.scene.shape.StrokeLineCap;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>Material Design ToggleButton Skin</h1>
|
||||||
|
*
|
||||||
|
* @author Shadi Shaheen
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2016-03-09
|
||||||
|
*/
|
||||||
|
public class JFXToggleButtonSkin extends ToggleButtonSkin {
|
||||||
|
|
||||||
|
|
||||||
|
private Runnable releaseManualRippler = null;
|
||||||
|
|
||||||
|
private JFXAnimationTimer timer;
|
||||||
|
private final Circle circle;
|
||||||
|
private final Line line;
|
||||||
|
|
||||||
|
public JFXToggleButtonSkin(JFXToggleButton toggleButton) {
|
||||||
|
super(toggleButton);
|
||||||
|
|
||||||
|
double circleRadius = toggleButton.getSize();
|
||||||
|
|
||||||
|
line = new Line();
|
||||||
|
line.setStroke(getSkinnable().isSelected() ? toggleButton.getToggleLineColor() : toggleButton.getUnToggleLineColor());
|
||||||
|
line.setStartX(0);
|
||||||
|
line.setStartY(0);
|
||||||
|
line.setEndX(circleRadius * 2 + 2);
|
||||||
|
line.setEndY(0);
|
||||||
|
line.setStrokeWidth(circleRadius * 1.5);
|
||||||
|
line.setStrokeLineCap(StrokeLineCap.ROUND);
|
||||||
|
line.setSmooth(true);
|
||||||
|
|
||||||
|
circle = new Circle();
|
||||||
|
circle.setFill(getSkinnable().isSelected() ? toggleButton.getToggleColor() : toggleButton.getUnToggleColor());
|
||||||
|
circle.setCenterX(-circleRadius);
|
||||||
|
circle.setCenterY(0);
|
||||||
|
circle.setRadius(circleRadius);
|
||||||
|
circle.setSmooth(true);
|
||||||
|
JFXDepthManager.setDepth(circle, 1);
|
||||||
|
|
||||||
|
StackPane circlePane = new StackPane();
|
||||||
|
circlePane.getChildren().add(circle);
|
||||||
|
circlePane.setPadding(new Insets(circleRadius * 1.5));
|
||||||
|
|
||||||
|
JFXRippler rippler = new JFXRippler(circlePane, RipplerMask.CIRCLE, RipplerPos.BACK);
|
||||||
|
rippler.setRipplerFill(getSkinnable().isSelected() ? toggleButton.getToggleLineColor() : toggleButton.getUnToggleLineColor());
|
||||||
|
rippler.setTranslateX(computeTranslation(circleRadius, line));
|
||||||
|
|
||||||
|
final StackPane main = new StackPane();
|
||||||
|
main.getChildren().setAll(line, rippler);
|
||||||
|
main.setCursor(Cursor.HAND);
|
||||||
|
|
||||||
|
// show focus traversal effect
|
||||||
|
getSkinnable().armedProperty().addListener((o, oldVal, newVal) -> {
|
||||||
|
if (newVal) {
|
||||||
|
releaseManualRippler = rippler.createManualRipple();
|
||||||
|
} else if (releaseManualRippler != null) {
|
||||||
|
releaseManualRippler.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleButton.focusedProperty().addListener((o, oldVal, newVal) -> {
|
||||||
|
if (!toggleButton.isDisableVisualFocus()) {
|
||||||
|
if (newVal) {
|
||||||
|
if (!getSkinnable().isPressed()) {
|
||||||
|
rippler.setOverlayVisible(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rippler.setOverlayVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleButton.pressedProperty().addListener(observable -> rippler.setOverlayVisible(false));
|
||||||
|
|
||||||
|
// add change listener to selected property
|
||||||
|
getSkinnable().selectedProperty().addListener(observable -> {
|
||||||
|
rippler.setRipplerFill(toggleButton.isSelected() ? toggleButton.getToggleLineColor() : toggleButton.getUnToggleLineColor());
|
||||||
|
if (!toggleButton.isDisableAnimation()) {
|
||||||
|
timer.reverseAndContinue();
|
||||||
|
} else {
|
||||||
|
rippler.setTranslateX(computeTranslation(circleRadius, line));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getSkinnable().setGraphic(main);
|
||||||
|
|
||||||
|
timer = new JFXAnimationTimer(
|
||||||
|
new JFXKeyFrame(Duration.millis(100),
|
||||||
|
JFXKeyValue.builder()
|
||||||
|
.setTarget(rippler.translateXProperty())
|
||||||
|
.setEndValueSupplier(() -> computeTranslation(circleRadius, line))
|
||||||
|
.setInterpolator(Interpolator.EASE_BOTH)
|
||||||
|
.setAnimateCondition(() -> !((JFXToggleButton) getSkinnable()).isDisableAnimation())
|
||||||
|
.build(),
|
||||||
|
|
||||||
|
JFXKeyValue.builder()
|
||||||
|
.setTarget(line.strokeProperty())
|
||||||
|
.setEndValueSupplier(() -> getSkinnable().isSelected() ?
|
||||||
|
((JFXToggleButton) getSkinnable()).getToggleLineColor()
|
||||||
|
: ((JFXToggleButton) getSkinnable()).getUnToggleLineColor())
|
||||||
|
.setInterpolator(Interpolator.EASE_BOTH)
|
||||||
|
.setAnimateCondition(() -> !((JFXToggleButton) getSkinnable()).isDisableAnimation())
|
||||||
|
.build(),
|
||||||
|
|
||||||
|
JFXKeyValue.builder()
|
||||||
|
.setTarget(circle.fillProperty())
|
||||||
|
.setEndValueSupplier(() -> getSkinnable().isSelected() ?
|
||||||
|
((JFXToggleButton) getSkinnable()).getToggleColor()
|
||||||
|
: ((JFXToggleButton) getSkinnable()).getUnToggleColor())
|
||||||
|
.setInterpolator(Interpolator.EASE_BOTH)
|
||||||
|
.setAnimateCondition(() -> !((JFXToggleButton) getSkinnable()).isDisableAnimation())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
timer.setCacheNodes(circle, line);
|
||||||
|
|
||||||
|
registerChangeListener(toggleButton.toggleColorProperty(), observableValue -> {
|
||||||
|
if (getSkinnable().isSelected()) {
|
||||||
|
circle.setFill(((JFXToggleButton) getSkinnable()).getToggleColor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
registerChangeListener(toggleButton.unToggleColorProperty(), observableValue -> {
|
||||||
|
if (!getSkinnable().isSelected()) {
|
||||||
|
circle.setFill(((JFXToggleButton) getSkinnable()).getUnToggleColor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
registerChangeListener(toggleButton.toggleLineColorProperty(), observableValue -> {
|
||||||
|
if (getSkinnable().isSelected()) {
|
||||||
|
line.setStroke(((JFXToggleButton) getSkinnable()).getToggleLineColor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
registerChangeListener(toggleButton.unToggleColorProperty(), observableValue -> {
|
||||||
|
if (!getSkinnable().isSelected()) {
|
||||||
|
line.setStroke(((JFXToggleButton) getSkinnable()).getUnToggleLineColor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeTranslation(double circleRadius, Line line) {
|
||||||
|
return (getSkinnable().isSelected() ? 1 : -1) * ((line.getLayoutBounds().getWidth() / 2) - circleRadius + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
timer.dispose();
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
HMCL/src/main/java/com/jfoenix/transitions/CacheMemento.java
Normal file
68
HMCL/src/main/java/com/jfoenix/transitions/CacheMemento.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.transitions;
|
||||||
|
|
||||||
|
import javafx.scene.CacheHint;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public final class CacheMemento {
|
||||||
|
private boolean cache;
|
||||||
|
private boolean cacheShape;
|
||||||
|
private boolean snapToPixel;
|
||||||
|
private CacheHint cacheHint = CacheHint.DEFAULT;
|
||||||
|
private final Node node;
|
||||||
|
private final AtomicBoolean isCached = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public CacheMemento(Node node) {
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method will cache the node only if it wasn't cached before
|
||||||
|
*/
|
||||||
|
public void cache() {
|
||||||
|
if (!isCached.getAndSet(true)) {
|
||||||
|
this.cache = node.isCache();
|
||||||
|
this.cacheHint = node.getCacheHint();
|
||||||
|
node.setCache(true);
|
||||||
|
node.setCacheHint(CacheHint.SPEED);
|
||||||
|
if (node instanceof Region region) {
|
||||||
|
this.cacheShape = region.isCacheShape();
|
||||||
|
this.snapToPixel = region.isSnapToPixel();
|
||||||
|
region.setCacheShape(true);
|
||||||
|
region.setSnapToPixel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restore() {
|
||||||
|
if (isCached.getAndSet(false)) {
|
||||||
|
node.setCache(cache);
|
||||||
|
node.setCacheHint(cacheHint);
|
||||||
|
if (node instanceof Region region) {
|
||||||
|
region.setCacheShape(cacheShape);
|
||||||
|
region.setSnapToPixel(snapToPixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.transitions;
|
||||||
|
|
||||||
|
import javafx.animation.AnimationTimer;
|
||||||
|
import javafx.beans.value.WritableValue;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom AnimationTimer that can be created the same way as a timeline,
|
||||||
|
* however it doesn't behave the same yet. it only animates in one direction,
|
||||||
|
* it doesn't support animation 0 -> 1 -> 0.5
|
||||||
|
*
|
||||||
|
* @author Shadi Shaheen
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2017-09-21
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class JFXAnimationTimer extends AnimationTimer {
|
||||||
|
|
||||||
|
private Set<AnimationHandler> animationHandlers = new HashSet<>();
|
||||||
|
private long startTime = -1;
|
||||||
|
private boolean running = false;
|
||||||
|
private List<CacheMemento> caches = new ArrayList<>();
|
||||||
|
private double totalElapsedMilliseconds;
|
||||||
|
|
||||||
|
public JFXAnimationTimer(JFXKeyFrame... keyFrames) {
|
||||||
|
for (JFXKeyFrame keyFrame : keyFrames) {
|
||||||
|
Duration duration = keyFrame.getDuration();
|
||||||
|
final Set<JFXKeyValue<?>> keyValuesSet = keyFrame.getValues();
|
||||||
|
if (!keyValuesSet.isEmpty()) {
|
||||||
|
animationHandlers.add(new AnimationHandler(duration, keyFrame.getAnimateCondition(), keyFrame.getValues()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HashMap<JFXKeyFrame, AnimationHandler> mutableFrames = new HashMap<>();
|
||||||
|
|
||||||
|
public void addKeyFrame(JFXKeyFrame keyFrame) throws Exception {
|
||||||
|
if (isRunning()) {
|
||||||
|
throw new Exception("Can't update animation timer while running");
|
||||||
|
}
|
||||||
|
Duration duration = keyFrame.getDuration();
|
||||||
|
final Set<JFXKeyValue<?>> keyValuesSet = keyFrame.getValues();
|
||||||
|
if (!keyValuesSet.isEmpty()) {
|
||||||
|
final AnimationHandler handler = new AnimationHandler(duration, keyFrame.getAnimateCondition(), keyFrame.getValues());
|
||||||
|
animationHandlers.add(handler);
|
||||||
|
mutableFrames.put(keyFrame, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeKeyFrame(JFXKeyFrame keyFrame) throws Exception {
|
||||||
|
if (isRunning()) {
|
||||||
|
throw new Exception("Can't update animation timer while running");
|
||||||
|
}
|
||||||
|
AnimationHandler handler = mutableFrames.get(keyFrame);
|
||||||
|
animationHandlers.remove(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
running = true;
|
||||||
|
startTime = -1;
|
||||||
|
for (AnimationHandler animationHandler : animationHandlers) {
|
||||||
|
animationHandler.init();
|
||||||
|
}
|
||||||
|
for (CacheMemento cache : caches) {
|
||||||
|
cache.cache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(long now) {
|
||||||
|
startTime = startTime == -1 ? now : startTime;
|
||||||
|
totalElapsedMilliseconds = (now - startTime) / 1000000.0;
|
||||||
|
boolean stop = true;
|
||||||
|
for (AnimationHandler handler : animationHandlers) {
|
||||||
|
handler.animate(totalElapsedMilliseconds);
|
||||||
|
if (!handler.finished) {
|
||||||
|
stop = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stop) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method will pause the timer and reverse the animation if the timer already
|
||||||
|
* started otherwise it will start the animation.
|
||||||
|
*/
|
||||||
|
public void reverseAndContinue() {
|
||||||
|
if (isRunning()) {
|
||||||
|
super.stop();
|
||||||
|
for (AnimationHandler handler : animationHandlers) {
|
||||||
|
handler.reverse(totalElapsedMilliseconds);
|
||||||
|
}
|
||||||
|
startTime = -1;
|
||||||
|
super.start();
|
||||||
|
} else {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
super.stop();
|
||||||
|
running = false;
|
||||||
|
for (AnimationHandler handler : animationHandlers) {
|
||||||
|
handler.clear();
|
||||||
|
}
|
||||||
|
for (CacheMemento cache : caches) {
|
||||||
|
cache.restore();
|
||||||
|
}
|
||||||
|
if (onFinished != null) {
|
||||||
|
onFinished.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyEndValues() {
|
||||||
|
if (isRunning()) {
|
||||||
|
super.stop();
|
||||||
|
}
|
||||||
|
for (AnimationHandler handler : animationHandlers) {
|
||||||
|
handler.applyEndValues();
|
||||||
|
}
|
||||||
|
startTime = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable onFinished = null;
|
||||||
|
|
||||||
|
public void setOnFinished(Runnable onFinished) {
|
||||||
|
this.onFinished = onFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheNodes(Node... nodesToCache) {
|
||||||
|
caches.clear();
|
||||||
|
if (nodesToCache != null) {
|
||||||
|
for (Node node : nodesToCache) {
|
||||||
|
caches.add(new CacheMemento(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
caches.clear();
|
||||||
|
for (AnimationHandler handler : animationHandlers) {
|
||||||
|
handler.dispose();
|
||||||
|
}
|
||||||
|
animationHandlers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AnimationHandler {
|
||||||
|
private final double duration;
|
||||||
|
private double currentDuration;
|
||||||
|
private final Set<JFXKeyValue<?>> keyValues;
|
||||||
|
private Supplier<Boolean> animationCondition = null;
|
||||||
|
private boolean finished = false;
|
||||||
|
|
||||||
|
private final HashMap<WritableValue<?>, Object> initialValuesMap = new HashMap<>();
|
||||||
|
private final HashMap<WritableValue<?>, Object> endValuesMap = new HashMap<>();
|
||||||
|
|
||||||
|
AnimationHandler(Duration duration, Supplier<Boolean> animationCondition, Set<JFXKeyValue<?>> keyValues) {
|
||||||
|
this.duration = duration.toMillis();
|
||||||
|
currentDuration = this.duration;
|
||||||
|
this.keyValues = keyValues;
|
||||||
|
this.animationCondition = animationCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
finished = animationCondition != null && !animationCondition.get();
|
||||||
|
for (JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue.getTarget() != null) {
|
||||||
|
// replaced putIfAbsent for mobile compatibility
|
||||||
|
if (!initialValuesMap.containsKey(keyValue.getTarget())) {
|
||||||
|
initialValuesMap.put(keyValue.getTarget(), keyValue.getTarget().getValue());
|
||||||
|
}
|
||||||
|
if (!endValuesMap.containsKey(keyValue.getTarget())) {
|
||||||
|
endValuesMap.put(keyValue.getTarget(), keyValue.getEndValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(double now) {
|
||||||
|
finished = animationCondition != null && !animationCondition.get();
|
||||||
|
currentDuration = duration - (currentDuration - now);
|
||||||
|
// update initial values
|
||||||
|
for (JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
final WritableValue<?> target = keyValue.getTarget();
|
||||||
|
if (target != null) {
|
||||||
|
initialValuesMap.put(target, target.getValue());
|
||||||
|
endValuesMap.put(target, keyValue.getEndValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now in milliseconds
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public void animate(double now) {
|
||||||
|
// if animate condition for the key frame is not met then do nothing
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (now <= currentDuration) {
|
||||||
|
for (JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue.isValid()) {
|
||||||
|
@SuppressWarnings("rawtypes") final WritableValue target = keyValue.getTarget();
|
||||||
|
final Object endValue = endValuesMap.get(target);
|
||||||
|
if (endValue != null && target != null && !target.getValue().equals(endValue)) {
|
||||||
|
target.setValue(keyValue.getInterpolator().interpolate(initialValuesMap.get(target), endValue, now / currentDuration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!finished) {
|
||||||
|
finished = true;
|
||||||
|
for (JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue.isValid()) {
|
||||||
|
@SuppressWarnings("rawtypes") final WritableValue target = keyValue.getTarget();
|
||||||
|
if (target != null) {
|
||||||
|
// set updated end value instead of cached
|
||||||
|
final Object endValue = keyValue.getEndValue();
|
||||||
|
if (endValue != null) {
|
||||||
|
target.setValue(endValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentDuration = duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void applyEndValues() {
|
||||||
|
for (JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue.isValid()) {
|
||||||
|
@SuppressWarnings("rawtypes") final WritableValue target = keyValue.getTarget();
|
||||||
|
if (target != null) {
|
||||||
|
final Object endValue = keyValue.getEndValue();
|
||||||
|
if (endValue != null && !target.getValue().equals(endValue)) {
|
||||||
|
target.setValue(endValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
initialValuesMap.clear();
|
||||||
|
endValuesMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
clear();
|
||||||
|
keyValues.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
HMCL/src/main/java/com/jfoenix/transitions/JFXKeyFrame.java
Normal file
104
HMCL/src/main/java/com/jfoenix/transitions/JFXKeyFrame.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.transitions;
|
||||||
|
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Shadi Shaheen
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2017-09-21
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class JFXKeyFrame {
|
||||||
|
|
||||||
|
private Duration duration;
|
||||||
|
private Set<JFXKeyValue<?>> keyValues = new CopyOnWriteArraySet<>();
|
||||||
|
private Supplier<Boolean> animateCondition = null;
|
||||||
|
|
||||||
|
public JFXKeyFrame(Duration duration, JFXKeyValue<?>... keyValues) {
|
||||||
|
this.duration = duration;
|
||||||
|
for (final JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue != null) {
|
||||||
|
this.keyValues.add(keyValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JFXKeyFrame() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Duration getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Set<JFXKeyValue<?>> getValues() {
|
||||||
|
return keyValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Supplier<Boolean> getAnimateCondition() {
|
||||||
|
return animateCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
private Duration duration;
|
||||||
|
private final Set<JFXKeyValue<?>> keyValues = new CopyOnWriteArraySet<>();
|
||||||
|
private Supplier<Boolean> animateCondition = null;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDuration(Duration duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setKeyValues(JFXKeyValue<?>... keyValues) {
|
||||||
|
for (final JFXKeyValue<?> keyValue : keyValues) {
|
||||||
|
if (keyValue != null) {
|
||||||
|
this.keyValues.add(keyValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAnimateCondition(Supplier<Boolean> animateCondition) {
|
||||||
|
this.animateCondition = animateCondition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyFrame build() {
|
||||||
|
JFXKeyFrame jFXKeyFrame = new JFXKeyFrame();
|
||||||
|
jFXKeyFrame.duration = this.duration;
|
||||||
|
jFXKeyFrame.keyValues = this.keyValues;
|
||||||
|
jFXKeyFrame.animateCondition = this.animateCondition;
|
||||||
|
return jFXKeyFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
157
HMCL/src/main/java/com/jfoenix/transitions/JFXKeyValue.java
Normal file
157
HMCL/src/main/java/com/jfoenix/transitions/JFXKeyValue.java
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.jfoenix.transitions;
|
||||||
|
|
||||||
|
import javafx.animation.Interpolator;
|
||||||
|
import javafx.beans.value.WritableValue;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Shadi Shaheen
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2017-09-21
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class JFXKeyValue<T> {
|
||||||
|
|
||||||
|
private WritableValue<T> target;
|
||||||
|
private Supplier<WritableValue<T>> targetSupplier;
|
||||||
|
private Supplier<T> endValueSupplier;
|
||||||
|
private T endValue;
|
||||||
|
private Supplier<Boolean> animateCondition = () -> true;
|
||||||
|
private Interpolator interpolator;
|
||||||
|
|
||||||
|
private JFXKeyValue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// this builder is created to ensure type inference from method arguments
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getEndValue() {
|
||||||
|
return endValue == null ? endValueSupplier.get() : endValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WritableValue<T> getTarget() {
|
||||||
|
return target == null ? targetSupplier.get() : target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interpolator getInterpolator() {
|
||||||
|
return interpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return animateCondition == null || animateCondition.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
public <T> JFXKeyValueBuilder<T> setTarget(WritableValue<T> target) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setTarget(target);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> JFXKeyValueBuilder<T> setTargetSupplier(Supplier<WritableValue<T>> targetSupplier) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setTargetSupplier(targetSupplier);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> JFXKeyValueBuilder<T> setEndValueSupplier(Supplier<T> endValueSupplier) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setEndValueSupplier(endValueSupplier);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> JFXKeyValueBuilder<T> setEndValue(T endValue) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setEndValue(endValue);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> JFXKeyValueBuilder<T> setAnimateCondition(Supplier<Boolean> animateCondition) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setAnimateCondition(animateCondition);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> JFXKeyValueBuilder<T> setInterpolator(Interpolator interpolator) {
|
||||||
|
JFXKeyValueBuilder<T> builder = new JFXKeyValueBuilder<>();
|
||||||
|
builder.setInterpolator(interpolator);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class JFXKeyValueBuilder<T> {
|
||||||
|
|
||||||
|
private WritableValue<T> target;
|
||||||
|
private Supplier<WritableValue<T>> targetSupplier;
|
||||||
|
private Supplier<T> endValueSupplier;
|
||||||
|
private T endValue;
|
||||||
|
private Supplier<Boolean> animateCondition = () -> true;
|
||||||
|
private Interpolator interpolator = Interpolator.EASE_BOTH;
|
||||||
|
|
||||||
|
private JFXKeyValueBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setTarget(WritableValue<T> target) {
|
||||||
|
this.target = target;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setTargetSupplier(Supplier<WritableValue<T>> targetSupplier) {
|
||||||
|
this.targetSupplier = targetSupplier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setEndValueSupplier(Supplier<T> endValueSupplier) {
|
||||||
|
this.endValueSupplier = endValueSupplier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setEndValue(T endValue) {
|
||||||
|
this.endValue = endValue;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setAnimateCondition(Supplier<Boolean> animateCondition) {
|
||||||
|
this.animateCondition = animateCondition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValueBuilder<T> setInterpolator(Interpolator interpolator) {
|
||||||
|
this.interpolator = interpolator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JFXKeyValue<T> build() {
|
||||||
|
JFXKeyValue<T> jFXKeyValue = new JFXKeyValue<>();
|
||||||
|
jFXKeyValue.target = this.target;
|
||||||
|
jFXKeyValue.interpolator = this.interpolator;
|
||||||
|
jFXKeyValue.targetSupplier = this.targetSupplier;
|
||||||
|
jFXKeyValue.endValue = this.endValue;
|
||||||
|
jFXKeyValue.endValueSupplier = this.endValueSupplier;
|
||||||
|
jFXKeyValue.animateCondition = this.animateCondition;
|
||||||
|
return jFXKeyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,12 +34,12 @@ import org.hildan.fxgson.factories.JavaFxPropertyTypeAdapterFactory;
|
|||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||||
|
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.*;
|
import org.jackhuang.hmcl.util.gson.*;
|
||||||
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
import org.jackhuang.hmcl.util.i18n.SupportedLocale;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -276,19 +276,34 @@ public final class Config extends ObservableSetting {
|
|||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
||||||
|
@SerializedName("themeBrightness")
|
||||||
|
private final StringProperty themeBrightness = new SimpleStringProperty("light");
|
||||||
|
|
||||||
|
public StringProperty themeBrightnessProperty() {
|
||||||
|
return themeBrightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getThemeBrightness() {
|
||||||
|
return themeBrightness.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThemeBrightness(String themeBrightness) {
|
||||||
|
this.themeBrightness.set(themeBrightness);
|
||||||
|
}
|
||||||
|
|
||||||
@SerializedName("theme")
|
@SerializedName("theme")
|
||||||
private final ObjectProperty<Theme> theme = new SimpleObjectProperty<>();
|
private final ObjectProperty<ThemeColor> themeColor = new SimpleObjectProperty<>(ThemeColor.DEFAULT);
|
||||||
|
|
||||||
public ObjectProperty<Theme> themeProperty() {
|
public ObjectProperty<ThemeColor> themeColorProperty() {
|
||||||
return theme;
|
return themeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Theme getTheme() {
|
public ThemeColor getThemeColor() {
|
||||||
return theme.get();
|
return themeColor.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTheme(Theme theme) {
|
public void setThemeColor(ThemeColor themeColor) {
|
||||||
this.theme.set(theme);
|
this.themeColor.set(themeColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SerializedName("fontFamily")
|
@SerializedName("fontFamily")
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import org.glavo.monetfx.Brightness;
|
||||||
|
import org.glavo.monetfx.ColorRole;
|
||||||
|
import org.glavo.monetfx.ColorScheme;
|
||||||
|
import org.jackhuang.hmcl.theme.Theme;
|
||||||
|
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||||
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -33,7 +39,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +59,7 @@ public final class StyleSheets {
|
|||||||
stylesheets = FXCollections.observableList(Arrays.asList(array));
|
stylesheets = FXCollections.observableList(Arrays.asList(array));
|
||||||
|
|
||||||
FontManager.fontProperty().addListener(o -> stylesheets.set(FONT_STYLE_SHEET_INDEX, getFontStyleSheet()));
|
FontManager.fontProperty().addListener(o -> stylesheets.set(FONT_STYLE_SHEET_INDEX, getFontStyleSheet()));
|
||||||
config().themeProperty().addListener(o -> stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet()));
|
Themes.colorSchemeProperty().addListener(o -> stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String toStyleSheetUri(String styleSheet, String fallback) {
|
private static String toStyleSheetUri(String styleSheet, String fallback) {
|
||||||
@@ -126,31 +131,55 @@ public final class StyleSheets {
|
|||||||
return toStyleSheetUri(builder.toString(), defaultCss);
|
return toStyleSheetUri(builder.toString(), defaultCss);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String rgba(Color color, double opacity) {
|
private static void addColor(StringBuilder builder, String name, Color color) {
|
||||||
return String.format("rgba(%d, %d, %d, %.1f)",
|
builder.append(" ").append(name)
|
||||||
(int) Math.ceil(color.getRed() * 256),
|
.append(": ").append(ThemeColor.getColorDisplayName(color)).append(";\n");
|
||||||
(int) Math.ceil(color.getGreen() * 256),
|
}
|
||||||
(int) Math.ceil(color.getBlue() * 256),
|
|
||||||
opacity);
|
private static void addColor(StringBuilder builder, String name, Color color, double opacity) {
|
||||||
|
builder.append(" ").append(name)
|
||||||
|
.append(": ").append(ThemeColor.getColorDisplayNameWithOpacity(color, opacity)).append(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addColor(StringBuilder builder, ColorScheme scheme, ColorRole role, double opacity) {
|
||||||
|
builder.append(" ").append(role.getVariableName()).append("-transparent-").append((int) (100 * opacity))
|
||||||
|
.append(": ").append(ThemeColor.getColorDisplayNameWithOpacity(scheme.getColor(role), opacity))
|
||||||
|
.append(";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getThemeStyleSheet() {
|
private static String getThemeStyleSheet() {
|
||||||
final String blueCss = "/assets/css/blue.css";
|
final String blueCss = "/assets/css/blue.css";
|
||||||
|
|
||||||
Theme theme = config().getTheme();
|
if (Theme.DEFAULT.equals(Themes.getTheme()))
|
||||||
if (theme == null || theme.getPaint().equals(Theme.BLUE.getPaint()))
|
|
||||||
return blueCss;
|
return blueCss;
|
||||||
|
|
||||||
return toStyleSheetUri(".root {" +
|
ColorScheme scheme = Themes.getColorScheme();
|
||||||
"-fx-base-color:" + theme.getColor() + ';' +
|
|
||||||
"-fx-base-darker-color: derive(-fx-base-color, -10%);" +
|
StringBuilder builder = new StringBuilder();
|
||||||
"-fx-base-check-color: derive(-fx-base-color, 30%);" +
|
builder.append("* {\n");
|
||||||
"-fx-rippler-color:" + rgba(theme.getPaint(), 0.3) + ';' +
|
for (ColorRole colorRole : ColorRole.ALL) {
|
||||||
"-fx-base-rippler-color: derive(" + rgba(theme.getPaint(), 0.3) + ", 100%);" +
|
addColor(builder, colorRole.getVariableName(), scheme.getColor(colorRole));
|
||||||
"-fx-base-disabled-text-fill:" + rgba(theme.getForegroundColor(), 0.7) + ";" +
|
}
|
||||||
"-fx-base-text-fill:" + Theme.getColorDisplayName(theme.getForegroundColor()) + ";" +
|
|
||||||
"-theme-thumb:" + rgba(theme.getPaint(), 0.7) + ";" +
|
addColor(builder, "-monet-primary-seed", scheme.getPrimaryColorSeed());
|
||||||
'}', blueCss);
|
|
||||||
|
addColor(builder, scheme, ColorRole.PRIMARY, 0.5);
|
||||||
|
addColor(builder, scheme, ColorRole.SECONDARY_CONTAINER, 0.5);
|
||||||
|
addColor(builder, scheme, ColorRole.SURFACE, 0.5);
|
||||||
|
addColor(builder, scheme, ColorRole.SURFACE, 0.8);
|
||||||
|
addColor(builder, scheme, ColorRole.ON_SURFACE_VARIANT, 0.38);
|
||||||
|
addColor(builder, scheme, ColorRole.SURFACE_CONTAINER_LOW, 0.8);
|
||||||
|
addColor(builder, scheme, ColorRole.SECONDARY_CONTAINER, 0.8);
|
||||||
|
|
||||||
|
// If we use -monet-error-container as the tag color, there may be a conflict between the tag and background colors on the mod management page
|
||||||
|
if (scheme.getBrightness() == Brightness.LIGHT) {
|
||||||
|
addColor(builder, "-warning-tag-background", Color.web("#f1aeb5"));
|
||||||
|
} else {
|
||||||
|
addColor(builder, "-warning-tag-background", Color.web("#2c0b0e"));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append("}\n");
|
||||||
|
return toStyleSheetUri(builder.toString(), blueCss);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init(Scene scene) {
|
public static void init(Scene scene) {
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher
|
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.jackhuang.hmcl.setting;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.JsonAdapter;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.beans.binding.ObjectBinding;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
|
||||||
|
|
||||||
@JsonAdapter(Theme.TypeAdapter.class)
|
|
||||||
public final class Theme {
|
|
||||||
public static final Theme BLUE = new Theme("blue", "#5C6BC0");
|
|
||||||
public static final Color BLACK = Color.web("#292929");
|
|
||||||
public static final Color[] SUGGESTED_COLORS = new Color[]{
|
|
||||||
Color.web("#3D6DA3"), // blue
|
|
||||||
Color.web("#283593"), // dark blue
|
|
||||||
Color.web("#43A047"), // green
|
|
||||||
Color.web("#E67E22"), // orange
|
|
||||||
Color.web("#9C27B0"), // purple
|
|
||||||
Color.web("#B71C1C") // red
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Theme getTheme() {
|
|
||||||
Theme theme = config().getTheme();
|
|
||||||
return theme == null ? BLUE : theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Color paint;
|
|
||||||
private final String color;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
Theme(String name, String color) {
|
|
||||||
this.name = name;
|
|
||||||
this.color = Objects.requireNonNull(color);
|
|
||||||
this.paint = Color.web(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color getPaint() {
|
|
||||||
return paint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCustom() {
|
|
||||||
return name.startsWith("#");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLight() {
|
|
||||||
return paint.grayscale().getRed() >= 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color getForegroundColor() {
|
|
||||||
return isLight() ? Color.BLACK : Color.WHITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Theme custom(String color) {
|
|
||||||
if (!color.startsWith("#"))
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
return new Theme(color, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<Theme> getTheme(String name) {
|
|
||||||
if (name == null)
|
|
||||||
return Optional.empty();
|
|
||||||
else if (name.startsWith("#"))
|
|
||||||
try {
|
|
||||||
Color.web(name);
|
|
||||||
return Optional.of(custom(name));
|
|
||||||
} catch (IllegalArgumentException ignore) {
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String color = null;
|
|
||||||
switch (name.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "blue":
|
|
||||||
return Optional.of(BLUE);
|
|
||||||
case "darker_blue":
|
|
||||||
color = "#283593";
|
|
||||||
break;
|
|
||||||
case "green":
|
|
||||||
color = "#43A047";
|
|
||||||
break;
|
|
||||||
case "orange":
|
|
||||||
color = "#E67E22";
|
|
||||||
break;
|
|
||||||
case "purple":
|
|
||||||
color = "#9C27B0";
|
|
||||||
break;
|
|
||||||
case "red":
|
|
||||||
color = "#F44336";
|
|
||||||
}
|
|
||||||
if (color != null)
|
|
||||||
return Optional.of(new Theme(name, color));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getColorDisplayName(Color c) {
|
|
||||||
return c != null ? String.format("#%02X%02X%02X", Math.round(c.getRed() * 255.0D), Math.round(c.getGreen() * 255.0D), Math.round(c.getBlue() * 255.0D)) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectBinding<Color> FOREGROUND_FILL;
|
|
||||||
|
|
||||||
public static ObjectBinding<Color> foregroundFillBinding() {
|
|
||||||
if (FOREGROUND_FILL == null)
|
|
||||||
FOREGROUND_FILL = Bindings.createObjectBinding(
|
|
||||||
() -> Theme.getTheme().getForegroundColor(),
|
|
||||||
config().themeProperty()
|
|
||||||
);
|
|
||||||
|
|
||||||
return FOREGROUND_FILL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color blackFill() {
|
|
||||||
return BLACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color whiteFill() {
|
|
||||||
return Color.WHITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TypeAdapter extends com.google.gson.TypeAdapter<Theme> {
|
|
||||||
@Override
|
|
||||||
public void write(JsonWriter out, Theme value) throws IOException {
|
|
||||||
out.value(value.getName().toLowerCase(Locale.ROOT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Theme read(JsonReader in) throws IOException {
|
|
||||||
return getTheme(in.nextString()).orElse(Theme.BLUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
94
HMCL/src/main/java/org/jackhuang/hmcl/theme/Theme.java
Normal file
94
HMCL/src/main/java/org/jackhuang/hmcl/theme/Theme.java
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.theme;
|
||||||
|
|
||||||
|
import org.glavo.monetfx.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/// @author Glavo
|
||||||
|
public final class Theme {
|
||||||
|
|
||||||
|
public static final Theme DEFAULT = new Theme(ThemeColor.DEFAULT, Brightness.DEFAULT, ColorStyle.FIDELITY, Contrast.DEFAULT);
|
||||||
|
|
||||||
|
private final ThemeColor primaryColorSeed;
|
||||||
|
private final Brightness brightness;
|
||||||
|
private final ColorStyle colorStyle;
|
||||||
|
private final Contrast contrast;
|
||||||
|
|
||||||
|
public Theme(ThemeColor primaryColorSeed,
|
||||||
|
Brightness brightness,
|
||||||
|
ColorStyle colorStyle,
|
||||||
|
Contrast contrast
|
||||||
|
) {
|
||||||
|
this.primaryColorSeed = primaryColorSeed;
|
||||||
|
this.brightness = brightness;
|
||||||
|
this.colorStyle = colorStyle;
|
||||||
|
this.contrast = contrast;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorScheme toColorScheme() {
|
||||||
|
return ColorScheme.newBuilder()
|
||||||
|
.setPrimaryColorSeed(primaryColorSeed.color())
|
||||||
|
.setColorStyle(colorStyle)
|
||||||
|
.setBrightness(brightness)
|
||||||
|
.setSpecVersion(ColorSpecVersion.SPEC_2025)
|
||||||
|
.setContrast(contrast)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThemeColor primaryColorSeed() {
|
||||||
|
return primaryColorSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Brightness brightness() {
|
||||||
|
return brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorStyle colorStyle() {
|
||||||
|
return colorStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contrast contrast() {
|
||||||
|
return contrast;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj == this || obj instanceof Theme that
|
||||||
|
&& this.primaryColorSeed.color().equals(that.primaryColorSeed.color())
|
||||||
|
&& this.brightness.equals(that.brightness)
|
||||||
|
&& this.colorStyle.equals(that.colorStyle)
|
||||||
|
&& this.contrast.equals(that.contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(primaryColorSeed, brightness, colorStyle, contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Theme[" +
|
||||||
|
"primaryColorSeed=" + primaryColorSeed + ", " +
|
||||||
|
"brightness=" + brightness + ", " +
|
||||||
|
"colorStyle=" + colorStyle + ", " +
|
||||||
|
"contrast=" + contrast + ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
193
HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColor.java
Normal file
193
HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColor.java
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.theme;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.WeakListener;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.scene.control.ColorPicker;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/// @author Glavo
|
||||||
|
@JsonAdapter(ThemeColor.TypeAdapter.class)
|
||||||
|
@JsonSerializable
|
||||||
|
public record ThemeColor(@NotNull String name, @NotNull Color color) {
|
||||||
|
|
||||||
|
public static final ThemeColor DEFAULT = new ThemeColor("blue", Color.web("#5C6BC0"));
|
||||||
|
|
||||||
|
public static final List<ThemeColor> STANDARD_COLORS = List.of(
|
||||||
|
DEFAULT,
|
||||||
|
new ThemeColor("darker_blue", Color.web("#283593")),
|
||||||
|
new ThemeColor("green", Color.web("#43A047")),
|
||||||
|
new ThemeColor("orange", Color.web("#E67E22")),
|
||||||
|
new ThemeColor("purple", Color.web("#9C27B0")),
|
||||||
|
new ThemeColor("red", Color.web("#B71C1C"))
|
||||||
|
);
|
||||||
|
|
||||||
|
public static String getColorDisplayName(Color c) {
|
||||||
|
return c != null ? String.format("#%02X%02X%02X",
|
||||||
|
Math.round(c.getRed() * 255.0D),
|
||||||
|
Math.round(c.getGreen() * 255.0D),
|
||||||
|
Math.round(c.getBlue() * 255.0D))
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getColorDisplayNameWithOpacity(Color c, double opacity) {
|
||||||
|
return c != null ? String.format("#%02X%02X%02X%02X",
|
||||||
|
Math.round(c.getRed() * 255.0D),
|
||||||
|
Math.round(c.getGreen() * 255.0D),
|
||||||
|
Math.round(c.getBlue() * 255.0D),
|
||||||
|
Math.round(opacity * 255.0))
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable ThemeColor of(String name) {
|
||||||
|
if (name == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!name.startsWith("#")) {
|
||||||
|
for (ThemeColor color : STANDARD_COLORS) {
|
||||||
|
if (name.equalsIgnoreCase(color.name()))
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new ThemeColor(name, Color.web(name));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("null -> null; !null -> !null")
|
||||||
|
public static ThemeColor of(Color color) {
|
||||||
|
return color != null ? new ThemeColor(getColorDisplayName(color), color) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class BidirectionalBinding implements InvalidationListener, WeakListener {
|
||||||
|
private final WeakReference<ColorPicker> colorPickerRef;
|
||||||
|
private final WeakReference<Property<ThemeColor>> propertyRef;
|
||||||
|
private final int hashCode;
|
||||||
|
|
||||||
|
private boolean updating = false;
|
||||||
|
|
||||||
|
private BidirectionalBinding(ColorPicker colorPicker, Property<ThemeColor> property) {
|
||||||
|
this.colorPickerRef = new WeakReference<>(colorPicker);
|
||||||
|
this.propertyRef = new WeakReference<>(property);
|
||||||
|
this.hashCode = System.identityHashCode(colorPicker) ^ System.identityHashCode(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidated(Observable sourceProperty) {
|
||||||
|
if (!updating) {
|
||||||
|
final ColorPicker colorPicker = colorPickerRef.get();
|
||||||
|
final Property<ThemeColor> property = propertyRef.get();
|
||||||
|
|
||||||
|
if (colorPicker == null || property == null) {
|
||||||
|
if (colorPicker != null) {
|
||||||
|
colorPicker.valueProperty().removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property != null) {
|
||||||
|
property.removeListener(this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updating = true;
|
||||||
|
try {
|
||||||
|
if (property == sourceProperty) {
|
||||||
|
ThemeColor newValue = property.getValue();
|
||||||
|
colorPicker.setValue(newValue != null ? newValue.color() : null);
|
||||||
|
} else {
|
||||||
|
Color newValue = colorPicker.getValue();
|
||||||
|
property.setValue(newValue != null ? ThemeColor.of(newValue) : null);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean wasGarbageCollected() {
|
||||||
|
return colorPickerRef.get() == null || propertyRef.get() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o)
|
||||||
|
return true;
|
||||||
|
if (!(o instanceof BidirectionalBinding that))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
final ColorPicker colorPicker = this.colorPickerRef.get();
|
||||||
|
final Property<ThemeColor> property = this.propertyRef.get();
|
||||||
|
|
||||||
|
final ColorPicker thatColorPicker = that.colorPickerRef.get();
|
||||||
|
final Property<?> thatProperty = that.propertyRef.get();
|
||||||
|
|
||||||
|
if (colorPicker == null || property == null || thatColorPicker == null || thatProperty == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return colorPicker == thatColorPicker && property == thatProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindBidirectional(ColorPicker colorPicker, Property<ThemeColor> property) {
|
||||||
|
var binding = new BidirectionalBinding(colorPicker, property);
|
||||||
|
|
||||||
|
colorPicker.valueProperty().removeListener(binding);
|
||||||
|
property.removeListener(binding);
|
||||||
|
|
||||||
|
ThemeColor themeColor = property.getValue();
|
||||||
|
colorPicker.setValue(themeColor != null ? themeColor.color() : null);
|
||||||
|
|
||||||
|
colorPicker.valueProperty().addListener(binding);
|
||||||
|
property.addListener(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class TypeAdapter extends com.google.gson.TypeAdapter<ThemeColor> {
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, ThemeColor value) throws IOException {
|
||||||
|
out.value(value.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThemeColor read(JsonReader in) throws IOException {
|
||||||
|
return Objects.requireNonNullElse(of(in.nextString()), ThemeColor.DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java
Normal file
126
HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.theme;
|
||||||
|
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.binding.ObjectBinding;
|
||||||
|
import javafx.beans.binding.ObjectExpression;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.glavo.monetfx.Brightness;
|
||||||
|
import org.glavo.monetfx.ColorScheme;
|
||||||
|
import org.glavo.monetfx.Contrast;
|
||||||
|
import org.glavo.monetfx.beans.property.ColorSchemeProperty;
|
||||||
|
import org.glavo.monetfx.beans.property.ReadOnlyColorSchemeProperty;
|
||||||
|
import org.glavo.monetfx.beans.property.SimpleColorSchemeProperty;
|
||||||
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
|
|
||||||
|
/// @author Glavo
|
||||||
|
public final class Themes {
|
||||||
|
|
||||||
|
private static final ObjectExpression<Theme> theme = new ObjectBinding<>() {
|
||||||
|
{
|
||||||
|
List<Observable> observables = new ArrayList<>();
|
||||||
|
|
||||||
|
observables.add(config().themeBrightnessProperty());
|
||||||
|
observables.add(config().themeColorProperty());
|
||||||
|
if (FXUtils.DARK_MODE != null) {
|
||||||
|
observables.add(FXUtils.DARK_MODE);
|
||||||
|
}
|
||||||
|
bind(observables.toArray(new Observable[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Brightness getBrightness() {
|
||||||
|
String themeBrightness = config().getThemeBrightness();
|
||||||
|
if (themeBrightness == null)
|
||||||
|
return Brightness.DEFAULT;
|
||||||
|
|
||||||
|
return switch (themeBrightness.toLowerCase(Locale.ROOT).trim()) {
|
||||||
|
case "auto" -> {
|
||||||
|
if (FXUtils.DARK_MODE != null) {
|
||||||
|
yield FXUtils.DARK_MODE.get() ? Brightness.DARK : Brightness.LIGHT;
|
||||||
|
} else {
|
||||||
|
yield Brightness.DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "dark" -> Brightness.DARK;
|
||||||
|
case "light" -> Brightness.LIGHT;
|
||||||
|
default -> Brightness.DEFAULT;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Theme computeValue() {
|
||||||
|
ThemeColor themeColor = Objects.requireNonNullElse(config().getThemeColor(), ThemeColor.DEFAULT);
|
||||||
|
|
||||||
|
return new Theme(themeColor, getBrightness(), Theme.DEFAULT.colorStyle(), Contrast.DEFAULT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final ColorSchemeProperty colorScheme = new SimpleColorSchemeProperty();
|
||||||
|
private static final BooleanBinding darkMode = Bindings.createBooleanBinding(
|
||||||
|
() -> colorScheme.get().getBrightness() == Brightness.DARK,
|
||||||
|
colorScheme
|
||||||
|
);
|
||||||
|
|
||||||
|
static {
|
||||||
|
ChangeListener<Theme> listener = (observable, oldValue, newValue) -> {
|
||||||
|
if (!Objects.equals(oldValue, newValue)) {
|
||||||
|
colorScheme.set(newValue != null ? newValue.toColorScheme() : Theme.DEFAULT.toColorScheme());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
listener.changed(theme, null, theme.get());
|
||||||
|
theme.addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectExpression<Theme> themeProperty() {
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Theme getTheme() {
|
||||||
|
return themeProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlyColorSchemeProperty colorSchemeProperty() {
|
||||||
|
return colorScheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColorScheme getColorScheme() {
|
||||||
|
return colorScheme.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObservableValue<Color> titleFillProperty() {
|
||||||
|
return colorSchemeProperty().getOnPrimaryContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BooleanBinding darkModeProperty() {
|
||||||
|
return darkMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Themes() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,6 @@ import javafx.util.Callback;
|
|||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import org.jackhuang.hmcl.setting.StyleSheets;
|
import org.jackhuang.hmcl.setting.StyleSheets;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.CacheFileTask;
|
import org.jackhuang.hmcl.task.CacheFileTask;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@@ -135,6 +134,7 @@ public final class FXUtils {
|
|||||||
public static final @Nullable ObservableMap<String, Object> PREFERENCES;
|
public static final @Nullable ObservableMap<String, Object> PREFERENCES;
|
||||||
public static final @Nullable ObservableBooleanValue DARK_MODE;
|
public static final @Nullable ObservableBooleanValue DARK_MODE;
|
||||||
public static final @Nullable Boolean REDUCED_MOTION;
|
public static final @Nullable Boolean REDUCED_MOTION;
|
||||||
|
public static final @Nullable ReadOnlyObjectProperty<Color> ACCENT_COLOR;
|
||||||
|
|
||||||
public static final @Nullable MethodHandle TEXT_TRUNCATED_PROPERTY;
|
public static final @Nullable MethodHandle TEXT_TRUNCATED_PROPERTY;
|
||||||
|
|
||||||
@@ -151,6 +151,7 @@ public final class FXUtils {
|
|||||||
|
|
||||||
ObservableMap<String, Object> preferences = null;
|
ObservableMap<String, Object> preferences = null;
|
||||||
ObservableBooleanValue darkMode = null;
|
ObservableBooleanValue darkMode = null;
|
||||||
|
ReadOnlyObjectProperty<Color> accentColorProperty = null;
|
||||||
Boolean reducedMotion = null;
|
Boolean reducedMotion = null;
|
||||||
if (JAVAFX_MAJOR_VERSION >= 22) {
|
if (JAVAFX_MAJOR_VERSION >= 22) {
|
||||||
try {
|
try {
|
||||||
@@ -162,14 +163,19 @@ public final class FXUtils {
|
|||||||
preferences = preferences0;
|
preferences = preferences0;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
var colorSchemeProperty =
|
var colorSchemeProperty = (ReadOnlyObjectProperty<? extends Enum<?>>)
|
||||||
(ReadOnlyObjectProperty<? extends Enum<?>>)
|
lookup.findVirtual(preferencesClass, "colorSchemeProperty", MethodType.methodType(ReadOnlyObjectProperty.class))
|
||||||
lookup.findVirtual(preferencesClass, "colorSchemeProperty", MethodType.methodType(ReadOnlyObjectProperty.class))
|
.invoke(preferences);
|
||||||
.invoke(preferences);
|
|
||||||
|
|
||||||
darkMode = Bindings.createBooleanBinding(() ->
|
darkMode = Bindings.createBooleanBinding(() ->
|
||||||
"DARK".equals(colorSchemeProperty.get().name()), colorSchemeProperty);
|
"DARK".equals(colorSchemeProperty.get().name()), colorSchemeProperty);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
var accentColorProperty0 = (ReadOnlyObjectProperty<Color>)
|
||||||
|
lookup.findVirtual(preferencesClass, "accentColorProperty", MethodType.methodType(ReadOnlyObjectProperty.class))
|
||||||
|
.invoke(preferences);
|
||||||
|
accentColorProperty = accentColorProperty0;
|
||||||
|
|
||||||
if (JAVAFX_MAJOR_VERSION >= 24) {
|
if (JAVAFX_MAJOR_VERSION >= 24) {
|
||||||
reducedMotion = (boolean)
|
reducedMotion = (boolean)
|
||||||
lookup.findVirtual(preferencesClass, "isReducedMotion", MethodType.methodType(boolean.class))
|
lookup.findVirtual(preferencesClass, "isReducedMotion", MethodType.methodType(boolean.class))
|
||||||
@@ -182,6 +188,7 @@ public final class FXUtils {
|
|||||||
PREFERENCES = preferences;
|
PREFERENCES = preferences;
|
||||||
DARK_MODE = darkMode;
|
DARK_MODE = darkMode;
|
||||||
REDUCED_MOTION = reducedMotion;
|
REDUCED_MOTION = reducedMotion;
|
||||||
|
ACCENT_COLOR = accentColorProperty;
|
||||||
|
|
||||||
MethodHandle textTruncatedProperty = null;
|
MethodHandle textTruncatedProperty = null;
|
||||||
if (JAVAFX_MAJOR_VERSION >= 23) {
|
if (JAVAFX_MAJOR_VERSION >= 23) {
|
||||||
@@ -1214,7 +1221,7 @@ public final class FXUtils {
|
|||||||
public static JFXButton newToggleButton4(SVG icon) {
|
public static JFXButton newToggleButton4(SVG icon) {
|
||||||
JFXButton button = new JFXButton();
|
JFXButton button = new JFXButton();
|
||||||
button.getStyleClass().add("toggle-icon4");
|
button.getStyleClass().add("toggle-icon4");
|
||||||
button.setGraphic(icon.createIcon(Theme.blackFill(), -1));
|
button.setGraphic(icon.createIcon());
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1447,11 +1454,11 @@ public final class FXUtils {
|
|||||||
for (int i = 0; i < children.getLength(); i++) {
|
for (int i = 0; i < children.getLength(); i++) {
|
||||||
org.w3c.dom.Node node = children.item(i);
|
org.w3c.dom.Node node = children.item(i);
|
||||||
|
|
||||||
if (node instanceof Element) {
|
if (node instanceof Element element) {
|
||||||
Element element = (Element) node;
|
|
||||||
if ("a".equals(element.getTagName())) {
|
if ("a".equals(element.getTagName())) {
|
||||||
String href = element.getAttribute("href");
|
String href = element.getAttribute("href");
|
||||||
Text text = new Text(element.getTextContent());
|
Text text = new Text(element.getTextContent());
|
||||||
|
text.getStyleClass().add("hyperlink");
|
||||||
onClicked(text, () -> {
|
onClicked(text, () -> {
|
||||||
String link = href;
|
String link = href;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import javafx.scene.image.ImageView;
|
|||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.setting.VersionIconType;
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
||||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||||
@@ -396,7 +395,7 @@ public class InstallerItem extends Control {
|
|||||||
pane.getChildren().add(buttonsContainer);
|
pane.getChildren().add(buttonsContainer);
|
||||||
|
|
||||||
JFXButton removeButton = new JFXButton();
|
JFXButton removeButton = new JFXButton();
|
||||||
removeButton.setGraphic(SVG.CLOSE.createIcon(Theme.blackFill(), -1));
|
removeButton.setGraphic(SVG.CLOSE.createIcon());
|
||||||
removeButton.getStyleClass().add("toggle-icon4");
|
removeButton.getStyleClass().add("toggle-icon4");
|
||||||
if (control.id.equals(MINECRAFT.getPatchId())) {
|
if (control.id.equals(MINECRAFT.getPatchId())) {
|
||||||
removeButton.setVisible(false);
|
removeButton.setVisible(false);
|
||||||
@@ -417,8 +416,8 @@ public class InstallerItem extends Control {
|
|||||||
JFXButton installButton = new JFXButton();
|
JFXButton installButton = new JFXButton();
|
||||||
installButton.graphicProperty().bind(Bindings.createObjectBinding(() ->
|
installButton.graphicProperty().bind(Bindings.createObjectBinding(() ->
|
||||||
control.resolvedStateProperty.get() instanceof InstallableState ?
|
control.resolvedStateProperty.get() instanceof InstallableState ?
|
||||||
SVG.ARROW_FORWARD.createIcon(Theme.blackFill(), -1) :
|
SVG.ARROW_FORWARD.createIcon() :
|
||||||
SVG.UPDATE.createIcon(Theme.blackFill(), -1),
|
SVG.UPDATE.createIcon(),
|
||||||
control.resolvedStateProperty
|
control.resolvedStateProperty
|
||||||
));
|
));
|
||||||
installButton.getStyleClass().add("toggle-icon4");
|
installButton.getStyleClass().add("toggle-icon4");
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import javafx.scene.layout.BorderPane;
|
|||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||||
|
|
||||||
public class ListPageSkin extends SkinBase<ListPage<?>> {
|
public class ListPageSkin extends SkinBase<ListPage<?>> {
|
||||||
@@ -67,7 +66,7 @@ public class ListPageSkin extends SkinBase<ListPage<?>> {
|
|||||||
JFXButton btnAdd = FXUtils.newRaisedButton("");
|
JFXButton btnAdd = FXUtils.newRaisedButton("");
|
||||||
FXUtils.setLimitWidth(btnAdd, 40);
|
FXUtils.setLimitWidth(btnAdd, 40);
|
||||||
FXUtils.setLimitHeight(btnAdd, 40);
|
FXUtils.setLimitHeight(btnAdd, 40);
|
||||||
btnAdd.setGraphic(SVG.ADD.createIcon(Theme.whiteFill(), -1));
|
btnAdd.setGraphic(SVG.ADD.createIcon());
|
||||||
btnAdd.setOnAction(e -> skinnable.add());
|
btnAdd.setOnAction(e -> skinnable.add());
|
||||||
|
|
||||||
JFXButton btnRefresh = new JFXButton();
|
JFXButton btnRefresh = new JFXButton();
|
||||||
@@ -75,7 +74,7 @@ public class ListPageSkin extends SkinBase<ListPage<?>> {
|
|||||||
FXUtils.setLimitHeight(btnRefresh, 40);
|
FXUtils.setLimitHeight(btnRefresh, 40);
|
||||||
btnRefresh.getStyleClass().add("jfx-button-raised-round");
|
btnRefresh.getStyleClass().add("jfx-button-raised-round");
|
||||||
btnRefresh.setButtonType(JFXButton.ButtonType.RAISED);
|
btnRefresh.setButtonType(JFXButton.ButtonType.RAISED);
|
||||||
btnRefresh.setGraphic(SVG.REFRESH.createIcon(Theme.whiteFill(), -1));
|
btnRefresh.setGraphic(SVG.REFRESH.createIcon());
|
||||||
btnRefresh.setOnAction(e -> skinnable.refresh());
|
btnRefresh.setOnAction(e -> skinnable.refresh());
|
||||||
|
|
||||||
vBox.getChildren().setAll(btnAdd);
|
vBox.getChildren().setAll(btnAdd);
|
||||||
|
|||||||
@@ -153,24 +153,25 @@ public enum SVG {
|
|||||||
return new Group(path);
|
return new Group(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node createIcon(ObservableValue<? extends Paint> fill, double size) {
|
public Node createIcon(double size) {
|
||||||
SVGPath p = new SVGPath();
|
SVGPath p = new SVGPath();
|
||||||
p.getStyleClass().add("svg");
|
|
||||||
p.setContent(path);
|
p.setContent(path);
|
||||||
if (fill != null)
|
p.getStyleClass().add("svg");
|
||||||
p.fillProperty().bind(fill);
|
|
||||||
|
|
||||||
return createIcon(p, size);
|
return createIcon(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node createIcon(Paint fill, double size) {
|
public Node createIcon() {
|
||||||
SVGPath p = new SVGPath();
|
SVGPath p = new SVGPath();
|
||||||
p.getStyleClass().add("svg");
|
|
||||||
p.setContent(path);
|
p.setContent(path);
|
||||||
if (fill != null)
|
p.getStyleClass().add("svg");
|
||||||
p.fillProperty().set(fill);
|
return createIcon(p, -1);
|
||||||
|
|
||||||
return createIcon(p, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Node createIcon(ObservableValue<? extends Paint> color) {
|
||||||
|
SVGPath p = new SVGPath();
|
||||||
|
p.setContent(path);
|
||||||
|
p.getStyleClass().add("svg");
|
||||||
|
p.fillProperty().bind(color);
|
||||||
|
return createIcon(p, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javafx.scene.layout.HBox;
|
|||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||||
|
|
||||||
@@ -85,20 +84,10 @@ public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>
|
|||||||
return stackPane;
|
return stackPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JFXButton createToolbarButton(String text, SVG svg, Runnable onClick) {
|
|
||||||
JFXButton ret = new JFXButton();
|
|
||||||
ret.getStyleClass().add("jfx-tool-bar-button");
|
|
||||||
ret.textFillProperty().bind(Theme.foregroundFillBinding());
|
|
||||||
ret.setGraphic(wrap(svg.createIcon(Theme.foregroundFillBinding(), -1)));
|
|
||||||
ret.setText(text);
|
|
||||||
ret.setOnAction(e -> onClick.run());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JFXButton createToolbarButton2(String text, SVG svg, Runnable onClick) {
|
public static JFXButton createToolbarButton2(String text, SVG svg, Runnable onClick) {
|
||||||
JFXButton ret = new JFXButton();
|
JFXButton ret = new JFXButton();
|
||||||
ret.getStyleClass().add("jfx-tool-bar-button");
|
ret.getStyleClass().add("jfx-tool-bar-button");
|
||||||
ret.setGraphic(wrap(svg.createIcon(Theme.blackFill(), -1)));
|
ret.setGraphic(wrap(svg.createIcon()));
|
||||||
ret.setText(text);
|
ret.setText(text);
|
||||||
ret.setOnAction(e -> {
|
ret.setOnAction(e -> {
|
||||||
onClick.run();
|
onClick.run();
|
||||||
@@ -110,8 +99,7 @@ public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>
|
|||||||
public static JFXButton createDecoratorButton(String tooltip, SVG svg, Runnable onClick) {
|
public static JFXButton createDecoratorButton(String tooltip, SVG svg, Runnable onClick) {
|
||||||
JFXButton ret = new JFXButton();
|
JFXButton ret = new JFXButton();
|
||||||
ret.getStyleClass().add("jfx-decorator-button");
|
ret.getStyleClass().add("jfx-decorator-button");
|
||||||
ret.textFillProperty().bind(Theme.foregroundFillBinding());
|
ret.setGraphic(wrap(svg.createIcon()));
|
||||||
ret.setGraphic(wrap(svg.createIcon(Theme.foregroundFillBinding(), -1)));
|
|
||||||
FXUtils.installFastTooltip(ret, tooltip);
|
FXUtils.installFastTooltip(ret, tooltip);
|
||||||
ret.setOnAction(e -> onClick.run());
|
ret.setOnAction(e -> onClick.run());
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
|||||||
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
|
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
|
||||||
import org.jackhuang.hmcl.game.TexturesLoader;
|
import org.jackhuang.hmcl.game.TexturesLoader;
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
@@ -117,10 +116,10 @@ public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
|||||||
});
|
});
|
||||||
btnMove.getStyleClass().add("toggle-icon4");
|
btnMove.getStyleClass().add("toggle-icon4");
|
||||||
if (skinnable.getAccount().isPortable()) {
|
if (skinnable.getAccount().isPortable()) {
|
||||||
btnMove.setGraphic(SVG.PUBLIC.createIcon(Theme.blackFill(), -1));
|
btnMove.setGraphic(SVG.PUBLIC.createIcon());
|
||||||
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_global"));
|
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_global"));
|
||||||
} else {
|
} else {
|
||||||
btnMove.setGraphic(SVG.OUTPUT.createIcon(Theme.blackFill(), -1));
|
btnMove.setGraphic(SVG.OUTPUT.createIcon());
|
||||||
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_portable"));
|
FXUtils.installFastTooltip(btnMove, i18n("account.move_to_portable"));
|
||||||
}
|
}
|
||||||
spinnerMove.setContent(btnMove);
|
spinnerMove.setContent(btnMove);
|
||||||
@@ -146,7 +145,7 @@ public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
|||||||
.start();
|
.start();
|
||||||
});
|
});
|
||||||
btnRefresh.getStyleClass().add("toggle-icon4");
|
btnRefresh.getStyleClass().add("toggle-icon4");
|
||||||
btnRefresh.setGraphic(SVG.REFRESH.createIcon(Theme.blackFill(), -1));
|
btnRefresh.setGraphic(SVG.REFRESH.createIcon());
|
||||||
FXUtils.installFastTooltip(btnRefresh, i18n("button.refresh"));
|
FXUtils.installFastTooltip(btnRefresh, i18n("button.refresh"));
|
||||||
spinnerRefresh.setContent(btnRefresh);
|
spinnerRefresh.setContent(btnRefresh);
|
||||||
right.getChildren().add(spinnerRefresh);
|
right.getChildren().add(spinnerRefresh);
|
||||||
@@ -163,7 +162,7 @@ public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnUpload.getStyleClass().add("toggle-icon4");
|
btnUpload.getStyleClass().add("toggle-icon4");
|
||||||
btnUpload.setGraphic(SVG.CHECKROOM.createIcon(Theme.blackFill(), -1));
|
btnUpload.setGraphic(SVG.CHECKROOM.createIcon());
|
||||||
FXUtils.installFastTooltip(btnUpload, i18n("account.skin.upload"));
|
FXUtils.installFastTooltip(btnUpload, i18n("account.skin.upload"));
|
||||||
btnUpload.disableProperty().bind(Bindings.not(skinnable.canUploadSkin()));
|
btnUpload.disableProperty().bind(Bindings.not(skinnable.canUploadSkin()));
|
||||||
spinnerUpload.setContent(btnUpload);
|
spinnerUpload.setContent(btnUpload);
|
||||||
@@ -175,7 +174,7 @@ public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
|||||||
spinnerCopyUUID.getStyleClass().add("small-spinner-pane");
|
spinnerCopyUUID.getStyleClass().add("small-spinner-pane");
|
||||||
btnUpload.getStyleClass().add("toggle-icon4");
|
btnUpload.getStyleClass().add("toggle-icon4");
|
||||||
btnCopyUUID.setOnAction(e -> FXUtils.copyText(skinnable.getAccount().getUUID().toString()));
|
btnCopyUUID.setOnAction(e -> FXUtils.copyText(skinnable.getAccount().getUUID().toString()));
|
||||||
btnCopyUUID.setGraphic(SVG.CONTENT_COPY.createIcon(Theme.blackFill(), -1));
|
btnCopyUUID.setGraphic(SVG.CONTENT_COPY.createIcon());
|
||||||
FXUtils.installFastTooltip(btnCopyUUID, i18n("account.copy_uuid"));
|
FXUtils.installFastTooltip(btnCopyUUID, i18n("account.copy_uuid"));
|
||||||
spinnerCopyUUID.setContent(btnCopyUUID);
|
spinnerCopyUUID.setContent(btnCopyUUID);
|
||||||
right.getChildren().add(spinnerCopyUUID);
|
right.getChildren().add(spinnerCopyUUID);
|
||||||
@@ -184,7 +183,7 @@ public final class AccountListItemSkin extends SkinBase<AccountListItem> {
|
|||||||
btnRemove.setOnAction(e -> Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"), skinnable::remove, null));
|
btnRemove.setOnAction(e -> Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"), skinnable::remove, null));
|
||||||
btnRemove.getStyleClass().add("toggle-icon4");
|
btnRemove.getStyleClass().add("toggle-icon4");
|
||||||
BorderPane.setAlignment(btnRemove, Pos.CENTER);
|
BorderPane.setAlignment(btnRemove, Pos.CENTER);
|
||||||
btnRemove.setGraphic(SVG.DELETE.createIcon(Theme.blackFill(), -1));
|
btnRemove.setGraphic(SVG.DELETE.createIcon());
|
||||||
FXUtils.installFastTooltip(btnRemove, i18n("button.delete"));
|
FXUtils.installFastTooltip(btnRemove, i18n("button.delete"));
|
||||||
right.getChildren().add(btnRemove);
|
right.getChildren().add(btnRemove);
|
||||||
root.setRight(right);
|
root.setRight(right);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import javafx.scene.layout.VBox;
|
|||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@@ -158,7 +157,7 @@ public final class AccountListPage extends DecoratorAnimatedPage implements Deco
|
|||||||
e.consume();
|
e.consume();
|
||||||
});
|
});
|
||||||
btnRemove.getStyleClass().add("toggle-icon4");
|
btnRemove.getStyleClass().add("toggle-icon4");
|
||||||
btnRemove.setGraphic(SVG.CLOSE.createIcon(Theme.blackFill(), 14));
|
btnRemove.setGraphic(SVG.CLOSE.createIcon(14));
|
||||||
item.setRightGraphic(btnRemove);
|
item.setRightGraphic(btnRemove);
|
||||||
|
|
||||||
ObservableValue<String> title = BindingMapping.of(server, AuthlibInjectorServer::getName);
|
ObservableValue<String> title = BindingMapping.of(server, AuthlibInjectorServer::getName);
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
|
|||||||
import org.jackhuang.hmcl.game.OAuthServer;
|
import org.jackhuang.hmcl.game.OAuthServer;
|
||||||
import org.jackhuang.hmcl.game.TexturesLoader;
|
import org.jackhuang.hmcl.game.TexturesLoader;
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||||
@@ -465,7 +464,7 @@ public class CreateAccountPane extends JFXDialogLayout implements DialogAware {
|
|||||||
linksContainer.setMinWidth(USE_PREF_SIZE);
|
linksContainer.setMinWidth(USE_PREF_SIZE);
|
||||||
|
|
||||||
JFXButton btnAddServer = new JFXButton();
|
JFXButton btnAddServer = new JFXButton();
|
||||||
btnAddServer.setGraphic(SVG.ADD.createIcon(Theme.blackFill(), 20));
|
btnAddServer.setGraphic(SVG.ADD.createIcon(20));
|
||||||
btnAddServer.getStyleClass().add("toggle-icon4");
|
btnAddServer.getStyleClass().add("toggle-icon4");
|
||||||
btnAddServer.setOnAction(e -> {
|
btnAddServer.setOnAction(e -> {
|
||||||
Controllers.dialog(new AddAuthlibInjectorServerPane());
|
Controllers.dialog(new AddAuthlibInjectorServerPane());
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import javafx.scene.input.MouseEvent;
|
|||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||||
@@ -109,8 +108,8 @@ public class AdvancedListBox extends ScrollPane {
|
|||||||
item.activeProperty().bind(tabHeader.getSelectionModel().selectedItemProperty().isEqualTo(tab));
|
item.activeProperty().bind(tabHeader.getSelectionModel().selectedItemProperty().isEqualTo(tab));
|
||||||
item.setOnAction(e -> tabHeader.select(tab));
|
item.setOnAction(e -> tabHeader.select(tab));
|
||||||
|
|
||||||
Node unselectedIcon = unselectedGraphic.createIcon((Paint) null, 20);
|
Node unselectedIcon = unselectedGraphic.createIcon(20);
|
||||||
Node selectedIcon = selectedGraphic.createIcon((Paint) null, 20);
|
Node selectedIcon = selectedGraphic.createIcon(20);
|
||||||
|
|
||||||
TransitionPane leftGraphic = new TransitionPane();
|
TransitionPane leftGraphic = new TransitionPane();
|
||||||
leftGraphic.setAlignment(Pos.CENTER);
|
leftGraphic.setAlignment(Pos.CENTER);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
@@ -44,7 +43,6 @@ public class ClassTitle extends StackPane {
|
|||||||
Rectangle rectangle = new Rectangle();
|
Rectangle rectangle = new Rectangle();
|
||||||
rectangle.widthProperty().bind(vbox.widthProperty());
|
rectangle.widthProperty().bind(vbox.widthProperty());
|
||||||
rectangle.setHeight(1.0);
|
rectangle.setHeight(1.0);
|
||||||
rectangle.setFill(Color.GRAY);
|
|
||||||
vbox.getChildren().add(rectangle);
|
vbox.getChildren().add(rectangle);
|
||||||
getChildren().setAll(vbox);
|
getChildren().setAll(vbox);
|
||||||
getStyleClass().add("class-title");
|
getStyleClass().add("class-title");
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import javafx.scene.input.MouseEvent;
|
|||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||||
@@ -79,7 +79,7 @@ final class ComponentListCell extends StackPane {
|
|||||||
|
|
||||||
VBox groupNode = new VBox();
|
VBox groupNode = new VBox();
|
||||||
|
|
||||||
Node expandIcon = SVG.KEYBOARD_ARROW_DOWN.createIcon(Theme.blackFill(), 20);
|
Node expandIcon = SVG.KEYBOARD_ARROW_DOWN.createIcon(20);
|
||||||
expandIcon.setMouseTransparent(true);
|
expandIcon.setMouseTransparent(true);
|
||||||
HBox.setMargin(expandIcon, new Insets(0, 8, 0, 8));
|
HBox.setMargin(expandIcon, new Insets(0, 8, 0, 8));
|
||||||
|
|
||||||
@@ -99,12 +99,14 @@ final class ComponentListCell extends StackPane {
|
|||||||
if (!overrideHeaderLeft) {
|
if (!overrideHeaderLeft) {
|
||||||
Label label = new Label();
|
Label label = new Label();
|
||||||
label.textProperty().bind(list.titleProperty());
|
label.textProperty().bind(list.titleProperty());
|
||||||
|
label.getStyleClass().add("title-label");
|
||||||
labelVBox.getChildren().add(label);
|
labelVBox.getChildren().add(label);
|
||||||
|
|
||||||
if (list.isHasSubtitle()) {
|
if (list.isHasSubtitle()) {
|
||||||
Label subtitleLabel = new Label();
|
Label subtitleLabel = new Label();
|
||||||
subtitleLabel.textProperty().bind(list.subtitleProperty());
|
subtitleLabel.textProperty().bind(list.subtitleProperty());
|
||||||
subtitleLabel.getStyleClass().add("subtitle-label");
|
subtitleLabel.getStyleClass().add("subtitle-label");
|
||||||
|
subtitleLabel.textFillProperty().bind(Themes.colorSchemeProperty().getOnSurfaceVariant());
|
||||||
labelVBox.getChildren().add(subtitleLabel);
|
labelVBox.getChildren().add(subtitleLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javafx.scene.layout.BorderPane;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.DirectoryChooser;
|
import javafx.stage.DirectoryChooser;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@@ -60,7 +59,7 @@ public class FileItem extends BorderPane {
|
|||||||
setLeft(left);
|
setLeft(left);
|
||||||
|
|
||||||
JFXButton right = new JFXButton();
|
JFXButton right = new JFXButton();
|
||||||
right.setGraphic(SVG.EDIT.createIcon(Theme.blackFill(), 16));
|
right.setGraphic(SVG.EDIT.createIcon(16));
|
||||||
right.getStyleClass().add("toggle-icon4");
|
right.getStyleClass().add("toggle-icon4");
|
||||||
right.setOnAction(e -> onExplore());
|
right.setOnAction(e -> onExplore());
|
||||||
FXUtils.installFastTooltip(right, i18n("button.edit"));
|
FXUtils.installFastTooltip(right, i18n("button.edit"));
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import javafx.geometry.Pos;
|
|||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.stage.DirectoryChooser;
|
import javafx.stage.DirectoryChooser;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@@ -82,7 +81,7 @@ public class FileSelector extends HBox {
|
|||||||
FXUtils.bindString(customField, valueProperty());
|
FXUtils.bindString(customField, valueProperty());
|
||||||
|
|
||||||
JFXButton selectButton = new JFXButton();
|
JFXButton selectButton = new JFXButton();
|
||||||
selectButton.setGraphic(SVG.FOLDER_OPEN.createIcon(Theme.blackFill(), 15));
|
selectButton.setGraphic(SVG.FOLDER_OPEN.createIcon(15));
|
||||||
selectButton.setOnAction(e -> {
|
selectButton.setOnAction(e -> {
|
||||||
if (directory) {
|
if (directory) {
|
||||||
DirectoryChooser chooser = new DirectoryChooser();
|
DirectoryChooser chooser = new DirectoryChooser();
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import javafx.scene.layout.Region;
|
|||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
|
||||||
|
// Referenced in root.css
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class FloatScrollBarSkin implements Skin<ScrollBar> {
|
public class FloatScrollBarSkin implements Skin<ScrollBar> {
|
||||||
private ScrollBar scrollBar;
|
private ScrollBar scrollBar;
|
||||||
private Region group;
|
private Region group;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import javafx.scene.layout.HBox;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.scene.text.TextFlow;
|
import javafx.scene.text.TextFlow;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@@ -67,7 +66,7 @@ public class HintPane extends VBox {
|
|||||||
throw new IllegalArgumentException("Unrecognized message box message type " + type);
|
throw new IllegalArgumentException("Unrecognized message box message type " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
HBox hbox = new HBox(svg.createIcon(Theme.blackFill(), 16), new Text(type.getDisplayName()));
|
HBox hbox = new HBox(svg.createIcon(16), new Text(type.getDisplayName()));
|
||||||
hbox.setAlignment(Pos.CENTER_LEFT);
|
hbox.setAlignment(Pos.CENTER_LEFT);
|
||||||
flow.getChildren().setAll(label);
|
flow.getChildren().setAll(label);
|
||||||
getChildren().setAll(hbox, flow);
|
getChildren().setAll(hbox, flow);
|
||||||
|
|||||||
@@ -18,14 +18,13 @@
|
|||||||
package org.jackhuang.hmcl.ui.construct;
|
package org.jackhuang.hmcl.ui.construct;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXPopup;
|
import com.jfoenix.controls.JFXPopup;
|
||||||
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;
|
||||||
|
|
||||||
public class IconedMenuItem extends IconedItem {
|
public final class IconedMenuItem extends IconedItem {
|
||||||
|
|
||||||
public IconedMenuItem(SVG icon, String text, Runnable action, JFXPopup popup) {
|
public IconedMenuItem(SVG icon, String text, Runnable action, JFXPopup popup) {
|
||||||
super(icon != null ? FXUtils.limitingSize(icon.createIcon(Theme.blackFill(), 14), 14, 14) : null, text);
|
super(icon != null ? icon.createIcon(14) : null, text);
|
||||||
|
|
||||||
getStyleClass().setAll("iconed-menu-item");
|
getStyleClass().setAll("iconed-menu-item");
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import javafx.scene.image.Image;
|
|||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
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;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
@@ -111,7 +110,7 @@ public class IconedTwoLineListItem extends HBox {
|
|||||||
if (externalLinkButton == null) {
|
if (externalLinkButton == null) {
|
||||||
externalLinkButton = new JFXButton();
|
externalLinkButton = new JFXButton();
|
||||||
externalLinkButton.getStyleClass().add("toggle-icon4");
|
externalLinkButton.getStyleClass().add("toggle-icon4");
|
||||||
externalLinkButton.setGraphic(SVG.OPEN_IN_NEW.createIcon(Theme.blackFill(), -1));
|
externalLinkButton.setGraphic(SVG.OPEN_IN_NEW.createIcon());
|
||||||
externalLinkButton.setOnAction(e -> FXUtils.openLink(externalLink.get()));
|
externalLinkButton.setOnAction(e -> FXUtils.openLink(externalLink.get()));
|
||||||
}
|
}
|
||||||
return externalLinkButton;
|
return externalLinkButton;
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import javafx.scene.image.ImageView;
|
|||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
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;
|
||||||
|
|
||||||
@@ -54,12 +53,12 @@ public final class ImagePickerItem extends BorderPane {
|
|||||||
imageView.setPreserveRatio(true);
|
imageView.setPreserveRatio(true);
|
||||||
|
|
||||||
JFXButton selectButton = new JFXButton();
|
JFXButton selectButton = new JFXButton();
|
||||||
selectButton.setGraphic(SVG.EDIT.createIcon(Theme.blackFill(), 20));
|
selectButton.setGraphic(SVG.EDIT.createIcon(20));
|
||||||
selectButton.onActionProperty().bind(onSelectButtonClicked);
|
selectButton.onActionProperty().bind(onSelectButtonClicked);
|
||||||
selectButton.getStyleClass().add("toggle-icon4");
|
selectButton.getStyleClass().add("toggle-icon4");
|
||||||
|
|
||||||
JFXButton deleteButton = new JFXButton();
|
JFXButton deleteButton = new JFXButton();
|
||||||
deleteButton.setGraphic(SVG.CLOSE.createIcon(Theme.blackFill(), 20));
|
deleteButton.setGraphic(SVG.CLOSE.createIcon(20));
|
||||||
deleteButton.onActionProperty().bind(onDeleteButtonClicked);
|
deleteButton.onActionProperty().bind(onDeleteButtonClicked);
|
||||||
deleteButton.getStyleClass().add("toggle-icon4");
|
deleteButton.getStyleClass().add("toggle-icon4");
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.jackhuang.hmcl.ui.construct;
|
package org.jackhuang.hmcl.ui.construct;
|
||||||
|
|
||||||
import javafx.scene.control.Hyperlink;
|
import javafx.scene.control.Hyperlink;
|
||||||
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;
|
||||||
|
|
||||||
@@ -27,7 +26,7 @@ public final class JFXHyperlink extends Hyperlink {
|
|||||||
public JFXHyperlink(String text) {
|
public JFXHyperlink(String text) {
|
||||||
super(text);
|
super(text);
|
||||||
|
|
||||||
setGraphic(SVG.OPEN_IN_NEW.createIcon(Theme.blackFill(), 16));
|
setGraphic(SVG.OPEN_IN_NEW.createIcon(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExternalLink(String externalLink) {
|
public void setExternalLink(String externalLink) {
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
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;
|
||||||
|
|
||||||
@@ -39,6 +38,7 @@ public class MenuUpDownButton extends Control {
|
|||||||
private final StringProperty text = new SimpleStringProperty(this, "text");
|
private final StringProperty text = new SimpleStringProperty(this, "text");
|
||||||
|
|
||||||
public MenuUpDownButton() {
|
public MenuUpDownButton() {
|
||||||
|
this.getStyleClass().add("menu-up-down-button");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,11 +78,10 @@ public class MenuUpDownButton extends Control {
|
|||||||
HBox content = new HBox(8);
|
HBox content = new HBox(8);
|
||||||
content.setAlignment(Pos.CENTER);
|
content.setAlignment(Pos.CENTER);
|
||||||
Label label = new Label();
|
Label label = new Label();
|
||||||
label.setStyle("-fx-text-fill: black;");
|
|
||||||
label.textProperty().bind(control.text);
|
label.textProperty().bind(control.text);
|
||||||
|
|
||||||
Node up = SVG.ARROW_DROP_UP.createIcon(Theme.blackFill(), 16);
|
Node up = SVG.ARROW_DROP_UP.createIcon(16);
|
||||||
Node down = SVG.ARROW_DROP_DOWN.createIcon(Theme.blackFill(), 16);
|
Node down = SVG.ARROW_DROP_DOWN.createIcon(16);
|
||||||
|
|
||||||
JFXButton button = new JFXButton();
|
JFXButton button = new JFXButton();
|
||||||
button.setGraphic(content);
|
button.setGraphic(content);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javafx.scene.layout.Priority;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.text.TextFlow;
|
import javafx.scene.text.TextFlow;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
@@ -91,7 +90,7 @@ public final class MessageDialogPane extends HBox {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unrecognized message box message type " + type);
|
throw new IllegalArgumentException("Unrecognized message box message type " + type);
|
||||||
}
|
}
|
||||||
graphic.setGraphic(svg.createIcon(Theme.blackFill(), 40));
|
graphic.setGraphic(svg.createIcon(40));
|
||||||
|
|
||||||
VBox vbox = new VBox();
|
VBox vbox = new VBox();
|
||||||
HBox.setHgrow(vbox, Priority.ALWAYS);
|
HBox.setHgrow(vbox, Priority.ALWAYS);
|
||||||
|
|||||||
@@ -31,12 +31,15 @@ import javafx.scene.control.Toggle;
|
|||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
|
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -308,11 +311,21 @@ public final class MultiFileItem<T> extends VBox {
|
|||||||
super(title, data);
|
super(title, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaintOption<T> setCustomColors(List<Color> colors) {
|
||||||
|
colorPicker.getCustomColors().setAll(colors);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public PaintOption<T> bindBidirectional(Property<Paint> property) {
|
public PaintOption<T> bindBidirectional(Property<Paint> property) {
|
||||||
FXUtils.bindPaint(colorPicker, property);
|
FXUtils.bindPaint(colorPicker, property);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaintOption<T> bindThemeColorBidirectional(Property<ThemeColor> property) {
|
||||||
|
ThemeColor.bindBidirectional(colorPicker, property);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createItem(ToggleGroup group) {
|
protected Node createItem(ToggleGroup group) {
|
||||||
BorderPane pane = new BorderPane();
|
BorderPane pane = new BorderPane();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import javafx.scene.paint.Color;
|
|||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||||
import org.jackhuang.hmcl.ui.animation.Motion;
|
import org.jackhuang.hmcl.ui.animation.Motion;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
@@ -50,7 +51,7 @@ public class RipplerContainer extends StackPane {
|
|||||||
private static final Duration DURATION = Duration.millis(200);
|
private static final Duration DURATION = Duration.millis(200);
|
||||||
|
|
||||||
private final ObjectProperty<Node> container = new SimpleObjectProperty<>(this, "container", null);
|
private final ObjectProperty<Node> container = new SimpleObjectProperty<>(this, "container", null);
|
||||||
private final StyleableObjectProperty<Paint> ripplerFill = new SimpleStyleableObjectProperty<>(StyleableProperties.RIPPLER_FILL,this, "ripplerFill", null);
|
private final StyleableObjectProperty<Paint> ripplerFill = new SimpleStyleableObjectProperty<>(StyleableProperties.RIPPLER_FILL, this, "ripplerFill", null);
|
||||||
private final BooleanProperty selected = new SimpleBooleanProperty(this, "selected", false);
|
private final BooleanProperty selected = new SimpleBooleanProperty(this, "selected", false);
|
||||||
|
|
||||||
private final StackPane buttonContainer = new StackPane();
|
private final StackPane buttonContainer = new StackPane();
|
||||||
@@ -136,7 +137,10 @@ public class RipplerContainer extends StackPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void interpolateBackground(double frac) {
|
private void interpolateBackground(double frac) {
|
||||||
setBackground(new Background(new BackgroundFill(Color.rgb(0, 0, 0, frac * 0.04), CornerRadii.EMPTY, Insets.EMPTY)));
|
Color onSurface = Themes.getColorScheme().getOnSurface();
|
||||||
|
setBackground(new Background(new BackgroundFill(
|
||||||
|
Color.color(onSurface.getRed(), onSurface.getGreen(), onSurface.getBlue(), frac * 0.04),
|
||||||
|
CornerRadii.EMPTY, Insets.EMPTY)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateChildren() {
|
protected void updateChildren() {
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ public class TaskExecutorDialogPane extends BorderPane {
|
|||||||
private final TaskListPane taskListPane;
|
private final TaskListPane taskListPane;
|
||||||
|
|
||||||
public TaskExecutorDialogPane(@NotNull TaskCancellationAction cancel) {
|
public TaskExecutorDialogPane(@NotNull TaskCancellationAction cancel) {
|
||||||
|
this.getStyleClass().add("task-executor-dialog-layout");
|
||||||
|
|
||||||
FXUtils.setLimitWidth(this, 500);
|
FXUtils.setLimitWidth(this, 500);
|
||||||
FXUtils.setLimitHeight(this, 300);
|
FXUtils.setLimitHeight(this, 300);
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ import org.jackhuang.hmcl.mod.multimc.MultiMCModpackInstallTask;
|
|||||||
import org.jackhuang.hmcl.mod.server.ServerModpackCompletionTask;
|
import org.jackhuang.hmcl.mod.server.ServerModpackCompletionTask;
|
||||||
import org.jackhuang.hmcl.mod.server.ServerModpackExportTask;
|
import org.jackhuang.hmcl.mod.server.ServerModpackExportTask;
|
||||||
import org.jackhuang.hmcl.mod.server.ServerModpackLocalInstallTask;
|
import org.jackhuang.hmcl.mod.server.ServerModpackLocalInstallTask;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||||
import org.jackhuang.hmcl.task.TaskListener;
|
import org.jackhuang.hmcl.task.TaskListener;
|
||||||
@@ -310,7 +309,7 @@ public final class TaskListPane extends StackPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateLeftIcon(StageNode.Status status) {
|
private void updateLeftIcon(StageNode.Status status) {
|
||||||
left.getChildren().setAll(status.svg.createIcon(Theme.blackFill(), STATUS_ICON_SIZE));
|
left.getChildren().setAll(status.svg.createIcon(STATUS_ICON_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import javafx.stage.Stage;
|
|||||||
|
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||||
@@ -233,19 +233,19 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
{
|
{
|
||||||
JFXButton btnHelp = new JFXButton();
|
JFXButton btnHelp = new JFXButton();
|
||||||
btnHelp.setFocusTraversable(false);
|
btnHelp.setFocusTraversable(false);
|
||||||
btnHelp.setGraphic(SVG.HELP.createIcon(Theme.foregroundFillBinding(), -1));
|
btnHelp.setGraphic(SVG.HELP.createIcon(Themes.titleFillProperty()));
|
||||||
btnHelp.getStyleClass().add("jfx-decorator-button");
|
btnHelp.getStyleClass().add("jfx-decorator-button");
|
||||||
btnHelp.setOnAction(e -> FXUtils.openLink(Metadata.CONTACT_URL));
|
btnHelp.setOnAction(e -> FXUtils.openLink(Metadata.CONTACT_URL));
|
||||||
|
|
||||||
JFXButton btnMin = new JFXButton();
|
JFXButton btnMin = new JFXButton();
|
||||||
btnMin.setFocusTraversable(false);
|
btnMin.setFocusTraversable(false);
|
||||||
btnMin.setGraphic(SVG.MINIMIZE.createIcon(Theme.foregroundFillBinding(), -1));
|
btnMin.setGraphic(SVG.MINIMIZE.createIcon(Themes.titleFillProperty()));
|
||||||
btnMin.getStyleClass().add("jfx-decorator-button");
|
btnMin.getStyleClass().add("jfx-decorator-button");
|
||||||
btnMin.setOnAction(e -> skinnable.minimize());
|
btnMin.setOnAction(e -> skinnable.minimize());
|
||||||
|
|
||||||
JFXButton btnClose = new JFXButton();
|
JFXButton btnClose = new JFXButton();
|
||||||
btnClose.setFocusTraversable(false);
|
btnClose.setFocusTraversable(false);
|
||||||
btnClose.setGraphic(SVG.CLOSE.createIcon(Theme.foregroundFillBinding(), -1));
|
btnClose.setGraphic(SVG.CLOSE.createIcon(Themes.titleFillProperty()));
|
||||||
btnClose.getStyleClass().add("jfx-decorator-button");
|
btnClose.getStyleClass().add("jfx-decorator-button");
|
||||||
btnClose.setOnAction(e -> skinnable.close());
|
btnClose.setOnAction(e -> skinnable.close());
|
||||||
|
|
||||||
@@ -265,6 +265,8 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
|
|
||||||
private Node createNavBar(Decorator skinnable, double leftPaneWidth, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) {
|
private Node createNavBar(Decorator skinnable, double leftPaneWidth, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) {
|
||||||
BorderPane navBar = new BorderPane();
|
BorderPane navBar = new BorderPane();
|
||||||
|
navBar.getStyleClass().add("navigation-bar");
|
||||||
|
|
||||||
{
|
{
|
||||||
HBox navLeft = new HBox();
|
HBox navLeft = new HBox();
|
||||||
navLeft.setAlignment(Pos.CENTER_LEFT);
|
navLeft.setAlignment(Pos.CENTER_LEFT);
|
||||||
@@ -273,9 +275,8 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
if (canBack) {
|
if (canBack) {
|
||||||
JFXButton backNavButton = new JFXButton();
|
JFXButton backNavButton = new JFXButton();
|
||||||
backNavButton.setFocusTraversable(false);
|
backNavButton.setFocusTraversable(false);
|
||||||
backNavButton.setGraphic(SVG.ARROW_BACK.createIcon(Theme.foregroundFillBinding(), -1));
|
backNavButton.setGraphic(SVG.ARROW_BACK.createIcon(Themes.titleFillProperty()));
|
||||||
backNavButton.getStyleClass().add("jfx-decorator-button");
|
backNavButton.getStyleClass().add("jfx-decorator-button");
|
||||||
backNavButton.ripplerFillProperty().set(Theme.whiteFill());
|
|
||||||
backNavButton.onActionProperty().bind(skinnable.onBackNavButtonActionProperty());
|
backNavButton.onActionProperty().bind(skinnable.onBackNavButtonActionProperty());
|
||||||
backNavButton.visibleProperty().set(canBack);
|
backNavButton.visibleProperty().set(canBack);
|
||||||
|
|
||||||
@@ -285,14 +286,13 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
if (canClose) {
|
if (canClose) {
|
||||||
JFXButton closeNavButton = new JFXButton();
|
JFXButton closeNavButton = new JFXButton();
|
||||||
closeNavButton.setFocusTraversable(false);
|
closeNavButton.setFocusTraversable(false);
|
||||||
closeNavButton.setGraphic(SVG.CLOSE.createIcon(Theme.foregroundFillBinding(), -1));
|
closeNavButton.setGraphic(SVG.CLOSE.createIcon(Themes.titleFillProperty()));
|
||||||
closeNavButton.getStyleClass().add("jfx-decorator-button");
|
closeNavButton.getStyleClass().add("jfx-decorator-button");
|
||||||
closeNavButton.ripplerFillProperty().set(Theme.whiteFill());
|
|
||||||
closeNavButton.onActionProperty().bind(skinnable.onCloseNavButtonActionProperty());
|
closeNavButton.onActionProperty().bind(skinnable.onCloseNavButtonActionProperty());
|
||||||
if (showCloseAsHome)
|
if (showCloseAsHome)
|
||||||
closeNavButton.setGraphic(SVG.HOME.createIcon(Theme.foregroundFillBinding(), -1));
|
closeNavButton.setGraphic(SVG.HOME.createIcon(Themes.titleFillProperty()));
|
||||||
else
|
else
|
||||||
closeNavButton.setGraphic(SVG.CLOSE.createIcon(Theme.foregroundFillBinding(), -1));
|
closeNavButton.setGraphic(SVG.CLOSE.createIcon(Themes.titleFillProperty()));
|
||||||
|
|
||||||
navLeft.getChildren().add(closeNavButton);
|
navLeft.getChildren().add(closeNavButton);
|
||||||
}
|
}
|
||||||
@@ -333,9 +333,8 @@ public class DecoratorSkin extends SkinBase<Decorator> {
|
|||||||
HBox navRight = new HBox();
|
HBox navRight = new HBox();
|
||||||
navRight.setAlignment(Pos.CENTER_RIGHT);
|
navRight.setAlignment(Pos.CENTER_RIGHT);
|
||||||
JFXButton refreshNavButton = new JFXButton();
|
JFXButton refreshNavButton = new JFXButton();
|
||||||
refreshNavButton.setGraphic(SVG.REFRESH.createIcon(Theme.foregroundFillBinding(), -1));
|
refreshNavButton.setGraphic(SVG.REFRESH.createIcon(Themes.titleFillProperty()));
|
||||||
refreshNavButton.getStyleClass().add("jfx-decorator-button");
|
refreshNavButton.getStyleClass().add("jfx-decorator-button");
|
||||||
refreshNavButton.ripplerFillProperty().set(Theme.whiteFill());
|
|
||||||
refreshNavButton.onActionProperty().bind(skinnable.onRefreshNavButtonActionProperty());
|
refreshNavButton.onActionProperty().bind(skinnable.onRefreshNavButtonActionProperty());
|
||||||
|
|
||||||
Rectangle separator = new Rectangle();
|
Rectangle separator = new Rectangle();
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public final class ExportWizardProvider implements WizardProvider {
|
|||||||
|
|
||||||
exported.setBackgroundImageType(config().getBackgroundImageType());
|
exported.setBackgroundImageType(config().getBackgroundImageType());
|
||||||
exported.setBackgroundImage(config().getBackgroundImage());
|
exported.setBackgroundImage(config().getBackgroundImage());
|
||||||
exported.setTheme(config().getTheme());
|
exported.setThemeColor(config().getThemeColor());
|
||||||
exported.setDownloadType(config().getDownloadType());
|
exported.setDownloadType(config().getDownloadType());
|
||||||
exported.setPreferredLoginType(config().getPreferredLoginType());
|
exported.setPreferredLoginType(config().getPreferredLoginType());
|
||||||
exported.getAuthlibInjectorServers().setAll(config().getAuthlibInjectorServers());
|
exported.getAuthlibInjectorServers().setAll(config().getAuthlibInjectorServers());
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ import com.google.gson.JsonArray;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
||||||
@@ -105,6 +107,12 @@ public final class AboutPage extends StackPane {
|
|||||||
getChildren().setAll(scrollPane);
|
getChildren().setAll(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Image loadImage(String url) {
|
||||||
|
return url.startsWith("/")
|
||||||
|
? FXUtils.newBuiltinImage(url)
|
||||||
|
: new Image(url);
|
||||||
|
}
|
||||||
|
|
||||||
private static ComponentList loadIconedTwoLineList(String path) {
|
private static ComponentList loadIconedTwoLineList(String path) {
|
||||||
ComponentList componentList = new ComponentList();
|
ComponentList componentList = new ComponentList();
|
||||||
|
|
||||||
@@ -122,10 +130,14 @@ public final class AboutPage extends StackPane {
|
|||||||
IconedTwoLineListItem item = new IconedTwoLineListItem();
|
IconedTwoLineListItem item = new IconedTwoLineListItem();
|
||||||
|
|
||||||
if (obj.has("image")) {
|
if (obj.has("image")) {
|
||||||
String image = obj.get("image").getAsString();
|
JsonElement image = obj.get("image");
|
||||||
item.setImage(image.startsWith("/")
|
if (image.isJsonPrimitive()) {
|
||||||
? FXUtils.newBuiltinImage(image)
|
item.setImage(loadImage(image.getAsString()));
|
||||||
: new Image(image));
|
} else if (image.isJsonObject()) {
|
||||||
|
item.imageProperty().bind(Bindings.when(Themes.darkModeProperty())
|
||||||
|
.then(loadImage(image.getAsJsonObject().get("dark").getAsString()))
|
||||||
|
.otherwise(loadImage(image.getAsJsonObject().get("light").getAsString())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.has("title"))
|
if (obj.has("title"))
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.main;
|
package org.jackhuang.hmcl.ui.main;
|
||||||
|
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import org.jackhuang.hmcl.theme.Themes;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
||||||
@@ -50,7 +52,9 @@ public class FeedbackPage extends SpinnerPane {
|
|||||||
users.setExternalLink(Metadata.GROUPS_URL);
|
users.setExternalLink(Metadata.GROUPS_URL);
|
||||||
|
|
||||||
IconedTwoLineListItem github = new IconedTwoLineListItem();
|
IconedTwoLineListItem github = new IconedTwoLineListItem();
|
||||||
github.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
|
github.imageProperty().bind(Bindings.when(Themes.darkModeProperty())
|
||||||
|
.then(FXUtils.newBuiltinImage("/assets/img/github-white.png"))
|
||||||
|
.otherwise(FXUtils.newBuiltinImage("/assets/img/github.png")));
|
||||||
github.setTitle(i18n("feedback.github"));
|
github.setTitle(i18n("feedback.github"));
|
||||||
github.setSubtitle(i18n("feedback.github.statement"));
|
github.setSubtitle(i18n("feedback.github.statement"));
|
||||||
github.setExternalLink("https://github.com/HMCL-dev/HMCL/issues/new/choose");
|
github.setExternalLink("https://github.com/HMCL-dev/HMCL/issues/new/choose");
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import org.jackhuang.hmcl.java.JavaManager;
|
|||||||
import org.jackhuang.hmcl.java.JavaRuntime;
|
import org.jackhuang.hmcl.java.JavaRuntime;
|
||||||
import org.jackhuang.hmcl.setting.ConfigHolder;
|
import org.jackhuang.hmcl.setting.ConfigHolder;
|
||||||
import org.jackhuang.hmcl.setting.DownloadProviders;
|
import org.jackhuang.hmcl.setting.DownloadProviders;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
@@ -263,7 +262,7 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
|
|||||||
{
|
{
|
||||||
JFXButton revealButton = new JFXButton();
|
JFXButton revealButton = new JFXButton();
|
||||||
revealButton.getStyleClass().add("toggle-icon4");
|
revealButton.getStyleClass().add("toggle-icon4");
|
||||||
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(Theme.blackFill(), 24), 24, 24));
|
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(24), 24, 24));
|
||||||
revealButton.setOnAction(e -> control.onReveal());
|
revealButton.setOnAction(e -> control.onReveal());
|
||||||
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
|
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
|
||||||
|
|
||||||
@@ -276,12 +275,12 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
|
|||||||
null
|
null
|
||||||
));
|
));
|
||||||
if (java.isManaged()) {
|
if (java.isManaged()) {
|
||||||
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE_FOREVER.createIcon(Theme.blackFill(), 24), 24, 24));
|
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE_FOREVER.createIcon(24), 24, 24));
|
||||||
FXUtils.installFastTooltip(removeButton, i18n("java.uninstall"));
|
FXUtils.installFastTooltip(removeButton, i18n("java.uninstall"));
|
||||||
if (JavaRuntime.CURRENT_JAVA != null && java.getBinary().equals(JavaRuntime.CURRENT_JAVA.getBinary()))
|
if (JavaRuntime.CURRENT_JAVA != null && java.getBinary().equals(JavaRuntime.CURRENT_JAVA.getBinary()))
|
||||||
removeButton.setDisable(true);
|
removeButton.setDisable(true);
|
||||||
} else {
|
} else {
|
||||||
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE.createIcon(Theme.blackFill(), 24), 24, 24));
|
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE.createIcon(24), 24, 24));
|
||||||
FXUtils.installFastTooltip(removeButton, i18n("java.disable"));
|
FXUtils.installFastTooltip(removeButton, i18n("java.disable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import org.jackhuang.hmcl.java.JavaManager;
|
import org.jackhuang.hmcl.java.JavaManager;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||||
@@ -160,7 +159,7 @@ public final class JavaRestorePage extends ListPageBase<JavaRestorePage.Disabled
|
|||||||
{
|
{
|
||||||
JFXButton revealButton = new JFXButton();
|
JFXButton revealButton = new JFXButton();
|
||||||
revealButton.getStyleClass().add("toggle-icon4");
|
revealButton.getStyleClass().add("toggle-icon4");
|
||||||
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(Theme.blackFill(), 24), 24, 24));
|
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(24), 24, 24));
|
||||||
revealButton.setOnAction(e -> skinnable.onReveal());
|
revealButton.setOnAction(e -> skinnable.onReveal());
|
||||||
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
|
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
|
||||||
|
|
||||||
@@ -169,7 +168,7 @@ public final class JavaRestorePage extends ListPageBase<JavaRestorePage.Disabled
|
|||||||
|
|
||||||
JFXButton removeButton = new JFXButton();
|
JFXButton removeButton = new JFXButton();
|
||||||
removeButton.getStyleClass().add("toggle-icon4");
|
removeButton.getStyleClass().add("toggle-icon4");
|
||||||
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE.createIcon(Theme.blackFill(), 24), 24, 24));
|
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE.createIcon(24), 24, 24));
|
||||||
removeButton.setOnAction(e -> skinnable.onRemove());
|
removeButton.setOnAction(e -> skinnable.onRemove());
|
||||||
FXUtils.installFastTooltip(removeButton, i18n("java.disabled.management.remove"));
|
FXUtils.installFastTooltip(removeButton, i18n("java.disabled.management.remove"));
|
||||||
|
|
||||||
@@ -177,7 +176,7 @@ public final class JavaRestorePage extends ListPageBase<JavaRestorePage.Disabled
|
|||||||
} else {
|
} else {
|
||||||
JFXButton restoreButton = new JFXButton();
|
JFXButton restoreButton = new JFXButton();
|
||||||
restoreButton.getStyleClass().add("toggle-icon4");
|
restoreButton.getStyleClass().add("toggle-icon4");
|
||||||
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24), 24, 24));
|
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(24), 24, 24));
|
||||||
restoreButton.setOnAction(e -> skinnable.onRestore());
|
restoreButton.setOnAction(e -> skinnable.onRestore());
|
||||||
FXUtils.installFastTooltip(restoreButton, i18n("java.disabled.management.restore"));
|
FXUtils.installFastTooltip(restoreButton, i18n("java.disabled.management.restore"));
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import org.jackhuang.hmcl.game.Version;
|
|||||||
import org.jackhuang.hmcl.setting.DownloadProviders;
|
import org.jackhuang.hmcl.setting.DownloadProviders;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
@@ -152,7 +151,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnHide.getStyleClass().add("announcement-close-button");
|
btnHide.getStyleClass().add("announcement-close-button");
|
||||||
btnHide.setGraphic(SVG.CLOSE.createIcon(Theme.blackFill(), 20));
|
btnHide.setGraphic(SVG.CLOSE.createIcon(20));
|
||||||
titleBar.setRight(btnHide);
|
titleBar.setRight(btnHide);
|
||||||
|
|
||||||
TextFlow body = FXUtils.segmentToTextFlow(content, Controllers::onHyperlinkAction);
|
TextFlow body = FXUtils.segmentToTextFlow(content, Controllers::onHyperlinkAction);
|
||||||
@@ -188,7 +187,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
StackPane.setMargin(hBox, new Insets(9, 12, 9, 16));
|
StackPane.setMargin(hBox, new Insets(9, 12, 9, 16));
|
||||||
{
|
{
|
||||||
Label lblIcon = new Label();
|
Label lblIcon = new Label();
|
||||||
lblIcon.setGraphic(SVG.UPDATE.createIcon(Theme.whiteFill(), 20));
|
lblIcon.setGraphic(SVG.UPDATE.createIcon(20));
|
||||||
|
|
||||||
TwoLineListItem prompt = new TwoLineListItem();
|
TwoLineListItem prompt = new TwoLineListItem();
|
||||||
prompt.setSubtitle(i18n("update.bubble.subtitle"));
|
prompt.setSubtitle(i18n("update.bubble.subtitle"));
|
||||||
@@ -200,7 +199,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JFXButton closeUpdateButton = new JFXButton();
|
JFXButton closeUpdateButton = new JFXButton();
|
||||||
closeUpdateButton.setGraphic(SVG.CLOSE.createIcon(Theme.whiteFill(), 10));
|
closeUpdateButton.setGraphic(SVG.CLOSE.createIcon(10));
|
||||||
StackPane.setAlignment(closeUpdateButton, Pos.TOP_RIGHT);
|
StackPane.setAlignment(closeUpdateButton, Pos.TOP_RIGHT);
|
||||||
closeUpdateButton.getStyleClass().add("toggle-icon-tiny");
|
closeUpdateButton.getStyleClass().add("toggle-icon-tiny");
|
||||||
StackPane.setMargin(closeUpdateButton, new Insets(5));
|
StackPane.setMargin(closeUpdateButton, new Insets(5));
|
||||||
@@ -277,7 +276,7 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
menuButton.setOnAction(e -> onMenu());
|
menuButton.setOnAction(e -> onMenu());
|
||||||
menuButton.setClip(new Rectangle(211, -100, 100, 200));
|
menuButton.setClip(new Rectangle(211, -100, 100, 200));
|
||||||
StackPane graphic = new StackPane();
|
StackPane graphic = new StackPane();
|
||||||
Node svg = SVG.ARROW_DROP_UP.createIcon(Theme.foregroundFillBinding(), 30);
|
Node svg = SVG.ARROW_DROP_UP.createIcon(30);
|
||||||
StackPane.setAlignment(svg, Pos.CENTER_RIGHT);
|
StackPane.setAlignment(svg, Pos.CENTER_RIGHT);
|
||||||
graphic.getChildren().setAll(svg);
|
graphic.getChildren().setAll(svg);
|
||||||
graphic.setTranslateX(6);
|
graphic.setTranslateX(6);
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ import javafx.scene.control.ColorPicker;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.FontSmoothingType;
|
import javafx.scene.text.FontSmoothingType;
|
||||||
import org.jackhuang.hmcl.setting.EnumBackgroundImage;
|
import org.jackhuang.hmcl.setting.EnumBackgroundImage;
|
||||||
import org.jackhuang.hmcl.setting.FontManager;
|
import org.jackhuang.hmcl.setting.FontManager;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.construct.*;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
@@ -78,6 +77,22 @@ public class PersonalizationPage extends StackPane {
|
|||||||
getChildren().setAll(scrollPane);
|
getChildren().setAll(scrollPane);
|
||||||
|
|
||||||
ComponentList themeList = new ComponentList();
|
ComponentList themeList = new ComponentList();
|
||||||
|
{
|
||||||
|
BorderPane brightnessPane = new BorderPane();
|
||||||
|
themeList.getContent().add(brightnessPane);
|
||||||
|
|
||||||
|
Label left = new Label(i18n("settings.launcher.brightness"));
|
||||||
|
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
||||||
|
|
||||||
|
brightnessPane.setLeft(left);
|
||||||
|
|
||||||
|
JFXComboBox<String> cboBrightness = new JFXComboBox<>(
|
||||||
|
FXCollections.observableArrayList("auto", "light", "dark"));
|
||||||
|
cboBrightness.setConverter(FXUtils.stringConverter(name -> i18n("settings.launcher.brightness." + name)));
|
||||||
|
cboBrightness.valueProperty().bindBidirectional(config().themeBrightnessProperty());
|
||||||
|
brightnessPane.setRight(cboBrightness);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
BorderPane themePane = new BorderPane();
|
BorderPane themePane = new BorderPane();
|
||||||
themeList.getContent().add(themePane);
|
themeList.getContent().add(themePane);
|
||||||
@@ -90,10 +105,9 @@ public class PersonalizationPage extends StackPane {
|
|||||||
themeColorPickerContainer.setMinHeight(30);
|
themeColorPickerContainer.setMinHeight(30);
|
||||||
themePane.setRight(themeColorPickerContainer);
|
themePane.setRight(themeColorPickerContainer);
|
||||||
|
|
||||||
ColorPicker picker = new JFXColorPicker(Color.web(Theme.getTheme().getColor()));
|
ColorPicker picker = new JFXColorPicker();
|
||||||
picker.getCustomColors().setAll(Theme.SUGGESTED_COLORS);
|
picker.getCustomColors().setAll(ThemeColor.STANDARD_COLORS.stream().map(ThemeColor::color).toList());
|
||||||
picker.setOnAction(e ->
|
ThemeColor.bindBidirectional(picker, config().themeColorProperty());
|
||||||
config().setTheme(Theme.custom(Theme.getColorDisplayName(picker.getValue()))));
|
|
||||||
themeColorPickerContainer.getChildren().setAll(picker);
|
themeColorPickerContainer.getChildren().setAll(picker);
|
||||||
Platform.runLater(() -> JFXDepthManager.setDepth(picker, 0));
|
Platform.runLater(() -> JFXDepthManager.setDepth(picker, 0));
|
||||||
}
|
}
|
||||||
@@ -264,7 +278,7 @@ public class PersonalizationPage extends StackPane {
|
|||||||
|
|
||||||
JFXButton clearButton = new JFXButton();
|
JFXButton clearButton = new JFXButton();
|
||||||
clearButton.getStyleClass().add("toggle-icon4");
|
clearButton.getStyleClass().add("toggle-icon4");
|
||||||
clearButton.setGraphic(SVG.RESTORE.createIcon(Theme.blackFill(), -1));
|
clearButton.setGraphic(SVG.RESTORE.createIcon());
|
||||||
clearButton.setOnAction(e -> cboFont.setValue(null));
|
clearButton.setOnAction(e -> cboFont.setValue(null));
|
||||||
|
|
||||||
hBox.getChildren().setAll(cboFont, clearButton);
|
hBox.getChildren().setAll(cboFont, clearButton);
|
||||||
|
|||||||
@@ -93,13 +93,13 @@ public final class SettingsPage extends SettingsView {
|
|||||||
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
||||||
|
|
||||||
lblUpdate.setText(i18n("update"));
|
lblUpdate.setText(i18n("update"));
|
||||||
lblUpdate.getStyleClass().setAll();
|
lblUpdate.getStyleClass().setAll("title-label");
|
||||||
} else {
|
} else {
|
||||||
lblUpdateSub.setText(i18n("update.latest"));
|
lblUpdateSub.setText(i18n("update.latest"));
|
||||||
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
lblUpdateSub.getStyleClass().setAll("subtitle-label");
|
||||||
|
|
||||||
lblUpdate.setText(i18n("update"));
|
lblUpdate.setText(i18n("update"));
|
||||||
lblUpdate.getStyleClass().setAll();
|
lblUpdate.getStyleClass().setAll("title-label");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
|
UpdateChecker.latestVersionProperty().addListener(new WeakInvalidationListener(updateListener));
|
||||||
|
|||||||
@@ -27,11 +27,8 @@ import javafx.scene.Cursor;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import javafx.scene.text.TextAlignment;
|
import javafx.scene.text.TextAlignment;
|
||||||
import javafx.scene.text.TextFlow;
|
|
||||||
import org.jackhuang.hmcl.setting.EnumCommonDirectory;
|
import org.jackhuang.hmcl.setting.EnumCommonDirectory;
|
||||||
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;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
@@ -115,6 +112,7 @@ public abstract class SettingsView extends StackPane {
|
|||||||
VBox headerLeft = new VBox();
|
VBox headerLeft = new VBox();
|
||||||
|
|
||||||
lblUpdate = new Label(i18n("update"));
|
lblUpdate = new Label(i18n("update"));
|
||||||
|
lblUpdate.getStyleClass().add("title-label");
|
||||||
lblUpdateSub = new Label();
|
lblUpdateSub = new Label();
|
||||||
lblUpdateSub.getStyleClass().add("subtitle-label");
|
lblUpdateSub.getStyleClass().add("subtitle-label");
|
||||||
|
|
||||||
@@ -126,7 +124,7 @@ public abstract class SettingsView extends StackPane {
|
|||||||
btnUpdate = new JFXButton();
|
btnUpdate = new JFXButton();
|
||||||
btnUpdate.setOnAction(e -> onUpdate());
|
btnUpdate.setOnAction(e -> onUpdate());
|
||||||
btnUpdate.getStyleClass().add("toggle-icon4");
|
btnUpdate.getStyleClass().add("toggle-icon4");
|
||||||
btnUpdate.setGraphic(SVG.UPDATE.createIcon(Theme.blackFill(), 20));
|
btnUpdate.setGraphic(SVG.UPDATE.createIcon(20));
|
||||||
|
|
||||||
updatePane.setHeaderRight(btnUpdate);
|
updatePane.setHeaderRight(btnUpdate);
|
||||||
}
|
}
|
||||||
@@ -138,7 +136,7 @@ public abstract class SettingsView extends StackPane {
|
|||||||
chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable"));
|
chkUpdateStable = new JFXRadioButton(i18n("update.channel.stable"));
|
||||||
chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev"));
|
chkUpdateDev = new JFXRadioButton(i18n("update.channel.dev"));
|
||||||
|
|
||||||
TextFlow noteWrapper = new TextFlow(new Text(i18n("update.note")));
|
Label noteWrapper = new Label(i18n("update.note"));
|
||||||
VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0));
|
VBox.setMargin(noteWrapper, new Insets(10, 0, 0, 0));
|
||||||
|
|
||||||
content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper);
|
content.getChildren().setAll(chkUpdateStable, chkUpdateDev, noteWrapper);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
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;
|
||||||
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
|
||||||
@@ -64,7 +63,7 @@ public class ProfileListItemSkin extends SkinBase<ProfileListItem> {
|
|||||||
btnRemove.setOnAction(e -> skinnable.remove());
|
btnRemove.setOnAction(e -> skinnable.remove());
|
||||||
btnRemove.getStyleClass().add("toggle-icon4");
|
btnRemove.getStyleClass().add("toggle-icon4");
|
||||||
BorderPane.setAlignment(btnRemove, Pos.CENTER);
|
BorderPane.setAlignment(btnRemove, Pos.CENTER);
|
||||||
btnRemove.setGraphic(SVG.CLOSE.createIcon(Theme.blackFill(), 14));
|
btnRemove.setGraphic(SVG.CLOSE.createIcon(14));
|
||||||
right.getChildren().add(btnRemove);
|
right.getChildren().add(btnRemove);
|
||||||
root.setRight(right);
|
root.setRight(right);
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import javafx.scene.text.TextFlow;
|
|||||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.terracotta.TerracottaManager;
|
import org.jackhuang.hmcl.terracotta.TerracottaManager;
|
||||||
@@ -559,7 +558,7 @@ public class TerracottaControllerPage extends StackPane {
|
|||||||
Label description = new Label(link.description().getText(I18n.getLocale().getCandidateLocales()));
|
Label description = new Label(link.description().getText(I18n.getLocale().getCandidateLocales()));
|
||||||
HBox placeholder = new HBox();
|
HBox placeholder = new HBox();
|
||||||
HBox.setHgrow(placeholder, Priority.ALWAYS);
|
HBox.setHgrow(placeholder, Priority.ALWAYS);
|
||||||
Node icon = SVG.OPEN_IN_NEW.createIcon(Theme.blackFill(), 16);
|
Node icon = SVG.OPEN_IN_NEW.createIcon(16);
|
||||||
node.getChildren().setAll(description, placeholder, icon);
|
node.getChildren().setAll(description, placeholder, icon);
|
||||||
|
|
||||||
String url = link.link();
|
String url = link.link();
|
||||||
@@ -670,11 +669,11 @@ public class TerracottaControllerPage extends StackPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLeftIcon(SVG left) {
|
public void setLeftIcon(SVG left) {
|
||||||
this.left.set(left.createIcon(Theme.blackFill(), 28));
|
this.left.set(left.createIcon(28));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRightIcon(SVG right) {
|
public void setRightIcon(SVG right) {
|
||||||
this.right.set(right.createIcon(Theme.blackFill(), 28));
|
this.right.set(right.createIcon(28));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import org.jackhuang.hmcl.mod.ModLoaderType;
|
|||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@@ -394,15 +393,15 @@ public class DownloadPage extends Control implements DecoratorPage {
|
|||||||
switch (dataItem.getVersionType()) {
|
switch (dataItem.getVersionType()) {
|
||||||
case Alpha:
|
case Alpha:
|
||||||
content.addTag(i18n("mods.channel.alpha"));
|
content.addTag(i18n("mods.channel.alpha"));
|
||||||
graphicPane.getChildren().setAll(SVG.ALPHA_CIRCLE.createIcon(Theme.blackFill(), 24));
|
graphicPane.getChildren().setAll(SVG.ALPHA_CIRCLE.createIcon(24));
|
||||||
break;
|
break;
|
||||||
case Beta:
|
case Beta:
|
||||||
content.addTag(i18n("mods.channel.beta"));
|
content.addTag(i18n("mods.channel.beta"));
|
||||||
graphicPane.getChildren().setAll(SVG.BETA_CIRCLE.createIcon(Theme.blackFill(), 24));
|
graphicPane.getChildren().setAll(SVG.BETA_CIRCLE.createIcon(24));
|
||||||
break;
|
break;
|
||||||
case Release:
|
case Release:
|
||||||
content.addTag(i18n("mods.channel.release"));
|
content.addTag(i18n("mods.channel.release"));
|
||||||
graphicPane.getChildren().setAll(SVG.RELEASE_CIRCLE.createIcon(Theme.blackFill(), 24));
|
graphicPane.getChildren().setAll(SVG.RELEASE_CIRCLE.createIcon(24));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import javafx.scene.control.SkinBase;
|
|||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
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;
|
||||||
import org.jackhuang.hmcl.ui.construct.IconedMenuItem;
|
import org.jackhuang.hmcl.ui.construct.IconedMenuItem;
|
||||||
@@ -81,7 +80,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
|||||||
JFXButton btnUpgrade = new JFXButton();
|
JFXButton btnUpgrade = new JFXButton();
|
||||||
btnUpgrade.setOnAction(e -> skinnable.update());
|
btnUpgrade.setOnAction(e -> skinnable.update());
|
||||||
btnUpgrade.getStyleClass().add("toggle-icon4");
|
btnUpgrade.getStyleClass().add("toggle-icon4");
|
||||||
btnUpgrade.setGraphic(FXUtils.limitingSize(SVG.UPDATE.createIcon(Theme.blackFill(), 24), 24, 24));
|
btnUpgrade.setGraphic(FXUtils.limitingSize(SVG.UPDATE.createIcon(24), 24, 24));
|
||||||
FXUtils.installFastTooltip(btnUpgrade, i18n("version.update"));
|
FXUtils.installFastTooltip(btnUpgrade, i18n("version.update"));
|
||||||
right.getChildren().add(btnUpgrade);
|
right.getChildren().add(btnUpgrade);
|
||||||
}
|
}
|
||||||
@@ -91,7 +90,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
|||||||
btnLaunch.setOnAction(e -> skinnable.launch());
|
btnLaunch.setOnAction(e -> skinnable.launch());
|
||||||
btnLaunch.getStyleClass().add("toggle-icon4");
|
btnLaunch.getStyleClass().add("toggle-icon4");
|
||||||
BorderPane.setAlignment(btnLaunch, Pos.CENTER);
|
BorderPane.setAlignment(btnLaunch, Pos.CENTER);
|
||||||
btnLaunch.setGraphic(FXUtils.limitingSize(SVG.ROCKET_LAUNCH.createIcon(Theme.blackFill(), 24), 24, 24));
|
btnLaunch.setGraphic(FXUtils.limitingSize(SVG.ROCKET_LAUNCH.createIcon(24), 24, 24));
|
||||||
FXUtils.installFastTooltip(btnLaunch, i18n("version.launch.test"));
|
FXUtils.installFastTooltip(btnLaunch, i18n("version.launch.test"));
|
||||||
right.getChildren().add(btnLaunch);
|
right.getChildren().add(btnLaunch);
|
||||||
}
|
}
|
||||||
@@ -106,7 +105,7 @@ public class GameListItemSkin extends SkinBase<GameListItem> {
|
|||||||
});
|
});
|
||||||
btnManage.getStyleClass().add("toggle-icon4");
|
btnManage.getStyleClass().add("toggle-icon4");
|
||||||
BorderPane.setAlignment(btnManage, Pos.CENTER);
|
BorderPane.setAlignment(btnManage, Pos.CENTER);
|
||||||
btnManage.setGraphic(FXUtils.limitingSize(SVG.MORE_VERT.createIcon(Theme.blackFill(), 24), 24, 24));
|
btnManage.setGraphic(FXUtils.limitingSize(SVG.MORE_VERT.createIcon(24), 24, 24));
|
||||||
FXUtils.installFastTooltip(btnManage, i18n("settings.game.management"));
|
FXUtils.installFastTooltip(btnManage, i18n("settings.game.management"));
|
||||||
right.getChildren().add(btnManage);
|
right.getChildren().add(btnManage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import org.jackhuang.hmcl.mod.RemoteModRepository;
|
|||||||
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
|
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
|
||||||
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
|
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.setting.VersionIconType;
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@@ -591,15 +590,15 @@ final class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
imageView.setImage(VersionIconType.COMMAND.getIcon());
|
imageView.setImage(VersionIconType.COMMAND.getIcon());
|
||||||
|
|
||||||
restoreButton.getStyleClass().add("toggle-icon4");
|
restoreButton.getStyleClass().add("toggle-icon4");
|
||||||
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24), 24, 24));
|
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(24), 24, 24));
|
||||||
|
|
||||||
FXUtils.installFastTooltip(restoreButton, i18n("mods.restore"));
|
FXUtils.installFastTooltip(restoreButton, i18n("mods.restore"));
|
||||||
|
|
||||||
revealButton.getStyleClass().add("toggle-icon4");
|
revealButton.getStyleClass().add("toggle-icon4");
|
||||||
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER.createIcon(Theme.blackFill(), 24), 24, 24));
|
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER.createIcon(24), 24, 24));
|
||||||
|
|
||||||
infoButton.getStyleClass().add("toggle-icon4");
|
infoButton.getStyleClass().add("toggle-icon4");
|
||||||
infoButton.setGraphic(FXUtils.limitingSize(SVG.INFO.createIcon(Theme.blackFill(), 24), 24, 24));
|
infoButton.setGraphic(FXUtils.limitingSize(SVG.INFO.createIcon(24), 24, 24));
|
||||||
|
|
||||||
container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton);
|
container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import javafx.scene.layout.StackPane;
|
|||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.schematic.LitematicFile;
|
import org.jackhuang.hmcl.schematic.LitematicFile;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
@@ -240,7 +239,7 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
StackPane icon = new StackPane();
|
StackPane icon = new StackPane();
|
||||||
icon.setPrefSize(size, size);
|
icon.setPrefSize(size, size);
|
||||||
icon.setMaxSize(size, size);
|
icon.setMaxSize(size, size);
|
||||||
icon.getChildren().add(getIcon().createIcon(Theme.blackFill(), size));
|
icon.getChildren().add(getIcon().createIcon(size));
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,12 +579,12 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
JFXButton btnReveal = new JFXButton();
|
JFXButton btnReveal = new JFXButton();
|
||||||
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
||||||
btnReveal.getStyleClass().add("toggle-icon4");
|
btnReveal.getStyleClass().add("toggle-icon4");
|
||||||
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon(Theme.blackFill(), -1));
|
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon());
|
||||||
btnReveal.setOnAction(event -> item.onReveal());
|
btnReveal.setOnAction(event -> item.onReveal());
|
||||||
|
|
||||||
JFXButton btnDelete = new JFXButton();
|
JFXButton btnDelete = new JFXButton();
|
||||||
btnDelete.getStyleClass().add("toggle-icon4");
|
btnDelete.getStyleClass().add("toggle-icon4");
|
||||||
btnDelete.setGraphic(SVG.DELETE_FOREVER.createIcon(Theme.blackFill(), -1));
|
btnDelete.setGraphic(SVG.DELETE_FOREVER.createIcon());
|
||||||
btnDelete.setOnAction(event ->
|
btnDelete.setOnAction(event ->
|
||||||
Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"),
|
Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"),
|
||||||
item::onDelete, null));
|
item::onDelete, null));
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import javafx.scene.layout.FlowPane;
|
|||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.event.Event;
|
import org.jackhuang.hmcl.event.Event;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.setting.VersionIconType;
|
import org.jackhuang.hmcl.setting.VersionIconType;
|
||||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
@@ -93,7 +92,7 @@ public class VersionIconDialog extends DialogPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node createCustomIcon() {
|
private Node createCustomIcon() {
|
||||||
Node shape = SVG.ADD_CIRCLE.createIcon(Theme.blackFill(), 32);
|
Node shape = SVG.ADD_CIRCLE.createIcon(32);
|
||||||
shape.setMouseTransparent(true);
|
shape.setMouseTransparent(true);
|
||||||
RipplerContainer container = new RipplerContainer(shape);
|
RipplerContainer container = new RipplerContainer(shape);
|
||||||
FXUtils.setLimitWidth(container, 36);
|
FXUtils.setLimitWidth(container, 36);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import org.jackhuang.hmcl.event.EventBus;
|
import org.jackhuang.hmcl.event.EventBus;
|
||||||
import org.jackhuang.hmcl.event.EventPriority;
|
import org.jackhuang.hmcl.event.EventPriority;
|
||||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||||
@@ -312,7 +311,7 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Node wrap(SVG svg) {
|
public static Node wrap(SVG svg) {
|
||||||
return wrap(svg.createIcon((Paint) null, 20));
|
return wrap(svg.createIcon(20));
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface VersionLoadable {
|
public interface VersionLoadable {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import javafx.scene.layout.HBox;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.jackhuang.hmcl.game.World;
|
import org.jackhuang.hmcl.game.World;
|
||||||
import org.jackhuang.hmcl.game.WorldLockedException;
|
import org.jackhuang.hmcl.game.WorldLockedException;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
@@ -258,14 +257,14 @@ public final class WorldBackupsPage extends ListPageBase<WorldBackupsPage.Backup
|
|||||||
right.getChildren().add(btnReveal);
|
right.getChildren().add(btnReveal);
|
||||||
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
||||||
btnReveal.getStyleClass().add("toggle-icon4");
|
btnReveal.getStyleClass().add("toggle-icon4");
|
||||||
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon(Theme.blackFill(), -1));
|
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon());
|
||||||
btnReveal.setOnAction(event -> skinnable.onReveal());
|
btnReveal.setOnAction(event -> skinnable.onReveal());
|
||||||
|
|
||||||
JFXButton btnDelete = new JFXButton();
|
JFXButton btnDelete = new JFXButton();
|
||||||
right.getChildren().add(btnDelete);
|
right.getChildren().add(btnDelete);
|
||||||
FXUtils.installFastTooltip(btnDelete, i18n("world.backup.delete"));
|
FXUtils.installFastTooltip(btnDelete, i18n("world.backup.delete"));
|
||||||
btnDelete.getStyleClass().add("toggle-icon4");
|
btnDelete.getStyleClass().add("toggle-icon4");
|
||||||
btnDelete.setGraphic(SVG.DELETE.createIcon(Theme.blackFill(), -1));
|
btnDelete.setGraphic(SVG.DELETE.createIcon());
|
||||||
btnDelete.setOnAction(event -> Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"), skinnable::onDelete, null));
|
btnDelete.setOnAction(event -> Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"), skinnable::onDelete, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import javafx.scene.layout.HBox;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.game.World;
|
import org.jackhuang.hmcl.game.World;
|
||||||
import org.jackhuang.hmcl.setting.Theme;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
@@ -161,7 +160,7 @@ public final class WorldInfoPage extends SpinnerPane {
|
|||||||
blur.setIterations(3);
|
blur.setIterations(3);
|
||||||
FXUtils.onChangeAndOperate(visibility, isVisibility -> {
|
FXUtils.onChangeAndOperate(visibility, isVisibility -> {
|
||||||
SVG icon = isVisibility ? SVG.VISIBILITY : SVG.VISIBILITY_OFF;
|
SVG icon = isVisibility ? SVG.VISIBILITY : SVG.VISIBILITY_OFF;
|
||||||
visibilityButton.getChildren().setAll(icon.createIcon(Theme.blackFill(), 12));
|
visibilityButton.getChildren().setAll(icon.createIcon(12));
|
||||||
randomSeedLabel.setEffect(isVisibility ? null : blur);
|
randomSeedLabel.setEffect(isVisibility ? null : blur);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import javafx.scene.layout.BorderPane;
|
|||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.jackhuang.hmcl.game.World;
|
import org.jackhuang.hmcl.game.World;
|
||||||
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;
|
||||||
import org.jackhuang.hmcl.ui.construct.*;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
@@ -89,7 +88,7 @@ public final class WorldListItemSkin extends SkinBase<WorldListItem> {
|
|||||||
JFXButton btnMore = new JFXButton();
|
JFXButton btnMore = new JFXButton();
|
||||||
right.getChildren().add(btnMore);
|
right.getChildren().add(btnMore);
|
||||||
btnMore.getStyleClass().add("toggle-icon4");
|
btnMore.getStyleClass().add("toggle-icon4");
|
||||||
btnMore.setGraphic(SVG.MORE_VERT.createIcon(Theme.blackFill(), -1));
|
btnMore.setGraphic(SVG.MORE_VERT.createIcon());
|
||||||
btnMore.setOnAction(event -> showPopupMenu(JFXPopup.PopupHPosition.RIGHT, 0, root.getHeight()));
|
btnMore.setOnAction(event -> showPopupMenu(JFXPopup.PopupHPosition.RIGHT, 0, root.getHeight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,5 +78,10 @@
|
|||||||
"title": "EasyTier",
|
"title": "EasyTier",
|
||||||
"subtitle": "Copyright 2024-present Easytier Programme within The Commons Conservancy",
|
"subtitle": "Copyright 2024-present Easytier Programme within The Commons Conservancy",
|
||||||
"externalLink": "https://github.com/EasyTier/EasyTier"
|
"externalLink": "https://github.com/EasyTier/EasyTier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "MonetFX",
|
||||||
|
"subtitle": "Copyright © 2025 Glavo.\nLicensed under the Apache 2.0 License.",
|
||||||
|
"externalLink": "https://github.com/Glavo/MonetFX"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -71,7 +71,10 @@
|
|||||||
"externalLink" : "https://github.com/mcmod-info-mirror"
|
"externalLink" : "https://github.com/mcmod-info-mirror"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"image" : "/assets/img/github.png",
|
"image" : {
|
||||||
|
"light" : "/assets/img/github.png",
|
||||||
|
"dark" : "/assets/img/github-white.png"
|
||||||
|
},
|
||||||
"titleLocalized" : "about.thanks_to.contributors",
|
"titleLocalized" : "about.thanks_to.contributors",
|
||||||
"subtitleLocalized" : "about.thanks_to.contributors.statement",
|
"subtitleLocalized" : "about.thanks_to.contributors.statement",
|
||||||
"externalLink" : "https://github.com/HMCL-dev/HMCL/graphs/contributors"
|
"externalLink" : "https://github.com/HMCL-dev/HMCL/graphs/contributors"
|
||||||
|
|||||||
@@ -1,28 +1,60 @@
|
|||||||
/**
|
* {
|
||||||
* Hello Minecraft! Launcher
|
-monet-primary: #4352A5;
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
-monet-on-primary: #FFFFFF;
|
||||||
*
|
-monet-primary-container: #5C6BC0;
|
||||||
* This program is free software: you can redistribute it and/or modify
|
-monet-on-primary-container: #F8F6FF;
|
||||||
* it under the terms of the GNU General Public License as published by
|
-monet-primary-fixed: #DEE0FF;
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
-monet-primary-fixed-dim: #BAC3FF;
|
||||||
* (at your option) any later version.
|
-monet-on-primary-fixed: #00105B;
|
||||||
*
|
-monet-on-primary-fixed-variant: #2F3F92;
|
||||||
* This program is distributed in the hope that it will be useful,
|
-monet-secondary: #575C7F;
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
-monet-on-secondary: #FFFFFF;
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
-monet-secondary-container: #D0D5FD;
|
||||||
* GNU General Public License for more details.
|
-monet-on-secondary-container: #565B7D;
|
||||||
*
|
-monet-secondary-fixed: #DEE0FF;
|
||||||
* You should have received a copy of the GNU General Public License
|
-monet-secondary-fixed-dim: #BFC4EC;
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
-monet-on-secondary-fixed: #141938;
|
||||||
*/
|
-monet-on-secondary-fixed-variant: #3F4566;
|
||||||
.root {
|
-monet-tertiary: #775200;
|
||||||
-fx-base-color: #5C6BC0;
|
-monet-on-tertiary: #FFFFFF;
|
||||||
-fx-base-darker-color: derive(-fx-base-color, -10%);
|
-monet-tertiary-container: #976900;
|
||||||
-fx-base-check-color: derive(-fx-base-color, 30%);
|
-monet-on-tertiary-container: #FFF6EE;
|
||||||
-fx-rippler-color: rgba(92, 107, 192, 0.3);
|
-monet-tertiary-fixed: #FFDEAC;
|
||||||
-fx-base-rippler-color: derive(rgba(92, 107, 192, 0.3), 100%);
|
-monet-tertiary-fixed-dim: #F6BD58;
|
||||||
-fx-base-disabled-text-fill: rgba(256, 256, 256, 0.7);
|
-monet-on-tertiary-fixed: #281900;
|
||||||
-fx-base-text-fill: white;
|
-monet-on-tertiary-fixed-variant: #5F4100;
|
||||||
|
-monet-error: #BA1A1A;
|
||||||
-theme-thumb: rgba(92, 107, 192, 0.7);
|
-monet-on-error: #FFFFFF;
|
||||||
|
-monet-error-container: #FFDAD6;
|
||||||
|
-monet-on-error-container: #93000A;
|
||||||
|
-monet-surface: #FBF8FF;
|
||||||
|
-monet-on-surface: #1B1B21;
|
||||||
|
-monet-surface-dim: #DBD9E1;
|
||||||
|
-monet-surface-bright: #FBF8FF;
|
||||||
|
-monet-surface-container-lowest: #FFFFFF;
|
||||||
|
-monet-surface-container-low: #F5F2FA;
|
||||||
|
-monet-surface-container: #EFEDF5;
|
||||||
|
-monet-surface-container-high: #E9E7EF;
|
||||||
|
-monet-surface-container-highest: #E3E1E9;
|
||||||
|
-monet-surface-variant: #E2E1EF;
|
||||||
|
-monet-on-surface-variant: #454651;
|
||||||
|
-monet-background: #FBF8FF;
|
||||||
|
-monet-on-background: #1B1B21;
|
||||||
|
-monet-outline: #767683;
|
||||||
|
-monet-outline-variant: #C6C5D3;
|
||||||
|
-monet-shadow: #000000;
|
||||||
|
-monet-scrim: #000000;
|
||||||
|
-monet-inverse-surface: #303036;
|
||||||
|
-monet-inverse-on-surface: #F2EFF7;
|
||||||
|
-monet-inverse-primary: #BAC3FF;
|
||||||
|
-monet-surface-tint: #4858AB;
|
||||||
|
-monet-primary-seed: #5C6BC0;
|
||||||
|
-monet-primary-transparent-50: #4352A580;
|
||||||
|
-monet-secondary-container-transparent-50: #D0D5FD80;
|
||||||
|
-monet-surface-transparent-50: #FBF8FF80;
|
||||||
|
-monet-surface-transparent-80: #FBF8FFCC;
|
||||||
|
-monet-on-surface-variant-transparent-38: #45465161;
|
||||||
|
-monet-surface-container-low-transparent-80: #F5F2FACC;
|
||||||
|
-monet-secondary-container-transparent-80: #D0D5FDCC;
|
||||||
|
-warning-tag-background: #F1AEB5;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
BIN
HMCL/src/main/resources/assets/img/github-white.png
Normal file
BIN
HMCL/src/main/resources/assets/img/github-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 851 B |
BIN
HMCL/src/main/resources/assets/img/github-white@2x.png
Normal file
BIN
HMCL/src/main/resources/assets/img/github-white@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1352,6 +1352,10 @@ settings.icon=Icon
|
|||||||
|
|
||||||
settings.launcher=Launcher Settings
|
settings.launcher=Launcher Settings
|
||||||
settings.launcher.appearance=Appearance
|
settings.launcher.appearance=Appearance
|
||||||
|
settings.launcher.brightness=Theme Mode
|
||||||
|
settings.launcher.brightness.auto=Follow System Settings
|
||||||
|
settings.launcher.brightness.dark=Dark Mode
|
||||||
|
settings.launcher.brightness.light=Light Mode
|
||||||
settings.launcher.common_path.tooltip=HMCL will put all game assets and dependencies here. If there are existing libraries in the game directory, then HMCL will prefer to use them first.
|
settings.launcher.common_path.tooltip=HMCL will put all game assets and dependencies here. If there are existing libraries in the game directory, then HMCL will prefer to use them first.
|
||||||
settings.launcher.debug=Debug
|
settings.launcher.debug=Debug
|
||||||
settings.launcher.disable_auto_game_options=Do not switch game language
|
settings.launcher.disable_auto_game_options=Do not switch game language
|
||||||
@@ -1385,7 +1389,7 @@ settings.launcher.proxy.password=Password
|
|||||||
settings.launcher.proxy.port=Port
|
settings.launcher.proxy.port=Port
|
||||||
settings.launcher.proxy.socks=SOCKS
|
settings.launcher.proxy.socks=SOCKS
|
||||||
settings.launcher.proxy.username=Username
|
settings.launcher.proxy.username=Username
|
||||||
settings.launcher.theme=Theme
|
settings.launcher.theme=Theme Color
|
||||||
settings.launcher.title_transparent=Transparent Titlebar
|
settings.launcher.title_transparent=Transparent Titlebar
|
||||||
settings.launcher.turn_off_animations=Disable Animation (Applies After Restart)
|
settings.launcher.turn_off_animations=Disable Animation (Applies After Restart)
|
||||||
settings.launcher.version_list_source=Version List
|
settings.launcher.version_list_source=Version List
|
||||||
|
|||||||
@@ -1140,6 +1140,10 @@ settings.icon=遊戲圖示
|
|||||||
|
|
||||||
settings.launcher=啟動器設定
|
settings.launcher=啟動器設定
|
||||||
settings.launcher.appearance=外觀
|
settings.launcher.appearance=外觀
|
||||||
|
settings.launcher.brightness=主題模式
|
||||||
|
settings.launcher.brightness.auto=跟隨系統設定
|
||||||
|
settings.launcher.brightness.dark=深色模式
|
||||||
|
settings.launcher.brightness.light=淺色模式
|
||||||
settings.launcher.common_path.tooltip=啟動器將所有遊戲資源及相依元件庫檔案放於此集中管理。如果遊戲目錄內有現成的將不會使用公共庫檔案。
|
settings.launcher.common_path.tooltip=啟動器將所有遊戲資源及相依元件庫檔案放於此集中管理。如果遊戲目錄內有現成的將不會使用公共庫檔案。
|
||||||
settings.launcher.debug=除錯
|
settings.launcher.debug=除錯
|
||||||
settings.launcher.disable_auto_game_options=不自動切換遊戲語言
|
settings.launcher.disable_auto_game_options=不自動切換遊戲語言
|
||||||
@@ -1173,7 +1177,7 @@ settings.launcher.proxy.password=密碼
|
|||||||
settings.launcher.proxy.port=連線埠
|
settings.launcher.proxy.port=連線埠
|
||||||
settings.launcher.proxy.socks=SOCKS
|
settings.launcher.proxy.socks=SOCKS
|
||||||
settings.launcher.proxy.username=帳戶
|
settings.launcher.proxy.username=帳戶
|
||||||
settings.launcher.theme=主題
|
settings.launcher.theme=主題色
|
||||||
settings.launcher.title_transparent=標題欄透明
|
settings.launcher.title_transparent=標題欄透明
|
||||||
settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
|
settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
|
||||||
settings.launcher.version_list_source=版本清單來源
|
settings.launcher.version_list_source=版本清單來源
|
||||||
|
|||||||
@@ -1150,6 +1150,10 @@ settings.icon=游戏图标
|
|||||||
|
|
||||||
settings.launcher=启动器设置
|
settings.launcher=启动器设置
|
||||||
settings.launcher.appearance=外观
|
settings.launcher.appearance=外观
|
||||||
|
settings.launcher.brightness=主题模式
|
||||||
|
settings.launcher.brightness.auto=跟随系统设置
|
||||||
|
settings.launcher.brightness.dark=深色模式
|
||||||
|
settings.launcher.brightness.light=浅色模式
|
||||||
settings.launcher.common_path.tooltip=启动器将所有游戏资源及依赖库文件存放于此集中管理。如果游戏文件夹内有现成的将不会使用公共库文件。
|
settings.launcher.common_path.tooltip=启动器将所有游戏资源及依赖库文件存放于此集中管理。如果游戏文件夹内有现成的将不会使用公共库文件。
|
||||||
settings.launcher.debug=调试
|
settings.launcher.debug=调试
|
||||||
settings.launcher.disable_auto_game_options=不自动切换游戏语言
|
settings.launcher.disable_auto_game_options=不自动切换游戏语言
|
||||||
@@ -1183,7 +1187,7 @@ settings.launcher.proxy.password=密码
|
|||||||
settings.launcher.proxy.port=端口
|
settings.launcher.proxy.port=端口
|
||||||
settings.launcher.proxy.socks=SOCKS
|
settings.launcher.proxy.socks=SOCKS
|
||||||
settings.launcher.proxy.username=账户
|
settings.launcher.proxy.username=账户
|
||||||
settings.launcher.theme=主题
|
settings.launcher.theme=主题色
|
||||||
settings.launcher.title_transparent=标题栏透明
|
settings.launcher.title_transparent=标题栏透明
|
||||||
settings.launcher.turn_off_animations=关闭动画 (重启后生效)
|
settings.launcher.turn_off_animations=关闭动画 (重启后生效)
|
||||||
settings.launcher.version_list_source=版本列表源
|
settings.launcher.version_list_source=版本列表源
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.setting;
|
||||||
|
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.jackhuang.hmcl.theme.ThemeColor;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
/// @author Glavo
|
||||||
|
public final class ThemeColorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOf() {
|
||||||
|
assertEquals(new ThemeColor("#AABBCC", Color.web("#AABBCC")), ThemeColor.of("#AABBCC"));
|
||||||
|
assertEquals(new ThemeColor("blue", Color.web("#5C6BC0")), ThemeColor.of("blue"));
|
||||||
|
assertEquals(new ThemeColor("darker_blue", Color.web("#283593")), ThemeColor.of("darker_blue"));
|
||||||
|
assertEquals(new ThemeColor("green", Color.web("#43A047")), ThemeColor.of("green"));
|
||||||
|
assertEquals(new ThemeColor("orange", Color.web("#E67E22")), ThemeColor.of("orange"));
|
||||||
|
assertEquals(new ThemeColor("purple", Color.web("#9C27B0")), ThemeColor.of("purple"));
|
||||||
|
assertEquals(new ThemeColor("red", Color.web("#B71C1C")), ThemeColor.of("red"));
|
||||||
|
|
||||||
|
assertNull(ThemeColor.of((String) null));
|
||||||
|
assertNull(ThemeColor.of(""));
|
||||||
|
assertNull(ThemeColor.of("unknown"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ jna = "5.18.1"
|
|||||||
pci-ids = "0.4.0"
|
pci-ids = "0.4.0"
|
||||||
java-info = "1.0"
|
java-info = "1.0"
|
||||||
authlib-injector = "1.2.6"
|
authlib-injector = "1.2.6"
|
||||||
|
monet-fx = "0.4.0"
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
junit = "6.0.1"
|
junit = "6.0.1"
|
||||||
@@ -46,6 +47,7 @@ jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
|
|||||||
pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" }
|
pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" }
|
||||||
java-info = { module = "org.glavo:java-info", version.ref = "java-info" }
|
java-info = { module = "org.glavo:java-info", version.ref = "java-info" }
|
||||||
authlib-injector = { module = "org.glavo.hmcl:authlib-injector", version.ref = "authlib-injector" }
|
authlib-injector = { module = "org.glavo.hmcl:authlib-injector", version.ref = "authlib-injector" }
|
||||||
|
monet-fx = { module = "org.glavo:MonetFX", version.ref = "monet-fx" }
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
||||||
|
|||||||
Reference in New Issue
Block a user