diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/AccountHelper.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/AccountHelper.kt index c7a2f0e8d..c64caae52 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/AccountHelper.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/AccountHelper.kt @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.game +import javafx.geometry.Rectangle2D import javafx.scene.image.Image import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount @@ -24,6 +25,7 @@ import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.task.FileDownloadTask import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.task.Task +import org.jackhuang.hmcl.ui.DEFAULT_ICON import org.jackhuang.hmcl.ui.DialogController import org.jackhuang.hmcl.util.toURL import java.net.Proxy @@ -63,16 +65,20 @@ object AccountHelper { } private fun getSkinFile(name: String) = SKIN_DIR.resolve("$name.png") - private val DEFAULT_IMAGE = Image("/assets/img/icon.png") fun getSkin(account: YggdrasilAccount, scaleRatio: Double = 1.0): Image { - if (account.selectedProfile == null) return DEFAULT_IMAGE - val name = account.selectedProfile?.name ?: return DEFAULT_IMAGE + if (account.selectedProfile == null) return DEFAULT_ICON + val name = account.selectedProfile?.name ?: return DEFAULT_ICON val file = getSkinFile(name) if (file.exists()) { val original = Image("file:" + file.absolutePath) return Image("file:" + file.absolutePath, original.width * scaleRatio, original.height * scaleRatio, false, false) } - else return DEFAULT_IMAGE + else return DEFAULT_ICON + } + + fun getViewport(scaleRatio: Double): Rectangle2D { + val size = 8.0 * scaleRatio + return Rectangle2D(size, size, size, size) } } \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt index 149165976..586cdb8b8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLGameRepository.kt @@ -127,6 +127,9 @@ class HMCLGameRepository(val profile: Profile, baseDirectory: File) return versionSettings[id] } + fun getVersionIcon(id: String): File = + getVersionRoot(id).resolve("icon.png") + fun markVersionAsModpack(id: String) { beingModpackVersions += id } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt index ba4da40f9..27ae0dd44 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountItem.kt @@ -98,11 +98,9 @@ class AccountItem(i: Int, val account: Account, group: ToggleGroup) : StackPane( if (account !is YggdrasilAccount) return pgsSkin.isVisible = false - val size = 8.0 * 4 - portraitView.viewport = Rectangle2D(size, size, size, size) + portraitView.viewport = AccountHelper.getViewport(4.0) portraitView.image = AccountHelper.getSkin(account, 4.0) - portraitView.fitHeight = 32.0 - portraitView.fitWidth = 32.0 + portraitView.limitSize(32.0, 32.0) } private fun getDefaultColor(i: Int): String { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt index 60a12e056..b812f7358 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt @@ -37,6 +37,7 @@ import org.jackhuang.hmcl.task.Scheduler import org.jackhuang.hmcl.task.taskResult import org.jackhuang.hmcl.ui.wizard.DecoratorPage import org.jackhuang.hmcl.util.onChange +import org.jackhuang.hmcl.util.onChangeAndOperate class AccountsPage() : StackPane(), DecoratorPage { override val titleProperty: StringProperty = SimpleStringProperty(this, "title", "Accounts") @@ -69,7 +70,7 @@ class AccountsPage() : StackPane(), DecoratorPage { txtPassword.setOnAction { onCreationAccept() } txtUsername.setOnAction { onCreationAccept() } - Settings.selectedAccountProperty.setChangedListener { account -> + Settings.selectedAccountProperty.onChangeAndOperate { account -> masonryPane.children.forEach { node -> if (node is AccountItem) { node.chkSelected.isSelected = account?.username == node.lblUser.text diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/FXUtils.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/FXUtils.kt index 1fcb8837e..2052db664 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/FXUtils.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/FXUtils.kt @@ -33,6 +33,8 @@ import javafx.scene.Node import javafx.scene.Parent import javafx.scene.Scene import javafx.scene.control.* +import javafx.scene.image.Image +import javafx.scene.image.ImageView import javafx.scene.image.WritableImage import javafx.scene.input.MouseEvent import javafx.scene.input.ScrollEvent @@ -248,4 +250,19 @@ fun JFXTextField.setValidateWhileTextChanged() { fun JFXPasswordField.setValidateWhileTextChanged() { textProperty().addListener { _ -> validate() } validate() -} \ No newline at end of file +} + +fun ImageView.limitSize(maxWidth: Double, maxHeight: Double) { + isPreserveRatio = true + imageProperty().onChangeAndOperate { + if (it != null && (it.width > maxWidth || it.height > maxHeight)) { + fitHeight = maxHeight + fitWidth = maxWidth + } else { + fitHeight = -1.0 + fitWidth = -1.0 + } + } +} + +val DEFAULT_ICON = Image("/assets/img/icon.png") \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt index f76c9b615..dab3e2e53 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/LeftPaneController.kt @@ -19,10 +19,13 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.JFXComboBox import javafx.scene.layout.VBox +import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount +import org.jackhuang.hmcl.game.AccountHelper import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.ui.construct.IconedItem import org.jackhuang.hmcl.ui.construct.RipplerContainer +import org.jackhuang.hmcl.util.onChangeAndOperate class LeftPaneController(private val leftPane: AdvancedListBox) { val versionsPane = VBox() @@ -63,7 +66,7 @@ class LeftPaneController(private val leftPane: AdvancedListBox) { } Controllers.mainPane.buttonLaunch.setOnMouseClicked { LauncherHelper.launch() }*/ - Settings.selectedAccountProperty.setChangedListener { + Settings.selectedAccountProperty.onChangeAndOperate { if (it == null) { accountItem.lblVersionName.text = "mojang@mojang.com" accountItem.lblGameVersion.text = "Yggdrasil" @@ -71,6 +74,13 @@ class LeftPaneController(private val leftPane: AdvancedListBox) { accountItem.lblVersionName.text = it.username accountItem.lblGameVersion.text = accountType(it) } + if (it is YggdrasilAccount) { + accountItem.imageView.image = AccountHelper.getSkin(it, 4.0) + accountItem.imageView.viewport = AccountHelper.getViewport(4.0) + } else { + accountItem.imageView.image = DEFAULT_ICON + accountItem.imageView.viewport = null + } } if (Settings.getAccounts().isEmpty()) diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt index fd72fa5e8..9b225d2e0 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/MainPage.kt @@ -25,6 +25,7 @@ import javafx.beans.property.StringProperty import javafx.fxml.FXML import javafx.scene.Node import javafx.scene.control.ToggleGroup +import javafx.scene.image.Image import javafx.scene.layout.StackPane import org.jackhuang.hmcl.ProfileChangedEvent import org.jackhuang.hmcl.ProfileLoadingEvent @@ -83,6 +84,9 @@ class MainPage : StackPane(), DecoratorPage { Controllers.decorator.showPage(Controllers.versionPane) Controllers.versionPane.load(version, profile) } + val iconFile = profile.repository.getVersionIcon(version) + if (iconFile.exists()) + iconView.image = Image("file:" + iconFile.absolutePath) } } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt index 7e61b50c6..bf01c6e0b 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionItem.kt @@ -25,6 +25,7 @@ import javafx.scene.control.Label import javafx.scene.control.ToggleGroup import javafx.scene.effect.BlurType import javafx.scene.effect.DropShadow +import javafx.scene.image.ImageView import javafx.scene.layout.Pane import javafx.scene.layout.StackPane import javafx.scene.layout.VBox @@ -41,6 +42,7 @@ class VersionItem(i: Int, group: ToggleGroup) : StackPane() { @FXML lateinit var lblVersionName: Label @FXML lateinit var chkSelected: JFXRadioButton @FXML lateinit var lblGameVersion: Label + @FXML lateinit var iconView: ImageView init { loadFXML("/assets/fxml/version-item.fxml") @@ -60,6 +62,7 @@ class VersionItem(i: Int, group: ToggleGroup) : StackPane() { // create image view icon.translateYProperty().bind(Bindings.createDoubleBinding(Callable { header.boundsInParent.height - icon.height }, header.boundsInParentProperty(), icon.heightProperty())) + iconView.limitSize(32.0, 32.0) } private fun getDefaultColor(i: Int): String { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt index a987d99fc..f59f48138 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionListItem.kt @@ -20,13 +20,15 @@ package org.jackhuang.hmcl.ui import javafx.fxml.FXML import javafx.scene.control.Button import javafx.scene.control.Label +import javafx.scene.image.ImageView import javafx.scene.layout.StackPane -class VersionListItem(val versionName: String, val gameVersion: String) : StackPane() { +class VersionListItem(versionName: String, gameVersion: String) : StackPane() { @FXML lateinit var lblVersionName: Label @FXML lateinit var lblGameVersion: Label - @FXML lateinit var btnSettings: Button + @FXML lateinit var imageView: ImageView + @FXML lateinit var imageViewContainer: StackPane private var handler: () -> Unit = {} @@ -34,6 +36,10 @@ class VersionListItem(val versionName: String, val gameVersion: String) : StackP loadFXML("/assets/fxml/version-list-item.fxml") lblVersionName.text = versionName lblGameVersion.text = gameVersion + + imageView.limitSize(32.0, 32.0) + imageViewContainer.limitWidth(32.0) + imageViewContainer.limitHeight(32.0) } fun onSettings() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt index 7fe094cb0..1a51ec7fd 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionPage.kt @@ -44,6 +44,8 @@ class VersionPage : StackPane(), DecoratorPage { @FXML lateinit var btnBrowseMenu: JFXButton @FXML lateinit var btnManagementMenu: JFXButton @FXML lateinit var btnExport: JFXButton + @FXML lateinit var rootPane: StackPane + @FXML lateinit var contentPane: StackPane val browsePopup: JFXPopup val managementPopup: JFXPopup lateinit var profile: Profile @@ -68,7 +70,7 @@ class VersionPage : StackPane(), DecoratorPage { this.profile = profile titleProperty.set(i18n("launcher.title.game") + " - " + id) - versionSettingsController.loadVersionSetting(profile.getVersionSetting(id)) + versionSettingsController.loadVersionSetting(profile, id, profile.getVersionSetting(id)) modController.loadMods(profile.modManager, id) installerController.loadVersion(profile, id) } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt index c1488d258..0c35613ca 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/VersionSettingsController.kt @@ -18,19 +18,24 @@ package org.jackhuang.hmcl.ui import com.jfoenix.controls.* -import javafx.beans.InvalidationListener import javafx.beans.value.ChangeListener import javafx.fxml.FXML import javafx.scene.control.Label import javafx.scene.control.ScrollPane import javafx.scene.control.Toggle import javafx.scene.control.ToggleGroup +import javafx.scene.image.Image +import javafx.scene.image.ImageView import javafx.scene.layout.BorderPane import javafx.scene.layout.Pane import javafx.scene.layout.VBox import javafx.stage.DirectoryChooser +import javafx.stage.FileChooser import org.jackhuang.hmcl.i18n +import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.setting.VersionSetting +import org.jackhuang.hmcl.task.Scheduler +import org.jackhuang.hmcl.task.task import org.jackhuang.hmcl.ui.construct.ComponentList import org.jackhuang.hmcl.ui.construct.NumberValidator import org.jackhuang.hmcl.util.JavaVersion @@ -64,9 +69,15 @@ class VersionSettingsController { @FXML lateinit var radioCustom: JFXRadioButton @FXML lateinit var btnJavaSelect: JFXButton @FXML lateinit var chkShowLogs: JFXToggleButton + @FXML lateinit var btnIconSelection: JFXButton + @FXML lateinit var iconView: ImageView + + lateinit var profile: Profile + lateinit var versionId: String val javaGroup = ToggleGroup() + fun initialize() { lblPhysicalMemory.text = i18n("settings.physical_memory") + ": ${OS.TOTAL_MEMORY}MB" @@ -122,9 +133,12 @@ class VersionSettingsController { } } - fun loadVersionSetting(version: VersionSetting) { + fun loadVersionSetting(profile: Profile, versionId: String, version: VersionSetting) { rootPane.children -= advancedSettingsPane + this.profile = profile + this.versionId = versionId + lastVersionSetting?.apply { widthProperty.unbind() heightProperty.unbind() @@ -192,14 +206,17 @@ class VersionSettingsController { } version.javaDirProperty.setChangedListener { initJavaSubtitle(version) } - version.javaProperty.setChangedListener { initJavaSubtitle(version)} + version.javaProperty.setChangedListener { initJavaSubtitle(version) } initJavaSubtitle(version) lastVersionSetting = version + + loadIcon() } private fun initJavaSubtitle(version: VersionSetting) { - componentJava.subtitle = version.javaVersion?.binary?.absolutePath ?: "Invalid Java Directory" + task { it["java"] = version.javaVersion } + .then(task(Scheduler.JAVAFX) { componentJava.subtitle = it.get<JavaVersion?>("java")?.binary?.absolutePath ?: "Invalid Java Directory" }) } fun onShowAdvanced() { @@ -216,4 +233,24 @@ class VersionSettingsController { if (selectedDir != null) txtJavaDir.text = selectedDir.absolutePath } + + fun onExploreIcon() { + val chooser = FileChooser() + chooser.extensionFilters += FileChooser.ExtensionFilter("Image", "*.png") + val selectedFile = chooser.showOpenDialog(Controllers.stage) + if (selectedFile != null) { + val iconFile = profile.repository.getVersionIcon(versionId) + selectedFile.copyTo(iconFile, overwrite = true) + loadIcon() + } + } + + private fun loadIcon() { + val iconFile = profile.repository.getVersionIcon(versionId) + if (iconFile.exists()) + iconView.image = Image("file:" + iconFile.absolutePath) + else + iconView.image = DEFAULT_ICON + iconView.limitSize(32.0, 32.0) + } } \ No newline at end of file diff --git a/HMCL/src/main/resources/assets/fxml/version-item.fxml b/HMCL/src/main/resources/assets/fxml/version-item.fxml index 83968f18b..397b3da32 100644 --- a/HMCL/src/main/resources/assets/fxml/version-item.fxml +++ b/HMCL/src/main/resources/assets/fxml/version-item.fxml @@ -42,7 +42,7 @@ </StackPane> </VBox> <StackPane fx:id="icon" StackPane.alignment="TOP_RIGHT" pickOnBounds="false"> - <ImageView StackPane.alignment="CENTER_RIGHT"> + <ImageView fx:id="iconView" StackPane.alignment="CENTER_RIGHT"> <StackPane.margin> <Insets right="12" /> </StackPane.margin> diff --git a/HMCL/src/main/resources/assets/fxml/version-list-item.fxml b/HMCL/src/main/resources/assets/fxml/version-list-item.fxml index 5f465f633..6a0098478 100644 --- a/HMCL/src/main/resources/assets/fxml/version-list-item.fxml +++ b/HMCL/src/main/resources/assets/fxml/version-list-item.fxml @@ -14,15 +14,17 @@ <BorderPane pickOnBounds="false"> <left> <HBox alignment="CENTER" mouseTransparent="true"> - <ImageView> + <StackPane fx:id="imageViewContainer"> + <ImageView preserveRatio="true" fx:id="imageView" smooth="false"> <Image url="/assets/img/icon.png" requestedWidth="25" requestedHeight="25" /> </ImageView> + </StackPane> <BorderPane style="-fx-padding: 0 0 0 10;"> <top> - <Label fx:id="lblVersionName" maxWidth="100" style="-fx-font-size: 15;" textAlignment="JUSTIFY" /> + <Label fx:id="lblVersionName" maxWidth="90" style="-fx-font-size: 15;" textAlignment="JUSTIFY" /> </top> <bottom> - <Label fx:id="lblGameVersion" maxWidth="100" style="-fx-font-size: 10;" textAlignment="JUSTIFY" /> + <Label fx:id="lblGameVersion" maxWidth="90" style="-fx-font-size: 10;" textAlignment="JUSTIFY" /> </bottom> </BorderPane> </HBox> diff --git a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml index ef0b32591..1c8b27ac5 100644 --- a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml +++ b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml @@ -1,36 +1,55 @@ <?xml version="1.0" encoding="UTF-8"?> -<?import javafx.scene.control.*?> -<?import javafx.scene.layout.*?> - -<?import com.jfoenix.controls.JFXTextField?> -<?import com.jfoenix.controls.JFXButton?> -<?import com.jfoenix.controls.JFXCheckBox?> -<?import javafx.geometry.Insets?> -<?import com.jfoenix.controls.JFXComboBox?> +<?import com.jfoenix.controls.*?> <?import javafx.collections.FXCollections?> +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.*?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.*?> <?import org.jackhuang.hmcl.ui.construct.ComponentList?> -<?import com.jfoenix.controls.JFXToggleButton?> -<?import com.jfoenix.controls.JFXRadioButton?> <StackPane xmlns="http://javafx.com/javafx" - xmlns:fx="http://javafx.com/fxml" - fx:controller="org.jackhuang.hmcl.ui.VersionSettingsController"> + xmlns:fx="http://javafx.com/fxml" + fx:controller="org.jackhuang.hmcl.ui.VersionSettingsController"> <ScrollPane fx:id="scroll" fitToHeight="true" fitToWidth="true"> <VBox fx:id="rootPane" style="-fx-padding: 20;"> + <ComponentList depth="1"> - <ComponentList fx:id="componentJava" title="%settings.java_dir" hasSubtitle="true"> <!-- Java Directory --> + <BorderPane> <!-- Icon --> + <left> + <Label text="settings.icon" /> + </left> + <right> + <HBox alignment="CENTER_RIGHT" spacing="8"> + <ImageView fx:id="iconView" smooth="false" preserveRatio="true"> + <StackPane.margin> + <Insets right="12"/> + </StackPane.margin> + <Image url="/assets/img/icon.png"/> + </ImageView> + <JFXButton fx:id="btnIconSelection" onMouseClicked="#onExploreIcon" styleClass="toggle-icon4"> + <graphic> + <fx:include source="/assets/svg/pencil.fxml" /> + </graphic> + </JFXButton> + </HBox> + </right> + </BorderPane> + + <ComponentList fx:id="componentJava" title="%settings.java_dir" + hasSubtitle="true"> <!-- Java Directory --> <VBox fx:id="javaPane" spacing="8" style="-fx-padding: 0 0 10 0;"> <BorderPane fx:id="javaPaneCustom" style="-fx-padding: 3;"> <left> - <JFXRadioButton fx:id="radioCustom" text="%settings.custom" /> + <JFXRadioButton fx:id="radioCustom" text="%settings.custom"/> </left> <right> <HBox spacing="3"> - <JFXTextField fx:id="txtJavaDir" BorderPane.alignment="CENTER_RIGHT" /> + <JFXTextField fx:id="txtJavaDir" BorderPane.alignment="CENTER_RIGHT"/> <JFXButton fx:id="btnJavaSelect" onMouseClicked="#onExploreJavaDir"> <graphic> - <fx:include source="/assets/svg/folder-open.fxml" /> + <fx:include source="/assets/svg/folder-open.fxml"/> </graphic> </JFXButton> </HBox> @@ -40,20 +59,29 @@ </ComponentList> <BorderPane> <!-- Max Memory --> - <left><VBox><Label text="%settings.max_memory" BorderPane.alignment="CENTER_LEFT" /><Label fx:id="lblPhysicalMemory" styleClass="subtitle-label" /></VBox></left> - <right><JFXTextField fx:id="txtMaxMemory" BorderPane.alignment="CENTER_RIGHT" /></right> + <left> + <VBox> + <Label text="%settings.max_memory" BorderPane.alignment="CENTER_LEFT"/> + <Label fx:id="lblPhysicalMemory" styleClass="subtitle-label"/> + </VBox> + </left> + <right> + <JFXTextField fx:id="txtMaxMemory" BorderPane.alignment="CENTER_RIGHT"/> + </right> </BorderPane> <BorderPane> <!-- Launcher Visibility --> - <left><Label text="%advancedsettings.launcher_visible" BorderPane.alignment="CENTER_LEFT" /></left> + <left> + <Label text="%advancedsettings.launcher_visible" BorderPane.alignment="CENTER_LEFT"/> + </left> <right> <JFXComboBox fx:id="cboLauncherVisibility" BorderPane.alignment="CENTER_RIGHT"> <items> <FXCollections fx:factory="observableArrayList"> - <Label text="%advancedsettings.launcher_visibility.close" /> - <Label text="%advancedsettings.launcher_visibility.hide" /> - <Label text="%advancedsettings.launcher_visibility.keep" /> - <Label text="%advancedsettings.launcher_visibility.hide_reopen" /> + <Label text="%advancedsettings.launcher_visibility.close"/> + <Label text="%advancedsettings.launcher_visibility.hide"/> + <Label text="%advancedsettings.launcher_visibility.keep"/> + <Label text="%advancedsettings.launcher_visibility.hide_reopen"/> </FXCollections> </items> </JFXComboBox> @@ -61,13 +89,15 @@ </BorderPane> <BorderPane> <!-- Run Directory --> - <left><Label text="%settings.run_directory" BorderPane.alignment="CENTER_LEFT" /></left> + <left> + <Label text="%settings.run_directory" BorderPane.alignment="CENTER_LEFT"/> + </left> <right> <JFXComboBox fx:id="cboRunDirectory" BorderPane.alignment="CENTER_RIGHT"> <items> <FXCollections fx:factory="observableArrayList"> - <Label text="%advancedsettings.game_dir.default" /> - <Label text="%advancedsettings.game_dir.independent" /> + <Label text="%advancedsettings.game_dir.default"/> + <Label text="%advancedsettings.game_dir.independent"/> </FXCollections> </items> </JFXComboBox> @@ -75,18 +105,21 @@ </BorderPane> <BorderPane> <!-- Dimension --> - <left><Label text="%settings.dimension" BorderPane.alignment="CENTER_LEFT" /></left> + <left> + <Label text="%settings.dimension" BorderPane.alignment="CENTER_LEFT"/> + </left> <right> <BorderPane> <left> <HBox prefWidth="210" spacing="3" alignment="CENTER" BorderPane.alignment="CENTER"> - <JFXTextField fx:id="txtWidth" promptText="800" prefWidth="100" /> + <JFXTextField fx:id="txtWidth" promptText="800" prefWidth="100"/> <Label>x</Label> - <JFXTextField fx:id="txtHeight" promptText="480" prefWidth="100" /> + <JFXTextField fx:id="txtHeight" promptText="480" prefWidth="100"/> </HBox> </left> <right> - <JFXCheckBox fx:id="chkFullscreen" text="%settings.fullscreen" alignment="CENTER" BorderPane.alignment="CENTER"> + <JFXCheckBox fx:id="chkFullscreen" text="%settings.fullscreen" alignment="CENTER" + BorderPane.alignment="CENTER"> <BorderPane.margin> <Insets right="7"/> </BorderPane.margin> @@ -96,28 +129,62 @@ </right> </BorderPane> - <BorderPane><left><Label text="%mainwindow.show_log" /></left><right><JFXToggleButton fx:id="chkShowLogs" size="7" /></right></BorderPane> + <BorderPane> + <left> + <Label text="%mainwindow.show_log"/> + </left> + <right> + <JFXToggleButton fx:id="chkShowLogs" size="7"/> + </right> + </BorderPane> </ComponentList> <HBox alignment="CENTER" style="-fx-padding: 10 0 10 0;"> - <JFXButton text="%advancedsettings" onMouseClicked="#onShowAdvanced" /> + <JFXButton text="%advancedsettings" onMouseClicked="#onShowAdvanced"/> </HBox> <ComponentList fx:id="advancedSettingsPane" depth="1"> - <JFXTextField labelFloat="true" promptText="%advancedsettings.jvm_args" styleClass="fit-width" fx:id="txtJVMArgs"> + <JFXTextField labelFloat="true" promptText="%advancedsettings.jvm_args" styleClass="fit-width" + fx:id="txtJVMArgs"> <tooltip> - <Tooltip text="%advancedsettings.java_args_default" /> + <Tooltip text="%advancedsettings.java_args_default"/> </tooltip> </JFXTextField> <fx:define> - <Insets fx:id="insets" bottom="8" /> + <Insets fx:id="insets" bottom="8"/> </fx:define> - <JFXTextField labelFloat="true" promptText="%advancedsettings.Minecraft_arguments" styleClass="fit-width" fx:id="txtGameArgs" StackPane.margin="$insets" /> - <JFXTextField labelFloat="true" promptText="%advancedsettings.java_permanent_generation_space" styleClass="fit-width" fx:id="txtMetaspace" StackPane.margin="$insets" /> - <JFXTextField labelFloat="true" promptText="%advancedsettings.wrapper_launcher" styleClass="fit-width" fx:id="txtWrapper" StackPane.margin="$insets" /> - <JFXTextField labelFloat="true" promptText="%advancedsettings.precall_command" styleClass="fit-width" fx:id="txtPrecallingCommand" StackPane.margin="$insets" /> - <JFXTextField labelFloat="true" promptText="%advancedsettings.server_ip" styleClass="fit-width" fx:id="txtServerIP" StackPane.margin="$insets" /> - <BorderPane><left><Label text="%advancedsettings.no_jvm_args" /></left><right><JFXToggleButton fx:id="chkNoJVMArgs" size="7" /></right></BorderPane> - <BorderPane><left><Label text="%advancedsettings.no_common" /></left><right><JFXToggleButton fx:id="chkNoCommon" size="7" /></right></BorderPane> - <BorderPane><left><Label text="%advancedsettings.dont_check_game_completeness" /></left><right><JFXToggleButton fx:id="chkNoGameCheck" size="7" /></right></BorderPane> + <JFXTextField labelFloat="true" promptText="%advancedsettings.Minecraft_arguments" + styleClass="fit-width" fx:id="txtGameArgs" StackPane.margin="$insets"/> + <JFXTextField labelFloat="true" promptText="%advancedsettings.java_permanent_generation_space" + styleClass="fit-width" fx:id="txtMetaspace" StackPane.margin="$insets"/> + <JFXTextField labelFloat="true" promptText="%advancedsettings.wrapper_launcher" styleClass="fit-width" + fx:id="txtWrapper" StackPane.margin="$insets"/> + <JFXTextField labelFloat="true" promptText="%advancedsettings.precall_command" styleClass="fit-width" + fx:id="txtPrecallingCommand" StackPane.margin="$insets"/> + <JFXTextField labelFloat="true" promptText="%advancedsettings.server_ip" styleClass="fit-width" + fx:id="txtServerIP" StackPane.margin="$insets"/> + <BorderPane> + <left> + <Label text="%advancedsettings.no_jvm_args"/> + </left> + <right> + <JFXToggleButton fx:id="chkNoJVMArgs" size="7"/> + </right> + </BorderPane> + <BorderPane> + <left> + <Label text="%advancedsettings.no_common"/> + </left> + <right> + <JFXToggleButton fx:id="chkNoCommon" size="7"/> + </right> + </BorderPane> + <BorderPane> + <left> + <Label text="%advancedsettings.dont_check_game_completeness"/> + </left> + <right> + <JFXToggleButton fx:id="chkNoGameCheck" size="7"/> + </right> + </BorderPane> </ComponentList> </VBox> </ScrollPane> diff --git a/HMCL/src/main/resources/assets/fxml/version/version.fxml b/HMCL/src/main/resources/assets/fxml/version/version.fxml index 765aa3a91..4686d011d 100644 --- a/HMCL/src/main/resources/assets/fxml/version/version.fxml +++ b/HMCL/src/main/resources/assets/fxml/version/version.fxml @@ -2,54 +2,64 @@ <?import com.jfoenix.controls.*?> <?import javafx.scene.control.*?> -<?import javafx.scene.layout.*?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.StackPane?> <fx:root xmlns="http://javafx.com/javafx" - xmlns:fx="http://javafx.com/fxml" - type="StackPane"> - <JFXTabPane> - <Tab text="%settings"> - <fx:include source="version-settings.fxml" fx:id="versionSettings" /> - </Tab> - <Tab text="%mods"> - <fx:include source="mod.fxml" fx:id="mod" /> - </Tab> - <Tab text="%settings.tabs.installers"> - <fx:include source="installer.fxml" fx:id="installer" /> - </Tab> - </JFXTabPane> + xmlns:fx="http://javafx.com/fxml" + fx:id="rootPane" + type="StackPane"> + <JFXRippler /> + <StackPane fx:id="contentPane"> + <JFXTabPane> + <Tab text="%settings"> + <fx:include source="version-settings.fxml" fx:id="versionSettings"/> + </Tab> + <Tab text="%mods"> + <fx:include source="mod.fxml" fx:id="mod"/> + </Tab> + <Tab text="%settings.tabs.installers"> + <fx:include source="installer.fxml" fx:id="installer"/> + </Tab> + </JFXTabPane> - <HBox alignment="TOP_RIGHT" style="-fx-padding: 3px;" pickOnBounds="false"> - <JFXButton fx:id="btnExport" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onExport" styleClass="toggle-icon3" ripplerFill="white"> - <graphic> - <fx:include source="/assets/svg/export.fxml"/> - </graphic> - </JFXButton> - <JFXButton fx:id="btnBrowseMenu" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onBrowseMenu" styleClass="toggle-icon3" ripplerFill="white"> - <graphic> - <fx:include source="/assets/svg/folder-open.fxml"/> - </graphic> - </JFXButton> - <JFXButton fx:id="btnManagementMenu" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onManagementMenu" styleClass="toggle-icon3" ripplerFill="white"> - <graphic> - <fx:include source="/assets/svg/wrench-black.fxml"/> - </graphic> - </JFXButton> - </HBox> + <HBox alignment="TOP_RIGHT" style="-fx-padding: 3px;" pickOnBounds="false"> + <JFXButton fx:id="btnExport" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onExport" + styleClass="toggle-icon3" ripplerFill="white"> + <graphic> + <fx:include source="/assets/svg/export.fxml"/> + </graphic> + </JFXButton> + <JFXButton fx:id="btnBrowseMenu" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onBrowseMenu" + styleClass="toggle-icon3" ripplerFill="white"> + <graphic> + <fx:include source="/assets/svg/folder-open.fxml"/> + </graphic> + </JFXButton> + <JFXButton fx:id="btnManagementMenu" maxHeight="28.0" minHeight="28.0" onMouseClicked="#onManagementMenu" + styleClass="toggle-icon3" ripplerFill="white"> + <graphic> + <fx:include source="/assets/svg/wrench-black.fxml"/> + </graphic> + </JFXButton> + </HBox> + </StackPane> - <JFXListView fx:id="browseList" styleClass="option-list-view" onMouseClicked="#onBrowse" maxWidth="150.0" minWidth="150.0"> - <Label text="%folder.game" /> - <Label text="%folder.mod" /> - <Label text="%folder.coremod" /> - <Label text="%folder.config" /> - <Label text="%folder.resourcepacks" /> - <Label text="%folder.screenshots" /> - <Label text="%folder.saves" /> + <JFXListView fx:id="browseList" styleClass="option-list-view" onMouseClicked="#onBrowse" maxWidth="150.0" + minWidth="150.0"> + <Label text="%folder.game"/> + <Label text="%folder.mod"/> + <Label text="%folder.coremod"/> + <Label text="%folder.config"/> + <Label text="%folder.resourcepacks"/> + <Label text="%folder.screenshots"/> + <Label text="%folder.saves"/> </JFXListView> - <JFXListView fx:id="managementList" styleClass="option-list-view" onMouseClicked="#onManagement" maxWidth="300.0" minWidth="300.0"> - <Label text="%versions.manage.rename" /> - <Label text="%versions.manage.remove" /> - <Label text="%versions.manage.redownload_assets_index" /> - <Label text="%versions.manage.remove_libraries" /> + <JFXListView fx:id="managementList" styleClass="option-list-view" onMouseClicked="#onManagement" + maxWidth="300.0" minWidth="300.0"> + <Label text="%versions.manage.rename"/> + <Label text="%versions.manage.remove"/> + <Label text="%versions.manage.redownload_assets_index"/> + <Label text="%versions.manage.remove_libraries"/> </JFXListView> </fx:root> diff --git a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lib.kt b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lib.kt index 334cb1ad6..2c312e0f4 100644 --- a/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lib.kt +++ b/HMCLCore/src/main/kotlin/org/jackhuang/hmcl/util/Lib.kt @@ -22,6 +22,7 @@ import javafx.collections.ListChangeListener import javafx.collections.ObservableList fun <T> ObservableValue<T>.onChange(op: (T?) -> Unit) = apply { addListener { _, _, new -> op(new) } } +fun <T> ObservableValue<T>.onChangeAndOperate(op: (T?) -> Unit) = apply { addListener { _, _, new -> op(new) }; op(value) } fun ObservableBooleanValue.onChange(op: (Boolean) -> Unit) = apply { addListener { _, _, new -> op(new ?: false) } } fun ObservableIntegerValue.onChange(op: (Int) -> Unit) = apply { addListener { _, _, new -> op((new ?: 0).toInt()) } } fun ObservableLongValue.onChange(op: (Long) -> Unit) = apply { addListener { _, _, new -> op((new ?: 0L).toLong()) } }