diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatController.java new file mode 100644 index 0000000..563d912 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/chatui/ChatController.java @@ -0,0 +1,89 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; +import javafx.scene.control.Label; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import javafx.scene.control.ScrollPane; + +/** + * Controller-Klasse für das Chat-System innerhalb der Spieloberfläche. + * + * Verwaltet das Anzeigen von Chatnachrichten, das Eingabefeld für eigene Nachrichten + * sowie den Senden-Button. Unterstützt drei Arten von Nachrichten: + * - Player-to-Player (Privat) + * - Lobby-Chat (Raum) + * - Globaler Chat (Serverweit) + * + * Nachrichten werden in einem {@link VBox}-Container als {@link Label} angezeigt. + * Eigene Nachrichten werden über {@link #onSendToNetwork(String)} an das + * Netzwerkprotokoll weitergeleitet, während eingehende Nachrichten über + * {@link #receiveMessage(String, String)} verarbeitet und angezeigt werden. + * + * Hinweis: Einige TODOs stehen in der zugehörigen FXML-Datei + */ +public class ChatController { + + @FXML + private VBox chatVBox; + + @FXML + private TextField inputField; + + @FXML + private Button sendButton; + + @FXML + private ScrollPane chatScrollPane; + + /** + * Initialisiert den ChatController nach dem Laden der FXML. + */ + public void initialize() { + inputField.setOnAction(event -> sendMessage()); + chatScrollPane.vvalueProperty().bind(chatVBox.heightProperty()); + } + + /** + * Diese Methode wird vom Senden-Button oder Enter ausgelöst. + * Sie gibt die eigene Nachricht an das Netzwerkprotokoll weiter. + */ + @FXML + private void sendMessage() { + String message = inputField.getText().trim(); + if (!message.isEmpty()) { + inputField.clear(); + + // Hier wird die eigene Nachricht ans Netzwerkprotokoll übergeben + onSendToNetwork(message); + } + } + + /** + * Diese Funktion muss vom Netzwerkprotokoll aufgerufen werden, + * wenn eine neue Nachricht von einem anderen Spieler kommt. + * @param player Name des Spielers + * @param message Nachricht des Spielers + */ + public void receiveMessage(String player, String message) { + String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm")); + Label label = new Label("[" + time + "] " + player + ": " + message); + label.getStyleClass().add("info-text"); + label.setWrapText(true); // Zeilenumbruch aktivieren + label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(20)); + chatVBox.getChildren().add(label); + } + + /** + * Schnittstelle zum Netzwerkprotokoll. + * Diese Funktion wird automatisch aufgerufen, wenn der Benutzer eine eigene Nachricht sendet. + * @param message Nachricht, die der Benutzer abgeschickt hat + */ + public void onSendToNetwork(String message) { + // TODO: Netzwerkcode einfügen + receiveMessage("Du", message); + } +} \ No newline at end of file diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java new file mode 100644 index 0000000..2862c99 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java @@ -0,0 +1,40 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui; + +// import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +// import javafx.scene.control.TextField; +// import javafx.scene.input.KeyCode; +// import javafx.scene.input.KeyEvent; +// import javafx.scene.input.MouseEvent; +// import javafx.scene.layout.HBox; +// import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +// import javafx.stage.Stage; +// import javafx.scene.Scene; +// import javafx.scene.web.WebView; + +/** + * Controller für die Casino-Spielfläche. + * + * Verantwortlich für: + * - die Darstellung des Pokertisches und der Spieleroberfläche, + * - die Verarbeitung von Benutzereingaben, + * - die Schnittstelle zur GameEngine und zum Netzwerkprotokoll. + * + * Hinweise: + * - Die Methode `onTableClick()` dient aktuell nur als Test-Logik. + * Sie ist ggf. nicht mehr funktionsfähig und wird zukünftig + * durch die finale Spielinteraktion ersetzt. + */ +public class CasinoGameController { + + @FXML private Label welcomeText; + @FXML private VBox casinoTable; + + // TODO: Test-Logik: wird durch echte Spielinteraktionen ersetzt, sobald die GameEngine fertig ist + @FXML + public void onTableClick() { + welcomeText.setText("Einsatz akzeptiert!"); + } +} \ No newline at end of file diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameUI.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameUI.java new file mode 100644 index 0000000..af94daf --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameUI.java @@ -0,0 +1,48 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.stage.Stage; + +import java.io.IOException; + +/** + * Hauptklasse für das Casino-Spiel-UI. + * + * Startet die JavaFX-Anwendung, lädt die grafische Oberfläche aus der FXML-Datei + * und initialisiert die Haupt-Stage für das Spiel. + * + * Aufgaben: + * - Lädt die FXML-Oberfläche "/ui-structure/Casinogameui.fxml". + * - Lädt das Anwendungs-Icon aus "/images/logoinverted.png". + * - Startet die Anwendung im Vollbildmodus. + */ +public class CasinoGameUI extends Application { + + /** + * Startet die Haupt-Stage der Anwendung. + * + * @param stage Die vom System bereitgestellte Haupt-Stage. + * @throws IOException Wenn die FXML-Datei oder Ressourcen nicht geladen werden können. + */ + @Override + public void start(Stage stage) throws IOException { + FXMLLoader fxmlLoader = new FXMLLoader(CasinoGameUI.class.getResource("/ui-structure/casinogameui.fxml")); + Scene scene = new Scene(fxmlLoader.load(), 1200, 800); + stage.setTitle("Casono (GAME)"); + + stage.getIcons().add(new javafx.scene.image.Image(getClass().getResource("/images/logoinverted.png").toExternalForm())); + stage.setScene(scene); + stage.setFullScreen(true); + stage.show(); + } + + /** + * Startpunkt der Anwendung. + * @param args Befehlszeilenargumente. + */ + public static void main(String[] args) { + launch(); + } +} \ No newline at end of file diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/CasinoBrowserController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/CasinoBrowserController.java new file mode 100644 index 0000000..d650221 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/CasinoBrowserController.java @@ -0,0 +1,364 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents; + +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.*; +import javafx.scene.shape.Rectangle; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import javafx.stage.Stage; + +import java.net.*; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +/** + * Experimenteller integrierter Browser für Casono. + * + * Diese Klasse implementiert einen einfachen eingebetteten Webbrowser + * auf Basis von {@link javafx.scene.web.WebView}. Der Browser dient + * primär als Hilfswerkzeug innerhalb des Spiels, um externe Inhalte + * wie Webseiten oder Videos anzuzeigen. + * + * Status + * Der Browser befindet sich derzeit in einer experimentellen Phase. + * Einige Sicherheitsmechanismen basieren auf experimentellen + * KI-gestützten Empfehlungen und können sich in zukünftigen + * Versionen noch ändern. + * + * Zweck + * Der Browser wird aktuell experimentell genutzt, um: + * Pokerregeln direkt im Spiel zu erklären + * Hilfeseiten oder Dokumentationen anzuzeigen + * Videos (z.B. Tutorials oder Erklärungen) über Plattformen wie YouTube abzuspielen + * + * Sicherheitsmechanismen + * Da externe Webseiten geladen werden können, wurden einige + * grundlegende Schutzmaßnahmen integriert: + * - HTTPS-Zwang für Webseiten + * - Whitelist für bekannte Domains + * - Warnung bei unbekannten Webseiten + * - JavaScript standardmäßig deaktiviert (man kann es jedoch für Google etc. einschalten) + * - Popup-Blocker + * - Automatische Cookie-Löschung beim Schließen + */ +public class CasinoBrowserController { + private static final Set TRUSTED_DOMAINS = new HashSet<>(); + private static final CookieManager COOKIE_MANAGER = + new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER); + + static { + CookieHandler.setDefault(COOKIE_MANAGER); + + TRUSTED_DOMAINS.add("wikipedia.org"); + TRUSTED_DOMAINS.add("github.com"); + TRUSTED_DOMAINS.add("oracle.com"); + TRUSTED_DOMAINS.add("stackoverflow.com"); + TRUSTED_DOMAINS.add("docs.oracle.com"); + TRUSTED_DOMAINS.add("developer.mozilla.org"); + TRUSTED_DOMAINS.add("maven.apache.org"); + TRUSTED_DOMAINS.add("gradle.org"); + TRUSTED_DOMAINS.add("spring.io"); + TRUSTED_DOMAINS.add("jetbrains.com"); + TRUSTED_DOMAINS.add("google.com"); + TRUSTED_DOMAINS.add("bing.com"); + TRUSTED_DOMAINS.add("duckduckgo.com"); + TRUSTED_DOMAINS.add("metager.de"); + TRUSTED_DOMAINS.add("unibas.ch"); + TRUSTED_DOMAINS.add("mojeek.com"); + TRUSTED_DOMAINS.add("searx.be "); + TRUSTED_DOMAINS.add("startpage.com"); + } + + private static boolean javascriptEnabled = false; + + /** + * Löscht alle gespeicherten Cookies der aktuellen Browser-Sitzung. + */ + private static void clearCookies() { + try { + COOKIE_MANAGER.getCookieStore().removeAll(); + } catch (Exception ignored) {} + } + + /** + * Öffnet ein neues Browserfenster und lädt eine angegebene Webseite. + * + * Falls die Webseite nicht zur Liste vertrauenswürdiger Domains gehört, + * wird der Benutzer gefragt, ob die Seite dennoch geladen werden soll. + * + * @param url die Startadresse der Webseite, die geladen werden soll + */ + public static void open(String url) { + Platform.runLater(() -> { + Stage stage = new Stage(); + + WebView webView = new WebView(); + WebEngine engine = webView.getEngine(); + + engine.setJavaScriptEnabled(false); + + // Popup Blocker + engine.setCreatePopupHandler(config -> { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("Popup blockiert"); + alert.setHeaderText(null); + alert.setContentText("Popup wurde aus Sicherheitsgründen blockiert."); + + try { + Image logo = + new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png")); + Image logomain = + new Image(CasinoBrowserController.class.getResourceAsStream("/images/logo.png")); + + if (logo != null) { + Stage alertStage = (Stage) alert.getDialogPane().getScene().getWindow(); + if (alertStage != null) { + alertStage.getIcons().add(logo); + } + } + + if (logomain != null) { + ImageView logoView = new ImageView(logomain); + logoView.setFitHeight(40); + logoView.setPreserveRatio(true); + alert.setGraphic(logoView); + } + } catch (Exception e) { + System.err.println("Logo konnte nicht geladen werden"); + } + + alert.showAndWait(); + return null; + }); + + webView.getStyleClass().add("web-view"); + + StackPane webContainer = new StackPane(webView); + webContainer.getStyleClass().add("browser-web-view"); + VBox.setVgrow(webContainer, Priority.ALWAYS); + + Rectangle clip = new Rectangle(); + clip.setArcWidth(40); + clip.setArcHeight(40); + webView.setClip(clip); + + webView.widthProperty().addListener((o,a,b)->clip.setWidth(b.doubleValue())); + webView.heightProperty().addListener((o,a,b)->clip.setHeight(b.doubleValue())); + + ImageView browserLogo = new ImageView(); + + try { + Image logo = + new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png")); + Image logomain = + new Image(CasinoBrowserController.class.getResourceAsStream("/images/logo.png")); + + if (logo != null) { + stage.getIcons().add(logo); + } + + if (logomain != null) { + browserLogo.setImage(logomain); + browserLogo.setFitHeight(30); + browserLogo.setPreserveRatio(true); + } + } catch (Exception e) { + System.err.println("Logo konnte nicht geladen werden"); + } + + // URL Feld + TextField urlField = new TextField(url); + urlField.getStyleClass().add("gray-input-field"); + HBox.setHgrow(urlField, Priority.ALWAYS); + + Label securityLabel = new Label("SICHER"); + securityLabel.getStyleClass().add("security-label"); + + // JS Toggle + Button jsToggle = new Button("JS EINSCHALTEN"); + jsToggle.getStyleClass().add("red-button"); + + jsToggle.setOnAction(e -> { + javascriptEnabled = !javascriptEnabled; + engine.setJavaScriptEnabled(javascriptEnabled); + + if (javascriptEnabled) { + jsToggle.setText("JS AUSSCHALTEN"); + jsToggle.getStyleClass().removeAll("red-button"); + jsToggle.getStyleClass().add("yellow-button"); + + } else { + jsToggle.setText("JS EINSCHALTEN"); + jsToggle.getStyleClass().removeAll("yellow-button"); + jsToggle.getStyleClass().add("red-button"); + } + }); + + // Navigation + Button backBtn = new Button("<"); + backBtn.getStyleClass().add("gray-button"); + backBtn.setOnAction(e -> { + if(engine.getHistory().getCurrentIndex() > 0){ + engine.getHistory().go(-1); + } + }); + + Button fwdBtn = new Button(">"); + fwdBtn.getStyleClass().add("gray-button"); + fwdBtn.setOnAction(e -> { + if(engine.getHistory().getCurrentIndex() < + engine.getHistory().getEntries().size()-1){ + engine.getHistory().go(1); + } + }); + + // Reload Button + Button reloadBtn = new Button("⟳"); + reloadBtn.getStyleClass().add("gray-button"); + reloadBtn.setOnAction(e -> engine.reload()); + + // Close + Button closeBtn = new Button("X"); + closeBtn.getStyleClass().add("red-button"); + closeBtn.setOnAction(e -> { + webView.getEngine().load("about:blank"); + clearCookies(); + stage.close(); + + }); + + // URL Enter + urlField.setOnAction(e -> + loadUrlSafely(engine, urlField.getText(), securityLabel)); + engine.locationProperty().addListener((obs,o,n)->urlField.setText(n)); + + // Taskbar + HBox taskbar = new HBox( + 10, + browserLogo, + backBtn, + fwdBtn, + reloadBtn, + urlField, + jsToggle, + securityLabel, + closeBtn + ); + + taskbar.getStyleClass().add("taskbar-browser"); + taskbar.setAlignment(Pos.CENTER_LEFT); + + // Root + VBox root = new VBox(10, taskbar, webContainer); + root.getStyleClass().add("browser-root"); + root.setPadding(new Insets(10)); + Scene scene = new Scene(root,1200,800); + var css = CasinoBrowserController.class.getResource("/ui-structure/casinogameui.css"); + + if(css != null) { + scene.getStylesheets().add(css.toExternalForm()); + } + + // F5 Reload + scene.setOnKeyPressed(event -> { + switch (event.getCode()) { + case F5 -> engine.reload(); + } + }); + + stage.setScene(scene); + stage.setTitle("Casono Browser"); + loadUrlSafely(engine, url, securityLabel); + stage.show(); + }); + } + + /** + * Lädt eine URL in den Browser, nachdem grundlegende Sicherheitsprüfungen + * durchgeführt wurden. + * + * Vor dem Laden einer Seite werden folgende Prüfungen durchgeführt: + * - Überprüfung des Protokolls (nur HTTPS erlaubt) + * - Überprüfung der Domain gegen eine Whitelist + * - Schutz vor Domain-Spoofing (Domain-Vortäuschung) + * + * Falls eine Domain nicht als vertrauenswürdig eingestuft wird, + * muss der Benutzer bestätigen, dass die Seite dennoch geöffnet + * werden darf. + * + * @param engine der WebEngine-Renderer des Browsers + * @param url die zu ladende Webadresse + * @param securityLabel Label zur Anzeige des aktuellen Sicherheitsstatus + */ + private static void loadUrlSafely(WebEngine engine, String url, Label securityLabel) { + try { + if(!url.startsWith("http")) { + url = "https://" + url; + } + + URI uri = new URI(url); + + // HTTPS Pflicht + if(!"https".equalsIgnoreCase(uri.getScheme())) { + securityLabel.setText("BLOCKIERT"); + return; + } + + String host = uri.getHost(); + if(host == null) { + securityLabel.setText("ERROR"); + return; + } + + // Sicherer Domain Check + boolean trusted = TRUSTED_DOMAINS.stream().anyMatch(domain -> + host.equals(domain) || host.endsWith("." + domain)); + + if(!trusted) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + + alert.setTitle("Unbekannte Website"); + alert.setHeaderText("Diese Website ist nicht bekannt"); + alert.setContentText( + host + "\n\nDiese Seite ist nicht vom Casono Browser verifiziert.\nMöchten Sie sie trotzdem öffnen?" + ); + + Image logo = new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png")); + if (logo != null) { + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + if(stage != null) { + stage.getIcons().add(logo); + } + ImageView logomain = new ImageView(logo); + logomain.setFitHeight(50); + logomain.setPreserveRatio(true); + alert.setGraphic(logomain); + } + + alert.getDialogPane().setPrefSize(600,300); + Optional result = alert.showAndWait(); + + if(result.isEmpty() || result.get() != ButtonType.OK) { + securityLabel.setText("BLOCKIERT"); + return; + } + + securityLabel.setText("UNBEKANNT"); + } else { + securityLabel.setText("SICHER"); + } + engine.load(uri.toString()); + } + + catch (Exception e) { + securityLabel.setText("ERROR"); + } + } +} \ No newline at end of file diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/TaskbarController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/TaskbarController.java new file mode 100644 index 0000000..cb25954 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/gameuicomponents/TaskbarController.java @@ -0,0 +1,133 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents; + +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; + +/** + * Controller für die interaktive Taskleiste innerhalb der Poker-UI. + * + * Verantwortlich für: + * - Drag-and-Drop-Verschieben der Taskleiste, + * - Eingabe und Verwaltung von Spieleinsätzen, + * - Steuerung allgemeiner Menüfunktionen wie Exit. + */ +public class TaskbarController { + + @FXML private HBox taskbar; + @FXML private TextField taskbarInput; + + private double xOffset = 0; + private double yOffset = 0; + + /** + * Wird aufgerufen, wenn die Taskleiste mit der Maus gedrückt wird. + * Speichert die relative Position, um später korrekt zu verschieben. + * + * @param event Das Mausereignis + */ + @FXML + private void onTaskbarPressed(MouseEvent event) { + xOffset = event.getSceneX() - taskbar.getLayoutX(); + yOffset = event.getSceneY() - taskbar.getLayoutY(); + } + + /** + * Wird aufgerufen, während die Taskleiste mit der Maus gezogen wird. + * Aktualisiert die Position und skaliert die Taskleiste leicht zur visuellen Rückmeldung. + * + * TODO: Es muss noch gefixt werden, dass die Taskleiste nicht aus dem Fenster verschwinden kann. + * + * @param event Das Mausereignis + */ + @FXML + private void onTaskbarDragged(MouseEvent event) { + taskbar.setLayoutX(event.getSceneX() - xOffset); + taskbar.setLayoutY(event.getSceneY() - yOffset); + + taskbar.setScaleX(0.9); + taskbar.setScaleY(0.9); + } + + /** + * Wird aufgerufen, wenn die Maus über der Taskleiste losgelassen wird. + * Setzt die Skalierung der Taskleiste wieder auf Normalgröße. + * + * @param event Das Mausereignis + */ + @FXML + private void onTaskbarReleased(MouseEvent event) { + taskbar.setScaleX(1.0); + taskbar.setScaleY(1.0); + } + + /** + * Wird aufgerufen, wenn im Textfeld die Enter-Taste gedrückt wird. + * + * @param event Das Tastaturereignis + */ + @FXML + private void onInputSubmitted(KeyEvent event) { + if (event.getCode() == KeyCode.ENTER) { + processBet(); + } + } + + /** + * Wird aufgerufen, wenn der Submit-Button in der Taskleiste gedrückt wird. + * Löst die Verarbeitung des Einsatzes aus. + */ + @FXML + private void onInputSubmittedAction() { + processBet(); + } + + /** + * Wird aufgerufen, wenn der Exit-Button in der Taskleiste gedrückt wird. + * + * TODO: Logik implementieren, um zur Lobby zurückzukehren, + * ohne die gesamte Anwendung zu schließen (kein System.exit/Platform.exit). + */ + @FXML + private void onExitButtonClick() { + Platform.exit(); + } + + /** + * Verarbeitet den im Textfeld eingegebenen Einsatz. + * Es werden ausschließlich ganzzahlige Werte im Bereich von 5 bis 100.000 + * Credits akzeptiert, die einem Vielfachen von 5 entsprechen (5er-Schritte). + * Der Einsatz wird aktuell nur auf der Konsole ausgegeben. + */ + private void processBet() { + String input = taskbarInput.getText(); + try { + int credits = Integer.parseInt(input.trim()); + + if (credits >= 5 && credits <= 100000 && credits % 5 == 0) { + // TODO: Credits müssen an die GameEngine gesendet werden + System.out.println("Einsatz gesetzt: " + credits + " Casono Credits"); + taskbarInput.clear(); + } else { + System.out.println("Fehler: Nur 5er-Schritte (5, 10, ... 100.000) erlaubt!"); + } + } catch (NumberFormatException e) { + System.out.println("Fehler: Bitte nur eine Zahl eingeben!"); + } + } + + /** + * Öffnet den integrierten Casono Webbrowser. + * + * TODO: Ersetze die Start-URL durch die offizielle Projekt-Website (z.B. Tipps & Tricks Seite), + * sobald die Inhalte für Strategien und Support bereitstehen. + */ + @FXML + private void onBrowserButtonClick() { + CasinoBrowserController.open("wikipedia.org"); + } +} \ No newline at end of file diff --git a/src/main/resources/ui-structure/Casinogameui.fxml b/src/main/resources/ui-structure/Casinogameui.fxml new file mode 100644 index 0000000..91bbe26 --- /dev/null +++ b/src/main/resources/ui-structure/Casinogameui.fxml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/ui-structure/casinogameui.css b/src/main/resources/ui-structure/casinogameui.css new file mode 100644 index 0000000..a512edc --- /dev/null +++ b/src/main/resources/ui-structure/casinogameui.css @@ -0,0 +1,251 @@ +.root { + -fx-background-color: #000000; + -fx-font-family: "Monospaced", "Courier New"; /* Schriftart */ +} + +.background { + -fx-background-image: url("/images/background.png"); + -fx-background-size: cover; /* Bild füllt das ganze Fenster aus */ + /* Zentriert das Bild und verhindert, dass es sich kachelartig wiederholt */ + -fx-background-position: center center; + -fx-background-repeat: no-repeat; +} + +.info-text { + -fx-text-fill: #ffffff; + -fx-font-size: 16px; +} + +.casino-table { + -fx-background-color: #0d9e3b; + -fx-background-radius: 210; + -fx-border-radius: 200; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 12; + /*-fx-min-height: 60vh;*/ + /*-fx-max-height: 60vh;*/ + /*-fx-min-width: 90vh;*/ + /*-fx-max-width: 90vh;*/ + -fx-effect: dropshadow(one-pass-box, rgba(0,0,0,0.8), 0, 0, 15, 15); +} + +.dealer-box { + -fx-background-color: #ffffff; + -fx-border-color: #000000; + -fx-border-width: 3; + -fx-background-radius: 0; + -fx-border-radius: 0; + -fx-min-width: 70; + -fx-min-height: 100; + -fx-effect: dropshadow(one-pass-box, rgba(0,0,0,0.8), 0, 0, 4, 4); +} + +.table-title { + -fx-text-fill: #ffffff; + -fx-font-size: 28px; + -fx-font-weight: bold; + -fx-effect: dropshadow(one-pass-box, #000000, 0, 0, 3, 3); +} + +.taskbar { + -fx-background-color: rgba(13, 158, 59); + -fx-background-radius: 23; + -fx-border-radius: 20; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 3; + -fx-padding: 10 25; + -fx-cursor: move; + -fx-effect: dropshadow(one-pass-box, rgba(0,0,0,0.8), 0, 0, 5, 5); + transition: all 0.2s ease-in-out; +} + +.taskbar:hover { + -fx-border-color: #ffffff; +} + +.black-input-field { + -fx-background-color: #1a1a1a; + -fx-text-fill: #ffffff; + -fx-font-family: "Courier New"; + -fx-font-weight: bold; + -fx-background-radius: 8; + -fx-border-radius: 8; + -fx-border-color: #444444; + -fx-border-width: 2; + -fx-padding: 5 12; +} + +.black-input-field:hover { + -fx-translate-y: -3; + -fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3); +} + + +.black-input-field:focused { + -fx-border-color: #ffffff; + -fx-background-color: #000000; +} + +.gray-input-field { + -fx-background-color: #333333; + -fx-text-fill: #ffffff; + -fx-font-family: "Courier New"; + -fx-font-weight: bold; + -fx-background-radius: 8; + -fx-border-radius: 8; + -fx-border-color: #666666; + -fx-color-color: #cccccc; + -fx-border-width: 2; + -fx-padding: 5 12; +} + +.gray-input-field:hover { + -fx-translate-y: -3; + -fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3); +} + +.gray-input-field:focused { + -fx-border-color: #ffffff; + -fx-background-color: #333333; +} + +.yellow-button { + -fx-background-color: #b8860b; + -fx-border-color: #ffd700; + -fx-text-fill: #ffffff; +} + +.red-button { + -fx-background-color: #8b0000; + -fx-border-color: #ff4444; + -fx-text-fill: #ffffff; +} + +.gray-button { + -fx-background-color: #333333; + -fx-border-color: #666666; + -fx-text-fill: #cccccc; +} + +.gray-button, .yellow-button, .red-button { + -fx-background-radius: 12; + -fx-border-radius: 12; + -fx-font-family: "Courier New"; + -fx-font-weight: bold; + -fx-border-width: 2; + -fx-padding: 6 15; + -fx-cursor: hand; +} + +.gray-button:hover, .yellow-button:hover, .red-button:hover { + -fx-translate-y: -3; + -fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3); +} + +.player-status-pane { + -fx-background-color: rgba(13, 158, 59, 0); + -fx-background-radius: 15; + -fx-border-radius: 15; + /* -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 2; + -fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 10, 0, 0, 4);*/ +} + +.player-status-pane:hover { + -fx-translate-y: -3; +} + +.status-inner-box-top { + -fx-background-color: rgba(13, 158, 59); + -fx-background-radius: 19; + -fx-border-radius: 15; + -fx-padding: 5 10; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 3; + -fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3); +} + +.status-inner-box-midle { + -fx-background-color: rgba(13, 158, 59, 0); +} + +.status-inner-box-bottom { + -fx-background-color: rgba(13, 158, 59); + -fx-background-radius: 19; + -fx-border-radius: 15; + -fx-padding: 5 10; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 3; + -fx-effect: dropshadow(one-pass-box, rgba(0, 0, 0, 0.8), 0, 0, 3, 3); +} + +.status-label-small { + -fx-text-fill: #ffffff; + -fx-font-family: "Monospaced"; /* Schriftart */ + -fx-font-size: 15px; +} + +.status-value-text { + -fx-text-fill: #ffffff; + -fx-font-family: "Monospaced"; /* Schriftart */ + -fx-font-size: 15px; + -fx-font-weight: bold; +} + +.status-value-money { + -fx-text-fill: #ffffff; + -fx-font-family: "Monospaced"; /* Schriftart */ + -fx-font-size: 15px; + -fx-font-weight: bold; +} + +.status-circle { + -fx-background-color: #000000; + -fx-background-radius: 50; + -fx-border-color: #ffffff; + -fx-border-width: 3; + -fx-border-radius: 50; +} + +.browser-root { + -fx-background-image: url("/images/background.png"); + -fx-background-size: cover; + -fx-background-position: center; + -fx-background-color: #0b2d15; +} + +.browser-web-view { + -fx-background-color: rgb(13, 158, 59); + -fx-background-radius: 23; + -fx-border-radius: 20; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 3; + -fx-padding: 0; + -fx-cursor: default; + -fx-effect: dropshadow(one-pass-box, rgba(0,0,0,0.8), 0, 0, 5, 5); +} + +.web-view { + -fx-background-color: transparent; +} + +.taskbar-browser { + -fx-background-color: rgb(13, 158, 59); + -fx-background-radius: 23; + -fx-border-radius: 20; + -fx-border-color: #5c3d10 #3d260a #3d260a #5c3d10; + -fx-border-width: 3; + -fx-padding: 10 25; + -fx-cursor: default; + -fx-effect: dropshadow(one-pass-box, rgba(0,0,0,0.8), 0, 0, 5, 5); +} + +/*.taskbar-browser:hover {*/ +/* -fx-border-color: #ffffff;*/ +/*}*/ + +.security-label { + -fx-text-fill: #000000; + -fx-font-weight: bold; + -fx-font-size: 16px; +} diff --git a/src/main/resources/ui-structure/components/chatbox.fxml b/src/main/resources/ui-structure/components/chatbox.fxml new file mode 100644 index 0000000..3e518ba --- /dev/null +++ b/src/main/resources/ui-structure/components/chatbox.fxml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + +