Feat/gameui #244

Merged
j.kropff merged 5 commits from feat/gameui into main 2026-04-09 10:57:24 +02:00
10 changed files with 184 additions and 186 deletions
@@ -5,17 +5,17 @@ import javafx.scene.control.Label;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
/** /**
* Controller für die Casino-Spielfläche. * Controller for the casino gaming area.
* *
* <p>Verantwortlich für: - die Darstellung des Pokertisches und der Spieleroberfläche, - die * <p>Responsible for: - the display of the poker table and the player interface, - the processing
* Verarbeitung von Benutzereingaben, - die Schnittstelle zur GameEngine und zum Netzwerkprotokoll. * of user input, - the interface to the game engine and the network protocol.
* *
* <p>Hinweise: - Die Methode `onTableClick()` dient aktuell nur als Test-Logik. Sie ist ggf. nicht * <p>Notes: - The `onTableClick()` method currently serves only as test logic. It may no longer be
* mehr funktionsfähig und wird zukünftig durch die finale Spielinteraktion ersetzt. * functional and will be replaced by the final game interaction in the future.
*/ */
public class CasinoGameController { public class CasinoGameController {
/** Standardkonstruktor. Wird von FXML verwendet. */ /** Standard constructor. Used by FXML. */
public CasinoGameController() { public CasinoGameController() {
// default constructor for FXML // default constructor for FXML
} }
@@ -23,13 +23,13 @@ public class CasinoGameController {
@FXML private Label welcomeText; @FXML private Label welcomeText;
@FXML private VBox casinoTable; @FXML private VBox casinoTable;
// TODO: Test-Logik: wird durch echte Spielinteraktionen ersetzt, // TODO: Test logic: will be replaced by real game interactions,
// sobald die GameEngine fertig ist // once the game engine is finished
/** /**
* Temporäre Test-Methode, die bei Klick auf den Tisch eine Platzhalteraktion ausführt. * Temporary test method that performs a placeholder action when the table is clicked.
* *
* <p>Wird in der finalen Implementierung durch die Spiel-Logik ersetzt. * <p>In the final implementation, this will be replaced by the game logic.
*/ */
@FXML @FXML
public void onTableClick() { public void onTableClick() {
@@ -7,17 +7,17 @@ import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
/** /**
* Hauptklasse für das Casino-Spiel-UI. * Main class for the Casono Game UI.
* *
* <p>Startet die JavaFX-Anwendung, lädt die grafische Oberfläche aus der FXML-Datei und * <p>Starts the JavaFX application, loads the graphical user interface from the FXML file, and
* initialisiert die Haupt-Stage für das Spiel. * initializes the main stage for the game.
* *
* <p>Aufgaben: - Lädt die FXML-Oberfläche "/ui-structure/Casinogameui.fxml". - Lädt das * <p>Tasks: - Loads the FXML interface "/ui-structure/Casinogameui.fxml". - Loads the application
* Anwendungs-Icon aus "/images/logoinverted.png". - Startet die Anwendung im Vollbildmodus. * icon from "/images/logoinverted.png". - Starts the application in full-screen mode.
*/ */
public class CasinoGameUI extends Application { public class CasinoGameUI extends Application {
/** Standardkonstruktor. */ /** default constructor */
public CasinoGameUI() { public CasinoGameUI() {
// default no-arg constructor // default no-arg constructor
} }
@@ -26,10 +26,10 @@ public class CasinoGameUI extends Application {
private static final int DEFAULT_HEIGHT = 800; private static final int DEFAULT_HEIGHT = 800;
/** /**
* Startet die Haupt-Stage der Anwendung. * Starts the main stage of the application.
* *
* @param stage Die vom System bereitgestellte Haupt-Stage. * @param stage The main stage provided by the system.
* @throws IOException Wenn die FXML-Datei oder Ressourcen nicht geladen werden können. * @throws IOException If the FXML file or resources cannot be loaded.
*/ */
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
@@ -46,9 +46,9 @@ public class CasinoGameUI extends Application {
} }
/** /**
* Startpunkt der Anwendung. * Starting point of the application.
* *
* @param args Befehlszeilenargumente. * @param args Command line arguments.
*/ */
public static void main(String[] args) { public static void main(String[] args) {
launch(); launch();
@@ -31,28 +31,27 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
/** /**
* Experimenteller integrierter Browser für Casono. * Experimental embedded browser for Casono.
* *
* <p>Diese Klasse implementiert einen einfachen eingebetteten Webbrowser auf Basis von {@link * <p>This class implements a simple embedded web browser based on {@link javafx.scene.web.WebView}.
* javafx.scene.web.WebView}. Der Browser dient primär als Hilfswerkzeug innerhalb des Spiels, um * The browser primarily serves as a utility within the game to display external content such as web
* externe Inhalte wie Webseiten oder Videos anzuzeigen. * pages or videos.
* *
* <p>Status Der Browser befindet sich derzeit in einer experimentellen Phase. Einige * <p>Status The browser is currently in an experimental phase. Some security mechanisms are based
* Sicherheitsmechanismen basieren auf experimentellen KI-gestützten Empfehlungen und können sich in * on experimental AI-driven recommendations and may change in future versions.
* zukünftigen Versionen noch ändern.
* *
* <p>Zweck Der Browser wird aktuell experimentell genutzt, um: Pokerregeln direkt im Spiel zu * <p>Purpose The browser is currently being used experimentally to: Explain poker rules directly
* erklären Hilfeseiten oder Dokumentationen anzuzeigen Videos (z.B. Tutorials oder Erklärungen) * within the game Display help pages or documentation Play videos (e.g., tutorials or explanations)
* über Plattformen wie YouTube abzuspielen * via platforms such as YouTube
* *
* <p>Sicherheitsmechanismen Da externe Webseiten geladen werden können, wurden einige grundlegende * <p>Security Mechanisms Since external websites can be loaded, some basic protective measures have
* Schutzmaßnahmen integriert: - HTTPS-Zwang für Webseiten - Whitelist für bekannte Domains - * been integrated: - Mandatory HTTPS for websites - Whitelist for known domains - Warning for
* Warnung bei unbekannten Webseiten - JavaScript standardmäßig deaktiviert (man kann es jedoch für * unknown websites - JavaScript disabled by default (but can be enabled for Google, etc.) - Pop-up
* Google etc. einschalten) - Popup-Blocker - Automatische Cookie-Löschung beim Schließen * blocker - Automatic cookie deletion upon closing
*/ */
public class CasinoBrowserController { public class CasinoBrowserController {
/** Standardkonstruktor. Initialisiert den CasinoBrowserController. */ /** Default constructor. Initializes the CasinoBrowserController. */
public CasinoBrowserController() { public CasinoBrowserController() {
// Intentionally left blank; controller initialization is FXML-driven. // Intentionally left blank; controller initialization is FXML-driven.
} }
@@ -101,7 +100,7 @@ public class CasinoBrowserController {
private static boolean javascriptEnabled = false; private static boolean javascriptEnabled = false;
/** Löscht alle gespeicherten Cookies der aktuellen Browser-Sitzung. */ /** Deletes all cookies stored during the current browser session. */
private static void clearCookies() { private static void clearCookies() {
try { try {
COOKIE_MANAGER.getCookieStore().removeAll(); COOKIE_MANAGER.getCookieStore().removeAll();
@@ -110,12 +109,12 @@ public class CasinoBrowserController {
} }
/** /**
* Öffnet ein neues Browserfenster und lädt eine angegebene Webseite. * Opens a new browser window and loads a specified webpage.
* *
* <p>Falls die Webseite nicht zur Liste vertrauenswürdiger Domains gehört, wird der Benutzer * <p>If the webpage is not on the list of trusted domains, the user will be asked whether the
* gefragt, ob die Seite dennoch geladen werden soll. * page should be loaded anyway.
* *
* @param url die Startadresse der Webseite, die geladen werden soll * @param url the URL of the webpage to be loaded
*/ */
public static void open(String url) { public static void open(String url) {
Platform.runLater( Platform.runLater(
@@ -182,10 +181,10 @@ public class CasinoBrowserController {
} }
/** /**
* WebView Container * WebView container
* *
* @param webView WebView Inhalt * @param webView WebView content
* @return StackPane Container * @return StackPane container
*/ */
public static StackPane createWebContainer(WebView webView) { public static StackPane createWebContainer(WebView webView) {
StackPane webContainer = new StackPane(webView); StackPane webContainer = new StackPane(webView);
@@ -198,7 +197,7 @@ public class CasinoBrowserController {
/** /**
* Popup Blocker * Popup Blocker
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
*/ */
public static void configurePopupBlocker(WebEngine engine) { public static void configurePopupBlocker(WebEngine engine) {
engine.setCreatePopupHandler( engine.setCreatePopupHandler(
@@ -212,8 +211,8 @@ public class CasinoBrowserController {
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH); var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
Image logo = new Image(stream); Image logo = new Image(stream);
// Variable 'streamM' abgekürzt, um das 100-Zeichen-Limit (LineLength) // Variable streamM abbreviated to comply with the 100-character
// einzuhalten // limit (LineLength)
var streamM = var streamM =
CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN); CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN);
Image logomain = new Image(streamM); Image logomain = new Image(streamM);
@@ -232,7 +231,7 @@ public class CasinoBrowserController {
alert.setGraphic(logoView); alert.setGraphic(logoView);
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("Logo konnte nicht geladen werden"); LOGGER.error("The logo could not be loaded");
} }
alert.showAndWait(); alert.showAndWait();
@@ -241,9 +240,9 @@ public class CasinoBrowserController {
} }
/** /**
* Logos laden * Load logos
* *
* @param stage Fenster Stage * @param stage Window Stage
* @return ImageView Logo * @return ImageView Logo
*/ */
private static ImageView loadLogos(Stage stage) { private static ImageView loadLogos(Stage stage) {
@@ -253,8 +252,7 @@ public class CasinoBrowserController {
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH); var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
Image logo = new Image(stream); Image logo = new Image(stream);
// Variable 'streamM' abgekürzt, um das 100-Zeichen-Limit (LineLength) // Variable streamM abbreviated to comply with the 100-character limit (LineLength)
// einzuhalten
var streamM = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN); var streamM = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN);
Image logomain = new Image(streamM); Image logomain = new Image(streamM);
@@ -268,17 +266,17 @@ public class CasinoBrowserController {
browserLogo.setPreserveRatio(true); browserLogo.setPreserveRatio(true);
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("Logo konnte nicht geladen werden"); LOGGER.error("The logo could not be loaded");
} }
return browserLogo; return browserLogo;
} }
/** /**
* URL Feld * URL field
* *
* @param url Start URL * @param url Start URL
* @return TextField Eingabe * @return TextField input
*/ */
public static TextField createUrlField(String url) { public static TextField createUrlField(String url) {
TextField urlField = new TextField(url); TextField urlField = new TextField(url);
@@ -289,12 +287,12 @@ public class CasinoBrowserController {
} }
/** /**
* Sicherheits Label * Security Label
* *
* @return Label Anzeige * @return Label display
*/ */
public static Label createSecurityLabel() { public static Label createSecurityLabel() {
Label securityLabel = new Label("SICHER"); Label securityLabel = new Label("SAFE");
securityLabel.getStyleClass().add("security-label"); securityLabel.getStyleClass().add("security-label");
return securityLabel; return securityLabel;
@@ -303,8 +301,8 @@ public class CasinoBrowserController {
/** /**
* JS Toggle * JS Toggle
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
* @return Button Umschalten * @return Toggle button
*/ */
public static Button createJsToggle(WebEngine engine) { public static Button createJsToggle(WebEngine engine) {
Button jsToggle = new Button("JS EINSCHALTEN"); Button jsToggle = new Button("JS EINSCHALTEN");
@@ -316,7 +314,7 @@ public class CasinoBrowserController {
engine.setJavaScriptEnabled(javascriptEnabled); engine.setJavaScriptEnabled(javascriptEnabled);
if (javascriptEnabled) { if (javascriptEnabled) {
jsToggle.setText("JS AUSSCHALTEN"); jsToggle.setText("JS TURN OFF");
jsToggle.getStyleClass().removeAll("red-button"); jsToggle.getStyleClass().removeAll("red-button");
jsToggle.getStyleClass().add("yellow-button"); jsToggle.getStyleClass().add("yellow-button");
@@ -331,10 +329,10 @@ public class CasinoBrowserController {
} }
/** /**
* Zurück Button * Back Button
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
* @return Button Zurück * @return Back button
*/ */
public static Button createBackButton(WebEngine engine) { public static Button createBackButton(WebEngine engine) {
Button backBtn = new Button("<"); Button backBtn = new Button("<");
@@ -350,10 +348,10 @@ public class CasinoBrowserController {
} }
/** /**
* Vorwärts Button * Forward Button
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
* @return Button Vorwärts * @return Forward button
*/ */
public static Button createForwardButton(WebEngine engine) { public static Button createForwardButton(WebEngine engine) {
Button fwdBtn = new Button(">"); Button fwdBtn = new Button(">");
@@ -373,8 +371,8 @@ public class CasinoBrowserController {
/** /**
* Reload Button * Reload Button
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
* @return Button Reload * @return Reload button
*/ */
public static Button createReloadButton(WebEngine engine) { public static Button createReloadButton(WebEngine engine) {
Button reloadBtn = new Button(""); Button reloadBtn = new Button("");
@@ -386,9 +384,9 @@ public class CasinoBrowserController {
/** /**
* Close Button * Close Button
* *
* @param stage Fenster Stage * @param stage Window stage
* @param webView WebView Inhalt * @param webView WebView content
* @return Button Schließen * @return Close button
*/ */
public static Button createCloseButton(Stage stage, WebView webView) { public static Button createCloseButton(Stage stage, WebView webView) {
Button closeBtn = new Button("X"); Button closeBtn = new Button("X");
@@ -406,9 +404,9 @@ public class CasinoBrowserController {
/** /**
* URL Events * URL Events
* *
* @param engine WebEngine nutzen * @param engine Use WebEngine
* @param urlField URL Textfeld * @param urlField URL text field
* @param securityLabel Sicherheits Label * @param securityLabel Security label
*/ */
public static void configureUrlEvents( public static void configureUrlEvents(
WebEngine engine, TextField urlField, Label securityLabel) { WebEngine engine, TextField urlField, Label securityLabel) {
@@ -417,11 +415,11 @@ public class CasinoBrowserController {
} }
/** /**
* Scene erstellen * Create a scene
* *
* @param taskbar Taskbar HBox * @param taskbar Taskbar HBox
* @param webContainer Web Container * @param webContainer Web container
* @return Scene Fenster * @return Scene window
*/ */
public static Scene createScene(HBox taskbar, StackPane webContainer) { public static Scene createScene(HBox taskbar, StackPane webContainer) {
VBox root = new VBox(VBOX_SPACING, taskbar, webContainer); VBox root = new VBox(VBOX_SPACING, taskbar, webContainer);
@@ -442,8 +440,8 @@ public class CasinoBrowserController {
/** /**
* Key Events * Key Events
* *
* @param scene Scene Fenster * @param scene Scene window
* @param engine WebEngine nutzen * @param engine Use WebEngine
*/ */
public static void configureKeyEvents(Scene scene, WebEngine engine) { public static void configureKeyEvents(Scene scene, WebEngine engine) {
scene.setOnKeyPressed( scene.setOnKeyPressed(
@@ -455,18 +453,18 @@ public class CasinoBrowserController {
} }
/** /**
* Lädt eine URL in den Browser, nachdem grundlegende Sicherheitsprüfungen durchgeführt wurden. * Loads a URL in the browser after performing basic security checks.
* *
* <p>Vor dem Laden einer Seite werden folgende Prüfungen durchgeführt: - Überprüfung des * <p>Before loading a page, the following checks are performed: - Verification of the protocol
* Protokolls (nur HTTPS erlaubt) - Überprüfung der Domain gegen eine Whitelist - Schutz vor * (only HTTPS allowed) - Verification of the domain against a whitelist - Protection against
* Domain-Spoofing (Domain-Vortäuschung) * domain spoofing
* *
* <p>Falls eine Domain nicht als vertrauenswürdig eingestuft wird, muss der Benutzer * <p>If a domain is not classified as trustworthy, the user must confirm that the page may
* bestätigen, dass die Seite dennoch geöffnet werden darf. * still be opened.
* *
* @param engine der WebEngine-Renderer des Browsers * @param engine the browser's WebEngine renderer
* @param url die zu ladende Webadresse * @param url the web address to be loaded
* @param securityLabel Label zur Anzeige des aktuellen Sicherheitsstatus * @param securityLabel label for displaying the current security status
*/ */
private static void loadUrlSafely(WebEngine engine, String url, Label securityLabel) { private static void loadUrlSafely(WebEngine engine, String url, Label securityLabel) {
try { try {
@@ -476,9 +474,9 @@ public class CasinoBrowserController {
URI uri = new URI(url); URI uri = new URI(url);
// HTTPS Pflicht // HTTPS required
if (!"https".equalsIgnoreCase(uri.getScheme())) { if (!"https".equalsIgnoreCase(uri.getScheme())) {
securityLabel.setText("BLOCKIERT"); securityLabel.setText("BLOCKED");
return; return;
} }
@@ -488,19 +486,19 @@ public class CasinoBrowserController {
return; return;
} }
// Sicherer Domain Check // Secure Domain Check
boolean trusted = boolean trusted =
TRUSTED_DOMAINS.stream() TRUSTED_DOMAINS.stream()
.anyMatch(domain -> host.equals(domain) || host.endsWith("." + domain)); .anyMatch(domain -> host.equals(domain) || host.endsWith("." + domain));
if (!trusted) { if (!trusted) {
if (!showUnknownWebsiteAlert(host)) { if (!showUnknownWebsiteAlert(host)) {
securityLabel.setText("BLOCKIERT"); securityLabel.setText("BLOCKED");
return; return;
} }
securityLabel.setText("UNBEKANNT"); securityLabel.setText("UNBEKANNT");
} else { } else {
securityLabel.setText("SICHER"); securityLabel.setText("SAFE");
} }
engine.load(uri.toString()); engine.load(uri.toString());
} catch (Exception e) { } catch (Exception e) {
@@ -509,20 +507,20 @@ public class CasinoBrowserController {
} }
/** /**
* Zeigt Warnung an. * Displays a warning.
* *
* @param host Website Host * @param host Website host
* @return OK gedrückt * @return OK pressed
*/ */
private static boolean showUnknownWebsiteAlert(String host) { private static boolean showUnknownWebsiteAlert(String host) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION); Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Unbekannte Website"); alert.setTitle("Unknown website");
alert.setHeaderText("Diese Website ist nicht bekannt"); alert.setHeaderText("This website is unknown");
String content = String content =
host host
+ "\n\nDiese Seite ist nicht vom Casono Browser verifiziert.\n" + "\n\nThis site has not been verified by the Casono browser.\n"
+ "Möchten Sie sie trotzdem öffnen?"; + "Do you still want to open it?";
alert.setContentText(content); alert.setContentText(content);
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH); var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
@@ -11,14 +11,14 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
/** /**
* Controller für die interaktive Taskleiste innerhalb der Poker-UI. * Controller for the interactive taskbar within the poker UI.
* *
* <p>Verantwortlich für: - Drag-and-Drop-Verschieben der Taskleiste, - Eingabe und Verwaltung von * <p>Responsible for: - Drag-and-drop movement of the taskbar, - Input and management of game
* Spieleinsätzen, - Steuerung allgemeiner Menüfunktionen wie Exit. * stakes, - Control of general menu functions such as Exit.
*/ */
public class TaskbarController { public class TaskbarController {
/** Standardkonstruktor. Wird von FXML verwendet. */ /** Standard constructor. Used by FXML. */
public TaskbarController() { public TaskbarController() {
// default constructor for FXML // default constructor for FXML
} }
@@ -36,10 +36,10 @@ public class TaskbarController {
private static final int CREDIT_STEP = 5; private static final int CREDIT_STEP = 5;
/** /**
* Wird aufgerufen, wenn die Taskleiste mit der Maus gedrückt wird. Speichert die relative * Called when the taskbar is clicked with the mouse. Saves the relative position for later,
* Position, um später korrekt zu verschieben. * correct repositioning.
* *
* @param event Das Mausereignis * @param event The mouse event
*/ */
@FXML @FXML
private void onTaskbarPressed(MouseEvent event) { private void onTaskbarPressed(MouseEvent event) {
@@ -48,11 +48,10 @@ public class TaskbarController {
} }
/** /**
* Wird aufgerufen, während die Taskleiste mit der Maus gezogen wird. Aktualisiert die Position * Called while dragging the taskbar with the mouse. Updates the position and slightly scales
* und skaliert die Taskleiste leicht zur visuellen Rückmeldung. * the taskbar for visual feedback.
* *
* <p>TODO: Es muss noch gefixt werden, dass die Taskleiste nicht aus dem Fenster verschwinden * <p>TODO: It still needs to be fixed that the taskbar cannot disappear out of the window.
* kann.
* *
* @param event Das Mausereignis * @param event Das Mausereignis
*/ */
@@ -66,10 +65,10 @@ public class TaskbarController {
} }
/** /**
* Wird aufgerufen, wenn die Maus über der Taskleiste losgelassen wird. Setzt die Skalierung der * Called when the mouse cursor is released over the taskbar. Resets the taskbar scaling to
* Taskleiste wieder auf Normalgröße. * normal size.
* *
* @param event Das Mausereignis * @param event The mouse event
*/ */
@FXML @FXML
private void onTaskbarReleased(MouseEvent event) { private void onTaskbarReleased(MouseEvent event) {
@@ -78,9 +77,9 @@ public class TaskbarController {
} }
/** /**
* Wird aufgerufen, wenn im Textfeld die Enter-Taste gedrückt wird. * Called up when the Enter key is pressed in the text field.
* *
* @param event Das Tastaturereignis * @param event The keyboard event
*/ */
@FXML @FXML
private void onInputSubmitted(KeyEvent event) { private void onInputSubmitted(KeyEvent event) {
@@ -90,8 +89,8 @@ public class TaskbarController {
} }
/** /**
* Wird aufgerufen, wenn der Submit-Button in der Taskleiste gedrückt wird. Löst die * Called when the submit button in the taskbar is pressed. Triggers the processing of the
* Verarbeitung des Einsatzes aus. * deployment.
*/ */
@FXML @FXML
private void onInputSubmittedAction() { private void onInputSubmittedAction() {
@@ -106,7 +105,7 @@ public class TaskbarController {
javafx.stage.Stage currentStage = javafx.stage.Stage currentStage =
(javafx.stage.Stage) taskbar.getScene().getWindow(); (javafx.stage.Stage) taskbar.getScene().getWindow();
currentStage.close(); currentStage.close();
// Lobby-UI starten // Start lobby UI
try { try {
new Casinomainui().start(new javafx.stage.Stage()); new Casinomainui().start(new javafx.stage.Stage());
} catch (Exception e) { } catch (Exception e) {
@@ -116,9 +115,9 @@ public class TaskbarController {
} }
/** /**
* Verarbeitet den im Textfeld eingegebenen Einsatz. Es werden ausschließlich ganzzahlige Werte * Processes the stake entered in the text field. Only integer values between 5 and 100,000
* im Bereich von 5 bis 100.000 Credits akzeptiert, die einem Vielfachen von 5 entsprechen * credits are accepted, in multiples of 5 (in increments of 5). The stake is currently only
* (5er-Schritte). Der Einsatz wird aktuell nur auf der Konsole ausgegeben. * displayed on the console.
*/ */
private void processBet() { private void processBet() {
String input = taskbarInput.getText(); String input = taskbarInput.getText();
@@ -126,22 +125,22 @@ public class TaskbarController {
int credits = Integer.parseInt(input.trim()); int credits = Integer.parseInt(input.trim());
if (credits >= MIN_CREDITS && credits <= MAX_CREDITS && credits % CREDIT_STEP == 0) { if (credits >= MIN_CREDITS && credits <= MAX_CREDITS && credits % CREDIT_STEP == 0) {
// TODO: Credits müssen an die GameEngine gesendet werden // TODO: Credits must be sent to the GameEngine
LOGGER.info("Einsatz gesetzt: {} Casono Credits", credits); LOGGER.info("Bet set: {} Casono Credits", credits);
taskbarInput.clear(); taskbarInput.clear();
} else { } else {
LOGGER.info("Fehler: Nur 5er-Schritte (5, 10, ... 100.000) erlaubt!"); LOGGER.error("Error: Only increments of 5 (5, 10, ... 100,000) are allowed!");
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
LOGGER.info("Fehler: Bitte nur eine Zahl eingeben!"); LOGGER.error("Error: Please enter only one number!");
} }
} }
/** /**
* Öffnet den integrierten Casono Webbrowser. * Opens the integrated Casono web browser.
* *
* <p>TODO: Ersetze die Start-URL durch die offizielle Projekt-Website (z.B. Tipps & Tricks * <p>TODO: Replace the start URL with the official project website (e.g., Tips & Tricks page)
* Seite), sobald die Inhalte für Strategien und Support bereitstehen. * once the content for strategies and support is available.
*/ */
@FXML @FXML
private void onBrowserButtonClick() { private void onBrowserButtonClick() {
@@ -51,8 +51,8 @@ public class Deck {
} }
/** /**
* Sets the cards of the deck. This method replaces the internal list * Sets the cards of the deck. This method replaces the internal list with a copy of the
* with a copy of the provided list. * provided list.
* *
* @param cards the new list of cards to set * @param cards the new list of cards to set
*/ */
@@ -1,12 +1,12 @@
.root { .root {
-fx-background-color: #000000; -fx-background-color: #000000;
-fx-font-family: "Monospaced", "Courier New"; /* Schriftart */ -fx-font-family: "Monospaced", "Courier New"; /* font */
} }
.background { .background {
-fx-background-image: url("/images/background.png"); -fx-background-image: url("/images/background.png");
-fx-background-size: cover; /* Bild füllt das ganze Fenster aus */ -fx-background-size: cover; /* Image fills the entire window */
/* Zentriert das Bild und verhindert, dass es sich kachelartig wiederholt */ /* Centers the image and prevents it from repeating in a tile-like pattern. */
-fx-background-position: center center; -fx-background-position: center center;
-fx-background-repeat: no-repeat; -fx-background-repeat: no-repeat;
} }
@@ -181,20 +181,20 @@
.status-label-small { .status-label-small {
-fx-text-fill: #ffffff; -fx-text-fill: #ffffff;
-fx-font-family: "Monospaced"; /* Schriftart */ -fx-font-family: "Monospaced"; /* font */
-fx-font-size: 15px; -fx-font-size: 15px;
} }
.status-value-text { .status-value-text {
-fx-text-fill: #ffffff; -fx-text-fill: #ffffff;
-fx-font-family: "Monospaced"; /* Schriftart */ -fx-font-family: "Monospaced"; /* font */
-fx-font-size: 15px; -fx-font-size: 15px;
-fx-font-weight: bold; -fx-font-weight: bold;
} }
.status-value-money { .status-value-money {
-fx-text-fill: #ffffff; -fx-text-fill: #ffffff;
-fx-font-family: "Monospaced"; /* Schriftart */ -fx-font-family: "Monospaced"; /* font */
-fx-font-size: 15px; -fx-font-size: 15px;
-fx-font-weight: bold; -fx-font-weight: bold;
} }
@@ -5,7 +5,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.image.*?> <?import javafx.scene.image.*?>
<!-- Hauptcontainer: Verknüpft die UI mit dem CasinoGameController und lädt Casinogameui.css --> <!-- Main container: Links the UI to the CasinoGameController and loads Casinogameui.css -->
<AnchorPane xmlns="http://javafx.com/javafx/21" <AnchorPane xmlns="http://javafx.com/javafx/21"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.CasinoGameController" fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.CasinoGameController"
@@ -14,28 +14,28 @@
<GridPane prefWidth="1200" prefHeight="800" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0"> <GridPane prefWidth="1200" prefHeight="800" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0">
<columnConstraints> <columnConstraints>
<!-- Tisch-Box: 70% --> <!-- Table-Box: 70% -->
<ColumnConstraints percentWidth="70.0" hgrow="ALWAYS" /> <ColumnConstraints percentWidth="70.0" hgrow="ALWAYS" />
<!-- Leere-Box: 5% --> <!-- Table-Box: 5% -->
<ColumnConstraints percentWidth="5.0" hgrow="ALWAYS" /> <ColumnConstraints percentWidth="5.0" hgrow="ALWAYS" />
<!-- Chat-Box: 20% --> <!-- Table-Box: 20% -->
<ColumnConstraints percentWidth="25.0" hgrow="ALWAYS" /> <ColumnConstraints percentWidth="25.0" hgrow="ALWAYS" />
</columnConstraints> </columnConstraints>
<!-- Sorgt dafür, dass diese Zeile den gesamten verfügbaren vertikalen Platz nutzt --> <!-- Ensures that this line uses all available vertical space -->
<rowConstraints> <rowConstraints>
<RowConstraints vgrow="ALWAYS" /> <RowConstraints vgrow="ALWAYS" />
</rowConstraints> </rowConstraints>
<children> <children>
<!-- Tisch-Box in Spalte 0 --> <!-- Table box in column 0 -->
<StackPane GridPane.columnIndex="0"> <StackPane GridPane.columnIndex="0">
<!-- Innenabstand: Hält den Inhalt 10 Pixel von oben/unten und 20 Pixel von den Seiten fern --> <!-- Inner spacing: Keeps the content 10 pixels away from the top/bottom and 20 pixels from the sides -->
<padding> <padding>
<Insets top="20" right="10" bottom="120" left="20"/> <Insets top="20" right="10" bottom="120" left="20"/>
</padding> </padding>
<!-- Zentraler Casinotisch: Zentriert den Inhalt und nutzt durch die maximale Größe (1.7976931348623157E308) das gesamte Fenster --> <!-- Central Casino Table: Centers the content and utilizes the entire window due to its maximum size (1.7976931348623157E308) -->
<VBox fx:id="casinoTable" <VBox fx:id="casinoTable"
alignment="CENTER" alignment="CENTER"
styleClass="casino-table" styleClass="casino-table"
@@ -44,7 +44,7 @@
maxWidth="Infinity" maxWidth="Infinity"
maxHeight="Infinity"> maxHeight="Infinity">
<!-- TODO: Platzhalter für die Poker-Spielfläche: Hier werden später dynamisch Karten, Chips und Einsätze der Gegner angezeigt --> <!-- TODO: Placeholder for the poker playing area: Cards, chips and opponents' bets will be dynamically displayed here later -->
<HBox alignment="CENTER" spacing="15"> <HBox alignment="CENTER" spacing="15">
<VBox styleClass="dealer-box" prefWidth="80" prefHeight="120" /> <VBox styleClass="dealer-box" prefWidth="80" prefHeight="120" />
<VBox styleClass="dealer-box" prefWidth="80" prefHeight="120" /> <VBox styleClass="dealer-box" prefWidth="80" prefHeight="120" />
@@ -52,7 +52,7 @@
</HBox> </HBox>
<VBox alignment="CENTER" spacing="10"> <VBox alignment="CENTER" spacing="10">
<!-- Label mit Logo --> <!-- Label with logo -->
<Label text="CAS0NO" styleClass="table-title"> <Label text="CAS0NO" styleClass="table-title">
<graphic> <graphic>
<ImageView fitHeight="30.0" preserveRatio="true"> <ImageView fitHeight="30.0" preserveRatio="true">
@@ -63,32 +63,32 @@
</graphic> </graphic>
</Label> </Label>
<!-- TODO: Platzhalter: Wird ersetzt, sobald die GameEngine fertig ist und echte Einsätze verarbeiten kann --> <!-- TODO: Placeholder: Will be replaced once the game engine is finished and can process real-world scenarios -->
<Label fx:id="welcomeText" text="Setzen Sie Ihren Einsatz" styleClass="table-title" /> <Label fx:id="welcomeText" text="Setzen Sie Ihren Einsatz" styleClass="table-title" />
</VBox> </VBox>
</VBox> </VBox>
</StackPane> </StackPane>
<!-- Leere-Box in Spalte 1: Schafft Platz zwischen dem Tisch-Box und der Chat-Box --> <!-- Empty box in column 1: Creates space between the table box and the chat box -->
<VBox GridPane.columnIndex="1" <VBox GridPane.columnIndex="1"
alignment="CENTER" alignment="CENTER"
minWidth="100" minWidth="100"
minHeight="100"> minHeight="100">
<!-- Bleibt leer --> <!-- Leave blank -->
</VBox> </VBox>
<!-- TODO: Platzhalter: Chat-Box in Spalte 2: --> <!-- TODO: Placeholder: Chat box in column 2: -->
<fx:include source="components/Chatbox.fxml" GridPane.columnIndex="2"/> <fx:include source="components/Chatbox.fxml" GridPane.columnIndex="2"/>
</children> </children>
</GridPane> </GridPane>
<!-- verschiebbare Taskbar --> <!-- movable taskbar -->
<AnchorPane> <AnchorPane>
<fx:include fx:id="taskbarInclude" source="gameuicomponents/Taskbar.fxml"/> <fx:include fx:id="taskbarInclude" source="gameuicomponents/Taskbar.fxml"/>
</AnchorPane> </AnchorPane>
<!-- Gegner-Status 1: Eines von drei Panels, das Icon, Name und Kontostand des Mitspielers anzeigt --> <!-- Opponent Status 1: One of three panels displaying the opponent's icon, name, and account balance -->
<GridPane AnchorPane.leftAnchor="0.0" <GridPane AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="50"> AnchorPane.topAnchor="50">
@@ -103,7 +103,7 @@
</children> </children>
</GridPane> </GridPane>
<!-- Gegner-Status 2: Eines von drei Panels, das Icon, Name und Kontostand des Mitspielers anzeigt --> <!-- Opponent Status 2: One of three panels displaying the opponent's icon, name, and account balance -->
<GridPane AnchorPane.leftAnchor="0.0" <GridPane AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="20"> AnchorPane.topAnchor="20">
@@ -118,7 +118,7 @@
</children> </children>
</GridPane> </GridPane>
<!-- Gegner-Status 3: Eines von drei Panels, das Icon, Name und Kontostand des Mitspielers anzeigt --> <!-- Opponent Status 3: One of three panels that displays the opponent's icon, name, and account balance -->
<GridPane AnchorPane.leftAnchor="0.0" <GridPane AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="50"> AnchorPane.topAnchor="50">
@@ -5,16 +5,16 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<!-- <!--
Dieses Fenster wird später mit den Serveranfragen verknüpft, This window will later be linked to the server requests,
um Nachrichten von Mitspielern und Systemmeldungen in Echtzeit anzuzeigen. to display messages from other players and system messages in real time.
Der Chat unterscheidet intern zwischen: The chat internally distinguishes between:
- Player-to-Player (Privater 2-Personen-Chat) - Player-to-Player (Private 2-person chat)
- Lobby-Chat (Aktueller Raum) - Lobby Chat (Current room)
- Globaler Chat (Gesamter Server) - Global Chat (Entire server)
Features, die später implementiert werden sollen: Features planned for later implementation:
- Schicke Chat-Bubbles mit Namen und Uhrzeit. - Stylish chat bubbles with names and timestamps.
--> -->
<VBox xmlns="http://javafx.com/javafx/21" <VBox xmlns="http://javafx.com/javafx/21"
@@ -23,7 +23,7 @@
alignment="CENTER" alignment="CENTER"
stylesheets="@Chatui.css"> stylesheets="@Chatui.css">
<!-- Innenabstand: Schafft oben, rechts und unten 30 Pixel Platz, links nur 10 Pixel (asymmetrisch) --> <!-- Inner spacing: Creates 30 pixels of space at the top, right and bottom, only 10 pixels on the left (asymmetrical) -->
<padding> <padding>
<Insets top="30" right="30" bottom="30" left="10"/> <Insets top="30" right="30" bottom="30" left="10"/>
</padding> </padding>
@@ -38,16 +38,16 @@
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/> <Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
<Region minHeight="4" styleClass="chat-separator"/> <Region minHeight="4" styleClass="chat-separator"/>
<!-- Chatnachrichten werden hier hinzugefügt --> <!-- Chat messages will be added here -->
<ScrollPane fx:id="chatScrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER" VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane"> <ScrollPane fx:id="chatScrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER" VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
<content> <content>
<VBox fx:id="chatVBox" spacing="10" styleClass="chat-VBox"/> <VBox fx:id="chatVBox" spacing="10" styleClass="chat-VBox"/>
</content> </content>
</ScrollPane> </ScrollPane>
<!-- Eingabebereich --> <!-- Input area -->
<HBox spacing="10"> <HBox spacing="10">
<!-- TODO: Größe des TextFields dynamisch anpassen --> <!-- TODO: Dynamically adjust the size of the text field -->
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..." styleClass="gray-input-field" onAction="#sendMessage"/> <TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..." styleClass="gray-input-field" onAction="#sendMessage"/>
<Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage" styleClass="yellow-button"/> <Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage" styleClass="yellow-button"/>
</HBox> </HBox>
@@ -5,10 +5,11 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<!-- <!--
TODO: Haupt-platzhalter für spieler-status & eingabe. TODO: Main placeholder for player status & input.
Dieses Layout dient aktuell der visuellen Struktur. Sobald die GameEngine und
Serveranfragen (API/Requests) durchgeführt werden können, werden Name, Kontostand This layout currently serves as a visual structure. As soon as the game engine and
und Status-Anzeigen dynamisch mit Echtzeit-Daten vom Server befüllt. server requests (API/requests) can be processed, the name, account balance
and status displays will be dynamically populated with real-time data from the server.
--> -->
<VBox fx:id="playerStatusBox" <VBox fx:id="playerStatusBox"
@@ -20,7 +21,7 @@
spacing="0"> spacing="0">
<children> <children>
<!-- Bereich für den Spielernamen --> <!-- Area for player name -->
<HBox styleClass="status-inner-box-top" <HBox styleClass="status-inner-box-top"
alignment="CENTER_LEFT" alignment="CENTER_LEFT"
maxWidth="Infinity" maxWidth="Infinity"
@@ -31,11 +32,11 @@
</padding> </padding>
<Label text="NAME: " styleClass="status-label-small"/> <Label text="NAME: " styleClass="status-label-small"/>
<!-- TODO: fx:id="playerName": Wird später durch den User-Namen aus der Server-Abfrage ersetzt --> <!-- TODO: fx:id="playerName": Will later be replaced by the username from the server query -->
<Label fx:id="playerName" text="SPIELER" styleClass="status-value-text"/> <Label fx:id="playerName" text="SPIELER" styleClass="status-value-text"/>
</HBox> </HBox>
<!-- Schaft platz zwischen den Boxen --> <!-- Shaft space between the boxes -->
<HBox styleClass="status-inner-box-midle" <HBox styleClass="status-inner-box-midle"
alignment="CENTER_LEFT" alignment="CENTER_LEFT"
maxWidth="Infinity" maxWidth="Infinity"
@@ -46,7 +47,7 @@
</padding> </padding>
</HBox> </HBox>
<!-- Anzeige des Kapitals/Geldstands --> <!-- Display of capital/money balance -->
<HBox styleClass="status-inner-box-bottom" <HBox styleClass="status-inner-box-bottom"
alignment="CENTER_LEFT" alignment="CENTER_LEFT"
maxWidth="Infinity" maxWidth="Infinity"
@@ -60,7 +61,7 @@
<Label fx:id="playerMoney" text="0 $" styleClass="status-value-money"/> <Label fx:id="playerMoney" text="0 $" styleClass="status-value-money"/>
</HBox> </HBox>
<!-- TODO: User-Logo oder Icon: Platzhalter für das Profilbild oder das individuelle Logo des Spielers --> <!-- TODO: User logo or icon: Placeholder for the profile picture or the player's individual logo -->
<Pane prefHeight="0" maxWidth="Infinity"> <Pane prefHeight="0" maxWidth="Infinity">
<Region styleClass="status-circle" <Region styleClass="status-circle"
layoutX="-10" layoutX="-10"
@@ -4,7 +4,7 @@
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<!-- verschiebbare Taskbar --> <!-- movable taskbar -->
<HBox xmlns="http://javafx.com/javafx/21" <HBox xmlns="http://javafx.com/javafx/21"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents.TaskbarController" fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents.TaskbarController"
@@ -17,36 +17,36 @@
onMouseReleased="#onTaskbarReleased" onMouseReleased="#onTaskbarReleased"
layoutX="50.0" layoutY="710.0"> layoutX="50.0" layoutY="710.0">
<!-- Platzhalter-Buttons --> <!-- Placeholder buttons -->
<Button text="EINSTELLUNGEN" styleClass="gray-button" /> <Button text="EINSTELLUNGEN" styleClass="gray-button" />
<Button text="INFO" styleClass="gray-button" /> <Button text="INFO" styleClass="gray-button" />
<!-- Buten für den Casono Browser --> <!-- Buten for the Casono Browser -->
<Button text="HILFE" onAction="#onBrowserButtonClick" styleClass="gray-button" /> <Button text="HILFE" onAction="#onBrowserButtonClick" styleClass="gray-button" />
<!-- Vertikale-Trennlinie: Erzeugt eine optische Abgrenzung zwischen zwei Butten-Bereichen --> <!-- Vertical dividing line: Creates a visual separation between two button areas -->
<Separator orientation="VERTICAL" prefHeight="20" opacity="0.3" /> <Separator orientation="VERTICAL" prefHeight="20" opacity="0.3" />
<!-- Eingabefeld: Reagiert auf die Enter-Taste, um den Einsatz zu bestätigen --> <!-- Input field: Responds to the Enter key to confirm the entry -->
<TextField fx:id="taskbarInput" <TextField fx:id="taskbarInput"
promptText="Betrag setzen..." promptText="Betrag setzen..."
onKeyPressed="#onInputSubmitted" onKeyPressed="#onInputSubmitted"
styleClass="gray-input-field" styleClass="gray-input-field"
prefWidth="150" /> prefWidth="150" />
<!-- Bestätigungs-Button: Alternative zum Enter-Key, um den Einsatz abzusenden --> <!-- Confirmation button: Alternative to the Enter key to submit the entry -->
<Button text="SETZTEN" <Button text="SETZTEN"
onAction="#onInputSubmittedAction" onAction="#onInputSubmittedAction"
styleClass="yellow-button"/> styleClass="yellow-button"/>
<!-- Vertikale-Trennlinie: Erzeugt eine optische Abgrenzung zwischen zwei Butten-Bereichen --> <!-- Vertical dividing line: Creates a visual separation between two button areas -->
<Separator orientation="VERTICAL" prefHeight="20" opacity="0.3" /> <Separator orientation="VERTICAL" prefHeight="20" opacity="0.3" />
<!-- Menü-Button: Bricht das aktuelle Spiel ab und kehrt zum Hauptmenü zurück --> <!-- Menu button: Cancels the current game and returns to the main menu -->
<Button text="VERLASSEN" <Button text="VERLASSEN"
onAction="#onExitButtonClick" onAction="#onExitButtonClick"
styleClass="red-button"/> styleClass="red-button"/>
<!-- Innenabstand: Hält den Inhalt 10 Pixel von oben/unten und 20 Pixel von den Seiten fern --> <!-- Inner spacing: Keeps the content 10 pixels away from the top/bottom and 20 pixels from the sides -->
<padding> <padding>
<Insets top="10" right="20" bottom="10" left="20"/> <Insets top="10" right="20" bottom="10" left="20"/>
</padding> </padding>