Hamburger and drawer

This commit is contained in:
huangyuhui 2017-08-10 20:48:18 +08:00
parent 301130bc0c
commit 54c4ca4180
11 changed files with 289 additions and 164 deletions

View File

@ -25,7 +25,7 @@ import org.jackhuang.hmcl.util.DEFAULT_USER_AGENT
import org.jackhuang.hmcl.util.OS
import java.io.File
class MainApplication : Application() {
class Main : Application() {
override fun start(stage: Stage) {
PRIMARY_STAGE = stage
@ -46,7 +46,7 @@ class MainApplication : Application() {
fun main(args: Array<String>) {
DEFAULT_USER_AGENT = "Hello Minecraft! Launcher"
launch(MainApplication::class.java, *args)
launch(Main::class.java, *args)
}
fun getWorkingDirectory(folder: String): File {

View File

@ -18,7 +18,7 @@
package org.jackhuang.hmcl.setting
import com.google.gson.annotations.SerializedName
import org.jackhuang.hmcl.MainApplication
import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.util.JavaVersion
import java.io.File
import java.util.TreeMap
@ -37,7 +37,7 @@ class Config {
Settings.save()
}
@SerializedName("commonpath")
var commonpath: File = MainApplication.getMinecraftDirectory()
var commonpath: File = Main.getMinecraftDirectory()
set(value) {
field = value
Settings.save()

View File

@ -20,7 +20,7 @@ package org.jackhuang.hmcl.setting
import com.google.gson.GsonBuilder
import javafx.beans.InvalidationListener
import java.io.IOException
import org.jackhuang.hmcl.MainApplication
import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider
import org.jackhuang.hmcl.download.DownloadProvider
import org.jackhuang.hmcl.download.MojangDownloadProvider
@ -117,7 +117,7 @@ object Settings {
else {
LOG.config("No settings file here, may be first loading.")
if (!c.configurations.containsKey(HOME_PROFILE))
c.configurations[HOME_PROFILE] = Profile(HOME_PROFILE, MainApplication.getMinecraftDirectory())
c.configurations[HOME_PROFILE] = Profile(HOME_PROFILE, Main.getMinecraftDirectory())
}
return c
}

View File

@ -19,7 +19,7 @@ package org.jackhuang.hmcl.setting
import com.google.gson.*
import javafx.beans.InvalidationListener
import org.jackhuang.hmcl.MainApplication
import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.game.LaunchOptions
import org.jackhuang.hmcl.util.*
import org.jackhuang.hmcl.util.property.*
@ -189,8 +189,8 @@ class VersionSetting() {
gameDir = gameDir,
java = if (java == null) JavaVersion.fromCurrentEnvironment()
else JavaVersion.fromExecutable(File(java)),
versionName = MainApplication.TITLE,
profileName = MainApplication.TITLE,
versionName = Main.TITLE,
profileName = Main.TITLE,
minecraftArgs = minecraftArgs,
javaArgs = javaArgs,
maxMemory = maxMemory,

View File

@ -0,0 +1,54 @@
/*
* 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
import javafx.scene.Node
import javafx.scene.control.ScrollPane
import javafx.scene.layout.Pane
import javafx.scene.layout.StackPane
import javafx.scene.layout.VBox
class AdvancedListBox: ScrollPane() {
val container = VBox()
init {
content = container
smoothScrolling()
isFitToHeight = true
isFitToWidth = true
container.spacing = 5.0
container.styleClass += "advanced-list-box-content"
}
fun add(child: Node): AdvancedListBox {
if (child is Pane) {
container.children += child
} else {
val pane = StackPane()
pane.styleClass += "advanced-list-box-item"
pane.children.setAll(child)
container.children += pane
}
return this
}
fun startCategory(category: String): AdvancedListBox = add(ClassTitle(category))
}

View File

@ -32,6 +32,7 @@ object Controllers {
val versionPane = VersionPage()
lateinit var leftPaneController: LeftPaneController
lateinit var sidePaneController: SidePaneController
lateinit var decorator: Decorator
@ -41,6 +42,7 @@ object Controllers {
decorator = Decorator(stage, mainPane, max = false)
decorator.showPage(null)
leftPaneController = LeftPaneController(decorator.leftPane)
sidePaneController = SidePaneController(decorator.sidePane)
decorator.isCustomMaximize = false

View File

@ -18,6 +18,8 @@
package org.jackhuang.hmcl.ui
import com.jfoenix.controls.JFXButton
import com.jfoenix.controls.JFXDrawer
import com.jfoenix.controls.JFXHamburger
import com.jfoenix.effects.JFXDepthManager
import com.jfoenix.svg.SVGGlyph
import javafx.animation.*
@ -33,6 +35,7 @@ import javafx.geometry.Insets
import javafx.scene.Cursor
import javafx.scene.Node
import javafx.scene.control.Label
import javafx.scene.control.ScrollPane
import javafx.scene.control.Tooltip
import javafx.scene.input.MouseEvent
import javafx.scene.layout.*
@ -40,7 +43,7 @@ import javafx.scene.paint.Color
import javafx.stage.Screen
import javafx.stage.Stage
import javafx.stage.StageStyle
import org.jackhuang.hmcl.MainApplication
import org.jackhuang.hmcl.Main
import org.jackhuang.hmcl.ui.animation.AnimationProducer
import org.jackhuang.hmcl.ui.animation.ContainerAnimations
import org.jackhuang.hmcl.ui.animation.TransitionHandler
@ -49,7 +52,7 @@ import org.jackhuang.hmcl.util.*
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
class Decorator @JvmOverloads constructor(private val primaryStage: Stage, private val mainPage: Node, private val max: Boolean = true, min: Boolean = true) : GridPane(), AbstractWizardDisplayer {
class Decorator @JvmOverloads constructor(private val primaryStage: Stage, private val mainPage: Node, private val max: Boolean = true, min: Boolean = true) : StackPane(), AbstractWizardDisplayer {
override val wizardController: WizardController = WizardController(this)
private var xOffset: Double = 0.0
@ -70,9 +73,13 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
@FXML lateinit var refreshMenuButton: JFXButton
@FXML lateinit var addMenuButton: JFXButton
@FXML lateinit var titleLabel: Label
@FXML lateinit var leftPane: VBox
@FXML lateinit var leftPane: AdvancedListBox
@FXML lateinit var drawer: JFXDrawer
@FXML lateinit var sidePane: AdvancedListBox
@FXML lateinit var titleBurgerContainer: StackPane
@FXML lateinit var titleBurger: JFXHamburger
private val onCloseButtonActionProperty: ObjectProperty<Runnable> = SimpleObjectProperty(Runnable { MainApplication.stop() })
private val onCloseButtonActionProperty: ObjectProperty<Runnable> = SimpleObjectProperty(Runnable { Main.stop() })
@JvmName("onCloseButtonActionProperty") get
var onCloseButtonAction: Runnable by onCloseButtonActionProperty
@ -123,6 +130,26 @@ class Decorator @JvmOverloads constructor(private val primaryStage: Stage, priva
animationHandler = TransitionHandler(contentPlaceHolder)
setOverflowHidden(lookup("#contentPlaceHolderRoot") as Pane)
setOverflowHidden(lookup("#drawerWrapper") as Pane)
// init the title hamburger icon
drawer.setOnDrawerOpening {
val animation = titleBurger.getAnimation()
animation.setRate(1.0)
animation.play()
}
drawer.setOnDrawerClosing {
val animation = titleBurger.getAnimation()
animation.setRate(-1.0)
animation.play()
}
titleBurgerContainer.setOnMouseClicked({
if (drawer.isHidden || drawer.isHiding) {
drawer.open()
} else {
drawer.close()
}
})
}
fun onMouseMoved(mouseEvent: MouseEvent) {

View File

@ -18,9 +18,7 @@
package org.jackhuang.hmcl.ui
import com.jfoenix.controls.JFXComboBox
import javafx.beans.property.StringProperty
import javafx.beans.value.ChangeListener
import javafx.scene.Node
import javafx.scene.layout.*
import javafx.scene.paint.Paint
import org.jackhuang.hmcl.ProfileChangedEvent
@ -33,24 +31,23 @@ import org.jackhuang.hmcl.game.minecraftVersion
import org.jackhuang.hmcl.setting.Settings
import org.jackhuang.hmcl.ui.download.DownloadWizardProvider
class LeftPaneController(val leftPane: VBox) {
class LeftPaneController(leftPane: AdvancedListBox) {
val versionsPane = VBox()
val cboProfiles = JFXComboBox<String>().apply { items.add("Default"); prefWidthProperty().bind(leftPane.widthProperty()) }
val accountItem = VersionListItem("mojang@mojang.com", "Yggdrasil")
init {
addChildren(ClassTitle("ACCOUNTS"))
addChildren(RipplerContainer(accountItem).apply {
accountItem.onSettingsButtonClicked {
Controllers.navigate(AccountsPage())
}
})
addChildren(ClassTitle("LAUNCHER"))
addChildren(IconedItem(SVG.gear("black"), "Settings").apply { prefWidthProperty().bind(leftPane.widthProperty()) })
addChildren(ClassTitle("PROFILES"))
addChildren(cboProfiles)
addChildren(ClassTitle("VERSIONS"))
addChildren(versionsPane)
leftPane
.startCategory("ACCOUNTS")
.add(RipplerContainer(accountItem).apply {
accountItem.onSettingsButtonClicked {
Controllers.navigate(AccountsPage())
}
})
.startCategory("PROFILES")
.add(cboProfiles)
.startCategory("VERSIONS")
.add(versionsPane)
EVENT_BUS.channel<RefreshedVersionsEvent>() += this::loadVersions
EVENT_BUS.channel<ProfileLoadingEvent>() += this::onProfilesLoading
@ -82,17 +79,6 @@ class LeftPaneController(val leftPane: VBox) {
Controllers.navigate(AccountsPage())
}
private fun addChildren(content: Node) {
if (content is Pane) {
leftPane.children += content
} else {
val pane = StackPane()
pane.styleClass += "left-pane-item"
pane.children.setAll(content)
leftPane.children += pane
}
}
fun onProfilesLoading() {
// TODO: Profiles
}

View File

@ -0,0 +1,26 @@
/*
* 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
class SidePaneController(sidePane: AdvancedListBox) {
init {
sidePane
.startCategory("LAUNCHER")
.add(IconedItem(SVG.gear("black"), "Settings").apply { prefWidthProperty().bind(sidePane.widthProperty()) })
}
}

View File

@ -25,22 +25,22 @@
-fx-text-fill: rgba(0.0, 0.0, 0.0, 0.87);
}
.class-title {
-fx-font-size: 12px;
-fx-padding: 0 16 0 16;
}
.rippler-container HBox {
-fx-font-size: 14px;
-fx-padding: 10 16 10 16;
-fx-spacing: 10;
}
.left-pane-item {
.class-title {
-fx-font-size: 12px;
-fx-padding: 0 16 0 16;
}
.advanced-list-box-item {
-fx-padding: 10 16 10 16;
}
.jfx-decorator-left-pane {
.advanced-list-box-content {
-fx-padding: 20 0 20 0;
}

View File

@ -1,130 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.*?>
<?import com.jfoenix.transitions.hamburger.HamburgerBackArrowBasicTransition?>
<?import javafx.geometry.Insets?>
<?import java.lang.String?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.Rectangle?>
<?import java.lang.String?>
<?import org.jackhuang.hmcl.ui.AdvancedListBox?>
<fx:root xmlns="http://javafx.com/javafx"
type="GridPane"
xmlns:fx="http://javafx.com/fxml"
pickOnBounds="false"
onMouseReleased="#onMouseReleased"
onMouseDragged="#onMouseDragged"
onMouseMoved="#onMouseMoved">
type="StackPane"
xmlns:fx="http://javafx.com/fxml">
<styleClass>
<String fx:value="jfx-decorator" />
<String fx:value="resize-border" />
<String fx:value="jfx-decorator"/>
<String fx:value="resize-border"/>
</styleClass>
<columnConstraints>
<ColumnConstraints minWidth="200" maxWidth="200" />
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints vgrow="ALWAYS" />
</rowConstraints>
<StackPane GridPane.rowIndex="1" GridPane.columnIndex="0" VBox.vgrow="ALWAYS" styleClass="jfx-decorator-content-container">
<BorderPane fx:id="leftRootPane">
<center>
<BorderPane fx:id="drawerWrapper">
<center>
<JFXDrawer fx:id="drawer" defaultDrawerSize="200" direction="LEFT">
<styleClass>
<String fx:value="body"/>
</styleClass>
<sidePane>
<AdvancedListBox fx:id="sidePane" />
</sidePane>
<BorderPane>
<center>
<ScrollPane fitToHeight="true" fitToWidth="true">
<VBox fx:id="leftPane" styleClass="jfx-decorator-left-pane" spacing="5">
</VBox>
</ScrollPane>
</center>
<bottom>
<BorderPane fx:id="menuBottomBar">
<left>
<JFXButton fx:id="refreshMenuButton" styleClass="toggle-icon4">
<graphic>
<fx:include source="/assets/svg/refresh-black.fxml"/>
</graphic></JFXButton>
</left>
<right>
<JFXButton fx:id="addMenuButton" styleClass="toggle-icon4">
<graphic>
<fx:include source="/assets/svg/plus-black.fxml"/>
</graphic></JFXButton>
</right>
</BorderPane>
</bottom>
</BorderPane>
</center>
<right>
<Rectangle height="${leftRootPane.height}" width="1" fill="gray" />
</right>
</BorderPane>
</StackPane>
<StackPane fx:id="contentPlaceHolderRoot" GridPane.rowIndex="1" GridPane.columnIndex="1" styleClass="jfx-decorator-content-container" VBox.vgrow="ALWAYS">
<StackPane fx:id="contentPlaceHolder" styleClass="jfx-decorator-content-container">
<styleClass>
<String fx:value="jfx-decorator-content-container" />
</styleClass>
<!-- Node -->
</StackPane>
</StackPane>
<BorderPane GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="titleContainer" minHeight="30" styleClass="jfx-tool-bar" pickOnBounds="false">
<left>
<BorderPane minWidth="200" maxWidth="200" fx:id="titleWrapper">
<center>
<Label text="Hello Minecraft! Launcher" BorderPane.alignment="CENTER" mouseTransparent="true" style="-fx-background-color: transparent; -fx-text-fill: white; -fx-font-size: 15px;" />
</center>
<right>
<Rectangle height="${navBar.height}" width="1" fill="gray" />
</right>
</BorderPane>
</left>
<center>
<BorderPane fx:id="navBar">
<left>
<HBox fx:id="navLeft" alignment="CENTER_LEFT" style="-fx-padding: 0;">
<JFXButton fx:id="backNavButton" onMouseClicked="#onBack" maxHeight="20" styleClass="toggle-icon3">
<graphic>
<fx:include source="/assets/svg/arrow-left.fxml"/>
</graphic>
</JFXButton>
<Label fx:id="titleLabel" style="-fx-text-fill:WHITE; -fx-font-size: 15;"/>
</HBox>
<StackPane minWidth="200" maxWidth="200" styleClass="jfx-decorator-content-container">
<BorderPane fx:id="leftRootPane">
<center>
<BorderPane>
<center>
<AdvancedListBox fx:id="leftPane" />
</center>
<bottom>
<BorderPane fx:id="menuBottomBar">
<left>
<JFXButton fx:id="refreshMenuButton" styleClass="toggle-icon4">
<graphic>
<fx:include source="/assets/svg/refresh-black.fxml"/>
</graphic>
</JFXButton>
</left>
<right>
<JFXButton fx:id="addMenuButton" styleClass="toggle-icon4">
<graphic>
<fx:include source="/assets/svg/plus-black.fxml"/>
</graphic>
</JFXButton>
</right>
</BorderPane>
</bottom>
</BorderPane>
</center>
<right>
<Rectangle height="${leftRootPane.height}" width="1" fill="gray"/>
</right>
</BorderPane>
</StackPane>
</left>
<right>
<HBox fx:id="navRight" alignment="CENTER_LEFT">
<JFXButton fx:id="refreshNavButton" onMouseClicked="#onRefresh" maxHeight="20" styleClass="toggle-icon3" disable="true">
<graphic>
<fx:include source="/assets/svg/refresh.fxml"/>
</graphic>
<StackPane.margin>
<Insets left="20"/>
</StackPane.margin>
</JFXButton>
<JFXButton fx:id="closeNavButton" onMouseClicked="#onCloseNav" maxHeight="20" styleClass="toggle-icon3">
<graphic>
<fx:include source="/assets/svg/close.fxml"/>
</graphic>
<StackPane.margin>
<Insets left="20"/>
</StackPane.margin>
</JFXButton>
<Rectangle height="${navBar.height}" width="1" fill="gray" />
</HBox>
</right>
<center>
<StackPane fx:id="contentPlaceHolderRoot" styleClass="jfx-decorator-content-container" VBox.vgrow="ALWAYS">
<StackPane fx:id="contentPlaceHolder" styleClass="jfx-decorator-content-container">
<styleClass>
<String fx:value="jfx-decorator-content-container"/>
</styleClass>
<!-- Node -->
</StackPane>
</StackPane>
</center>
</BorderPane>
</center>
<right>
<HBox fx:id="buttonsContainer" style="-fx-background-color: transparent;" alignment="CENTER_RIGHT">
<padding>
<Insets topRightBottomLeft="4.0" />
</padding>
<JFXButton fx:id="btnMin" styleClass="jfx-decorator-button" ripplerFill="white" onAction="#onMin">
</JFXButton>
<JFXButton fx:id="btnMax" styleClass="jfx-decorator-button" ripplerFill="white" onAction="#onMax">
</JFXButton>
<JFXButton fx:id="btnClose" styleClass="jfx-decorator-button" ripplerFill="white" onAction="#onClose">
</JFXButton>
</HBox>
</right>
</BorderPane>
</JFXDrawer>
</center>
<top>
<BorderPane fx:id="titleContainer" minHeight="30" styleClass="jfx-tool-bar"
pickOnBounds="false"
onMouseReleased="#onMouseReleased"
onMouseDragged="#onMouseDragged"
onMouseMoved="#onMouseMoved">
<left>
<BorderPane minWidth="200" maxWidth="200" fx:id="titleWrapper">
<center>
<HBox>
<JFXRippler maskType="CIRCLE" style="-fx-ripple-color:WHITE;">
<StackPane fx:id="titleBurgerContainer">
<JFXHamburger fx:id="titleBurger">
<HamburgerBackArrowBasicTransition/>
</JFXHamburger>
</StackPane>
</JFXRippler>
<Label text="Hello Minecraft! Launcher" BorderPane.alignment="CENTER"
mouseTransparent="true"
style="-fx-background-color: transparent; -fx-text-fill: white; -fx-font-size: 15px;"/>
</HBox>
</center>
<right>
<Rectangle height="${navBar.height}" width="1" fill="gray"/>
</right>
</BorderPane>
</left>
<center>
<BorderPane fx:id="navBar">
<left>
<HBox fx:id="navLeft" alignment="CENTER_LEFT" style="-fx-padding: 0;">
<JFXButton fx:id="backNavButton" onMouseClicked="#onBack" maxHeight="20"
styleClass="toggle-icon3">
<graphic>
<fx:include source="/assets/svg/arrow-left.fxml"/>
</graphic>
</JFXButton>
<Label fx:id="titleLabel" style="-fx-text-fill:WHITE; -fx-font-size: 15;"/>
</HBox>
</left>
<right>
<HBox fx:id="navRight" alignment="CENTER_LEFT">
<JFXButton fx:id="refreshNavButton" onMouseClicked="#onRefresh" maxHeight="20"
styleClass="toggle-icon3" disable="true">
<graphic>
<fx:include source="/assets/svg/refresh.fxml"/>
</graphic>
<StackPane.margin>
<Insets left="20"/>
</StackPane.margin>
</JFXButton>
<JFXButton fx:id="closeNavButton" onMouseClicked="#onCloseNav" maxHeight="20"
styleClass="toggle-icon3">
<graphic>
<fx:include source="/assets/svg/close.fxml"/>
</graphic>
<StackPane.margin>
<Insets left="20"/>
</StackPane.margin>
</JFXButton>
<Rectangle height="${navBar.height}" width="1" fill="gray"/>
</HBox>
</right>
</BorderPane>
</center>
<right>
<HBox fx:id="buttonsContainer" style="-fx-background-color: transparent;" alignment="CENTER_RIGHT">
<padding>
<Insets topRightBottomLeft="4.0"/>
</padding>
<JFXButton fx:id="btnMin" styleClass="jfx-decorator-button" ripplerFill="white"
onAction="#onMin">
</JFXButton>
<JFXButton fx:id="btnMax" styleClass="jfx-decorator-button" ripplerFill="white"
onAction="#onMax">
</JFXButton>
<JFXButton fx:id="btnClose" styleClass="jfx-decorator-button" ripplerFill="white"
onAction="#onClose">
</JFXButton>
</HBox>
</right>
</BorderPane>
</top>
</BorderPane>
</fx:root>