Skip to content

Commit a8dbea2

Browse files
committed
Merge branch 'main' into litematica
2 parents 3c8eaab + c0f4143 commit a8dbea2

35 files changed

+1095
-715
lines changed

HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.glavo.monetfx.beans.property.ReadOnlyColorSchemeProperty;
3737
import org.glavo.monetfx.beans.property.SimpleColorSchemeProperty;
3838
import org.jackhuang.hmcl.ui.FXUtils;
39+
import org.jackhuang.hmcl.util.io.FileUtils;
3940
import org.jackhuang.hmcl.ui.WindowsNativeUtils;
4041
import org.jackhuang.hmcl.util.platform.NativeUtils;
4142
import org.jackhuang.hmcl.util.platform.OSVersion;
@@ -46,9 +47,12 @@
4647
import org.jackhuang.hmcl.util.platform.windows.WinReg;
4748
import org.jackhuang.hmcl.util.platform.windows.WinTypes;
4849

50+
import java.nio.file.Path;
51+
import java.time.Duration;
4952
import java.util.*;
5053

5154
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
55+
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
5256

5357
/// @author Glavo
5458
public final class Themes {
@@ -113,6 +117,7 @@ private static Brightness getDefaultBrightness() {
113117
if (defaultBrightness != null)
114118
return defaultBrightness;
115119

120+
LOG.info("Detecting system theme brightness");
116121
Brightness brightness = Brightness.DEFAULT;
117122
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
118123
WinReg reg = WinReg.INSTANCE;
@@ -130,7 +135,38 @@ private static Brightness getDefaultBrightness() {
130135
// If the key does not exist, it means Light mode is used
131136
brightness = Brightness.LIGHT;
132137
}
138+
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
139+
Path dbusSend = SystemUtils.which("dbus-send");
140+
if (dbusSend != null) {
141+
try {
142+
String[] result = SystemUtils.run(List.of(
143+
FileUtils.getAbsolutePath(dbusSend),
144+
"--session",
145+
"--print-reply=literal",
146+
"--reply-timeout=1000",
147+
"--dest=org.freedesktop.portal.Desktop",
148+
"/org/freedesktop/portal/desktop",
149+
"org.freedesktop.portal.Settings.Read",
150+
"string:org.freedesktop.appearance",
151+
"string:color-scheme"
152+
), Duration.ofSeconds(2)).trim().split(" ");
153+
154+
if (result.length > 0) {
155+
String value = result[result.length - 1];
156+
// 1: prefer dark
157+
// 2: prefer light
158+
if ("1".equals(value)) {
159+
brightness = Brightness.DARK;
160+
} else if ("2".equals(value)) {
161+
brightness = Brightness.LIGHT;
162+
}
163+
}
164+
} catch (Exception e) {
165+
LOG.warning("Failed to get system theme from D-Bus", e);
166+
}
167+
}
133168
}
169+
LOG.info("Detected system theme brightness: " + brightness);
134170

135171
return defaultBrightness = brightness;
136172
}

HMCL/src/main/java/org/jackhuang/hmcl/ui/ToolbarListPageSkin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import javafx.scene.Node;
2626
import javafx.scene.control.ListCell;
2727
import javafx.scene.control.SkinBase;
28+
import javafx.scene.input.KeyCode;
29+
import javafx.scene.input.KeyEvent;
2830
import javafx.scene.layout.HBox;
2931
import javafx.scene.layout.Priority;
3032
import javafx.scene.layout.StackPane;
@@ -65,6 +67,7 @@ public ToolbarListPageSkin(P skinnable) {
6567
this.listView.setCellFactory(listView -> createListCell((JFXListView<E>) listView));
6668
ComponentList.setVgrow(listView, Priority.ALWAYS);
6769
Bindings.bindContent(this.listView.getItems(), skinnable.itemsProperty());
70+
FXUtils.ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE);
6871
root.getContent().add(listView);
6972
}
7073

HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItemSkin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.jackhuang.hmcl.ui.FXUtils;
2626

