From a05818cbe41168b749943b5d0ba19e5376d9004e Mon Sep 17 00:00:00 2001
From: Peter <pt033@hdm-stuttgart.de>
Date: Thu, 4 Jan 2024 14:05:39 +0100
Subject: [PATCH] add(ui): add screen calculator for responsive ui #14

---
 .../Controller/GameSceneController.java       | 57 ++++++++++++++-----
 .../Controller/Utilities/ScreenClasses.java   | 28 +++++++++
 .../Utilities/ScreenDimensionCalculator.java  | 12 ++++
 src/main/java/module-info.java                |  2 +
 src/main/resources/fxml/GameScene.fxml        | 13 +++--
 5 files changed, 93 insertions(+), 19 deletions(-)
 create mode 100644 src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenClasses.java
 create mode 100644 src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenDimensionCalculator.java

diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java
index 82dc6a44..1743c096 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java
@@ -1,5 +1,7 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
+import de.hdm_stuttgart.battlearena.Controller.Utilities.ScreenClasses;
+import de.hdm_stuttgart.battlearena.Controller.Utilities.ScreenDimensionCalculator;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityClass;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityFactory;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityType;
@@ -10,10 +12,14 @@ import de.hdm_stuttgart.battlearena.Model.Map.TileManager;
 import javafx.animation.AnimationTimer;
 import javafx.fxml.FXML;
 import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.geometry.Rectangle2D;
 import javafx.scene.canvas.Canvas;
 import javafx.scene.canvas.GraphicsContext;
 
 import javafx.scene.control.Slider;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.StackPane;
 import javafx.scene.layout.VBox;
 import javafx.scene.shape.Rectangle;
 import javafx.scene.text.Font;
