Log Window refined

This commit is contained in:
huangyuhui 2017-08-21 13:40:16 +08:00
parent f92275fa50
commit be202a6e1a
12 changed files with 152 additions and 16 deletions

View File

@ -85,8 +85,12 @@ class Main : Application() {
fun getMinecraftDirectory(): File = getWorkingDirectory("minecraft") fun getMinecraftDirectory(): File = getWorkingDirectory("minecraft")
fun stop() = runOnUiThread { fun stop() = runOnUiThread {
Controllers.stage.close() stopWithoutJavaFXPlatform()
Platform.exit() Platform.exit()
}
fun stopWithoutJavaFXPlatform() = runOnUiThread {
Controllers.stage.close()
Scheduler.shutdown() Scheduler.shutdown()
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.jackhuang.hmcl.game package org.jackhuang.hmcl.game
import javafx.application.Platform
import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.auth.AuthInfo import org.jackhuang.hmcl.auth.AuthInfo
import org.jackhuang.hmcl.auth.AuthenticationException import org.jackhuang.hmcl.auth.AuthenticationException
@ -169,9 +170,14 @@ object LauncherHelper {
private fun checkExit(launcherVisibility: LauncherVisibility) { private fun checkExit(launcherVisibility: LauncherVisibility) {
when (launcherVisibility) { when (launcherVisibility) {
LauncherVisibility.HIDE_AND_REOPEN -> runOnUiThread { Controllers.stage.show() } LauncherVisibility.HIDE_AND_REOPEN -> runOnUiThread { Controllers.stage.show() }
LauncherVisibility.KEEP -> {} LauncherVisibility.KEEP -> { /* no operations here. */ }
LauncherVisibility.CLOSE -> {} LauncherVisibility.CLOSE -> { throw Error("Never get to here") }
LauncherVisibility.HIDE -> Main.stop() LauncherVisibility.HIDE -> runOnUiThread {
// Shut down the platform when user closed log window.
Platform.setImplicitExit(true)
// If we use Main.stop(), log window will be halt immediately.
Main.stopWithoutJavaFXPlatform()
}
} }
} }

View File

@ -115,13 +115,13 @@ class Config {
Settings.save() Settings.save()
} }
@SerializedName("fontFamily") @SerializedName("fontFamily")
var fontFamily: String? = null var fontFamily: String? = "Consolas"
set(value) { set(value) {
field = value field = value
Settings.save() Settings.save()
} }
@SerializedName("fontSize") @SerializedName("fontSize")
var fontSize: Int = 12 var fontSize: Double = 12.0
set(value) { set(value) {
field = value field = value
Settings.save() Settings.save()

View File

@ -19,6 +19,7 @@ package org.jackhuang.hmcl.setting
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import javafx.beans.InvalidationListener import javafx.beans.InvalidationListener
import javafx.scene.text.Font
import java.io.IOException import java.io.IOException
import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider
@ -192,6 +193,13 @@ object Settings {
init { loadProxy() } init { loadProxy() }
var font: Font
get() = Font.font(SETTINGS.fontFamily, SETTINGS.fontSize)
set(value) {
SETTINGS.fontFamily = value.family
SETTINGS.fontSize = value.size
}
var downloadProvider: DownloadProvider var downloadProvider: DownloadProvider
get() = when (SETTINGS.downloadtype) { get() = when (SETTINGS.downloadtype) {
0 -> MojangDownloadProvider 0 -> MojangDownloadProvider

View File

@ -17,6 +17,7 @@
*/ */
package org.jackhuang.hmcl.setting package org.jackhuang.hmcl.setting
import javafx.scene.text.Font
import org.jackhuang.hmcl.auth.Account import org.jackhuang.hmcl.auth.Account
import org.jackhuang.hmcl.auth.AccountFactory import org.jackhuang.hmcl.auth.AccountFactory
import org.jackhuang.hmcl.auth.OfflineAccount import org.jackhuang.hmcl.auth.OfflineAccount
@ -102,3 +103,7 @@ object Locales {
else -> throw IllegalArgumentException("Unknown argument: " + supportedLocale) else -> throw IllegalArgumentException("Unknown argument: " + supportedLocale)
} }
} }
object Fonts {
val FONTS = Font.getFamilies()
}

View File

@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui
import com.jfoenix.controls.JFXDialog import com.jfoenix.controls.JFXDialog
import javafx.scene.Node import javafx.scene.Node
import javafx.scene.Scene import javafx.scene.Scene
import javafx.scene.image.Image
import javafx.scene.layout.Region import javafx.scene.layout.Region
import javafx.stage.Stage import javafx.stage.Stage
import org.jackhuang.hmcl.Main import org.jackhuang.hmcl.Main
@ -51,6 +52,9 @@ object Controllers {
stage.maxWidth = 800.0 stage.maxWidth = 800.0
stage.maxHeight = 480.0 stage.maxHeight = 480.0
stage.minHeight = 480.0 stage.minHeight = 480.0
stage.icons += Image("/assets/img/icon.png")
stage.title = Main.TITLE
} }
fun dialog(content: Region): JFXDialog { fun dialog(content: Region): JFXDialog {

View File

@ -23,7 +23,10 @@ import javafx.scene.layout.StackPane
import javafx.scene.web.WebEngine import javafx.scene.web.WebEngine
import javafx.scene.web.WebView import javafx.scene.web.WebView
import javafx.stage.Stage import javafx.stage.Stage
import org.jackhuang.hmcl.i18n
import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.util.Log4jLevel import org.jackhuang.hmcl.util.Log4jLevel
import org.jackhuang.hmcl.util.readFullyAsString
import org.w3c.dom.Document import org.w3c.dom.Document
import org.w3c.dom.Node import org.w3c.dom.Node
@ -38,20 +41,25 @@ class LogWindow : Stage() {
init { init {
scene = Scene(rootPane, 800.0, 480.0) scene = Scene(rootPane, 800.0, 480.0)
title = i18n("logwindow.title")
contentPane.onScroll
engine = contentPane.engine engine = contentPane.engine
engine.loadContent("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /></head><body></body></html>") engine.loadContent(javaClass.getResourceAsStream("/assets/log-window-content.html").readFullyAsString().replace("\${FONT}", "${Settings.font.size}px \"${Settings.font.family}\""))
engine.loadWorker.stateProperty().addListener { _, _, newValue -> engine.loadWorker.stateProperty().addListener { _, _, newValue ->
if (newValue == Worker.State.SUCCEEDED) { if (newValue == Worker.State.SUCCEEDED) {
document = engine.document document = engine.document
body = document.getElementsByTagName("body").item(0) body = document.getElementsByTagName("body").item(0)
} }
} }
} }
fun logLine(line: String, level: Log4jLevel) { fun logLine(line: String, level: Log4jLevel) {
body.appendChild(contentPane.engine.document.createElement("div").apply { body.appendChild(contentPane.engine.document.createElement("div").apply {
setAttribute("style", "color: #${level.color.toString().substring(2)};") setAttribute("style", "background-color: #${level.color.toString().substring(2)};")
textContent = line textContent = line
}) })
engine.executeScript("scrollToBottom()")
} }
} }

View File

@ -25,12 +25,15 @@ import javafx.collections.FXCollections
import javafx.fxml.FXML import javafx.fxml.FXML
import javafx.scene.control.Label import javafx.scene.control.Label
import javafx.scene.layout.StackPane import javafx.scene.layout.StackPane
import javafx.scene.text.Font
import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.i18n
import org.jackhuang.hmcl.setting.DownloadProviders import org.jackhuang.hmcl.setting.DownloadProviders
import org.jackhuang.hmcl.setting.Locales import org.jackhuang.hmcl.setting.Locales
import org.jackhuang.hmcl.setting.Proxies import org.jackhuang.hmcl.setting.Proxies
import org.jackhuang.hmcl.setting.Settings import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.ui.construct.FileItem import org.jackhuang.hmcl.ui.construct.FileItem
import org.jackhuang.hmcl.ui.construct.FontComboBox
import org.jackhuang.hmcl.ui.construct.Validator
import org.jackhuang.hmcl.ui.wizard.DecoratorPage import org.jackhuang.hmcl.ui.wizard.DecoratorPage
class SettingsPage : StackPane(), DecoratorPage { class SettingsPage : StackPane(), DecoratorPage {
@ -41,10 +44,13 @@ class SettingsPage : StackPane(), DecoratorPage {
@FXML lateinit var txtProxyUsername: JFXTextField @FXML lateinit var txtProxyUsername: JFXTextField
@FXML lateinit var txtProxyPassword: JFXTextField @FXML lateinit var txtProxyPassword: JFXTextField
@FXML lateinit var cboProxyType: JFXComboBox<*> @FXML lateinit var cboProxyType: JFXComboBox<*>
@FXML lateinit var cboFont: FontComboBox
@FXML lateinit var cboLanguage: JFXComboBox<*> @FXML lateinit var cboLanguage: JFXComboBox<*>
@FXML lateinit var cboDownloadSource: JFXComboBox<*> @FXML lateinit var cboDownloadSource: JFXComboBox<*>
@FXML lateinit var fileCommonLocation: FileItem @FXML lateinit var fileCommonLocation: FileItem
@FXML lateinit var fileBackgroundLocation: FileItem @FXML lateinit var fileBackgroundLocation: FileItem
@FXML lateinit var lblDisplay: Label
@FXML lateinit var txtFontSize: JFXTextField
init { init {
loadFXML("/assets/fxml/setting.fxml") loadFXML("/assets/fxml/setting.fxml")
@ -77,6 +83,23 @@ class SettingsPage : StackPane(), DecoratorPage {
Settings.downloadProvider = DownloadProviders.getDownloadProvider(newValue.toInt()) Settings.downloadProvider = DownloadProviders.getDownloadProvider(newValue.toInt())
} }
cboFont.selectionModel.select(Settings.font.family)
cboFont.valueProperty().addListener { _, _, newValue ->
val font = Font.font(newValue, Settings.font.size)
Settings.font = font
lblDisplay.style = "-fx-font: ${Settings.font.size} \"${font.family}\";"
}
txtFontSize.text = Settings.font.size.toString()
txtFontSize.validators += Validator { it.toDoubleOrNull() != null }
txtFontSize.textProperty().addListener { _, _, newValue ->
if (txtFontSize.validate()) {
val font = Font.font(Settings.font.family, newValue.toDouble())
Settings.font = font
lblDisplay.style = "-fx-font: ${font.size} \"${Settings.font.family}\";"
}
}
lblDisplay.style = "-fx-font: ${Settings.font.size} \"${Settings.font.family}\";"
val list = FXCollections.observableArrayList<Label>() val list = FXCollections.observableArrayList<Label>()
for (locale in Locales.LOCALES) { for (locale in Locales.LOCALES) {
list += Label(locale.getName(Settings.locale.resourceBundle)) list += Label(locale.getName(Settings.locale.resourceBundle))

View File

@ -0,0 +1,45 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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 com.jfoenix.controls.JFXComboBox
import javafx.beans.NamedArg
import javafx.collections.FXCollections
import javafx.scene.control.ListCell
import javafx.scene.text.Font
import javafx.util.Callback
class FontComboBox(@NamedArg("fontSize") fontSize: Double = 12.0, @NamedArg("enableStyle") enableStyle: Boolean = false) : JFXComboBox<String>(FXCollections.observableArrayList(Font.getFamilies())) {
init {
valueProperty().addListener { _, _, newValue ->
if (enableStyle)
style = "-fx-font-family: \"$newValue\";"
}
cellFactory = Callback {
object : ListCell<String>() {
override fun updateItem(item: String?, empty: Boolean) {
super.updateItem(item, empty)
item?.apply {
text = item
font = Font(item, fontSize)
}
}
}
}
}
}

View File

@ -8,6 +8,7 @@
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import org.jackhuang.hmcl.ui.construct.ComponentList?> <?import org.jackhuang.hmcl.ui.construct.ComponentList?>
<?import org.jackhuang.hmcl.ui.construct.FileItem?> <?import org.jackhuang.hmcl.ui.construct.FileItem?>
<?import org.jackhuang.hmcl.ui.construct.FontComboBox?>
<fx:root xmlns="http://javafx.com/javafx" <fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml" xmlns:fx="http://javafx.com/fxml"
type="StackPane"> type="StackPane">
@ -18,7 +19,7 @@
<ComponentList fx:id="settingsPane"> <ComponentList fx:id="settingsPane">
<FileItem fx:id="fileCommonLocation" name="%launcher.common_location" title="%launcher.choose_commonpath" tooltip="%launcher.commpath_tooltip" /> <FileItem fx:id="fileCommonLocation" name="%launcher.common_location" title="%launcher.choose_commonpath" tooltip="%launcher.commpath_tooltip" />
<!--FileItem fx:id="fileBackgroundLocation" name="%launcher.background_location" title="%launcher.choose_bgpath" tooltip="%launcher.background_tooltip" /--> <!--FileItem fx:id="fileBackgroundLocation" name="%launcher.background_location" title="%launcher.choose_bgpath" tooltip="%launcher.background_tooltip" /-->
<BorderPane><left><Label text="%launcher.download_source" /></left><right><JFXComboBox fx:id="cboDownloadSource"> <BorderPane><left><Label text="%launcher.download_source" BorderPane.alignment="CENTER_LEFT" /></left><right><JFXComboBox fx:id="cboDownloadSource">
<items> <items>
<FXCollections fx:factory="observableArrayList"> <FXCollections fx:factory="observableArrayList">
<Label text="%download.mojang" /> <Label text="%download.mojang" />
@ -26,8 +27,8 @@
</FXCollections> </FXCollections>
</items> </items>
</JFXComboBox></right></BorderPane> </JFXComboBox></right></BorderPane>
<BorderPane><left><Label text="%launcher.lang" /></left><right><JFXComboBox fx:id="cboLanguage" /></right></BorderPane> <BorderPane><left><Label text="%launcher.lang" BorderPane.alignment="CENTER_LEFT" /></left><right><JFXComboBox fx:id="cboLanguage" /></right></BorderPane>
<BorderPane><left><Label text="%launcher.proxy" /></left><right><HBox alignment="CENTER_LEFT" spacing="5"> <BorderPane><left><Label text="%launcher.proxy" BorderPane.alignment="CENTER_LEFT" /></left><right><HBox alignment="CENTER_LEFT" spacing="5">
<JFXComboBox fx:id="cboProxyType"> <JFXComboBox fx:id="cboProxyType">
<items> <items>
<FXCollections fx:factory="observableArrayList"> <FXCollections fx:factory="observableArrayList">
@ -47,6 +48,10 @@
<JFXTextField fx:id="txtProxyPassword" maxWidth="50" /> <JFXTextField fx:id="txtProxyPassword" maxWidth="50" />
</HBox></right></BorderPane> </HBox></right></BorderPane>
<BorderPane><left><Label text="%launcher.theme" /></left><right></right></BorderPane> <BorderPane><left><Label text="%launcher.theme" /></left><right></right></BorderPane>
<VBox spacing="5">
<BorderPane><left><Label text="%launcher.log_font" BorderPane.alignment="CENTER_LEFT" /></left><right><HBox spacing="3"><FontComboBox fontSize="12" enableStyle="false" fx:id="cboFont" /><JFXTextField fx:id="txtFontSize" maxWidth="50" minWidth="50" /></HBox></right></BorderPane>
<Label fx:id="lblDisplay" text="[23:33:33] [Client Thread/INFO] [WaterPower]: Loaded mod WaterPower." />
</VBox>
</ComponentList> </ComponentList>
</VBox> </VBox>
</ScrollPane> </ScrollPane>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body {
padding: 0;
margin: 0;
overflow-x: hidden;
}
div {
font: ${FONT};
margin: 0px;
padding: 2px;
border-style: solid;
border-width: 0 0 1px 0;
border-color: #dddddd;
}
</style>
<script>
function scrollToBottom() {
window.scrollTo(0, document.body.scrollHeight)
}
</script>
</head>
<body>
</body>
</html>

View File

@ -60,11 +60,11 @@ internal object DefaultFormatter : Formatter() {
*/ */
enum class Log4jLevel constructor(val level: Int, val color: Color) { enum class Log4jLevel constructor(val level: Int, val color: Color) {
FATAL(1, Color.RED), FATAL(1, Color.web("#F7A699")),
ERROR(2, Color.RED), ERROR(2, Color.web("#FFCCBB")),
WARN(3, Color.ORANGE), WARN(3, Color.web("#FFEECC")),
INFO(4, Color.BLACK), INFO(4, Color.web("#FBFBFB")),
DEBUG(5, Color.BLUE), DEBUG(5, Color.web("#EEE9E0")),
TRACE(6, Color.BLUE), TRACE(6, Color.BLUE),
ALL(2147483647, Color.BLACK); ALL(2147483647, Color.BLACK);