From bcdc129e6770c42a517550cf2f88d258d8ae90b8 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Mon, 11 May 2026 14:29:41 +0200 Subject: [PATCH] Shadows, Zoom, Icons added --- .../polimi/ingsw/gc14/ClientLauncherGUI.java | 2 - .../gc14/View/GUI/MainFXMLController.java | 267 +++++++++++++----- src/main/resources/GUIScene/main.fxml | 8 +- src/main/resources/GUIScene/styles.css | 15 +- 4 files changed, 206 insertions(+), 86 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java index 9c59ef6..913de38 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java @@ -14,8 +14,6 @@ public class ClientLauncherGUI extends Application { @Override public void start(Stage stage) { - Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); - LoginView loginView = new LoginView(); GUI view = new GUI(stage); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java index 08d2851..84da107 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java @@ -8,16 +8,26 @@ import it.polimi.ingsw.gc14.Model.Game; import it.polimi.ingsw.gc14.Model.PlayableCard; import it.polimi.ingsw.gc14.Model.Player; import it.polimi.ingsw.gc14.Model.Slot; +import javafx.animation.ScaleTransition; import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; import javafx.scene.control.Label; +import javafx.scene.effect.ColorAdjust; +import javafx.scene.effect.DropShadow; import javafx.scene.image.*; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; +import javafx.scene.paint.Color; import javafx.scene.shape.*; +import javafx.scene.text.Font; import javafx.stage.Popup; +import javafx.util.Duration; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; public class MainFXMLController { @@ -42,6 +52,7 @@ public class MainFXMLController { private Game model; private ClientController controller; private String username; + private final Map cardCache = new HashMap<>(); public void setModel(Game model) {this.model = model;} public void setController(ClientController controller) {this.controller = controller;} @@ -52,7 +63,8 @@ public class MainFXMLController { @FXML public void initialize() { - // Reapply CSS + // Import font and apply CSS + Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> { if (newScene != null) { newScene.getRoot().applyCss(); @@ -73,6 +85,80 @@ public class MainFXMLController { renderSidePanel(); } + // ==== HELPER ==== + private ImageView createSlot(Slot slot) { + ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-"+slot.getSlotId()+".png"))); + img.setFitHeight(240); + img.setPreserveRatio(true); + + Rectangle clip = new Rectangle(); + clip.setWidth(img.getBoundsInLocal().getWidth()); + clip.setHeight(240); + clip.setArcWidth(20); + clip.setArcHeight(20); + img.setClip(clip); + return img; + } + private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow) { + String id = card.getIdIMG(); + ImageView img; + if (cardCache.containsKey(id)) { + img = new ImageView(cardCache.get(id).getImage()); + } else { + img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + id + ".png"))); + cardCache.put(id, img); + } + img.setFitHeight(200); + img.setPreserveRatio(true); + + Rectangle clip = new Rectangle(); + clip.setWidth(img.getBoundsInLocal().getWidth()); + clip.setHeight(200); + clip.setArcWidth(20); + clip.setArcHeight(20); + img.setClip(clip); + + StackPane wrapper = new StackPane(img); + + if (withShadow) { + addShadow(wrapper); + } + if (withZoom) { + addHoverZoom(wrapper); + } + return wrapper; + } + private void addHoverZoom(Node node) { + ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), node); + scaleUp.setToX(1.1); + scaleUp.setToY(1.1); + ScaleTransition scaleDown = new ScaleTransition(Duration.millis(150), node); + scaleDown.setToX(1.0); + scaleDown.setToY(1.0); + node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> { scaleUp.play(); node.setCursor(Cursor.HAND); }); + node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); + } + + private void addShadow(Node node) { + DropShadow shadow = new DropShadow(); + shadow.setColor(Color.rgb(0, 0, 0, 0.3)); + shadow.setRadius(6); + shadow.setOffsetX(2); + shadow.setOffsetY(2); + node.setEffect(shadow); + node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> { + shadow.setRadius(16); + shadow.setOffsetX(4); + shadow.setOffsetY(4); + shadow.setColor(Color.rgb(0, 0, 0, 0.5)); + }); + node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { + shadow.setRadius(6); + shadow.setOffsetX(2); + shadow.setOffsetY(2); + shadow.setColor(Color.rgb(0, 0, 0, 0.3)); + }); + } @@ -93,41 +179,15 @@ public class MainFXMLController { } // UPPER, LOWER AND BOARD - private ImageView createCard(PlayableCard card) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png"))); - img.setFitHeight(200); - img.setPreserveRatio(true); - - Rectangle clip = new Rectangle(); - clip.setWidth(img.getBoundsInLocal().getWidth()); - clip.setHeight(200); - clip.setArcWidth(20); - clip.setArcHeight(20); - img.setClip(clip); - return img; - } - private ImageView createSlot(Slot slot) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-"+slot.getSlotId()+".png"))); - img.setFitHeight(240); - img.setPreserveRatio(true); - - Rectangle clip = new Rectangle(); - clip.setWidth(img.getBoundsInLocal().getWidth()); - clip.setHeight(240); - clip.setArcWidth(20); - clip.setArcHeight(20); - img.setClip(clip); - return img; - } private void renderUpper() { - upperList.setSpacing(6); + upperList.setSpacing(14); upperList.setAlignment(Pos.CENTER); upperList.getChildren().clear(); int i = 0; for (TribeCard card : model.getUpperListTribeCards()) { final int index = i; - ImageView img = createCard(card); + StackPane img = createCard(card, true, true); img.setOnMouseClicked(e -> controller.drawUpperTribeCard(username, index)); upperList.getChildren().add(img); i++; @@ -135,14 +195,14 @@ public class MainFXMLController { i = 0; for (BuildingCard card : model.getUpperListBuilding()) { final int index = i; - ImageView img = createCard(card); + StackPane img = createCard(card, true, true); img.setOnMouseClicked(e -> controller.drawUpperBuildingCard(username, index)); upperList.getChildren().add(img); i++; } } private void renderBoard() { - board.setSpacing(6); + board.setSpacing(14); board.setAlignment(Pos.CENTER); board.getChildren().clear(); @@ -157,14 +217,14 @@ public class MainFXMLController { } } private void renderLower() { - lowerList.setSpacing(6); + lowerList.setSpacing(14); lowerList.setAlignment(Pos.CENTER); lowerList.getChildren().clear(); int i = 0; for (TribeCard card : model.getLowerListTribeCards()) { final int index = i; - ImageView img = createCard(card); + StackPane img = createCard(card, true, true); img.setOnMouseClicked(e -> controller.drawLowerTribeCard(username, index)); lowerList.getChildren().add(img); i++; @@ -172,7 +232,7 @@ public class MainFXMLController { i = 0; for (BuildingCard card : model.getLowerListBuilding()) { final int index = i; - ImageView img = createCard(card); + StackPane img = createCard(card, true, true); img.setOnMouseClicked(e -> controller.drawLowerBuildingCard(username, index)); lowerList.getChildren().add(img); i++; @@ -180,32 +240,9 @@ public class MainFXMLController { } // MY HAND - private void drawMyHandList(HBox myHand, ArrayList cardList) { - if (!cardList.isEmpty()) { - - ImageView img = createCard(cardList.getLast()); - Label label = new Label(String.valueOf(cardList.size())); - label.setTranslateY(-55); - label.setTranslateX(10); - label.getStyleClass().add("label-large"); - StackPane.setAlignment(label, Pos.TOP_RIGHT); - - StackPane stack = new StackPane(img, label); - stack.setClip(null); - stack.setOnMouseClicked(e -> openPopup(cardList)); - - myHand.getChildren().add(stack); - } else { - Region placeholder = new Region(); - placeholder.setPrefHeight(200); - placeholder.setPrefWidth(200 * 0.675); - placeholder.setStyle("-fx-background-color: transparent;"); - myHand.getChildren().add(placeholder); - } - } private void renderMyHand() { myHand.getChildren().clear(); - myHand.setSpacing(6); + myHand.setSpacing(14); myHand.setAlignment(Pos.CENTER); drawMyHandList(myHand, model.getPlayerByUsername(username).artists); @@ -216,16 +253,36 @@ public class MainFXMLController { drawMyHandList(myHand, model.getPlayerByUsername(username).hunters); drawMyHandList(myHand, model.getPlayerByUsername(username).buildingCards); } + private void drawMyHandList(HBox myHand, ArrayList cardList) { + if (!cardList.isEmpty()) { + StackPane img = createCard(cardList.getLast(), true, true); + Label label = new Label(String.valueOf(cardList.size())); + label.setTranslateY(-55); + label.setTranslateX(10); + label.getStyleClass().add("label-large"); + StackPane.setAlignment(label, Pos.TOP_RIGHT); + img.getChildren().add(label); // aggiungi il label dentro lo StackPane di createCard + img.setOnMouseClicked(e -> openPopup(cardList)); + myHand.getChildren().add(img); + } else { + Region placeholder = new Region(); + placeholder.setPrefHeight(200); + placeholder.setPrefWidth(200 * 0.675); + placeholder.setStyle("-fx-background-color: transparent;"); + myHand.getChildren().add(placeholder); + } + } + // SIDE PANEL private void renderSidePanel() { sidePanel.getChildren().clear(); sidePanel.setSpacing(6); - sidePanel.setAlignment(Pos.CENTER); era.setText(Integer.toString(model.getCurrentState().getEra())); round.setText(Integer.toString(model.getCurrentState().getRound())); player.setText(model.getCurrentState().getCurrentPlayer().getUserName()); + VBox.setMargin(info, new Insets(5, 5, 5, 5)); sidePanel.getChildren().add(info); renderPlayers(sidePanel); @@ -249,42 +306,104 @@ public class MainFXMLController { foodLabel.getStyleClass().add("label-small"); Label prestigeLabel = new Label("Prestige: " + player.getPrestigeValue()); prestigeLabel.getStyleClass().add("label-small"); - card.getChildren().addAll(usernameLabel, foodLabel, prestigeLabel); + HBox icons = new HBox(); + icons.setSpacing(6); + icons.setAlignment(Pos.CENTER); + renderIcons(icons, player); + card.getChildren().addAll(usernameLabel, foodLabel, prestigeLabel, icons); - ArrayList playerCard = new ArrayList<>(); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).artists); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).gatherers); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).inventors); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).builders); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).shamans); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).hunters); - playerCard.addAll(model.getPlayerByUsername(player.getUserName()).buildingCards); - - card.setOnMouseClicked(e -> openPopup(playerCard)); playersHand.getChildren().add(card); } } + private void renderIcons(HBox icons, Player player) { + String[][] iconTypes = { + {"Artist", "artists"}, + {"Gatherer", "gatherers"}, + {"Inventor", "inventors"}, + {"Builder", "builders"}, + {"Shaman", "shamans"}, + {"Hunter", "hunters"} + }; + + for (String[] type : iconTypes) { + String iconName = type[0]; + String fieldName = type[1]; + + ImageView icon = new ImageView(); + icon.setFitWidth(28); + icon.setFitHeight(28); + icon.setPreserveRatio(true); + icon.setImage(new Image(getClass().getResourceAsStream("/GUIImages/Icons/" + iconName + ".png"))); + + ArrayList cards = getPlayerCards(player.getUserName(), fieldName); + if (cards.isEmpty()) { + ColorAdjust grayscale = new ColorAdjust(); + grayscale.setSaturation(-1.0); + icon.setEffect(grayscale); + icon.setOpacity(0.5); + } else { + icon.setOnMouseClicked(e -> openPopup(cards)); + addHoverZoom(icon); + } + + icons.getChildren().add(icon); + } + } + private ArrayList getPlayerCards(String username, String type) { + Player p = model.getPlayerByUsername(username); + return switch (type) { + case "artists" -> new ArrayList<>(p.artists); + case "gatherers" -> new ArrayList<>(p.gatherers); + case "inventors" -> new ArrayList<>(p.inventors); + case "builders" -> new ArrayList<>(p.builders); + case "shamans" -> new ArrayList<>(p.shamans); + case "hunters" -> new ArrayList<>(p.hunters); + default -> new ArrayList<>(); + }; + } + // POPUP private void initPopup() { popupCards = new HBox(10); popupCards.setAlignment(Pos.CENTER); popupCards.setPadding(new Insets(10)); - popupCards.getStyleClass().add("popup"); + popupCards.setStyle( + "-fx-background-color: #b42224;" + + "-fx-border-color: black;" + + "-fx-border-width: 2;" + + "-fx-border-radius: 10;" + + "-fx-background-radius: 10;" + ); + + Rectangle clip = new Rectangle(); + clip.setArcWidth(20); + clip.setArcHeight(20); + clip.widthProperty().bind(popupCards.widthProperty()); + clip.heightProperty().bind(popupCards.heightProperty()); + popupCards.setClip(clip); popup = new Popup(); popup.getContent().add(popupCards); popup.setAutoHide(true); + + // Aspetta che la scena del popup esista, poi la rendi trasparente + popup.addEventHandler(javafx.event.Event.ANY, e -> { + if (popup.getScene() != null) { + popup.getScene().setFill(Color.TRANSPARENT); + } + }); } private void openPopup(ArrayList cardList) { popupCards.getChildren().clear(); - for (PlayableCard card : cardList) { - ImageView img = createCard(card); + StackPane img = createCard(card, false, false); popupCards.getChildren().add(img); } - javafx.stage.Window window = myHand.getScene().getWindow(); popup.show(window, (window.getWidth() - popup.getWidth()) / 2, (window.getHeight() - popup.getHeight()) / 2); + + // La scena esiste solo dopo show() + popup.getScene().setFill(Color.TRANSPARENT); } } diff --git a/src/main/resources/GUIScene/main.fxml b/src/main/resources/GUIScene/main.fxml index ccfd6e9..d1bbb93 100644 --- a/src/main/resources/GUIScene/main.fxml +++ b/src/main/resources/GUIScene/main.fxml @@ -43,23 +43,23 @@ - + - - - diff --git a/src/main/resources/GUIScene/styles.css b/src/main/resources/GUIScene/styles.css index e0d7a59..0720a4c 100644 --- a/src/main/resources/GUIScene/styles.css +++ b/src/main/resources/GUIScene/styles.css @@ -38,10 +38,13 @@ -fx-background-color: #b42224; } -.popup { - -fx-background-color: #b42224; - -fx-border-color: black; - -fx-border-width: 2; - -fx-border-radius: 10; - -fx-background-radius: 10; +.frame { + -fx-background-color: + #8B6914, + #FFF8DC, + #8B6914, + #FFF8DC; + -fx-background-insets: 0, 5, 10, 15; + -fx-background-radius: 15, 12, 8, 4; + -fx-padding: 15 15 15 15; } \ No newline at end of file