Files
2026-06-19 22:57:43 +02:00

494 lines
24 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html id="htmlId">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Coverage Report > LeaderboardFXMLController</title>
<style type="text/css">
@import "../../css/coverage.css";
@import "../../css/idea.min.css";
</style>
<script type="text/javascript" src="../../js/highlight.min.js"></script>
<script type="text/javascript" src="../../js/highlightjs-line-numbers.min.js"></script>
</head>
<body>
<div class="content">
<div class="breadCrumbs">
Current scope: <a href="../../index.html">all classes</a>
<span class="separator">|</span>
<a href="../index.html">it.polimi.ingsw.gc14.View.GUI</a>
</div>
<h1>Coverage Summary for Class: LeaderboardFXMLController (it.polimi.ingsw.gc14.View.GUI)</h1>
<table class="coverageStats">
<tr>
<th class="name">Class</th>
<th class="coverageStat
">
Class, %
</th>
<th class="coverageStat
">
Method, %
</th>
<th class="coverageStat
">
Branch, %
</th>
<th class="coverageStat
">
Line, %
</th>
</tr>
<tr>
<td class="name">LeaderboardFXMLController</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/1)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/19)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/34)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/181)
</span>
</td>
</tr>
</table>
<br/>
<br/>
<pre>
<code class="sourceCode" id="sourceCode">&nbsp;package it.polimi.ingsw.gc14.View.GUI;
&nbsp;
&nbsp;import it.polimi.ingsw.gc14.Controller.ClientController;
&nbsp;import it.polimi.ingsw.gc14.Model.Player;
&nbsp;import javafx.animation.ScaleTransition;
&nbsp;import it.polimi.ingsw.gc14.Model.PlayableCard;
&nbsp;import javafx.event.Event;
&nbsp;import javafx.fxml.FXML;
&nbsp;import javafx.scene.control.ScrollPane;
&nbsp;import javafx.stage.Popup;
&nbsp;import javafx.geometry.Insets;
&nbsp;import javafx.geometry.Pos;
&nbsp;import javafx.scene.Cursor;
&nbsp;import javafx.scene.Node;
&nbsp;import javafx.scene.control.Label;
&nbsp;import javafx.scene.effect.DropShadow;
&nbsp;import javafx.scene.image.Image;
&nbsp;import javafx.scene.image.ImageView;
&nbsp;import javafx.scene.input.MouseEvent;
&nbsp;import javafx.scene.layout.*;
&nbsp;import javafx.scene.paint.Color;
&nbsp;import javafx.scene.paint.LinearGradient;
&nbsp;import javafx.scene.paint.Stop;
&nbsp;import javafx.scene.paint.CycleMethod;
&nbsp;import javafx.scene.text.Font;
&nbsp;import javafx.stage.Window;
&nbsp;import javafx.util.Duration;
&nbsp;
&nbsp;import java.util.*;
&nbsp;
&nbsp;/**
&nbsp; * FXML controller for the end-of-game leaderboard scene.
&nbsp; *
&nbsp; * &lt;p&gt;Displays the final player rankings and a winner/game-over banner.
&nbsp; */
<b class="nc">&nbsp;public class LeaderboardFXMLController {</b>
&nbsp; /** Root pane of the leaderboard scene; used to set the background and anchor the popup. */
&nbsp; @FXML private StackPane rootPane;
&nbsp; /** Main vertical container holding the outcome label and ranking rows. */
&nbsp; @FXML private VBox mainVBox;
&nbsp; /** Vertical list populated with one {@code HBox} row per ranked player. */
&nbsp; @FXML private VBox rankingList;
&nbsp;
&nbsp; /** Client controller for fetching game state and sending actions. */
&nbsp; private ClientController controller;
&nbsp; /** Auto-hiding popup that shows detailed player card information. */
&nbsp; private Popup popup;
&nbsp; /** Content container inside {@link #popup}. */
&nbsp; private VBox popupContent;
&nbsp; /** Shared image cache to avoid reloading resources multiple times. */
<b class="nc">&nbsp; private static final Map&lt;String, Image&gt; imageCache = new HashMap&lt;&gt;();</b>
&nbsp; /** Action run when the player returns to the login screen (disconnect + scene switch). */
&nbsp; private Runnable action;
&nbsp;
&nbsp; /** Returns a cached {@link Image} for the given classpath {@code path}, loading it on first access. */
&nbsp; private Image loadImage(String path) {
<b class="nc">&nbsp; return imageCache.computeIfAbsent(path,</b>
<b class="nc">&nbsp; p -&gt; new Image(Objects.requireNonNull(getClass().getResourceAsStream(p))));</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; /**
&nbsp; * Injects the client controller, a post-game action, and the login scene reference.
&nbsp; *
&nbsp; * @param controller the client controller.
&nbsp; * @param action the action to run when the player returns to the login screen.
&nbsp; */
&nbsp; public void setController(ClientController controller, Runnable action) {
<b class="nc">&nbsp; this.controller = controller;</b>
<b class="nc">&nbsp; this.action = action;</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; /** Initializes the scene: loads fonts, sets up the background, and initializes the popup. */
&nbsp; @FXML
&nbsp; public void initialize() {
<b class="nc">&nbsp; Font.loadFont(getClass().getResourceAsStream(&quot;/Fonts/InknutAntiqua-Regular.ttf&quot;), 14);</b>
<b class="nc">&nbsp; mainVBox.sceneProperty().addListener((obs, oldScene, newScene) -&gt; {</b>
<b class="nc">&nbsp; if (newScene != null) newScene.getRoot().applyCss();</b>
&nbsp; });
<b class="nc">&nbsp; renderBackground();</b>
<b class="nc">&nbsp; initPopup();</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; /** Populates the ranking list with the final player standings and shows the outcome banner. */
&nbsp; public void render() {
<b class="nc">&nbsp; rankingList.getChildren().clear();</b>
<b class="nc">&nbsp; if(!controller.getMiniModel().standingPlayers.isEmpty())</b>
&nbsp; {
<b class="nc">&nbsp; List&lt;Player&gt; sorted = controller.getMiniModel().standingPlayers;</b>
&nbsp;
<b class="nc">&nbsp; boolean iWon = sorted.get(0).getUserName().equals(controller.getMyUsername());</b>
&nbsp;
&nbsp; // Label grande Winner / Game Over
<b class="nc">&nbsp; Label outcomeLabel = new Label(iWon ? &quot;\uD83C\uDFC6 WINNER! \uD83C\uDFC6&quot; : &quot;GAME OVER&quot;);</b>
<b class="nc">&nbsp; outcomeLabel.setStyle(</b>
&nbsp; &quot;-fx-font-size: 64px;&quot; +
&nbsp; &quot;-fx-font-weight: bold;&quot; +
<b class="nc">&nbsp; &quot;-fx-text-fill: &quot; + (iWon ? &quot;#FFD700;&quot; : &quot;#FF4444;&quot;)</b>
&nbsp; );
<b class="nc">&nbsp; DropShadow glow = new DropShadow();</b>
<b class="nc">&nbsp; glow.setColor(iWon ? Color.rgb(255, 200, 0, 0.95) : Color.rgb(220, 0, 0, 0.95));</b>
<b class="nc">&nbsp; glow.setRadius(35);</b>
<b class="nc">&nbsp; glow.setSpread(0.35);</b>
<b class="nc">&nbsp; outcomeLabel.setEffect(glow);</b>
<b class="nc">&nbsp; rankingList.getChildren().add(outcomeLabel);</b>
&nbsp;
<b class="nc">&nbsp; Region sep = new Region();</b>
<b class="nc">&nbsp; sep.setPrefHeight(16);</b>
<b class="nc">&nbsp; rankingList.getChildren().add(sep);</b>
&nbsp;
<b class="nc">&nbsp; for (int i = 0; i &lt; sorted.size(); i++) {</b>
<b class="nc">&nbsp; rankingList.getChildren().add(createPlayerRow(i + 1, sorted.get(i)));</b>
&nbsp; }
&nbsp; }
&nbsp; }
&nbsp;
&nbsp;
&nbsp; // ==== EFFECTS ====
&nbsp; /** Scales {@code node} to 1.02× on hover and sets a hand cursor. */
&nbsp; private void addHoverZoom(Node node) {
<b class="nc">&nbsp; ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), node);</b>
<b class="nc">&nbsp; scaleUp.setToX(1.02);</b>
<b class="nc">&nbsp; scaleUp.setToY(1.02);</b>
<b class="nc">&nbsp; ScaleTransition scaleDown = new ScaleTransition(Duration.millis(150), node);</b>
<b class="nc">&nbsp; scaleDown.setToX(1.0);</b>
<b class="nc">&nbsp; scaleDown.setToY(1.0);</b>
<b class="nc">&nbsp; node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -&gt; { scaleUp.play(); node.setCursor(Cursor.HAND); });</b>
<b class="nc">&nbsp; node.addEventHandler(MouseEvent.MOUSE_EXITED, e -&gt; { scaleDown.play(); node.setCursor(Cursor.DEFAULT); });</b>
&nbsp; }
&nbsp;
&nbsp; /** Applies a static drop-shadow to {@code node}. */
&nbsp; private void addShadow(Node node) {
<b class="nc">&nbsp; DropShadow shadow = new DropShadow();</b>
<b class="nc">&nbsp; shadow.setColor(Color.rgb(0, 0, 0, 0.6));</b>
<b class="nc">&nbsp; shadow.setRadius(12);</b>
<b class="nc">&nbsp; shadow.setOffsetX(3);</b>
<b class="nc">&nbsp; shadow.setOffsetY(3);</b>
<b class="nc">&nbsp; node.setEffect(shadow);</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; // ==== ROW ====
&nbsp; /** Builds a styled leaderboard row showing rank, totem, username, stats, and prestige for {@code player}. */
&nbsp; private HBox createPlayerRow(int position, Player player) {
<b class="nc">&nbsp; HBox row = new HBox(20);</b>
<b class="nc">&nbsp; row.setAlignment(Pos.CENTER_LEFT);</b>
<b class="nc">&nbsp; row.setPadding(new Insets(14, 28, 14, 28));</b>
<b class="nc">&nbsp; row.setMaxWidth(Double.MAX_VALUE);</b>
&nbsp;
<b class="nc">&nbsp; LinearGradient gradient = new LinearGradient(</b>
&nbsp; 0, 0, 1, 0, true, CycleMethod.NO_CYCLE,
<b class="nc">&nbsp; new Stop(0.0, Color.rgb(0, 0, 0, 0.75)),</b>
<b class="nc">&nbsp; new Stop(0.5, Color.rgb(0, 0, 0, 0.60)),</b>
<b class="nc">&nbsp; new Stop(1.0, Color.rgb(0, 0, 0, 0.75))</b>
&nbsp; );
<b class="nc">&nbsp; row.setBackground(new Background(new BackgroundFill(</b>
&nbsp; gradient,
&nbsp; new CornerRadii(12),
&nbsp; Insets.EMPTY
&nbsp; )));
<b class="nc">&nbsp; addShadow(row);</b>
<b class="nc">&nbsp; addHoverZoom(row);</b>
&nbsp;
<b class="nc">&nbsp; Label posLabel = new Label(position + &quot;°&quot;);</b>
<b class="nc">&nbsp; posLabel.setMinWidth(55);</b>
<b class="nc">&nbsp; String medalColor = switch (position) {</b>
<b class="nc">&nbsp; case 1 -&gt; &quot;#FFD700&quot;; // oro</b>
<b class="nc">&nbsp; case 2 -&gt; &quot;#C0C0C0&quot;; // argento</b>
<b class="nc">&nbsp; case 3 -&gt; &quot;#CD7F32&quot;; // bronzo</b>
<b class="nc">&nbsp; default -&gt; &quot;#EEEEEE&quot;;</b>
<b class="nc">&nbsp; };</b>
<b class="nc">&nbsp; posLabel.setStyle(&quot;-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: &quot; + medalColor + &quot;;&quot;);</b>
&nbsp;
&nbsp;
<b class="nc">&nbsp; ImageView totem = new ImageView(loadImage(</b>
<b class="nc">&nbsp; &quot;/GUIImages/Totems/totem_&quot; + player.getTotem().toString().toLowerCase(Locale.ROOT) + &quot;.png&quot;));</b>
<b class="nc">&nbsp; totem.setFitHeight(55);</b>
<b class="nc">&nbsp; totem.setPreserveRatio(true);</b>
&nbsp;
<b class="nc">&nbsp; Label nameLabel = new Label(player.getUserName());</b>
<b class="nc">&nbsp; nameLabel.setStyle(</b>
&nbsp; &quot;-fx-font-size: 22px; -fx-font-weight: bold; -fx-text-fill: &quot; +
<b class="nc">&nbsp; (player.getUserName().equals(controller.getMyUsername()) ? &quot;#ff6b6b;&quot; : &quot;#FFFFFF;&quot;)</b>
&nbsp; );
<b class="nc">&nbsp; HBox.setHgrow(nameLabel, Priority.ALWAYS);</b>
&nbsp;
<b class="nc">&nbsp; HBox stats = createStatsBox(player);</b>
&nbsp;
<b class="nc">&nbsp; HBox ppBox = new HBox(6);</b>
<b class="nc">&nbsp; ppBox.setAlignment(Pos.CENTER);</b>
<b class="nc">&nbsp; ImageView ppIcon = new ImageView(loadImage(&quot;/GUIImages/Icons/PrestigePoint.png&quot;));</b>
<b class="nc">&nbsp; ppIcon.setFitHeight(45);</b>
<b class="nc">&nbsp; ppIcon.setPreserveRatio(true);</b>
<b class="nc">&nbsp; Label ppLabel = new Label(String.valueOf(player.getPrestigeValue()));</b>
<b class="nc">&nbsp; ppLabel.setStyle(&quot;-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: #FFD700;&quot;);</b>
<b class="nc">&nbsp; ppBox.getChildren().addAll(ppIcon, ppLabel);</b>
&nbsp;
<b class="nc">&nbsp; row.getChildren().addAll(posLabel, totem, nameLabel, stats, ppBox);</b>
<b class="nc">&nbsp; row.setOnMouseClicked(e -&gt; openPlayerPopup(player));</b>
<b class="nc">&nbsp; return row;</b>
&nbsp; }
&nbsp;
&nbsp; /** Creates a compact icon+count stats strip for all card types of {@code player}. */
&nbsp; private HBox createStatsBox(Player player) {
<b class="nc">&nbsp; HBox stats = new HBox(14);</b>
<b class="nc">&nbsp; stats.setAlignment(Pos.CENTER);</b>
&nbsp;
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Food.png&quot;, String.valueOf(player.getFoodValue()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Artist.png&quot;, String.valueOf(player.getArtists().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Gatherer.png&quot;, String.valueOf(player.getGatherers().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Inventor.png&quot;, String.valueOf(player.getInventors().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Builder.png&quot;, String.valueOf(player.getBuilders().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Shaman.png&quot;, String.valueOf(player.getShamans().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Hunter.png&quot;, String.valueOf(player.getHunters().size()), 26));</b>
<b class="nc">&nbsp; stats.getChildren().add(createStatItem(&quot;/GUIImages/Icons/Building.png&quot;, String.valueOf(player.getBuildingCards().size()), 26));</b>
&nbsp;
<b class="nc">&nbsp; return stats;</b>
&nbsp; }
&nbsp;
&nbsp; /** Creates a single icon + label widget for one stat type. */
&nbsp; private HBox createStatItem(String iconPath, String value, double iconHeight) {
<b class="nc">&nbsp; HBox box = new HBox(4);</b>
<b class="nc">&nbsp; box.setAlignment(Pos.CENTER);</b>
<b class="nc">&nbsp; ImageView icon = new ImageView(loadImage(iconPath));</b>
<b class="nc">&nbsp; icon.setFitHeight(iconHeight);</b>
<b class="nc">&nbsp; icon.setPreserveRatio(true);</b>
<b class="nc">&nbsp; Label label = new Label(value);</b>
<b class="nc">&nbsp; label.setStyle(&quot;-fx-font-size: 16px; -fx-text-fill: #FFFFFF; -fx-font-weight: bold;&quot;);</b>
<b class="nc">&nbsp; DropShadow textShadow = new DropShadow();</b>
<b class="nc">&nbsp; textShadow.setColor(Color.rgb(0, 0, 0, 0.9));</b>
<b class="nc">&nbsp; textShadow.setRadius(4);</b>
<b class="nc">&nbsp; label.setEffect(textShadow);</b>
<b class="nc">&nbsp; box.getChildren().addAll(icon, label);</b>
<b class="nc">&nbsp; return box;</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; // ==== POPUP ====
&nbsp; /** Creates and configures the auto-hiding player-detail popup. */
&nbsp; private void initPopup() {
<b class="nc">&nbsp; popupContent = new VBox(12);</b>
<b class="nc">&nbsp; popupContent.setAlignment(Pos.CENTER);</b>
<b class="nc">&nbsp; popupContent.setPadding(new Insets(16));</b>
<b class="nc">&nbsp; popupContent.setStyle(</b>
&nbsp; &quot;-fx-background-color: rgba(20,10,5,0.97);&quot; +
&nbsp; &quot;-fx-border-color: #8B4513;&quot; +
&nbsp; &quot;-fx-border-width: 3;&quot; +
&nbsp; &quot;-fx-border-radius: 14;&quot; +
&nbsp; &quot;-fx-background-radius: 14;&quot;
&nbsp; );
&nbsp;
<b class="nc">&nbsp; popup = new Popup();</b>
<b class="nc">&nbsp; popup.getContent().add(popupContent);</b>
<b class="nc">&nbsp; popup.setAutoHide(true);</b>
<b class="nc">&nbsp; popup.addEventHandler(Event.ANY, e -&gt; {</b>
<b class="nc">&nbsp; if (popup.getScene() != null) popup.getScene().setFill(Color.TRANSPARENT);</b>
&nbsp; });
&nbsp; }
&nbsp;
&nbsp; /** Opens the player-detail popup showing all cards held by {@code player}, grouped by type. */
&nbsp; private void openPlayerPopup(Player player) {
<b class="nc">&nbsp; popupContent.getChildren().clear();</b>
&nbsp;
<b class="nc">&nbsp; HBox header = new HBox(10);</b>
<b class="nc">&nbsp; header.setAlignment(Pos.CENTER);</b>
<b class="nc">&nbsp; ImageView totem = new ImageView(loadImage(</b>
<b class="nc">&nbsp; &quot;/GUIImages/Totems/totem_&quot; + player.getTotem().toString().toLowerCase(Locale.ROOT) + &quot;.png&quot;));</b>
<b class="nc">&nbsp; totem.setFitHeight(30);</b>
<b class="nc">&nbsp; totem.setPreserveRatio(true);</b>
<b class="nc">&nbsp; Label nameLabel = new Label(player.getUserName());</b>
<b class="nc">&nbsp; nameLabel.setStyle(&quot;-fx-font-size: 18px; -fx-font-weight: bold; -fx-text-fill: #FFD700;&quot;);</b>
<b class="nc">&nbsp; header.getChildren().addAll(totem, nameLabel);</b>
<b class="nc">&nbsp; popupContent.getChildren().add(header);</b>
&nbsp;
<b class="nc">&nbsp; String[][] types = {</b>
&nbsp; {&quot;Artist&quot;, &quot;artists&quot;},
&nbsp; {&quot;Gatherer&quot;, &quot;gatherers&quot;},
&nbsp; {&quot;Inventor&quot;, &quot;inventors&quot;},
&nbsp; {&quot;Builder&quot;, &quot;builders&quot;},
&nbsp; {&quot;Shaman&quot;, &quot;shamans&quot;},
&nbsp; {&quot;Hunter&quot;, &quot;hunters&quot;},
&nbsp; {&quot;Building&quot;, &quot;buildingCards&quot;}
&nbsp; };
&nbsp;
<b class="nc">&nbsp; VBox grid = new VBox(6);</b>
<b class="nc">&nbsp; grid.setAlignment(Pos.CENTER_LEFT);</b>
<b class="nc">&nbsp; boolean hasAnyCard = false;</b>
&nbsp;
<b class="nc">&nbsp; for (String[] type : types) {</b>
<b class="nc">&nbsp; String typeName = type[0];</b>
<b class="nc">&nbsp; String field = type[1];</b>
<b class="nc">&nbsp; ArrayList&lt;PlayableCard&gt; cards = getPlayerCards(player.getUserName(), field);</b>
<b class="nc">&nbsp; if (cards.isEmpty()) continue;</b>
<b class="nc">&nbsp; hasAnyCard = true;</b>
&nbsp;
<b class="nc">&nbsp; HBox row = new HBox(6);</b>
<b class="nc">&nbsp; row.setAlignment(Pos.CENTER_LEFT);</b>
&nbsp;
<b class="nc">&nbsp; ImageView typeIcon = new ImageView(loadImage(&quot;/GUIImages/Icons/&quot;+typeName+&quot;.png&quot;));</b>
<b class="nc">&nbsp; typeIcon.setFitHeight(22);</b>
<b class="nc">&nbsp; typeIcon.setPreserveRatio(true);</b>
<b class="nc">&nbsp; row.getChildren().add(typeIcon);</b>
&nbsp;
<b class="nc">&nbsp; for (PlayableCard card : cards) {</b>
<b class="nc">&nbsp; ImageView img = new ImageView(loadImage(&quot;/GUIImages/Fronts/card-&quot; + card.getIdIMG() + &quot;.png&quot;));</b>
<b class="nc">&nbsp; img.setFitHeight(230);</b>
<b class="nc">&nbsp; img.setPreserveRatio(true);</b>
<b class="nc">&nbsp; img.setCursor(Cursor.HAND);</b>
<b class="nc">&nbsp; row.getChildren().add(img);</b>
&nbsp; }
&nbsp;
<b class="nc">&nbsp; grid.getChildren().add(row);</b>
&nbsp; }
&nbsp;
<b class="nc">&nbsp; if (!hasAnyCard) {</b>
<b class="nc">&nbsp; Label empty = new Label(&quot;No cards&quot;);</b>
<b class="nc">&nbsp; empty.setStyle(&quot;-fx-font-size: 14px; -fx-text-fill: #888888;&quot;);</b>
<b class="nc">&nbsp; grid.getChildren().add(empty);</b>
&nbsp; }
&nbsp;
<b class="nc">&nbsp; ScrollPane scrollPane = new ScrollPane(grid);</b>
<b class="nc">&nbsp; scrollPane.setFitToWidth(true);</b>
<b class="nc">&nbsp; scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);</b>
<b class="nc">&nbsp; scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);</b>
<b class="nc">&nbsp; scrollPane.setStyle(&quot;-fx-background: transparent; -fx-background-color: transparent;&quot;);</b>
&nbsp;
<b class="nc">&nbsp; Window window = rootPane.getScene().getWindow();</b>
<b class="nc">&nbsp; scrollPane.setMaxHeight(window.getHeight() * 0.8); // cap scroll area to 80% of window height</b>
<b class="nc">&nbsp; popupContent.getChildren().add(scrollPane);</b>
<b class="nc">&nbsp; popup.show(window, 0, 0);</b>
<b class="nc">&nbsp; popup.getScene().setFill(Color.TRANSPARENT);</b>
<b class="nc">&nbsp; popup.setX(window.getX() + (window.getWidth() - popup.getWidth()) / 2);</b>
<b class="nc">&nbsp; popup.setY(window.getY() + (window.getHeight() - popup.getHeight()) / 2);</b>
&nbsp; }
&nbsp;
&nbsp; /** Returns a copy of the named card collection for {@code username}. */
&nbsp; private ArrayList&lt;PlayableCard&gt; getPlayerCards(String username, String type) {
<b class="nc">&nbsp; Player p = controller.getMiniModel().players.get(username);</b>
<b class="nc">&nbsp; return switch (type) {</b>
<b class="nc">&nbsp; case &quot;artists&quot; -&gt; new ArrayList&lt;&gt;(p.getArtists());</b>
<b class="nc">&nbsp; case &quot;gatherers&quot; -&gt; new ArrayList&lt;&gt;(p.getGatherers());</b>
<b class="nc">&nbsp; case &quot;inventors&quot; -&gt; new ArrayList&lt;&gt;(p.getInventors());</b>
<b class="nc">&nbsp; case &quot;builders&quot; -&gt; new ArrayList&lt;&gt;(p.getBuilders());</b>
<b class="nc">&nbsp; case &quot;shamans&quot; -&gt; new ArrayList&lt;&gt;(p.getShamans());</b>
<b class="nc">&nbsp; case &quot;hunters&quot; -&gt; new ArrayList&lt;&gt;(p.getHunters());</b>
<b class="nc">&nbsp; case &quot;buildingCards&quot; -&gt; new ArrayList&lt;&gt;(p.getBuildingCards());</b>
<b class="nc">&nbsp; default -&gt; new ArrayList&lt;&gt;();</b>
&nbsp; };
&nbsp; }
&nbsp;
&nbsp; // ==== BACKGROUND ====
&nbsp; /** Sets the full-cover background image on the root pane. */
&nbsp; private void renderBackground() {
<b class="nc">&nbsp; BackgroundSize size = new BackgroundSize(</b>
&nbsp; BackgroundSize.AUTO, BackgroundSize.AUTO,
&nbsp; false, false, true, true
&nbsp; );
<b class="nc">&nbsp; rootPane.setBackground(new Background(new BackgroundImage(</b>
<b class="nc">&nbsp; loadImage(&quot;/GUIImages/Background.png&quot;),</b>
&nbsp; BackgroundRepeat.NO_REPEAT,
&nbsp; BackgroundRepeat.NO_REPEAT,
&nbsp; BackgroundPosition.CENTER,
&nbsp; size
&nbsp; )));
&nbsp; }
&nbsp;
&nbsp;
&nbsp; // ==== ACTIONS ====
&nbsp; /** Disconnects the client and invokes the post-game action to return to the login scene. */
&nbsp; @FXML
&nbsp; private void onNewGame() {
<b class="nc">&nbsp; controller.disconnect();</b>
<b class="nc">&nbsp; action.run();</b>
&nbsp; }
&nbsp;}
</code>
</pre>
</div>
<script type="text/javascript">
(function() {
var msie = false, msie9 = false;
/*@cc_on
msie = true;
@if (@_jscript_version >= 9)
msie9 = true;
@end
@*/
if (!msie || msie && msie9) {
hljs.highlightAll()
hljs.initLineNumbersOnLoad();
}
})();
</script>
<div class="footer">
<div style="float:right;">generated on 2026-06-19 22:53</div>
</div>
</body>
</html>