nicer dialog on first startup

This commit is contained in:
Jannik 2019-05-16 15:09:01 +02:00
parent 3f69169a6a
commit 7d376535ae
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
4 changed files with 163 additions and 194 deletions

View File

@ -27,7 +27,6 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.Optional;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -36,18 +35,18 @@ import org.apache.logging.log4j.Logger;
import com.cemu_UI.controller.CloudController; import com.cemu_UI.controller.CloudController;
import com.cemu_UI.controller.XMLController; import com.cemu_UI.controller.XMLController;
import com.cemu_UI.uiElements.JFXOkayCancelAlert;
import javafx.application.Application; import javafx.application.Application;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class Main extends Application { public class Main extends Application {
@ -105,12 +104,13 @@ public class Main extends Application {
// check if client_secret.json is present // check if client_secret.json is present
if (Main.class.getResourceAsStream("/client_secret.json") == null) { if (Main.class.getResourceAsStream("/client_secret.json") == null) {
LOGGER.error("client_secret is missing!!!!!"); LOGGER.error("client_secret is missing!!!!!");
Alert alert = new Alert(AlertType.ERROR); JFXOkayCancelAlert noCSAlert = new JFXOkayCancelAlert("Error",
alert.setTitle("cemu_UI"); "client_secret is missing! Please contact the maintainer. \nIf you compiled cemu_UI by yourself see: \nhttps://git.mosad.xyz/Seil0/cemu_UI/wiki/Documantation",
alert.setHeaderText("Error"); "-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
alert.setContentText("client_secret is missing! Please contact the maintainer. \nIf you compiled cemu_UI by yourself see: \nhttps://git.mosad.xyz/Seil0/cemu_UI/wiki/Documantation"); noCSAlert.setOkayAction(e -> {});
alert.showAndWait(); noCSAlert.setCancelAction(e -> {});
noCSAlert.showAndWait();
} }
if (!XMLController.getDirCemuUI().exists()) { if (!XMLController.getDirCemuUI().exists()) {
@ -181,33 +181,35 @@ public class Main extends Application {
} }
private void firstStart() { private void firstStart() {
Alert alert = new Alert(AlertType.CONFIRMATION); // new alert with file-chooser
alert.setTitle("cemu_UI"); JFXOkayCancelAlert cemuInstallAlert = new JFXOkayCancelAlert("cemu installation",
alert.setHeaderText("cemu installation"); "please select your cemu installation",
alert.setContentText("please select your cemu installation"); "-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
cemuInstallAlert.setOkayAction(e -> {
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
DirectoryChooser directoryChooser = new DirectoryChooser(); DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDirectory = directoryChooser.showDialog(primaryStage); File selectedDirectory = directoryChooser.showDialog(primaryStage);
XMLController.setCemuPath(selectedDirectory.getAbsolutePath()); XMLController.setCemuPath(selectedDirectory.getAbsolutePath());
} else { });
cemuInstallAlert.setCancelAction(e -> {
XMLController.setCemuPath(null); XMLController.setCemuPath(null);
} LOGGER.info("Action canceld by user!");
});
cemuInstallAlert.showAndWait();
Alert alert2 = new Alert(AlertType.CONFIRMATION); // new alert with file-chooser JFXOkayCancelAlert romDirectoryAlert = new JFXOkayCancelAlert("rom directory",
alert2.setTitle("cemu_UI"); "please select your rom directory",
alert2.setHeaderText("rom directory"); "-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
alert2.setContentText("please select your rom directory"); romDirectoryAlert.setOkayAction(e -> {
Optional<ButtonType> result2 = alert2.showAndWait();
if (result2.get() == ButtonType.OK) {
DirectoryChooser directoryChooser = new DirectoryChooser(); DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDirectory = directoryChooser.showDialog(primaryStage); File selectedDirectory = directoryChooser.showDialog(primaryStage);
XMLController.setRomDirectoryPath(selectedDirectory.getAbsolutePath()); XMLController.setRomDirectoryPath(selectedDirectory.getAbsolutePath());
} else { });
romDirectoryAlert.setCancelAction(e -> {
XMLController.setRomDirectoryPath(null); XMLController.setRomDirectoryPath(null);
} LOGGER.info("Action canceld by user!");
});
romDirectoryAlert.showAndWait();
} }
private void initActions() { private void initActions() {

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017-2018 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. * MA 02110-1301, USA.
*/ */
package com.cemu_UI.application; package com.cemu_UI.application;
import java.awt.Graphics2D; import java.awt.Graphics2D;
@ -89,6 +90,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton; import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@ -140,6 +142,8 @@ public class MainWindowController {
@FXML private AnchorPane gamesAnchorPane; @FXML private AnchorPane gamesAnchorPane;
@FXML private AnchorPane settingsAnchorPane; @FXML private AnchorPane settingsAnchorPane;
@FXML private AnchorPane smmdbAnchorPane; @FXML private AnchorPane smmdbAnchorPane;
@FXML private FlowPane gamesFlowPane;
@FXML private ScrollPane mainScrollPane; @FXML private ScrollPane mainScrollPane;
@FXML private ScrollPane settingsScrollPane; @FXML private ScrollPane settingsScrollPane;
@ -375,30 +379,19 @@ public class MainWindowController {
LOGGER.info("remove " + selectedGameTitle + "(" + selectedGameTitleID + ")"); LOGGER.info("remove " + selectedGameTitle + "(" + selectedGameTitleID + ")");
String headingText = bundle.getString("removeHeadingText") + " \"" + selectedGameTitle + "\""; String headingText = bundle.getString("removeHeadingText") + " \"" + selectedGameTitle + "\"";
String bodyText = bundle.getString("removeBodyText") + " " + selectedGameTitle + " ?"; String bodyText = bundle.getString("removeBodyText") + " " + selectedGameTitle + " ?";
EventHandler<ActionEvent> okayAction = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
try {
games.remove(selectedUIDataIndex); // remove game form games-list
dbController.removeGame(selectedGameTitleID); // remove game from database
refreshUIData(); // refresh all games at gamesAnchorPane (UI)
} catch (Exception e) {
LOGGER.error("error while removing ROM from database!", e);
}
}
};
EventHandler<ActionEvent> cancelAction = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
LOGGER.info("Action canceld by user!");
}
};
JFXOkayCancelAlert removeGameAlert = new JFXOkayCancelAlert(headingText, JFXOkayCancelAlert removeGameAlert = new JFXOkayCancelAlert(headingText,
bodyText, dialogBtnStyle, primaryStage); bodyText, dialogBtnStyle, primaryStage);
removeGameAlert.setOkayAction(okayAction); removeGameAlert.setOkayAction(e -> {
removeGameAlert.setCancelAction(cancelAction); try {
games.remove(selectedUIDataIndex); // remove game form games-list
dbController.removeGame(selectedGameTitleID); // remove game from database
refreshUIData(); // refresh all games at gamesAnchorPane (UI)
} catch (Exception ex) {
LOGGER.error("error while removing ROM from database!", ex);
}
});
removeGameAlert.setCancelAction(e -> LOGGER.info("Action canceld by user!"));
removeGameAlert.showAndWait(); removeGameAlert.showAndWait();
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("error while removing " + selectedGameTitle + "(" + selectedGameTitleID + ")", e); LOGGER.error("error while removing " + selectedGameTitle + "(" + selectedGameTitleID + ")", e);
@ -587,116 +580,88 @@ public class MainWindowController {
} }
}); });
helpLbl.setOnMouseClicked(new EventHandler<MouseEvent>() { helpLbl.setOnMouseClicked(e -> {
@Override if (e.getButton().equals(MouseButton.PRIMARY)) {
public void handle(MouseEvent mouseEvent) { Main.getMain().getHostServices().showDocument("https://git.mosad.xyz/Seil0/cemu_UI/issues/3");
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
Main.getMain().getHostServices().showDocument("https://git.mosad.xyz/Seil0/cemu_UI/issues/3");
}
} }
}); });
languageChoisBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() { languageChoisBox.getSelectionModel().selectedIndexProperty().addListener((e, oldValue, newValue) -> {
@Override String language = languageChoisBox.getItems().get((int) newValue).toString();
public void changed(ObservableValue<? extends Number> ov, Number value, Number new_value) { language = language.substring(language.length() - 6, language.length() - 1); // reading only en_US from
String language = languageChoisBox.getItems().get((int) new_value).toString(); // English (en_US)
language = language.substring(language.length() - 6, language.length() - 1); // reading only en_US from XMLController.setUsrLocal(language);
// English (en_US) setUILanguage();
XMLController.setUsrLocal(language); xmlController.saveSettings();
setUILanguage();
xmlController.saveSettings();
}
}); });
branchChoisBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() { branchChoisBox.getSelectionModel().selectedIndexProperty().addListener((e, oldValue, newValue) -> {
@Override if (branchChoisBox.getItems().get((int) newValue).toString() == "beta") {
public void changed(ObservableValue<? extends Number> ov, Number value, Number new_value) { XMLController.setUseBeta(true);
if (branchChoisBox.getItems().get((int) new_value).toString() == "beta") { } else {
XMLController.setUseBeta(true); XMLController.setUseBeta(false);
} else {
XMLController.setUseBeta(false);
}
xmlController.saveSettings();
} }
xmlController.saveSettings();
}); });
licensesLbl.setOnMouseClicked(new EventHandler<MouseEvent>() { licensesLbl.setOnMouseClicked(e -> {
@Override if (e.getButton().equals(MouseButton.PRIMARY)) {
public void handle(MouseEvent mouseEvent) {
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
EventHandler<ActionEvent> okayAction = new EventHandler<ActionEvent>() { EventHandler<ActionEvent> cancelAction = cE -> {
@Override String bodyText = "";
public void handle(ActionEvent event) {
// do nothing try {
BufferedReader licenseBR = new BufferedReader(
new InputStreamReader(getClass().getResourceAsStream("/licenses/licenses_show.txt")));
String currentLine;
while ((currentLine = licenseBR.readLine()) != null) {
bodyText = bodyText + currentLine + "\n";
} }
};
EventHandler<ActionEvent> cancelAction = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
String headingText = "cemu_UI";
String bodyText = "";
try { licenseBR.close();
BufferedReader licenseBR = new BufferedReader( } catch (IOException ex) {
new InputStreamReader(getClass().getResourceAsStream("/licenses/licenses_show.txt"))); LOGGER.error("Cloud not read the license file!", ex);
String currentLine; }
while ((currentLine = licenseBR.readLine()) != null) { JFXTextAreaInfoDialog licenseDialog = new JFXTextAreaInfoDialog("cemu_UI", "",
bodyText = bodyText + currentLine + "\n"; dialogBtnStyle, 510, 450, main.getPane());
} licenseDialog.getTextArea().setEditable(false);
licenseDialog.show();
licenseBR.close(); };
} catch (IOException e) {
LOGGER.error("Cloud not read the license file!", e); JFXOkayCancelAlert licenseOverviewAlert = new JFXOkayCancelAlert(
} bundle.getString("licensesLblHeadingText"), bundle.getString("licensesLblBodyText"),
dialogBtnStyle, primaryStage);
JFXTextAreaInfoDialog licenseDialog = new JFXTextAreaInfoDialog(headingText, bodyText, licenseOverviewAlert.setOkayAction(oE -> {});
dialogBtnStyle, 510, 450, main.getPane()); licenseOverviewAlert.setCancelAction(cancelAction);
licenseDialog.show(); licenseOverviewAlert.setCancelText(bundle.getString("showLicenses"));
licenseDialog.getTextArea().setEditable(false); licenseOverviewAlert.showAndWait();
}
};
JFXOkayCancelAlert licenseOverviewAlert = new JFXOkayCancelAlert(
bundle.getString("licensesLblHeadingText"), bundle.getString("licensesLblBodyText"),
dialogBtnStyle, primaryStage);
licenseOverviewAlert.setOkayAction(okayAction);
licenseOverviewAlert.setCancelAction(cancelAction);
licenseOverviewAlert.setCancelText(bundle.getString("showLicenses"));
licenseOverviewAlert.showAndWait();
}
}
});
cemuTextField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (new File(newValue).exists()) {
XMLController.setCemuPath(newValue);
xmlController.saveSettings();
} else {
String bodyText = newValue + ": No such file or directory";
JFXInfoAlert fileErrorDialog = new JFXInfoAlert("Waring!", bodyText, dialogBtnStyle, primaryStage);
fileErrorDialog.showAndWait();
LOGGER.warn(newValue + ": No such file or directory");
}
} }
}); });
romTextField.textProperty().addListener(new ChangeListener<String>() { cemuTextField.textProperty().addListener((e, oldValue, newValue) -> {
@Override if (new File(newValue).exists()) {
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { XMLController.setCemuPath(newValue);
if (new File(newValue).exists()) { xmlController.saveSettings();
XMLController.setRomDirectoryPath(newValue); } else {
xmlController.saveSettings(); String bodyText = newValue + ": No such file or directory";
reloadRoms(); JFXInfoAlert fileErrorDialog = new JFXInfoAlert("Waring!", bodyText, dialogBtnStyle, primaryStage);
} else { fileErrorDialog.showAndWait();
String bodyText = newValue + ": No such file or directory"; LOGGER.warn(newValue + ": No such file or directory");
JFXInfoAlert fileErrorDialog = new JFXInfoAlert("Waring!", bodyText, dialogBtnStyle, primaryStage); }
fileErrorDialog.showAndWait(); });
LOGGER.warn(newValue + ": No such file or directory");
} romTextField.textProperty().addListener((e, oldValue, newValue) -> {
if (new File(newValue).exists()) {
XMLController.setRomDirectoryPath(newValue);
xmlController.saveSettings();
reloadRoms();
} else {
String bodyText = newValue + ": No such file or directory";
JFXInfoAlert fileErrorDialog = new JFXInfoAlert("Waring!", bodyText, dialogBtnStyle, primaryStage);
fileErrorDialog.showAndWait();
LOGGER.warn(newValue + ": No such file or directory");
} }
}); });
@ -897,52 +862,44 @@ public class MainWindowController {
private void cloudSyncToggleBtnAction() { private void cloudSyncToggleBtnAction() {
XMLController.setCloudSync(!XMLController.isCloudSync()); XMLController.setCloudSync(!XMLController.isCloudSync());
if(XMLController.isCloudSync()) { if (XMLController.isCloudSync()) {
EventHandler<ActionEvent> okayAction = new EventHandler<ActionEvent>(){ EventHandler<ActionEvent> okayAction = e -> {
@Override // TODO rework for other cloud services
public void handle(ActionEvent event){ // CloudService service = CloudService.GoogleDrive;
//TODO rework for other cloud services XMLController.setCloudService(CloudService.GoogleDrive);
// CloudService service = CloudService.GoogleDrive;
XMLController.setCloudService(CloudService.GoogleDrive);
// start cloud sync in new thread
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
if (main.getCloudController().initializeConnection(XMLController.getCloudService(), XMLController.getCemuPath())) { // start cloud sync in new thread
main.getCloudController().sync(XMLController.getCloudService(), XMLController.getCemuPath(), XMLController.getDirCemuUIPath()); Thread thread = new Thread(new Runnable() {
xmlController.saveSettings(); @Override
} else { public void run() {
cloudSyncToggleBtn.setSelected(false);
// cloud sync init error dialog if (main.getCloudController().initializeConnection(XMLController.getCloudService(),
JFXInfoAlert cloudSyncErrorDialog = new JFXInfoAlert( XMLController.getCemuPath())) {
bundle.getString("cloudSyncErrorHeadingText"), main.getCloudController().sync(XMLController.getCloudService(), XMLController.getCemuPath(),
bundle.getString("cloudSyncErrorBodyText"), dialogBtnStyle, primaryStage); XMLController.getDirCemuUIPath());
cloudSyncErrorDialog.showAndWait(); xmlController.saveSettings();
} } else {
cloudSyncToggleBtn.setSelected(false);
// cloud sync init error dialog
JFXInfoAlert cloudSyncErrorDialog = new JFXInfoAlert(
bundle.getString("cloudSyncErrorHeadingText"),
bundle.getString("cloudSyncErrorBodyText"), dialogBtnStyle, primaryStage);
cloudSyncErrorDialog.showAndWait();
} }
});
thread.start(); }
} });
}; thread.start();
};
EventHandler<ActionEvent> cancelAction = new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
cloudSyncToggleBtn.setSelected(false);
}
};
JFXOkayCancelAlert cloudSyncWarningAlert = new JFXOkayCancelAlert( JFXOkayCancelAlert cloudSyncWarningAlert = new JFXOkayCancelAlert(
bundle.getString("cloudSyncWaringHeadingText"), bundle.getString("cloudSyncWaringHeadingText"), bundle.getString("cloudSyncWaringHeadingText"), bundle.getString("cloudSyncWaringHeadingText"),
dialogBtnStyle, primaryStage); dialogBtnStyle, primaryStage);
cloudSyncWarningAlert.setOkayAction(okayAction); cloudSyncWarningAlert.setOkayAction(okayAction);
cloudSyncWarningAlert.setCancelAction(cancelAction); cloudSyncWarningAlert.setCancelAction(e -> cloudSyncToggleBtn.setSelected(false));
cloudSyncWarningAlert.showAndWait(); cloudSyncWarningAlert.showAndWait();
} }
} }
@FXML @FXML
@ -1136,13 +1093,16 @@ public class MainWindowController {
xNextElement = 0; xNextElement = 0;
// add all games to gamesAnchorPane (UI) // add all games to gamesAnchorPane (UI)
for (UIROMDataType game : games) { // for (UIROMDataType game : games) {
generatePosition(); // generatePosition();
//
game.setLayoutX(xPos); // game.setLayoutX(xPos);
game.setLayoutY(yPos); // game.setLayoutY(yPos);
gamesAnchorPane.getChildren().add(game); // gamesAnchorPane.getChildren().add(game);
} // }
// TODO
gamesFlowPane.getChildren().addAll(games);
} }
// set the selected local strings to all needed elements // set the selected local strings to all needed elements