@@ -39,8 +45,12 @@ public class GameSceneController implements Initializable {
     private VBox healthVBox, hpVBox;
     @FXML
     private Text playerHp, enemyHp;
-    private final int health = 900;
-    final private double  healthBarWidth = Screen.getPrimary().getVisualBounds().getWidth() / 2.844;
+    @FXML
+    private StackPane stackPane;
+    Screen screen = Screen.getPrimary();
+    Rectangle2D visualBounds = screen.getVisualBounds();
+    final private double healthBarWidth = screen.getBounds().getWidth() / 2.844;
+    ScreenDimensionCalculator screenCalculator = new ScreenDimensionCalculator();
 
     private GraphicsContext graphicsContext2D;
 
@@ -81,6 +91,8 @@ public class GameSceneController implements Initializable {
 
     @Override
     public void initialize(URL url, ResourceBundle resourceBundle) {
+        double diagonalInches = screenCalculator.calculateDiagonalInches(visualBounds.getWidth(),
+                visualBounds.getHeight(), screen.getDpi());
 //        for some reason scene builder overwrites css fonts bruh
         playerHp.setFont(Font.loadFont(getClass().getResourceAsStream("/fonts/StarshipShadow.ttf"), 55));
         enemyHp.setFont(Font.loadFont(getClass().getResourceAsStream("/fonts/StarshipShadow.ttf"), 55));
@@ -95,10 +107,37 @@ public class GameSceneController implements Initializable {
         playerHealth.setWidth(healthBarWidth);
         enemyHealth.setWidth(healthBarWidth);
 
+//        make it responsive
+        if (ScreenClasses.inRange((int) diagonalInches) == ScreenClasses.INCH27) {
+            canvas2D.setScaleX(1.2);
+            canvas2D.setScaleY(1.2);
+        } else if (ScreenClasses.inRange((int) diagonalInches) == ScreenClasses.INCH13_SURFACE) {
+//            TODO: make a enum for MacBook screens
+        } else {
+            canvas2D.setScaleX(0.87);
+            canvas2D.setScaleY(0.87);
+            playerHealth.setHeight(50);
+            enemyHealth.setHeight(50);
+            BorderPane.setMargin(stackPane, new Insets(-40, 0, 0, 0));
+        }
+        System.out.println("dpi: " + screen.getDpi());
+
+//        testing hp bar
+        slider.valueProperty().addListener((observableValue, oldValue, newValue) -> {
+            double newWidth = healthBarWidth * (newValue.doubleValue() / 100);
+            playerHealth.setWidth(newWidth);
+            playerHp.setText(newValue.intValue() + "%");
+        });
+        slider2.valueProperty().addListener((observableValue, oldValue, newValue) -> {
+            double newWidth = healthBarWidth * (newValue.doubleValue() / 100);
+            enemyHealth.setWidth(newWidth);
+            enemyHp.setText(newValue.intValue() + "%");
+        });
+
+        System.out.println("inches: " + diagonalInches);
+
         graphicsContext2D = canvas2D.getGraphicsContext2D();
         graphicsContext2D.setImageSmoothing(false);
-        canvas2D.setScaleX(1.2);
-        canvas2D.setScaleY(1.2);
 
         player = EntityFactory.createEntity(EntityType.PLAYER, graphicsContext2D, inputHandler, playerClass, this);
         enemy = EntityFactory.createEntity(EntityType.ENEMY_PLAYER, graphicsContext2D, inputHandler, enemyClass, this);
@@ -115,16 +154,6 @@ public class GameSceneController implements Initializable {
         };
         gameLoop.start();
         log.debug("Game loop started");
-
-//        testing
-        slider.valueProperty().addListener((observableValue, oldValue, newValue) -> {
-            playerHealth.setWidth(health * (newValue.doubleValue() / 100));
-            playerHp.setText(newValue.intValue() + "%");
-        });
-        slider2.valueProperty().addListener((observableValue, oldValue, newValue) -> {
-            enemyHealth.setWidth(health * (newValue.doubleValue() / 100));
-            enemyHp.setText(newValue.intValue() + "%");
-        });
     }
 
     private void updateContent() {
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenClasses.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenClasses.java
new file mode 100644
index 00000000..469d628a
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenClasses.java
@@ -0,0 +1,28 @@
+package de.hdm_stuttgart.battlearena.Controller.Utilities;
+
+public enum ScreenClasses {
+//    enums have a range because the screen calculations are not precise, especially with screen scaling in the OS settings
+    INCH27(26, 28),
+    INCH24(23, 25),
+    INCH13_SURFACE(12, 14);
+
+    final int lBound, uBound;
+
+    ScreenClasses(int lBound, int uBound) {
+        this.lBound = lBound;
+        this.uBound = uBound;
+    }
+
+    public static ScreenClasses inRange(int inches) {
+        for (ScreenClasses screens : ScreenClasses.values()) {
+            if (screens.isInRange(inches)) {
+                return screens;
+            }
+        }
+        return null;
+    }
+
+    private boolean isInRange(int inches) {
+        return inches >= lBound && inches <= uBound;
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenDimensionCalculator.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenDimensionCalculator.java
new file mode 100644
index 00000000..4dee18cf
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ScreenDimensionCalculator.java
@@ -0,0 +1,12 @@
+package de.hdm_stuttgart.battlearena.Controller.Utilities;
+
+public class ScreenDimensionCalculator {
+    public double calculateDiagonalInches(double width, double height, double dpi) {
+        double diagonalPixels = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+        double diagonalInches = diagonalPixels / dpi;
+        System.out.println("diagonal pixels: " + diagonalPixels);
+        System.out.println("width: " + width);
+        System.out.println("height: " + height);
+        return diagonalInches;
+    }
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 13a3d1d3..8a313280 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -12,4 +12,6 @@ module gui {
     exports de.hdm_stuttgart.battlearena.Model.Entity;
     exports de.hdm_stuttgart.battlearena.Model.Inputs;
     exports de.hdm_stuttgart.battlearena.Model.Map;
+    exports de.hdm_stuttgart.battlearena.Controller.Utilities;
+    opens de.hdm_stuttgart.battlearena.Controller.Utilities to javafx.fxml;
 }
\ No newline at end of file
diff --git a/src/main/resources/fxml/GameScene.fxml b/src/main/resources/fxml/GameScene.fxml
index 2eaf6522..a85f39a2 100644
--- a/src/main/resources/fxml/GameScene.fxml
+++ b/src/main/resources/fxml/GameScene.fxml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
+<?import javafx.geometry.Insets?>
 <?import javafx.scene.canvas.Canvas?>
 <?import javafx.scene.control.Slider?>
 <?import javafx.scene.layout.BorderPane?>
@@ -11,13 +12,15 @@
 <?import javafx.scene.text.Font?>
 <?import javafx.scene.text.Text?>
 
-
 <BorderPane fx:id="gameScene" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.GameSceneController">
    <center>
-      <StackPane prefHeight="400.0" prefWidth="600.0" BorderPane.alignment="CENTER">
+      <StackPane fx:id="stackPane" prefHeight="400.0" prefWidth="600.0" BorderPane.alignment="CENTER">
          <children>
             <Canvas fx:id="canvas2D" height="864.0" width="864.0" />
          </children>
+         <BorderPane.margin>
+            <Insets />
+         </BorderPane.margin>
       </StackPane>
    </center>
    <top>
@@ -30,7 +33,7 @@
                   <Rectangle fx:id="enemyHealth" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="70.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" width="900.0" />
                </children>
             </VBox>
-            <VBox fx:id="hpVBox" alignment="CENTER_LEFT" spacing="20.0">
+            <VBox fx:id="hpVBox" alignment="CENTER_LEFT" spacing="20.0" HBox.hgrow="NEVER">
                <children>
                   <Pane VBox.vgrow="ALWAYS" />
                   <Text fx:id="playerHp" strokeType="OUTSIDE" strokeWidth="0.0" VBox.vgrow="ALWAYS">
@@ -51,8 +54,8 @@
    <left>
       <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
          <children>
-            <Slider fx:id="slider2" orientation="VERTICAL" />
-            <Slider fx:id="slider" orientation="VERTICAL" />
+            <Slider fx:id="slider" orientation="VERTICAL" value="100.0" />
+            <Slider fx:id="slider2" orientation="VERTICAL" value="100.0" />
          </children>
       </VBox>
    </left>
-- 
GitLab