From ba67c968cf0eb5ab35f089437755716d9fba0017 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sat, 22 Sep 2018 22:25:53 +0800 Subject: [PATCH] Change version selection list look --- .../hmcl/game/HMCLGameRepository.java | 17 +++- .../java/org/jackhuang/hmcl/ui/MainPage.java | 30 ++++--- .../ui/construct/AdvancedListItemSkin.java | 2 +- .../hmcl/ui/construct/PopupMenu.java | 66 ++++++++++++++ .../ui/versions/GameAdvancedListItem.java | 6 +- .../jackhuang/hmcl/ui/versions/GameItem.java | 84 ++++++++++++++++++ .../hmcl/ui/versions/GameItemSkin.java | 36 ++++++++ .../hmcl/ui/versions/GameListItem.java | 45 +--------- .../hmcl/ui/versions/GameListItemSkin.java | 30 +------ .../hmcl/ui/versions/VersionPage.java | 11 ++- .../hmcl/ui/versions/VersionSettingsPage.java | 6 +- .../hmcl/ui/versions/WorldListItemSkin.java | 7 +- HMCL/src/main/resources/assets/css/root.css | 4 + HMCL/src/main/resources/assets/fxml/main.fxml | 2 +- .../src/main/resources/assets/img/furnace.png | Bin 0 -> 8200 bytes .../resources/assets/lang/I18N_zh.properties | 2 +- .../assets/lang/I18N_zh_CN.properties | 2 +- 17 files changed, 247 insertions(+), 103 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/PopupMenu.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItemSkin.java create mode 100644 HMCL/src/main/resources/assets/img/furnace.png diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 5ae8b0d88..c49c18f19 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.game; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import javafx.scene.image.Image; import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.event.RefreshingVersionsEvent; @@ -144,10 +145,24 @@ public class HMCLGameRepository extends DefaultGameRepository { return setting; } - public File getVersionIcon(String id) { + public File getVersionIconFile(String id) { return new File(getVersionRoot(id), "icon.png"); } + public Image getVersionIconImage(String id) { + if (id == null) + return new Image("/assets/img/grass.png"); + + Version version = getVersion(id); + File iconFile = getVersionIconFile(id); + if (iconFile.exists()) + return new Image("file:" + iconFile.getAbsolutePath()); + else if ("net.minecraft.launchwrapper.Launch".equals(version.getMainClass())) + return new Image("/assets/img/furnace.png"); + else + return new Image("/assets/img/grass.png"); + } + public boolean saveVersionSetting(String id) { if (!versionSettings.containsKey(id)) return false; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java index 47f15f58a..e9be8246b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPage.java @@ -32,12 +32,13 @@ import javafx.scene.shape.Rectangle; import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.game.HMCLGameRepository; -import org.jackhuang.hmcl.setting.ConfigHolder; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Theme; -import org.jackhuang.hmcl.ui.construct.IconedMenuItem; +import org.jackhuang.hmcl.ui.construct.PopupMenu; +import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; +import org.jackhuang.hmcl.ui.versions.GameItem; import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.util.VersionNumber; @@ -49,7 +50,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class MainPage extends StackPane implements DecoratorPage { private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("main_page")); - private final VBox menu = new VBox(); + private final PopupMenu menu = new PopupMenu(); private final JFXPopup popup = new JFXPopup(menu); @FXML @@ -69,7 +70,7 @@ public final class MainPage extends StackPane implements DecoratorPage { btnLaunch.setClip(new Rectangle(-100, -100, 310, 200)); btnMenu.setClip(new Rectangle(211, -100, 100, 200)); - menu.getStyleClass().setAll("menu"); + menu.setMaxHeight(400); StackPane graphic = new StackPane(); Node svg = SVG.triangle(Theme.whiteFillBinding(), 10, 10); @@ -102,17 +103,26 @@ public final class MainPage extends StackPane implements DecoratorPage { } private void loadVersions(HMCLGameRepository repository) { - List children = repository.getVersions().parallelStream() + List children = repository.getVersions().parallelStream() .filter(version -> !version.isHidden()) .sorted((a, b) -> VersionNumber.COMPARATOR.compare(VersionNumber.asVersion(a.getId()), VersionNumber.asVersion(b.getId()))) - .map(version -> new IconedMenuItem(null, version.getId(), () -> { - repository.getProfile().setSelectedVersion(version.getId()); - popup.hide(); - })) + .map(version -> { + StackPane pane = new StackPane(); + GameItem item = new GameItem(repository.getProfile(), version.getId()); + pane.getChildren().setAll(item); + pane.getStyleClass().setAll("menu-container"); + item.setMouseTransparent(true); + RipplerContainer container = new RipplerContainer(pane); + container.setOnMouseClicked(e -> { + repository.getProfile().setSelectedVersion(version.getId()); + popup.hide(); + }); + return container; + }) .collect(Collectors.toList()); JFXUtilities.runInFX(() -> { if (profile == repository.getProfile()) - menu.getChildren().setAll(children); + menu.getContent().setAll(children); }); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItemSkin.java index 901693879..e97311143 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListItemSkin.java @@ -90,7 +90,7 @@ public class AdvancedListItemSkin extends SkinBase { JFXButton settings = new JFXButton(); FXUtils.setLimitWidth(settings, 40); settings.getStyleClass().setAll("toggle-icon4"); - settings.setGraphic(SVG.dotsVertical(Theme.blackFillBinding(), -1, -1)); + settings.setGraphic(SVG.gear(Theme.blackFillBinding(), -1, -1)); right.getChildren().setAll(settings); root.setRight(right); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/PopupMenu.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/PopupMenu.java new file mode 100644 index 000000000..3d4c9166a --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/PopupMenu.java @@ -0,0 +1,66 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.construct; + +import javafx.beans.binding.Bindings; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.Node; +import javafx.scene.control.Control; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Skin; +import javafx.scene.control.SkinBase; +import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.ui.FXUtils; + +public class PopupMenu extends Control { + + private final ObservableList content = FXCollections.observableArrayList(); + + public PopupMenu() { + } + + public ObservableList getContent() { + return content; + } + + @Override + protected Skin createDefaultSkin() { + return new PopupMenuSkin(); + } + + private class PopupMenuSkin extends SkinBase { + + protected PopupMenuSkin() { + super(PopupMenu.this); + + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setFitToHeight(true); + scrollPane.setFitToWidth(true); + + VBox content = new VBox(); + content.getStyleClass().add("menu"); + Bindings.bindContent(content.getChildren(), PopupMenu.this.getContent()); + scrollPane.setContent(content); + + FXUtils.smoothScrolling(scrollPane); + + getChildren().setAll(scrollPane); + } + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java index ab652618d..f271d7979 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java @@ -38,11 +38,7 @@ public class GameAdvancedListItem extends AdvancedListItem { public GameAdvancedListItem() { FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), version -> { FXUtils.runLaterIf(() -> !Objects.nonNull(Profiles.getSelectedProfile()), () -> { - File iconFile = Profiles.getSelectedProfile().getRepository().getVersionIcon(version); - if (iconFile.exists()) - imageProperty().set(new Image("file:" + iconFile.getAbsolutePath())); - else - imageProperty().set(new Image("/assets/img/grass.png")); + imageProperty().set(Profiles.getSelectedProfile().getRepository().getVersionIconImage(version)); if (version != null) { titleProperty().set(version); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java new file mode 100644 index 000000000..7c1ae7708 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java @@ -0,0 +1,84 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.versions; + +import javafx.beans.property.*; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.scene.image.Image; +import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.game.GameVersion; +import org.jackhuang.hmcl.setting.Profile; + +import static org.jackhuang.hmcl.util.StringUtils.removePrefix; +import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public class GameItem extends Control { + private final Profile profile; + private final String version; + private final StringProperty title = new SimpleStringProperty(); + private final StringProperty subtitle = new SimpleStringProperty(); + private final ObjectProperty image = new SimpleObjectProperty<>(); + + public GameItem(Profile profile, String id) { + this.profile = profile; + this.version = id; + + String game = GameVersion.minecraftVersion(profile.getRepository().getVersionJar(id)).orElse("Unknown"); + + StringBuilder libraries = new StringBuilder(game); + LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id)); + analyzer.getForge().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", "")))); + analyzer.getLiteLoader().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", "")))); + analyzer.getOptiFine().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", "")))); + + title.set(id); + subtitle.set(libraries.toString()); + image.set(profile.getRepository().getVersionIconImage(version)); + } + + @Override + protected Skin createDefaultSkin() { + return new GameItemSkin(this); + } + + public Profile getProfile() { + return profile; + } + + public String getVersion() { + return version; + } + + public StringProperty titleProperty() { + return title; + } + + public StringProperty subtitleProperty() { + return subtitle; + } + + public ObjectProperty imageProperty() { + return image; + } + + private static String modifyVersion(String gameVersion, String version) { + return removeSuffix(removePrefix(removeSuffix(removePrefix(version.replace(gameVersion, "").trim(), "-"), "-"), "_"), "_"); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItemSkin.java new file mode 100644 index 000000000..9a616edcc --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItemSkin.java @@ -0,0 +1,36 @@ +package org.jackhuang.hmcl.ui.versions; + +import javafx.geometry.Pos; +import javafx.scene.control.SkinBase; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.construct.TwoLineListItem; + +public class GameItemSkin extends SkinBase { + public GameItemSkin(GameItem skinnable) { + super(skinnable); + + HBox center = new HBox(); + center.setSpacing(8); + center.setAlignment(Pos.CENTER_LEFT); + + StackPane imageViewContainer = new StackPane(); + FXUtils.setLimitWidth(imageViewContainer, 32); + FXUtils.setLimitHeight(imageViewContainer, 32); + + ImageView imageView = new ImageView(); + FXUtils.limitSize(imageView, 32, 32); + imageView.imageProperty().bind(skinnable.imageProperty()); + imageViewContainer.getChildren().setAll(imageView); + + TwoLineListItem item = new TwoLineListItem(); + item.titleProperty().bind(skinnable.titleProperty()); + item.subtitleProperty().bind(skinnable.subtitleProperty()); + BorderPane.setAlignment(item, Pos.CENTER); + center.getChildren().setAll(imageView, item); + getChildren().setAll(center); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java index 9edcdf80c..ca6059702 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java @@ -21,27 +21,16 @@ import javafx.beans.property.*; import javafx.scene.control.Control; import javafx.scene.control.Skin; import javafx.scene.control.ToggleGroup; -import javafx.scene.image.Image; -import org.jackhuang.hmcl.download.LibraryAnalyzer; -import org.jackhuang.hmcl.game.GameVersion; + import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.ui.Controllers; -import java.io.File; - -import static org.jackhuang.hmcl.util.StringUtils.removePrefix; -import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - public class GameListItem extends Control { private final Profile profile; private final String version; private final boolean isModpack; private final ToggleGroup toggleGroup; - private final StringProperty title = new SimpleStringProperty(); - private final StringProperty subtitle = new SimpleStringProperty(); private final BooleanProperty selected = new SimpleBooleanProperty(); - private final ObjectProperty image = new SimpleObjectProperty<>(); public GameListItem(ToggleGroup toggleGroup, Profile profile, String id) { this.profile = profile; @@ -49,23 +38,7 @@ public class GameListItem extends Control { this.toggleGroup = toggleGroup; this.isModpack = profile.getRepository().isModpack(id); - String game = GameVersion.minecraftVersion(profile.getRepository().getVersionJar(id)).orElse("Unknown"); - - StringBuilder libraries = new StringBuilder(game); - LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id)); - analyzer.getForge().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", "")))); - analyzer.getLiteLoader().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", "")))); - analyzer.getOptiFine().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", "")))); - - title.set(id); - subtitle.set(libraries.toString()); selected.set(id.equals(profile.getSelectedVersion())); - - File iconFile = profile.getRepository().getVersionIcon(version); - if (iconFile.exists()) - image.set(new Image("file:" + iconFile.getAbsolutePath())); - else - image.set(new Image("/assets/img/grass.png")); } @Override @@ -85,22 +58,10 @@ public class GameListItem extends Control { return version; } - public StringProperty titleProperty() { - return title; - } - - public StringProperty subtitleProperty() { - return subtitle; - } - public BooleanProperty selectedProperty() { return selected; } - public ObjectProperty imageProperty() { - return image; - } - public void checkSelection() { selected.set(version.equals(profile.getSelectedVersion())); } @@ -141,8 +102,4 @@ public class GameListItem extends Control { public void update() { Versions.updateVersion(profile, version); } - - private static String modifyVersion(String gameVersion, String version) { - return removeSuffix(removePrefix(removeSuffix(removePrefix(version.replace(gameVersion, "").trim(), "-"), "-"), "_"), "_"); - } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java index 6ad6eb59b..cafe976b9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java @@ -24,17 +24,14 @@ import com.jfoenix.controls.JFXRadioButton; import com.jfoenix.effects.JFXDepthManager; import javafx.geometry.Pos; import javafx.scene.control.SkinBase; -import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.IconedMenuItem; import org.jackhuang.hmcl.ui.construct.MenuSeparator; -import org.jackhuang.hmcl.ui.construct.TwoLineListItem; +import org.jackhuang.hmcl.ui.construct.PopupMenu; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -52,29 +49,12 @@ public class GameListItemSkin extends SkinBase { chkSelected.setToggleGroup(skinnable.getToggleGroup()); root.setLeft(chkSelected); - HBox center = new HBox(); - center.setSpacing(8); - center.setAlignment(Pos.CENTER_LEFT); + root.setCenter(new GameItem(skinnable.getProfile(), skinnable.getVersion())); - StackPane imageViewContainer = new StackPane(); - FXUtils.setLimitWidth(imageViewContainer, 32); - FXUtils.setLimitHeight(imageViewContainer, 32); - - ImageView imageView = new ImageView(); - FXUtils.limitSize(imageView, 32, 32); - imageView.imageProperty().bind(skinnable.imageProperty()); - imageViewContainer.getChildren().setAll(imageView); - - TwoLineListItem item = new TwoLineListItem(); - BorderPane.setAlignment(item, Pos.CENTER); - center.getChildren().setAll(imageView, item); - root.setCenter(center); - - VBox menu = new VBox(); - menu.getStyleClass().setAll("menu"); + PopupMenu menu = new PopupMenu(); JFXPopup popup = new JFXPopup(menu); - menu.getChildren().setAll( + menu.getContent().setAll( new IconedMenuItem(FXUtils.limitingSize(SVG.gear(Theme.blackFillBinding(), 14, 14), 14, 14), i18n("version.manage.manage"), FXUtils.withJFXPopupClosing(skinnable::modifyGameSettings, popup)), new MenuSeparator(), new IconedMenuItem(FXUtils.limitingSize(SVG.pencil(Theme.blackFillBinding(), 14, 14), 14, 14), i18n("version.manage.rename"), FXUtils.withJFXPopupClosing(skinnable::rename, popup)), @@ -109,8 +89,6 @@ public class GameListItemSkin extends SkinBase { root.setStyle("-fx-background-color: white; -fx-padding: 8 8 8 0;"); JFXDepthManager.setDepth(root, 1); - item.titleProperty().bind(skinnable.titleProperty()); - item.subtitleProperty().bind(skinnable.subtitleProperty()); getChildren().setAll(root); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java index 967bed484..e1daed4a3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java @@ -30,6 +30,7 @@ import org.jackhuang.hmcl.download.game.GameAssetIndexDownloadTask; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.IconedMenuItem; +import org.jackhuang.hmcl.ui.construct.PopupMenu; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.util.FileUtils; @@ -74,10 +75,9 @@ public final class VersionPage extends StackPane implements DecoratorPage { { FXUtils.loadFXML(this, "/assets/fxml/version/version.fxml"); - VBox browseList = new VBox(); - browseList.getStyleClass().setAll("menu"); + PopupMenu browseList = new PopupMenu(); browsePopup = new JFXPopup(browseList); - browseList.getChildren().setAll( + browseList.getContent().setAll( new IconedMenuItem(null, i18n("folder.game"), FXUtils.withJFXPopupClosing(() -> onBrowse(""), browsePopup)), new IconedMenuItem(null, i18n("folder.mod"), FXUtils.withJFXPopupClosing(() -> onBrowse("mods"), browsePopup)), new IconedMenuItem(null, i18n("folder.config"), FXUtils.withJFXPopupClosing(() -> onBrowse("config"), browsePopup)), @@ -86,10 +86,9 @@ public final class VersionPage extends StackPane implements DecoratorPage { new IconedMenuItem(null, i18n("folder.saves"), FXUtils.withJFXPopupClosing(() -> onBrowse("resourcepacks"), browsePopup)) ); - VBox managementList = new VBox(); - managementList.getStyleClass().setAll("menu"); + PopupMenu managementList = new PopupMenu(); managementPopup = new JFXPopup(managementList); - managementList.getChildren().setAll( + managementList.getContent().setAll( new IconedMenuItem(null, i18n("version.manage.rename"), FXUtils.withJFXPopupClosing(() -> Versions.renameVersion(profile, version), managementPopup)), new IconedMenuItem(null, i18n("version.manage.remove"), FXUtils.withJFXPopupClosing(() -> Versions.deleteVersion(profile, version), managementPopup)), new IconedMenuItem(null, i18n("version.manage.redownload_assets_index"), FXUtils.withJFXPopupClosing(() -> new GameAssetIndexDownloadTask(profile.getDependency(), profile.getRepository().getResolvedVersion(version)).start(), managementPopup)), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index fdec7553c..f06abb7c7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -276,7 +276,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.png"), "*.png")); File selectedFile = chooser.showOpenDialog(Controllers.getStage()); if (selectedFile != null) { - File iconFile = profile.getRepository().getVersionIcon(versionId); + File iconFile = profile.getRepository().getVersionIconFile(versionId); try { FileUtils.copyFile(selectedFile, iconFile); loadIcon(); @@ -291,7 +291,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag if (versionId == null) return; - File iconFile = profile.getRepository().getVersionIcon(versionId); + File iconFile = profile.getRepository().getVersionIconFile(versionId); if (iconFile.exists()) iconFile.delete(); loadIcon(); @@ -303,7 +303,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag return; } - File iconFile = profile.getRepository().getVersionIcon(versionId); + File iconFile = profile.getRepository().getVersionIconFile(versionId); if (iconFile.exists()) iconPickerItem.setImage(new Image("file:" + iconFile.getAbsolutePath())); else diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java index 96edc0efd..48a4d274a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldListItemSkin.java @@ -9,11 +9,11 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.IconedMenuItem; +import org.jackhuang.hmcl.ui.construct.PopupMenu; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -43,11 +43,10 @@ public class WorldListItemSkin extends SkinBase { center.getChildren().setAll(imageView, item); root.setCenter(center); - VBox menu = new VBox(); - menu.getStyleClass().setAll("menu"); + PopupMenu menu = new PopupMenu(); JFXPopup popup = new JFXPopup(menu); - menu.getChildren().setAll( + menu.getContent().setAll( new IconedMenuItem(FXUtils.limitingSize(SVG.gear(Theme.blackFillBinding(), 14, 14), 14, 14), i18n("world.datapack"), FXUtils.withJFXPopupClosing(skinnable::manageDatapacks, popup)), new IconedMenuItem(FXUtils.limitingSize(SVG.export(Theme.blackFillBinding(), 14, 14), 14, 14), i18n("world.export"), FXUtils.withJFXPopupClosing(skinnable::export, popup))); diff --git a/HMCL/src/main/resources/assets/css/root.css b/HMCL/src/main/resources/assets/css/root.css index 3c99506aa..6d66c04e0 100644 --- a/HMCL/src/main/resources/assets/css/root.css +++ b/HMCL/src/main/resources/assets/css/root.css @@ -81,6 +81,10 @@ -fx-alignment: CENTER_LEFT; } +.menu-container { + -fx-padding: 8 16 8 16; +} + .menu { -fx-padding: 4 0 4 0; } diff --git a/HMCL/src/main/resources/assets/fxml/main.fxml b/HMCL/src/main/resources/assets/fxml/main.fxml index 48e42b2f3..d4c105133 100644 --- a/HMCL/src/main/resources/assets/fxml/main.fxml +++ b/HMCL/src/main/resources/assets/fxml/main.fxml @@ -14,7 +14,7 @@ diff --git a/HMCL/src/main/resources/assets/img/furnace.png b/HMCL/src/main/resources/assets/img/furnace.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc95fc2c159f53913d5b5bce8310f88db42ef27 GIT binary patch literal 8200 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