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()) } }