alt: change UI of game installation wizard. Also UI performance improved.

This commit is contained in:
huanghongxun
2020-02-21 00:10:16 +08:00
parent 5707e1d57e
commit 6ad5ba3736
16 changed files with 258 additions and 237 deletions

View File

@@ -0,0 +1,49 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.effects.JFXDepthManager;
import javafx.geometry.Insets;
import javafx.scene.control.ListCell;
import javafx.scene.layout.StackPane;
public abstract class FloatListCell<T> extends ListCell<T> {
protected final StackPane pane = new StackPane();
{
setText(null);
setGraphic(null);
pane.setStyle("-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND");
setPadding(new Insets(5));
JFXDepthManager.setDepth(pane, 1);
}
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
updateControl(item);
setGraphic(pane);
}
}
protected abstract void updateControl(T dataItem);
}

View File

@@ -52,7 +52,7 @@ public class DecoratorWizardDisplayer extends StackPane implements TaskExecutorD
wizardController.setProvider(provider);
wizardController.onStart();
getStyleClass().add("white-background");
// getStyleClass().add("white-background");
}
@Override

View File

@@ -37,60 +37,20 @@ import java.util.Optional;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
class AdditionalInstallersPage extends StackPane implements WizardPage {
private final InstallerWizardProvider provider;
private final WizardController controller;
@FXML
private VBox list;
@FXML
private JFXButton btnFabric;
@FXML
private JFXButton btnForge;
@FXML
private JFXButton btnLiteLoader;
@FXML
private JFXButton btnOptiFine;
@FXML
private Label lblGameVersion;
@FXML
private Label lblVersionName;
@FXML
private Label lblFabric;
@FXML
private Label lblForge;
@FXML
private Label lblLiteLoader;
@FXML
private Label lblOptiFine;
@FXML
private JFXButton btnInstall;
class AdditionalInstallersPage extends InstallersPage {
protected final InstallerWizardProvider provider;
public AdditionalInstallersPage(InstallerWizardProvider provider, WizardController controller, GameRepository repository, DownloadProvider downloadProvider) {
super(controller, repository, provider.getGameVersion(), downloadProvider);
this.provider = provider;
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/download/additional-installers.fxml");
lblGameVersion.setText(provider.getGameVersion());
lblVersionName.setText(provider.getVersion().getId());
JFXButton[] buttons = new JFXButton[]{btnFabric, btnForge, btnLiteLoader, btnOptiFine};
String[] libraryIds = new String[]{"fabric", "forge", "liteloader", "optifine"};
for (int i = 0; i < libraryIds.length; ++i) {
String libraryId = libraryIds[i];
buttons[i].setOnMouseClicked(e -> {
controller.onNext(new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), provider.getGameVersion(), downloadProvider, libraryId, () -> {
controller.onPrev(false);
}));
});
}
btnInstall.setOnMouseClicked(e -> onInstall());
txtName.getValidators().clear();
txtName.setText(provider.getVersion().getId());
txtName.setEditable(false);
}
private void onInstall() {
@Override
protected void onInstall() {
controller.onFinish();
}
@@ -105,17 +65,16 @@ class AdditionalInstallersPage extends StackPane implements WizardPage {
@Override
public void onNavigate(Map<String, Object> settings) {
lblGameVersion.setText(i18n("install.new_game.current_game_version") + ": " + provider.getGameVersion());
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(provider.getVersion().resolvePreservingPatches(provider.getProfile().getRepository()));
String game = analyzer.getVersion(MINECRAFT).orElse(null);
String fabric = analyzer.getVersion(FABRIC).orElse(null);
String forge = analyzer.getVersion(FORGE).orElse(null);
String liteLoader = analyzer.getVersion(LITELOADER).orElse(null);
String optiFine = analyzer.getVersion(OPTIFINE).orElse(null);
Label[] labels = new Label[]{lblFabric, lblForge, lblLiteLoader, lblOptiFine};
String[] libraryIds = new String[]{"fabric", "forge", "liteloader", "optifine"};
String[] versions = new String[]{fabric, forge, liteLoader, optiFine};
Label[] labels = new Label[]{lblGame, lblFabric, lblForge, lblLiteLoader, lblOptiFine};
String[] libraryIds = new String[]{"game", "fabric", "forge", "liteloader", "optifine"};
String[] versions = new String[]{game, fabric, forge, liteLoader, optiFine};
for (int i = 0; i < libraryIds.length; ++i) {
String libraryId = libraryIds[i];

View File

@@ -19,8 +19,12 @@ package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.effects.JFXDepthManager;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.download.DownloadProvider;
@@ -40,50 +44,52 @@ import java.util.Map;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class InstallersPage extends StackPane implements WizardPage {
private final WizardController controller;
protected final WizardController controller;
@FXML
private VBox list;
protected VBox list;
@FXML
private JFXButton btnFabric;
protected Node btnGame;
@FXML
private JFXButton btnForge;
protected Node btnFabric;
@FXML
private JFXButton btnLiteLoader;
protected Node btnForge;
@FXML
private JFXButton btnOptiFine;
protected Node btnLiteLoader;
@FXML
private Label lblGameVersion;
protected Node btnOptiFine;
@FXML
private Label lblFabric;
protected Label lblGame;
@FXML
private Label lblForge;
protected Label lblFabric;
@FXML
private Label lblLiteLoader;
protected Label lblForge;
@FXML
private Label lblOptiFine;
protected Label lblLiteLoader;
@FXML
private JFXTextField txtName;
protected Label lblOptiFine;
@FXML
private JFXButton btnInstall;
protected JFXTextField txtName;
public InstallersPage(WizardController controller, GameRepository repository, DownloadProvider downloadProvider) {
@FXML
protected JFXButton btnInstall;
public InstallersPage(WizardController controller, GameRepository repository, String gameVersion, DownloadProvider downloadProvider) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/download/installers.fxml");
String gameVersion = ((RemoteVersion) controller.getSettings().get("game")).getGameVersion();
Validator hasVersion = new Validator(s -> !repository.hasVersion(s) && StringUtils.isNotBlank(s));
hasVersion.setMessage(i18n("install.new_game.already_exists"));
Validator nameValidator = new Validator(OperatingSystem::isNameValid);
@@ -92,11 +98,18 @@ public class InstallersPage extends StackPane implements WizardPage {
txtName.textProperty().addListener(e -> btnInstall.setDisable(!txtName.validate()));
txtName.setText(gameVersion);
JFXButton[] buttons = new JFXButton[]{btnFabric, btnForge, btnLiteLoader, btnOptiFine};
String[] libraryIds = new String[]{"fabric", "forge", "liteloader", "optifine"};
Label[] labels = new Label[]{lblGame, lblFabric, lblForge, lblLiteLoader, lblOptiFine};
Node[] buttons = new Node[]{btnGame, btnFabric, btnForge, btnLiteLoader, btnOptiFine};
String[] libraryIds = new String[]{"game", "fabric", "forge", "liteloader", "optifine"};
for (Node node : list.getChildren()) {
JFXDepthManager.setDepth(node, 1);
}
for (int i = 0; i < libraryIds.length; ++i) {
String libraryId = libraryIds[i];
BorderPane.setMargin(labels[i], new Insets(0, 0, 0, 8));
if (libraryId.equals("game")) continue;
buttons[i].setOnMouseClicked(e ->
controller.onNext(new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, downloadProvider, libraryId, () -> controller.onPrev(false))));
}
@@ -113,10 +126,8 @@ public class InstallersPage extends StackPane implements WizardPage {
@Override
public void onNavigate(Map<String, Object> settings) {
lblGameVersion.setText(i18n("install.new_game.current_game_version") + ": " + getVersion("game"));
Label[] labels = new Label[]{lblFabric, lblForge, lblLiteLoader, lblOptiFine};
String[] libraryIds = new String[]{"fabric", "forge", "liteloader", "optifine"};
Label[] labels = new Label[]{lblGame, lblFabric, lblForge, lblLiteLoader, lblOptiFine};
String[] libraryIds = new String[]{"game", "fabric", "forge", "liteloader", "optifine"};
for (int i = 0; i < libraryIds.length; ++i) {
String libraryId = libraryIds[i];
@@ -132,7 +143,7 @@ public class InstallersPage extends StackPane implements WizardPage {
}
@FXML
private void onInstall() {
protected void onInstall() {
controller.getSettings().put("name", txtName.getText());
controller.onFinish();
}

View File

@@ -72,7 +72,7 @@ public final class VanillaInstallWizardProvider implements WizardProvider {
DownloadProvider provider = profile.getDependency().getPrimaryDownloadProvider();
switch (step) {
case 0:
return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer.game")), "", provider, "game", () -> controller.onNext(new InstallersPage(controller, profile.getRepository(), provider)));
return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer.game")), "", provider, "game", () -> controller.onNext(new InstallersPage(controller, profile.getRepository(), ((RemoteVersion) controller.getSettings().get("game")).getGameVersion(), provider)));
default:
throw new IllegalStateException("error step " + step + ", settings: " + settings + ", pages: " + controller.getPages());
}

View File

@@ -23,16 +23,28 @@ import com.jfoenix.controls.JFXSpinner;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.download.fabric.FabricRemoteVersion;
import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion;
import org.jackhuang.hmcl.download.game.GameRemoteVersion;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion;
import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion;
import org.jackhuang.hmcl.task.TaskExecutor;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionHandler;
import org.jackhuang.hmcl.ui.construct.FloatListCell;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.ui.wizard.Refreshable;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
@@ -43,6 +55,7 @@ import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class VersionsPage extends BorderPane implements WizardPage, Refreshable {
private final String gameVersion;
@@ -51,7 +64,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
private final WizardController controller;
@FXML
private JFXListView<VersionsPageItem> list;
private JFXListView<RemoteVersion> list;
@FXML
private JFXSpinner spinner;
@FXML
@@ -96,16 +109,65 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
chkSnapshot.selectedProperty().addListener(listener);
chkOld.selectedProperty().addListener(listener);
list.setCellFactory(listView -> new FloatListCell<RemoteVersion>() {
ImageView imageView = new ImageView();
TwoLineListItem content = new TwoLineListItem();
{
HBox container = new HBox(12);
container.setPadding(new Insets(0, 0, 0, 6));
container.setAlignment(Pos.CENTER_LEFT);
pane.getChildren().add(container);
container.getChildren().setAll(imageView, content);
}
@Override
protected void updateControl(RemoteVersion remoteVersion) {
content.setTitle(remoteVersion.getSelfVersion());
content.setSubtitle(remoteVersion.getGameVersion());
if (remoteVersion instanceof GameRemoteVersion) {
switch (remoteVersion.getVersionType()) {
case RELEASE:
content.setSubtitle(i18n("version.game.release"));
imageView.setImage(new Image("/assets/img/grass.png", 32, 32, false, true));
break;
case SNAPSHOT:
content.setSubtitle(i18n("version.game.snapshot"));
imageView.setImage(new Image("/assets/img/command.png", 32, 32, false, true));
break;
default:
content.setSubtitle(i18n("version.game.old"));
imageView.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true));
break;
}
} else if (remoteVersion instanceof LiteLoaderRemoteVersion) {
imageView.setImage(new Image("/assets/img/chicken.png", 32, 32, false, true));
content.setSubtitle(remoteVersion.getGameVersion());
} else if (remoteVersion instanceof OptiFineRemoteVersion) {
imageView.setImage(new Image("/assets/img/command.png", 32, 32, false, true));
content.setSubtitle(remoteVersion.getGameVersion());
} else if (remoteVersion instanceof ForgeRemoteVersion) {
imageView.setImage(new Image("/assets/img/forge.png", 32, 32, false, true));
content.setSubtitle(remoteVersion.getGameVersion());
} else if (remoteVersion instanceof FabricRemoteVersion) {
imageView.setImage(new Image("/assets/img/fabric.png", 32, 32, false, true));
content.setSubtitle(remoteVersion.getGameVersion());
}
}
});
list.setOnMouseClicked(e -> {
if (list.getSelectionModel().getSelectedIndex() < 0)
return;
controller.getSettings().put(libraryId, list.getSelectionModel().getSelectedItem().getRemoteVersion());
controller.getSettings().put(libraryId, list.getSelectionModel().getSelectedItem());
callback.run();
});
refresh();
}
private List<VersionsPageItem> loadVersions() {
private List<RemoteVersion> loadVersions() {
return versionList.getVersions(gameVersion).stream()
.filter(it -> {
switch (it.getVersionType()) {
@@ -119,8 +181,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
return true;
}
})
.sorted()
.map(VersionsPageItem::new).collect(Collectors.toList());
.sorted().collect(Collectors.toList());
}
@Override
@@ -128,7 +189,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
transitionHandler.setContent(spinner, ContainerAnimations.FADE.getAnimationProducer());
executor = versionList.refreshAsync(gameVersion).whenComplete(exception -> {
if (exception == null) {
List<VersionsPageItem> items = loadVersions();
List<RemoteVersion> items = loadVersions();
Platform.runLater(() -> {
if (versionList.getVersions(gameVersion).isEmpty()) {

View File

@@ -1,91 +0,0 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.download;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion;
import org.jackhuang.hmcl.download.game.GameRemoteVersion;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion;
import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion;
import org.jackhuang.hmcl.ui.FXUtils;
import java.util.Objects;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
/**
* @author huangyuhui
*/
public final class VersionsPageItem extends StackPane {
private final RemoteVersion remoteVersion;
@FXML
private Label lblSelfVersion;
@FXML
private Label lblGameVersion;
@FXML
private ImageView imageView;
@FXML
private HBox leftPane;
@FXML
private StackPane imageViewContainer;
public VersionsPageItem(RemoteVersion remoteVersion) {
this.remoteVersion = Objects.requireNonNull(remoteVersion);
FXUtils.loadFXML(this, "/assets/fxml/download/versions-list-item.fxml");
lblSelfVersion.setText(remoteVersion.getSelfVersion());
if (remoteVersion instanceof GameRemoteVersion) {
switch (remoteVersion.getVersionType()) {
case RELEASE:
lblGameVersion.setText(i18n("version.game.release"));
imageView.setImage(new Image("/assets/img/icon.png", 32, 32, false, true));
break;
case SNAPSHOT:
lblGameVersion.setText(i18n("version.game.snapshot"));
imageView.setImage(new Image("/assets/img/command.png", 32, 32, false, true));
break;
default:
lblGameVersion.setText(i18n("version.game.old"));
imageView.setImage(new Image("/assets/img/grass.png", 32, 32, false, true));
break;
}
} else if (remoteVersion instanceof LiteLoaderRemoteVersion) {
imageView.setImage(new Image("/assets/img/chicken.png", 32, 32, false, true));
lblGameVersion.setText(remoteVersion.getGameVersion());
} else if (remoteVersion instanceof OptiFineRemoteVersion) {
// optifine has no icon.
lblGameVersion.setText(remoteVersion.getGameVersion());
} else if (remoteVersion instanceof ForgeRemoteVersion) {
imageView.setImage(new Image("/assets/img/forge.png", 32, 32, false, true));
lblGameVersion.setText(remoteVersion.getGameVersion());
}
leftPane.getChildren().remove(imageViewContainer);
}
public RemoteVersion getRemoteVersion() {
return remoteVersion;
}
}

View File

@@ -53,7 +53,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
super(skinnable);
StackPane pane = new StackPane();
pane.getStyleClass().addAll("notice-pane", "white-background");
pane.getStyleClass().addAll("notice-pane");
BorderPane root = new BorderPane();
JFXTreeTableView<ModInfoObject> tableView = new JFXTreeTableView<>();

View File

@@ -137,7 +137,6 @@
.sponsor-pane {
-fx-padding: 16;
-fx-background-color: white;
-fx-cursor: hand;
}
@@ -522,6 +521,12 @@
-fx-cursor: hand;
}
.jfx-button .jfx-rippler {
-jfx-rippler-fill: -fx-base-check-color;
-jfx-mask-type: CIRCLE;
-fx-padding: 0.0;
}
.jfx-button-raised {
-fx-background-color: -fx-base-color;
}
@@ -614,7 +619,8 @@
*******************************************************************************/
.jfx-list-cell, .list-cell {
-fx-background-color: WHITE;
/*-fx-background-color: WHITE;*/
-fx-background-color: transparent;
}
.list-cell:selected, .jfx-list-cell:selected,
@@ -637,6 +643,17 @@
-jfx-cell-vertical-margin: 5.0;
-jfx-vertical-gap: 10.0;
-jfx-expanded: false;
-fx-background-color: transparent;
}
.jfx-list-view-float {
-fx-padding: 5;
-fx-background-insets: 0.0;
-jfx-cell-horizontal-margin: 0.0;
-jfx-cell-vertical-margin: 5.0;
-jfx-vertical-gap: 10.0;
-jfx-expanded: false;
-fx-background-color: transparent;
}
.options-list {

View File

@@ -3,70 +3,85 @@
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import com.jfoenix.effects.JFXDepthManager?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane" style="-fx-padding: 16;">
<BorderPane>
<top>
<VBox alignment="CENTER" style="-fx-padding: 40px;" spacing="20">
<Label fx:id="lblGameVersion" alignment="CENTER"/>
<JFXTextField fx:id="txtName" labelFloat="true" promptText="%modpack.enter_name" maxWidth="300"/>
</VBox>
</top>
<center>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<JFXButton fx:id="btnFabric" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblFabric"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnForge" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblForge"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnLiteLoader" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblLiteLoader"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnOptiFine" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblOptiFine"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<VBox fx:id="list" spacing="8">
<HBox spacing="8" alignment="CENTER_LEFT" style="-fx-background-color: white; -fx-padding: 20 8 20 16">
<Label text="%archive.name" />
<JFXTextField fx:id="txtName" maxWidth="300"/>
</HBox>
<BorderPane fx:id="btnGame" style="-fx-background-color: white; -fx-padding: 8">
<left>
<ImageView>
<Image url="/assets/img/grass.png" requestedHeight="32" requestedWidth="32" smooth="true" />
</ImageView>
</left>
<center>
<Label fx:id="lblGame" BorderPane.alignment="CENTER_LEFT" />
</center>
</BorderPane>
<BorderPane fx:id="btnFabric" style="-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND">
<left>
<ImageView>
<Image url="/assets/img/fabric.png" requestedHeight="32" requestedWidth="32" smooth="true" />
</ImageView>
</left>
<center>
<Label fx:id="lblFabric" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<fx:include BorderPane.alignment="CENTER_RIGHT" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
<BorderPane fx:id="btnForge" style="-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND">
<left>
<ImageView>
<Image url="/assets/img/forge.png" requestedHeight="32" requestedWidth="32" smooth="true" />
</ImageView>
</left>
<center>
<Label fx:id="lblForge" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<fx:include BorderPane.alignment="CENTER_RIGHT" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
<BorderPane fx:id="btnLiteLoader" style="-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND">
<left>
<ImageView>
<Image url="/assets/img/chicken.png" requestedHeight="32" requestedWidth="32" smooth="true" />
</ImageView>
</left>
<center>
<Label fx:id="lblLiteLoader" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<fx:include BorderPane.alignment="CENTER_RIGHT" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
<BorderPane fx:id="btnOptiFine" style="-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND">
<left>
<ImageView>
<Image url="/assets/img/command.png" requestedHeight="32" requestedWidth="32" smooth="true" />
</ImageView>
</left>
<center>
<Label fx:id="lblOptiFine" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<fx:include BorderPane.alignment="CENTER_RIGHT" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</VBox>
</center>
<bottom>
<HBox alignment="CENTER">
<HBox alignment="CENTER_RIGHT">
<JFXButton fx:id="btnInstall" onMouseClicked="#onInstall" prefWidth="100" prefHeight="40"
buttonType="RAISED" text="%button.install" styleClass="jfx-button-raised"/>
</HBox>

View File

@@ -21,7 +21,7 @@
<JFXCheckBox fx:id="chkSnapshot" text="%version.game.snapshot" />
<JFXCheckBox fx:id="chkOld" text="%version.game.old" />
</HBox>
<JFXListView fx:id="list" styleClass="jfx-list-view" VBox.vgrow="ALWAYS">
<JFXListView fx:id="list" styleClass="jfx-list-view-float" VBox.vgrow="ALWAYS">
</JFXListView>
</VBox>
<StackPane fx:id="failedPane" styleClass="notice-pane">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -100,7 +100,7 @@ download.failed.empty=No candidates. Click here to return.
download.failed.refresh=Unable to download version list. Click here to retry.
download.provider.mcbbs=MCBBS (https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Mojang (Forge and OptiFine installation are downloaded from BMCLAPI)
download.provider.mojang=Mojang (OptiFine download service is provided by BMCLAPI)
extension.bat=Windows Bat file
extension.mod=Mod file

View File

@@ -99,7 +99,7 @@ download.failed.empty=沒有能安裝的版本,按一下此處返回。
download.failed.refresh=載入版本列表失敗,按一下此處重試。
download.provider.mcbbs=我的世界中文論壇 (MCBBS, https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPI (bangbang93https://bmclapi2.bangbang93.com/)
download.provider.mojang=官方伺服器 (Forge 和 OptiFine 自動安裝的下載來源是 BMCLAPI)
download.provider.mojang=官方伺服器 (OptiFine 自動安裝的下載來源是 BMCLAPI)
extension.bat=Windows 指令碼
extension.mod=模組檔案

View File

@@ -99,7 +99,7 @@ download.failed.empty=没有可供安装的版本,点击此处返回。
download.failed.refresh=加载版本列表失败,点击此处重试。
download.provider.mcbbs=我的世界中文论坛 (MCBBS, https://www.mcbbs.net/)
download.provider.bmclapi=BMCLAPIbangbang93https://bmclapi2.bangbang93.com/
download.provider.mojang=官方(Forge 和 OptiFine 自动安装使用 BMCLAPI 下载源)
download.provider.mojang=官方OptiFine 自动安装使用 BMCLAPI 下载源)
extension.bat=Windows 脚本
extension.mod=模组文件