2727
public class AdvancedListItemSkin extends SkinBase<AdvancedListItem> {
28-
private final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected");
28+
private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected");
2929

3030
public AdvancedListItemSkin(AdvancedListItem skinnable) {
3131
super(skinnable);

HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/ComponentList.java

Lines changed: 59 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,8 @@
1717
*/
1818
package org.jackhuang.hmcl.ui.construct;
1919

20-
import javafx.beans.DefaultProperty;
20+
import javafx.beans.InvalidationListener;
2121
import javafx.beans.binding.Bindings;
22-
import javafx.beans.binding.ObjectBinding;
23-
import javafx.beans.property.IntegerProperty;
24-
import javafx.beans.property.SimpleIntegerProperty;
25-
import javafx.beans.property.SimpleStringProperty;
26-
import javafx.beans.property.StringProperty;
2722
import javafx.collections.FXCollections;
2823
import javafx.collections.ObservableList;
2924
import javafx.css.PseudoClass;
@@ -33,88 +28,21 @@
3328
import javafx.scene.Node;
3429
import javafx.scene.control.Control;
3530
import javafx.scene.control.Label;
36-
import javafx.scene.layout.HBox;
37-
import javafx.scene.layout.Priority;
38-
import javafx.scene.layout.VBox;
31+
import javafx.scene.layout.*;
3932
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
4033

41-
import java.util.List;
42-
import java.util.function.Supplier;
43-
44-
@DefaultProperty("content")
45-
public class ComponentList extends Control {
46-
private final StringProperty title = new SimpleStringProperty(this, "title", "Group");
47-
private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle", "");
48-
private final IntegerProperty depth = new SimpleIntegerProperty(this, "depth", 0);
49-
private boolean hasSubtitle = false;
50-
public final ObservableList<Node> content = FXCollections.observableArrayList();
51-
private Supplier<List<? extends Node>> lazyInitializer;
34+
public class ComponentList extends Control implements NoPaddingComponent {
5235

5336
public ComponentList() {
5437
getStyleClass().add("options-list");
5538
}
5639

57-
public ComponentList(Supplier<List<? extends Node>> lazyInitializer) {
58-
this();
59-
this.lazyInitializer = lazyInitializer;
60-
}
61-
62-
public String getTitle() {
63-
return title.get();
64-
}
65-
66-
public StringProperty titleProperty() {
67-
return title;
68-
}
69-
70-
public void setTitle(String title) {
71-
this.title.set(title);
72-
}
73-
74-
public String getSubtitle() {
75-
return subtitle.get();
76-
}
77-
78-
public StringProperty subtitleProperty() {
79-
return subtitle;
80-
}
81-
82-
public void setSubtitle(String subtitle) {
83-
this.subtitle.set(subtitle);
84-
}
85-
86-
public int getDepth() {
87-
return depth.get();
88-
}
89-
90-
public IntegerProperty depthProperty() {
91-
return depth;
92-
}
93-
94-
public void setDepth(int depth) {
95-
this.depth.set(depth);
96-
}
97-
98-
public boolean isHasSubtitle() {
99-
return hasSubtitle;
100-
}
101-
102-
public void setHasSubtitle(boolean hasSubtitle) {
103-
this.hasSubtitle = hasSubtitle;
104-
}
40+
private final ObservableList<Node> content = FXCollections.observableArrayList();
10541

10642
public ObservableList<Node> getContent() {
10743
return content;
10844
}
10945

110-
void doLazyInit() {
111-
if (lazyInitializer != null) {
112-
this.getContent().setAll(lazyInitializer.get());
113-
setNeedsLayout(true);
114-
lazyInitializer = null;
115-
}
116-
}
117-
11846
@Override
11947
public Orientation getContentBias() {
12048
return Orientation.HORIZONTAL;
@@ -130,49 +58,72 @@ private static final class Skin extends ControlSkinBase<ComponentList> {
13058
private static final PseudoClass PSEUDO_CLASS_LAST = PseudoClass.getPseudoClass("last");
13159

13260
private final ObservableList<Node> list;
133-
private final ObjectBinding<Node> firstItem;
134-
private final ObjectBinding<Node> lastItem;
13561

13662
Skin(ComponentList control) {
13763
super(control);
13864

13965
list = MappedObservableList.create(control.getContent(), node -> {
140-
ComponentListCell cell = new ComponentListCell(node);
141-
cell.getStyleClass().add("options-list-item");
142-
if (node.getProperties().containsKey("ComponentList.vgrow")) {
143-
VBox.setVgrow(cell, (Priority) node.getProperties().get("ComponentList.vgrow"));
66+
Pane wrapper;
67+
if (node instanceof ComponentSublist sublist) {
68+
sublist.getStyleClass().remove("options-list");
69+
sublist.getStyleClass().add("options-sublist");
70+
wrapper = new ComponentSublistWrapper(sublist);
71+
} else {
72+
wrapper = new StackPane(node);
73+
}
74+
75+
wrapper.getStyleClass().add("options-list-item");
76+
77+
if (node.getProperties().get("ComponentList.vgrow") instanceof Priority priority) {
78+
VBox.setVgrow(wrapper, priority);
14479
}
145-
if (node instanceof LineButtonBase || node instanceof LinePane || node.getProperties().containsKey("ComponentList.noPadding")) {
146-
cell.getStyleClass().add("no-padding");
80+
81+
if (node instanceof NoPaddingComponent || node.getProperties().containsKey("ComponentList.noPadding")) {
82+
wrapper.getStyleClass().add("no-padding");
14783
}
148-
return cell;
84+
return wrapper;
14985
});
15086

151-
firstItem = Bindings.valueAt(list, 0);
152-
firstItem.addListener((observable, oldValue, newValue) -> {
153-
if (newValue != null)
154-
newValue.pseudoClassStateChanged(PSEUDO_CLASS_FIRST, true);
155-
if (oldValue != null)
156-
oldValue.pseudoClassStateChanged(PSEUDO_CLASS_FIRST, false);
157-
});
158-
if (!list.isEmpty())
159-
list.get(0).pseudoClassStateChanged(PSEUDO_CLASS_FIRST, true);
160-
161-
lastItem = Bindings.valueAt(list, Bindings.subtract(Bindings.size(list), 1));
162-
lastItem.addListener((observable, oldValue, newValue) -> {
163-
if (newValue != null)
164-
newValue.pseudoClassStateChanged(PSEUDO_CLASS_LAST, true);
165-
if (oldValue != null)
166-
oldValue.pseudoClassStateChanged(PSEUDO_CLASS_LAST, false);
167-
});
168-
if (!list.isEmpty())
169-
list.get(list.size() - 1).pseudoClassStateChanged(PSEUDO_CLASS_LAST, true);
87+
updateStyle();
88+
list.addListener((InvalidationListener) o -> updateStyle());
17089

17190
VBox vbox = new VBox();
17291
vbox.setFillWidth(true);
17392
Bindings.bindContent(vbox.getChildren(), list);
17493
node = vbox;
17594
}
95+
96+
private Node prevFirstItem;
97+
private Node prevLastItem;
98+
99+
private void updateStyle() {
100+
Node firstItem;
101+
Node lastItem;
102+
103+
if (list.isEmpty()) {
104+
firstItem = null;
105+
lastItem = null;
106+
} else {
107+
firstItem = list.get(0);
108+
lastItem = list.get(list.size() - 1);
109+
}
110+
111+
if (firstItem != prevFirstItem) {
112+
if (prevFirstItem != null)
113+
prevFirstItem.pseudoClassStateChanged(PSEUDO_CLASS_FIRST, false);
114+
if (firstItem != null)
115+
firstItem.pseudoClassStateChanged(PSEUDO_CLASS_FIRST, true);
116+
prevFirstItem = firstItem;
117+
}
118+
119+
if (lastItem != prevLastItem) {
120+
if (prevLastItem != null)
121+
prevLastItem.pseudoClassStateChanged(PSEUDO_CLASS_LAST, false);
122+
if (lastItem != null)
123+
lastItem.pseudoClassStateChanged(PSEUDO_CLASS_LAST, true);
124+
prevLastItem = lastItem;
125+
}
126+
}
176127
}
177128

178129
public static Node createComponentListTitle(String title) {
@@ -189,4 +140,8 @@ public static Node createComponentListTitle(String title) {
189140
public static void setVgrow(Node node, Priority priority) {
190141
node.getProperties().put("ComponentList.vgrow", priority);
191142
}
143+
144+
public static void setNoPadding(Node node) {
145+
node.getProperties().put("ComponentList.noPadding", true);
146+
}
192147
}

0 commit comments

Comments
 (0)