View File

@ -106,11 +106,14 @@ public class XMLController {
props.setProperty("useBeta", String.valueOf(isUseBeta())); props.setProperty("useBeta", String.valueOf(isUseBeta()));
if (getCloudService() == null) { if (getCloudService() == null) {
props.setProperty("cloudService", ""); props.setProperty("cloudService", "");
props.setProperty("folderID", "");
props.setProperty("lastLocalSync", "");
} else { } else {
props.setProperty("cloudService", getCloudService().toString()); props.setProperty("cloudService", getCloudService().toString());
props.setProperty("folderID", getFolderID());
props.setProperty("lastLocalSync", Long.toString(getLastLocalSync()));
} }
props.setProperty("folderID", getFolderID());
props.setProperty("lastLocalSync", Long.toString(getLastLocalSync()));
props.setProperty("windowWidth", Double.toString(getWindowWidth())); props.setProperty("windowWidth", Double.toString(getWindowWidth()));
props.setProperty("windowHeight", Double.toString(getWindowHeight())); props.setProperty("windowHeight", Double.toString(getWindowHeight()));

View File

@ -13,19 +13,23 @@
<?import javafx.scene.control.Separator?> <?import javafx.scene.control.Separator?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.text.TextFlow?> <?import javafx.scene.text.TextFlow?>
<AnchorPane fx:id="mainAnchorPane" minHeight="405.0" minWidth="260.0" prefHeight="600.0" prefWidth="904.0" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1"> <AnchorPane fx:id="mainAnchorPane" minHeight="405.0" minWidth="260.0" prefHeight="600.0" prefWidth="904.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<ScrollPane fx:id="mainScrollPane" fitToWidth="true" layoutY="38.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0"> <ScrollPane fx:id="mainScrollPane" fitToWidth="true" layoutY="38.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<content> <content>
<AnchorPane fx:id="gamesAnchorPane"> <AnchorPane fx:id="gamesAnchorPane">
<padding> <padding>
<Insets bottom="17.0" /> <Insets bottom="17.0" />
</padding></AnchorPane> </padding>
<children>
<FlowPane fx:id="gamesFlowPane" prefHeight="217.0" prefWidth="902.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children></AnchorPane>
</content> </content>
</ScrollPane> </ScrollPane>
<HBox fx:id="topHBox" prefHeight="38.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <HBox fx:id="topHBox" prefHeight="38.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">