From 833247d133272abd34265982a50f139cd3c36722 Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Fri, 25 Aug 2017 08:54:33 +0800 Subject: [PATCH] Icon selection --- .../org/jackhuang/hmcl/game/AccountHelper.kt | 14 +- .../jackhuang/hmcl/game/HMCLGameRepository.kt | 3 + .../org/jackhuang/hmcl/ui/AccountItem.kt | 6 +- .../org/jackhuang/hmcl/ui/AccountsPage.kt | 3 +- .../kotlin/org/jackhuang/hmcl/ui/FXUtils.kt | 19 ++- .../jackhuang/hmcl/ui/LeftPaneController.kt | 12 +- .../kotlin/org/jackhuang/hmcl/ui/MainPage.kt | 4 + .../org/jackhuang/hmcl/ui/VersionItem.kt | 3 + .../org/jackhuang/hmcl/ui/VersionListItem.kt | 10 +- .../org/jackhuang/hmcl/ui/VersionPage.kt | 4 +- .../hmcl/ui/VersionSettingsController.kt | 45 +++++- .../resources/assets/fxml/version-item.fxml | 2 +- .../assets/fxml/version-list-item.fxml | 8 +- .../assets/fxml/version/version-settings.fxml | 153 +++++++++++++----- .../assets/fxml/version/version.fxml | 98 ++++++----- .../kotlin/org/jackhuang/hmcl/util/Lib.kt | 1 + 16 files changed, 276 insertions(+), 109 deletions(-) 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("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 @@ - + 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 @@ - + + + - - 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 @@ - - - - - - - - + + + + + + - - + xmlns:fx="http://javafx.com/fxml" + fx:controller="org.jackhuang.hmcl.ui.VersionSettingsController"> + - + + + + + + + + + + + + + + + + + + + + + - + - + - + @@ -40,20 +59,29 @@ - - + + + + + + + - + + - @@ -61,13 +89,15 @@ - + + - @@ -75,18 +105,21 @@ - + + - + - + - + @@ -96,28 +129,62 @@ - + + + + + + + - + - + - + - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ - + + - - - - - - - - - - - + xmlns:fx="http://javafx.com/fxml" + fx:id="rootPane" + type="StackPane"> + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - 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 ObservableValue.onChange(op: (T?) -> Unit) = apply { addListener { _, _, new -> op(new) } } +fun ObservableValue.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()) } }