Fix: full view refactor
This commit is contained in:
@@ -11,10 +11,18 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ambient fire particle system for the main game scene.
|
||||||
|
*
|
||||||
|
* <p>Spawns embers, sparks, and dust from the four screen corners and animates
|
||||||
|
* them toward the center using an {@link AnimationTimer} capped at 30 fps.
|
||||||
|
* Add the pane returned by {@link #getPane()} to the scene root, then call
|
||||||
|
* {@link #start()} to begin the animation.
|
||||||
|
*/
|
||||||
public class FireParticleSystem {
|
public class FireParticleSystem {
|
||||||
|
|
||||||
private static final int MAX_PARTICLES = 30;
|
private static final int MAX_PARTICLES = 30;
|
||||||
private static final long SPAWN_INTERVAL_NS = 1_00_000_000L;
|
private static final long SPAWN_INTERVAL_NS = 100_000_000L;
|
||||||
private static final long FRAME_INTERVAL_NS = 1_000_000_000L / 30; // 30 fps cap
|
private static final long FRAME_INTERVAL_NS = 1_000_000_000L / 30; // 30 fps cap
|
||||||
private static final int STEPS_PER_FRAME = 3; // physics steps per frame → 3× speed
|
private static final int STEPS_PER_FRAME = 3; // physics steps per frame → 3× speed
|
||||||
|
|
||||||
@@ -34,8 +42,10 @@ public class FireParticleSystem {
|
|||||||
pane.setPickOnBounds(false);
|
pane.setPickOnBounds(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the transparent overlay pane that holds all particle nodes. */
|
||||||
public Pane getPane() { return pane; }
|
public Pane getPane() { return pane; }
|
||||||
|
|
||||||
|
/** Starts the animation timer. */
|
||||||
public void start() {
|
public void start() {
|
||||||
timer = new AnimationTimer() {
|
timer = new AnimationTimer() {
|
||||||
@Override
|
@Override
|
||||||
@@ -48,6 +58,7 @@ public class FireParticleSystem {
|
|||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stops the animation timer. */
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if (timer != null) timer.stop();
|
if (timer != null) timer.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,24 +34,23 @@ import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.TOTEM_CHOICE;
|
|||||||
*/
|
*/
|
||||||
public class GUI extends Application implements IView {
|
public class GUI extends Application implements IView {
|
||||||
private Stage primaryStage;
|
private Stage primaryStage;
|
||||||
MiniModel miniModel;
|
private volatile MiniModel miniModel;
|
||||||
|
|
||||||
|
private FXMLLoader loaderLogin;
|
||||||
|
private Scene loginScene;
|
||||||
|
private LoginFXMLController controllerLogin;
|
||||||
|
|
||||||
FXMLLoader loaderLogin;
|
private FXMLLoader loaderTotem;
|
||||||
Scene loginScene;
|
private Scene totemScene;
|
||||||
LoginFXMLController controllerLogin;
|
private TotemFXMLController controllerTotem;
|
||||||
|
|
||||||
FXMLLoader loaderTotem;
|
private FXMLLoader loaderMain;
|
||||||
Scene totemScene;
|
private Scene mainScene;
|
||||||
TotemFXMLController controllerTotem;
|
private MainFXMLController controllerMain;
|
||||||
|
|
||||||
FXMLLoader loaderMain;
|
private FXMLLoader loaderLeaderboard;
|
||||||
Scene mainScene;
|
private Scene leaderboardScene;
|
||||||
MainFXMLController controllerMain;
|
private LeaderboardFXMLController controllerLeaderboard;
|
||||||
|
|
||||||
FXMLLoader loaderLeaderboard;
|
|
||||||
Scene leaderboardScene;
|
|
||||||
LeaderboardFXMLController controllerLeaderboard;
|
|
||||||
|
|
||||||
|
|
||||||
private ClientController controller;
|
private ClientController controller;
|
||||||
@@ -164,7 +163,7 @@ public class GUI extends Application implements IView {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setModel(MiniModel miniModel) {
|
public void setModel(MiniModel miniModel) {
|
||||||
this.miniModel=miniModel;
|
this.miniModel = miniModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,7 +182,6 @@ public class GUI extends Application implements IView {
|
|||||||
public void render() {
|
public void render() {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (miniModel == null) return;
|
if (miniModel == null) return;
|
||||||
synchronized (miniModel) {
|
|
||||||
if (controller.getMiniModel().currentState.getGameStage() == TOTEM_CHOICE) {
|
if (controller.getMiniModel().currentState.getGameStage() == TOTEM_CHOICE) {
|
||||||
controllerTotem.render();
|
controllerTotem.render();
|
||||||
fadeToScene(totemScene);
|
fadeToScene(totemScene);
|
||||||
@@ -194,7 +192,6 @@ public class GUI extends Application implements IView {
|
|||||||
controllerMain.render();
|
controllerMain.render();
|
||||||
fadeToScene(mainScene);
|
fadeToScene(mainScene);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,11 +259,9 @@ public class GUI extends Application implements IView {
|
|||||||
fadeToScene(loginScene);
|
fadeToScene(loginScene);
|
||||||
} else {
|
} else {
|
||||||
if (miniModel == null) return;
|
if (miniModel == null) return;
|
||||||
synchronized (miniModel) {
|
controllerMain.setError(true);
|
||||||
controllerMain.isError = true;
|
|
||||||
controllerMain.render();
|
controllerMain.render();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,17 +40,15 @@ public class LeaderboardFXMLController {
|
|||||||
@FXML private StackPane rootPane;
|
@FXML private StackPane rootPane;
|
||||||
@FXML private VBox mainVBox;
|
@FXML private VBox mainVBox;
|
||||||
@FXML private VBox rankingList;
|
@FXML private VBox rankingList;
|
||||||
// titleLabel rimossa: il testo Winner/GameOver è aggiunto dinamicamente in render()
|
// title label removed; outcome text is added dynamically in render()
|
||||||
|
|
||||||
private ClientController controller;
|
private ClientController controller;
|
||||||
|
|
||||||
private Popup popup;
|
private Popup popup;
|
||||||
private VBox popupContent;
|
private VBox popupContent;
|
||||||
|
|
||||||
// Cache condivisa con MainFXMLController
|
|
||||||
private static final Map<String, Image> imageCache = new HashMap<>();
|
private static final Map<String, Image> imageCache = new HashMap<>();
|
||||||
private Scene loginScene;
|
private Scene loginScene;
|
||||||
private Stage primaryStage;
|
|
||||||
private Runnable action;
|
private Runnable action;
|
||||||
|
|
||||||
/** Returns a cached {@link Image} for the given classpath {@code path}, loading it on first access. */
|
/** Returns a cached {@link Image} for the given classpath {@code path}, loading it on first access. */
|
||||||
@@ -69,8 +67,8 @@ public class LeaderboardFXMLController {
|
|||||||
*/
|
*/
|
||||||
public void setController(ClientController controller, Runnable action, Scene loginScene) {
|
public void setController(ClientController controller, Runnable action, Scene loginScene) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.loginScene=loginScene;
|
this.loginScene = loginScene;
|
||||||
this.action=action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -109,7 +107,6 @@ public class LeaderboardFXMLController {
|
|||||||
outcomeLabel.setEffect(glow);
|
outcomeLabel.setEffect(glow);
|
||||||
rankingList.getChildren().add(outcomeLabel);
|
rankingList.getChildren().add(outcomeLabel);
|
||||||
|
|
||||||
// Separatore
|
|
||||||
Region sep = new Region();
|
Region sep = new Region();
|
||||||
sep.setPrefHeight(16);
|
sep.setPrefHeight(16);
|
||||||
rankingList.getChildren().add(sep);
|
rankingList.getChildren().add(sep);
|
||||||
@@ -153,7 +150,6 @@ public class LeaderboardFXMLController {
|
|||||||
row.setPadding(new Insets(14, 28, 14, 28));
|
row.setPadding(new Insets(14, 28, 14, 28));
|
||||||
row.setMaxWidth(Double.MAX_VALUE);
|
row.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
|
||||||
// Sfumatura scura semitrasparente come sfondo della riga
|
|
||||||
LinearGradient gradient = new LinearGradient(
|
LinearGradient gradient = new LinearGradient(
|
||||||
0, 0, 1, 0, true, CycleMethod.NO_CYCLE,
|
0, 0, 1, 0, true, CycleMethod.NO_CYCLE,
|
||||||
new Stop(0.0, Color.rgb(0, 0, 0, 0.75)),
|
new Stop(0.0, Color.rgb(0, 0, 0, 0.75)),
|
||||||
@@ -168,7 +164,6 @@ public class LeaderboardFXMLController {
|
|||||||
addShadow(row);
|
addShadow(row);
|
||||||
addHoverZoom(row);
|
addHoverZoom(row);
|
||||||
|
|
||||||
// Posizione medaglia
|
|
||||||
Label posLabel = new Label(position + "°");
|
Label posLabel = new Label(position + "°");
|
||||||
posLabel.setMinWidth(55);
|
posLabel.setMinWidth(55);
|
||||||
String medalColor = switch (position) {
|
String medalColor = switch (position) {
|
||||||
@@ -180,13 +175,11 @@ public class LeaderboardFXMLController {
|
|||||||
posLabel.setStyle("-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: " + medalColor + ";");
|
posLabel.setStyle("-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: " + medalColor + ";");
|
||||||
|
|
||||||
|
|
||||||
// Totem
|
|
||||||
ImageView totem = new ImageView(loadImage(
|
ImageView totem = new ImageView(loadImage(
|
||||||
"/GUIImages/Totems/totem_" + player.getTotem().toString().toLowerCase(Locale.ROOT) + ".png"));
|
"/GUIImages/Totems/totem_" + player.getTotem().toString().toLowerCase(Locale.ROOT) + ".png"));
|
||||||
totem.setFitHeight(55);
|
totem.setFitHeight(55);
|
||||||
totem.setPreserveRatio(true);
|
totem.setPreserveRatio(true);
|
||||||
|
|
||||||
// Username
|
|
||||||
Label nameLabel = new Label(player.getUserName());
|
Label nameLabel = new Label(player.getUserName());
|
||||||
nameLabel.setStyle(
|
nameLabel.setStyle(
|
||||||
"-fx-font-size: 22px; -fx-font-weight: bold; -fx-text-fill: " +
|
"-fx-font-size: 22px; -fx-font-weight: bold; -fx-text-fill: " +
|
||||||
@@ -194,10 +187,8 @@ public class LeaderboardFXMLController {
|
|||||||
);
|
);
|
||||||
HBox.setHgrow(nameLabel, Priority.ALWAYS);
|
HBox.setHgrow(nameLabel, Priority.ALWAYS);
|
||||||
|
|
||||||
// Statistiche (icona + numero)
|
|
||||||
HBox stats = createStatsBox(player);
|
HBox stats = createStatsBox(player);
|
||||||
|
|
||||||
// Punti prestigio in evidenza a destra
|
|
||||||
HBox ppBox = new HBox(6);
|
HBox ppBox = new HBox(6);
|
||||||
ppBox.setAlignment(Pos.CENTER);
|
ppBox.setAlignment(Pos.CENTER);
|
||||||
ImageView ppIcon = new ImageView(loadImage("/GUIImages/Icons/PrestigePoint.png"));
|
ImageView ppIcon = new ImageView(loadImage("/GUIImages/Icons/PrestigePoint.png"));
|
||||||
@@ -238,7 +229,6 @@ public class LeaderboardFXMLController {
|
|||||||
icon.setPreserveRatio(true);
|
icon.setPreserveRatio(true);
|
||||||
Label label = new Label(value);
|
Label label = new Label(value);
|
||||||
label.setStyle("-fx-font-size: 16px; -fx-text-fill: #FFFFFF; -fx-font-weight: bold;");
|
label.setStyle("-fx-font-size: 16px; -fx-text-fill: #FFFFFF; -fx-font-weight: bold;");
|
||||||
// Ombra sul testo per leggibilità extra
|
|
||||||
DropShadow textShadow = new DropShadow();
|
DropShadow textShadow = new DropShadow();
|
||||||
textShadow.setColor(Color.rgb(0, 0, 0, 0.9));
|
textShadow.setColor(Color.rgb(0, 0, 0, 0.9));
|
||||||
textShadow.setRadius(4);
|
textShadow.setRadius(4);
|
||||||
@@ -274,7 +264,6 @@ public class LeaderboardFXMLController {
|
|||||||
private void openPlayerPopup(Player player) {
|
private void openPlayerPopup(Player player) {
|
||||||
popupContent.getChildren().clear();
|
popupContent.getChildren().clear();
|
||||||
|
|
||||||
// Intestazione con totem + nome
|
|
||||||
HBox header = new HBox(10);
|
HBox header = new HBox(10);
|
||||||
header.setAlignment(Pos.CENTER);
|
header.setAlignment(Pos.CENTER);
|
||||||
ImageView totem = new ImageView(loadImage(
|
ImageView totem = new ImageView(loadImage(
|
||||||
@@ -286,7 +275,6 @@ public class LeaderboardFXMLController {
|
|||||||
header.getChildren().addAll(totem, nameLabel);
|
header.getChildren().addAll(totem, nameLabel);
|
||||||
popupContent.getChildren().add(header);
|
popupContent.getChildren().add(header);
|
||||||
|
|
||||||
// Tutte le carte in un unico FlowPane, raggruppate per tipo con separatore icona
|
|
||||||
String[][] types = {
|
String[][] types = {
|
||||||
{"Artist", "artists"},
|
{"Artist", "artists"},
|
||||||
{"Gatherer", "gatherers"},
|
{"Gatherer", "gatherers"},
|
||||||
@@ -297,7 +285,6 @@ public class LeaderboardFXMLController {
|
|||||||
{"Building", "buildingCards"}
|
{"Building", "buildingCards"}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Griglia unica: icona tipo | carte... per ogni riga
|
|
||||||
VBox grid = new VBox(6);
|
VBox grid = new VBox(6);
|
||||||
grid.setAlignment(Pos.CENTER_LEFT);
|
grid.setAlignment(Pos.CENTER_LEFT);
|
||||||
boolean hasAnyCard = false;
|
boolean hasAnyCard = false;
|
||||||
@@ -312,13 +299,11 @@ public class LeaderboardFXMLController {
|
|||||||
HBox row = new HBox(6);
|
HBox row = new HBox(6);
|
||||||
row.setAlignment(Pos.CENTER_LEFT);
|
row.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
|
||||||
// Icona tipo come intestazione riga
|
|
||||||
ImageView typeIcon = new ImageView(loadImage("/GUIImages/Icons/"+typeName+".png"));
|
ImageView typeIcon = new ImageView(loadImage("/GUIImages/Icons/"+typeName+".png"));
|
||||||
typeIcon.setFitHeight(22);
|
typeIcon.setFitHeight(22);
|
||||||
typeIcon.setPreserveRatio(true);
|
typeIcon.setPreserveRatio(true);
|
||||||
row.getChildren().add(typeIcon);
|
row.getChildren().add(typeIcon);
|
||||||
|
|
||||||
// Carte piccole in riga
|
|
||||||
for (PlayableCard card : cards) {
|
for (PlayableCard card : cards) {
|
||||||
ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png"));
|
ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png"));
|
||||||
img.setFitHeight(230);
|
img.setFitHeight(230);
|
||||||
@@ -331,7 +316,7 @@ public class LeaderboardFXMLController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAnyCard) {
|
if (!hasAnyCard) {
|
||||||
Label empty = new Label("Nessuna carta");
|
Label empty = new Label("No cards");
|
||||||
empty.setStyle("-fx-font-size: 14px; -fx-text-fill: #888888;");
|
empty.setStyle("-fx-font-size: 14px; -fx-text-fill: #888888;");
|
||||||
grid.getChildren().add(empty);
|
grid.getChildren().add(empty);
|
||||||
}
|
}
|
||||||
@@ -342,9 +327,8 @@ public class LeaderboardFXMLController {
|
|||||||
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||||
scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;");
|
scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;");
|
||||||
|
|
||||||
// altezza massima = 80% della finestra
|
|
||||||
Window window = rootPane.getScene().getWindow();
|
Window window = rootPane.getScene().getWindow();
|
||||||
scrollPane.setMaxHeight(window.getHeight() * 0.8);
|
scrollPane.setMaxHeight(window.getHeight() * 0.8); // cap scroll area to 80% of window height
|
||||||
popupContent.getChildren().add(scrollPane);
|
popupContent.getChildren().add(scrollPane);
|
||||||
popup.show(window, 0, 0);
|
popup.show(window, 0, 0);
|
||||||
popup.getScene().setFill(Color.TRANSPARENT);
|
popup.getScene().setFill(Color.TRANSPARENT);
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ public class LoginFXMLController {
|
|||||||
private boolean isRMI = true;
|
private boolean isRMI = true;
|
||||||
private ClientController controller;
|
private ClientController controller;
|
||||||
|
|
||||||
// Definiamo lo pseudo-stato custom per il CSS corrispondente a ":active-protocol"
|
|
||||||
private final PseudoClass activeProtocolPseudo = PseudoClass.getPseudoClass("active-protocol");
|
private final PseudoClass activeProtocolPseudo = PseudoClass.getPseudoClass("active-protocol");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +70,6 @@ public class LoginFXMLController {
|
|||||||
protocolToggle.setOnMouseClicked(e -> switchProtocol());
|
protocolToggle.setOnMouseClicked(e -> switchProtocol());
|
||||||
protocolToggle.setStyle(protocolToggle.getStyle() + " -fx-cursor: hand;");
|
protocolToggle.setStyle(protocolToggle.getStyle() + " -fx-cursor: hand;");
|
||||||
|
|
||||||
// Inizializza lo stato grafico iniziale (RMI attivo)
|
|
||||||
labelRMI.pseudoClassStateChanged(activeProtocolPseudo, true);
|
labelRMI.pseudoClassStateChanged(activeProtocolPseudo, true);
|
||||||
labelTCP.pseudoClassStateChanged(activeProtocolPseudo, false);
|
labelTCP.pseudoClassStateChanged(activeProtocolPseudo, false);
|
||||||
|
|
||||||
@@ -87,7 +85,7 @@ public class LoginFXMLController {
|
|||||||
tt.setToX(isRMI ? 0 : 110);
|
tt.setToX(isRMI ? 0 : 110);
|
||||||
tt.play();
|
tt.play();
|
||||||
|
|
||||||
// Modifica in modo sicuro lo stato senza distruggere i parametri di layout dei nodi
|
// pseudoClassStateChanged preserves layout properties unlike direct style mutation
|
||||||
labelRMI.pseudoClassStateChanged(activeProtocolPseudo, isRMI);
|
labelRMI.pseudoClassStateChanged(activeProtocolPseudo, isRMI);
|
||||||
labelTCP.pseudoClassStateChanged(activeProtocolPseudo, !isRMI);
|
labelTCP.pseudoClassStateChanged(activeProtocolPseudo, !isRMI);
|
||||||
}
|
}
|
||||||
@@ -95,10 +93,10 @@ public class LoginFXMLController {
|
|||||||
/** Validates form input and starts a background thread to connect to the server. */
|
/** Validates form input and starts a background thread to connect to the server. */
|
||||||
@FXML
|
@FXML
|
||||||
private void onAccediClick() {
|
private void onAccediClick() {
|
||||||
String nome = campoNome.getText().trim();
|
String name = campoNome.getText().trim();
|
||||||
String ip = campoIP.getText().trim();
|
String ip = campoIP.getText().trim();
|
||||||
|
|
||||||
if (nome.isEmpty()) {
|
if (name.isEmpty()) {
|
||||||
showError("Please select a name.");
|
showError("Please select a name.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -112,13 +110,13 @@ public class LoginFXMLController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateLoginButton(false);
|
updateLoginButton(false);
|
||||||
controller.setMyUsername(nome);
|
controller.setMyUsername(name);
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
String localInterface = InterfaceResolver.resolveLocalInterface(ip);
|
String localInterface = InterfaceResolver.resolveLocalInterface(ip);
|
||||||
System.setProperty("java.rmi.server.hostname", localInterface);
|
System.setProperty("java.rmi.server.hostname", localInterface);
|
||||||
connect(nome, ip, numPlayers, localInterface);
|
connect(name, ip, numPlayers, localInterface);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
showError("Network error: " + ex.getMessage());
|
showError("Network error: " + ex.getMessage());
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ public class MainFXMLController {
|
|||||||
private ClientController controller;
|
private ClientController controller;
|
||||||
|
|
||||||
/** {@code true} when the last received event was an error response. */
|
/** {@code true} when the last received event was an error response. */
|
||||||
public boolean isError;
|
private boolean isError;
|
||||||
|
|
||||||
|
/** Sets the error flag; called by {@link GUI} before delegating to {@link #render()}. */
|
||||||
|
public void setError(boolean error) { this.isError = error; }
|
||||||
|
|
||||||
// ==== IMAGE CACHE ====
|
// ==== IMAGE CACHE ====
|
||||||
private static final Map<String, Image> imageCache = new HashMap<>();
|
private static final Map<String, Image> imageCache = new HashMap<>();
|
||||||
@@ -215,7 +218,6 @@ public class MainFXMLController {
|
|||||||
card.getStyleClass().add("player-card");
|
card.getStyleClass().add("player-card");
|
||||||
card.setPadding(new Insets(4));
|
card.setPadding(new Insets(4));
|
||||||
|
|
||||||
// Riga 1: totem + nome
|
|
||||||
HBox headerRow = new HBox(8);
|
HBox headerRow = new HBox(8);
|
||||||
headerRow.setAlignment(Pos.CENTER);
|
headerRow.setAlignment(Pos.CENTER);
|
||||||
ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_"
|
ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_"
|
||||||
@@ -233,7 +235,6 @@ public class MainFXMLController {
|
|||||||
}
|
}
|
||||||
headerRow.getChildren().addAll(totem, usernameLabel);
|
headerRow.getChildren().addAll(totem, usernameLabel);
|
||||||
|
|
||||||
// Riga 2: cibo + prestigio + building
|
|
||||||
HBox statsRow = new HBox(10);
|
HBox statsRow = new HBox(10);
|
||||||
statsRow.setAlignment(Pos.CENTER);
|
statsRow.setAlignment(Pos.CENTER);
|
||||||
|
|
||||||
@@ -269,7 +270,6 @@ public class MainFXMLController {
|
|||||||
|
|
||||||
statsRow.getChildren().addAll(foodBox, prestigeBox, buildingIcon);
|
statsRow.getChildren().addAll(foodBox, prestigeBox, buildingIcon);
|
||||||
|
|
||||||
// Righe 3-4: icone carte
|
|
||||||
HBox iconsRow1 = new HBox(6);
|
HBox iconsRow1 = new HBox(6);
|
||||||
iconsRow1.setSpacing(20);
|
iconsRow1.setSpacing(20);
|
||||||
iconsRow1.setAlignment(Pos.CENTER);
|
iconsRow1.setAlignment(Pos.CENTER);
|
||||||
@@ -287,7 +287,7 @@ public class MainFXMLController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
List<ImageView> icons = new ArrayList<>();
|
List<ImageView> icons = new ArrayList<>();
|
||||||
// aggiungo anche building come prima icona della lista per updateSidePanel
|
// building must be index 0; updateSidePanel iterates icons in ["building","artists",...] order
|
||||||
icons.add(buildingIcon);
|
icons.add(buildingIcon);
|
||||||
|
|
||||||
for (int i = 0; i < iconTypes.length; i++) {
|
for (int i = 0; i < iconTypes.length; i++) {
|
||||||
@@ -406,7 +406,6 @@ public class MainFXMLController {
|
|||||||
icons.get(i).setEffect(empty ? new ColorAdjust() : null);
|
icons.get(i).setEffect(empty ? new ColorAdjust() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// aggiorna current player highlight
|
|
||||||
VBox card = playerCards.get(u);
|
VBox card = playerCards.get(u);
|
||||||
if(controller.getMiniModel().disconnectedPlayers.contains(u))
|
if(controller.getMiniModel().disconnectedPlayers.contains(u))
|
||||||
{
|
{
|
||||||
@@ -432,7 +431,6 @@ public class MainFXMLController {
|
|||||||
card.setStyle("");
|
card.setStyle("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// animazione shake su errore
|
|
||||||
if (isError && u.equals(controller.getMyUsername())) {
|
if (isError && u.equals(controller.getMyUsername())) {
|
||||||
TranslateTransition tt = new TranslateTransition(Duration.millis(56), card);
|
TranslateTransition tt = new TranslateTransition(Duration.millis(56), card);
|
||||||
tt.setFromX(0);
|
tt.setFromX(0);
|
||||||
@@ -611,7 +609,6 @@ public class MainFXMLController {
|
|||||||
for (int i = 0; i < controller.getMiniModel().orderLogicCard.getPlayerList().size(); i++) {
|
for (int i = 0; i < controller.getMiniModel().orderLogicCard.getPlayerList().size(); i++) {
|
||||||
OrderPlayer op = controller.getMiniModel().orderLogicCard.getPlayerList().get(i);
|
OrderPlayer op = controller.getMiniModel().orderLogicCard.getPlayerList().get(i);
|
||||||
|
|
||||||
// Carica immagine totem come in createSlot
|
|
||||||
ImageView totem = new ImageView(loadImage(
|
ImageView totem = new ImageView(loadImage(
|
||||||
"/GUIImages/Totems/totem_" + op.getPlayer().getTotem().toString().toLowerCase(Locale.ROOT) + ".png"
|
"/GUIImages/Totems/totem_" + op.getPlayer().getTotem().toString().toLowerCase(Locale.ROOT) + ".png"
|
||||||
));
|
));
|
||||||
@@ -626,10 +623,8 @@ public class MainFXMLController {
|
|||||||
overlay.prefHeightProperty().bind(card.heightProperty());
|
overlay.prefHeightProperty().bind(card.heightProperty());
|
||||||
overlay.prefWidthProperty().bind(card.widthProperty());
|
overlay.prefWidthProperty().bind(card.widthProperty());
|
||||||
|
|
||||||
// Scala altezza totem proporzionalmente come in createSlot (0.127 della card)
|
|
||||||
totem.fitHeightProperty().bind(card.heightProperty().multiply(0.323));
|
totem.fitHeightProperty().bind(card.heightProperty().multiply(0.323));
|
||||||
|
|
||||||
// Posizione Y proporzionale, X fissa
|
|
||||||
card.heightProperty().addListener((obs, ov, nv) -> {
|
card.heightProperty().addListener((obs, ov, nv) -> {
|
||||||
totem.setLayoutY(nv.doubleValue() * (yRatio-0.196));
|
totem.setLayoutY(nv.doubleValue() * (yRatio-0.196));
|
||||||
});
|
});
|
||||||
@@ -637,7 +632,7 @@ public class MainFXMLController {
|
|||||||
totem.setLayoutX(nv.doubleValue() * 0.364);
|
totem.setLayoutX(nv.doubleValue() * 0.364);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Inizializzazione immediata se già dimensionato
|
// initialize immediately if already laid out
|
||||||
if (card.getHeight() > 0) totem.setLayoutY(card.getHeight() *(yRatio-0.196));
|
if (card.getHeight() > 0) totem.setLayoutY(card.getHeight() *(yRatio-0.196));
|
||||||
if (card.getWidth() > 0) totem.setLayoutX(card.getWidth() * 0.364);
|
if (card.getWidth() > 0) totem.setLayoutX(card.getWidth() * 0.364);
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ import java.util.Locale;
|
|||||||
*/
|
*/
|
||||||
public class TotemFXMLController {
|
public class TotemFXMLController {
|
||||||
|
|
||||||
/** Background image view injected via FXML. */
|
@FXML private ImageView backgroundImage;
|
||||||
public ImageView backgroundImage;
|
|
||||||
@FXML private HBox mainHBox;
|
@FXML private HBox mainHBox;
|
||||||
@FXML private Label turnBanner;
|
@FXML private Label turnBanner;
|
||||||
@FXML private Button confirmButton;
|
@FXML private Button confirmButton;
|
||||||
@@ -157,7 +156,6 @@ public class TotemFXMLController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
card.setOnMouseClicked(e -> {
|
card.setOnMouseClicked(e -> {
|
||||||
// reset tutti
|
|
||||||
mainHBox.getChildren().forEach(n -> {
|
mainHBox.getChildren().forEach(n -> {
|
||||||
if (n instanceof VBox v) {
|
if (n instanceof VBox v) {
|
||||||
StackPane f = (StackPane) v.getChildren().get(0);
|
StackPane f = (StackPane) v.getChildren().get(0);
|
||||||
@@ -199,16 +197,13 @@ public class TotemFXMLController {
|
|||||||
|
|
||||||
/** Returns the CSS style string for the totem card frame, highlighting it when {@code selected}. */
|
/** Returns the CSS style string for the totem card frame, highlighting it when {@code selected}. */
|
||||||
private String frameStyle(boolean selected) {
|
private String frameStyle(boolean selected) {
|
||||||
return "-fx-border-color: " + (selected ? "#75FF79" : "rgba(200,120,20,0.28)") + ";" +
|
return selected ? "-fx-effect: dropshadow(gaussian, #ffffff, 20, 0.33, 0, 0);" : "";
|
||||||
"-fx-border-width: " + (selected ? "0" : "0") + ";" +
|
|
||||||
"-fx-border-radius: 4 4 0 0; -fx-background-radius: 4 4 0 0;" +
|
|
||||||
(selected ? "-fx-effect: dropshadow(gaussian, #ffffff, 20, 0.33, 0, 0);" : "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the CSS style string for the totem name label, brightening it when {@code selected}. */
|
/** Returns the CSS style string for the totem name label, brightening it when {@code selected}. */
|
||||||
private String nameStyle(boolean selected) {
|
private String nameStyle(boolean selected) {
|
||||||
return "-fx-font-family: 'Cinzel'; -fx-font-size: 10; -fx-letter-spacing: 2;" +
|
return "-fx-font-family: 'Cinzel'; -fx-font-size: 10; -fx-letter-spacing: 2;" +
|
||||||
"-fx-text-fill: " + (selected ? "#ffffff" : "#ffffff") + ";";
|
"-fx-text-fill: " + (selected ? "#FFD700" : "#ffffff") + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the totem name with only the first letter capitalised. */
|
/** Returns the totem name with only the first letter capitalised. */
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ public interface IView {
|
|||||||
*
|
*
|
||||||
* @param miniModel the latest mini model received from the server.
|
* @param miniModel the latest mini model received from the server.
|
||||||
*/
|
*/
|
||||||
public void setModel(MiniModel miniModel);
|
void setModel(MiniModel miniModel);
|
||||||
|
|
||||||
/** Re-renders the view based on the current mini model state. */
|
/** Re-renders the view based on the current mini model state. */
|
||||||
public void render();
|
void render();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays an error message to the user.
|
* Displays an error message to the user.
|
||||||
@@ -21,6 +21,6 @@ public interface IView {
|
|||||||
* @param error the error type.
|
* @param error the error type.
|
||||||
* @param message a human-readable description of the error.
|
* @param message a human-readable description of the error.
|
||||||
*/
|
*/
|
||||||
public void showError(ErrorType error,String message);
|
void showError(ErrorType error, String message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,9 +78,9 @@ public class TUI implements IView {
|
|||||||
public synchronized void render() {
|
public synchronized void render() {
|
||||||
if (model == null) return;
|
if (model == null) return;
|
||||||
GameStages stage = model.currentState.getGameStage();
|
GameStages stage = model.currentState.getGameStage();
|
||||||
if (stage.equals(GameStages.TOTEM_CHOICE)) {
|
if (stage == GameStages.TOTEM_CHOICE) {
|
||||||
display(buildTotemsContent());
|
display(buildTotemsContent());
|
||||||
} else if (stage.equals(GameStages.ENDED)) {
|
} else if (stage == GameStages.ENDED) {
|
||||||
display(buildStandingContent() + "\nType 'rematch' to play again or 'quit' to exit");
|
display(buildStandingContent() + "\nType 'rematch' to play again or 'quit' to exit");
|
||||||
} else {
|
} else {
|
||||||
display(buildBoardContent());
|
display(buildBoardContent());
|
||||||
@@ -106,7 +106,7 @@ public class TUI implements IView {
|
|||||||
*/
|
*/
|
||||||
public void showError(ErrorType error, String message) {
|
public void showError(ErrorType error, String message) {
|
||||||
String text;
|
String text;
|
||||||
if (error.equals(ErrorType.WRONG_ACTION)
|
if (error == ErrorType.WRONG_ACTION
|
||||||
&& model != null
|
&& model != null
|
||||||
&& model.currentState.getCurrentPlayer() != null
|
&& model.currentState.getCurrentPlayer() != null
|
||||||
&& !model.currentState.getCurrentPlayer().getUserName().equals(username)) {
|
&& !model.currentState.getCurrentPlayer().getUserName().equals(username)) {
|
||||||
@@ -169,7 +169,7 @@ public class TUI implements IView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String buildStandingContent() {
|
private String buildStandingContent() {
|
||||||
if (model.standingPlayers == null) return "";
|
if (model.standingPlayers == null || model.standingPlayers.isEmpty()) return "";
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
int size = model.standingPlayers.size();
|
int size = model.standingPlayers.size();
|
||||||
for (int i = 0; i < size / 2; i++) {
|
for (int i = 0; i < size / 2; i++) {
|
||||||
@@ -253,7 +253,7 @@ public class TUI implements IView {
|
|||||||
|
|
||||||
/** Returns the display width of a string in terminal columns, stripping ANSI escape codes. */
|
/** Returns the display width of a string in terminal columns, stripping ANSI escape codes. */
|
||||||
private int visibleLength(String line) {
|
private int visibleLength(String line) {
|
||||||
return AsciiTable.displayWidth(line.replaceAll("\033\\[[^m]*m", ""));
|
return AsciiTable.displayWidth(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Board / players stamp helpers ─────────────────────────────────────────
|
// ── Board / players stamp helpers ─────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user