package org.example.mesosll07; import javafx.application.Application; import javafx.embed.swing.SwingFXUtils; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class DeckGridApp extends Application { // Inizializza il Logger private static final Logger logger = LogManager.getLogger(DeckGridApp.class); private PDDocument document; private PDFRenderer pdfRenderer; private int totalCards = 0; // Contenitori per le tre righe private HBox topRow; private HBox centerRow; private HBox bottomRow; private Button btnShuffle; @Override public void start(Stage primaryStage) { primaryStage.setTitle("Tavolo da Gioco - Carte Casuali"); logger.info("Avvio dell'applicazione JavaFX"); // Pulsanti Button btnLoad = new Button("Carica PDF Mazzo"); btnShuffle = new Button("Rimescola Carte"); btnShuffle.setDisable(true); // Disabilitato finché non si carica un PDF btnLoad.setOnAction(e -> loadPdf(primaryStage)); btnShuffle.setOnAction(e -> distributeRandomCards()); HBox topMenu = new HBox(15, btnLoad, btnShuffle); topMenu.setAlignment(Pos.CENTER); topMenu.setPadding(new Insets(10)); // Setup delle tre righe (spazio tra le carte impostato a 10px) topRow = createRowContainer(); centerRow = createRowContainer(); bottomRow = createRowContainer(); // Contenitore verticale per le righe VBox tableArea = new VBox(30, new Label("TOP (8 Carte):"), topRow, new Label("CENTER (6 Carte):"), centerRow, new Label("BOTTOM (7 Carte):"), bottomRow ); tableArea.setAlignment(Pos.CENTER); tableArea.setPadding(new Insets(20)); // Mettiamo il tavolo in uno ScrollPane nel caso le carte siano troppo grandi per lo schermo ScrollPane scrollPane = new ScrollPane(tableArea); scrollPane.setFitToWidth(true); BorderPane root = new BorderPane(); root.setTop(topMenu); root.setCenter(scrollPane); // Finestra un po' più grande per contenere tutte queste carte Scene scene = new Scene(root, 1200, 800); primaryStage.setScene(scene); primaryStage.show(); } private HBox createRowContainer() { HBox row = new HBox(15); // 15px di spazio tra una carta e l'altra row.setAlignment(Pos.CENTER); return row; } private void loadPdf(Stage stage) { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Seleziona il PDF del mazzo di carte"); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("File PDF", "*.pdf")); File file = fileChooser.showOpenDialog(stage); if (file != null) { try { if (document != null) { document.close(); } logger.info("Caricamento file PDF: {}", file.getAbsolutePath()); document = PDDocument.load(file); pdfRenderer = new PDFRenderer(document); totalCards = document.getNumberOfPages(); logger.info("PDF caricato. Pagine totali (carte): {}", totalCards); btnShuffle.setDisable(false); // Distribuisci le carte per la prima volta distributeRandomCards(); } catch (IOException e) { logger.error("Errore nel caricamento del PDF", e); } } } private void distributeRandomCards() { if (document == null || totalCards == 0) return; logger.info("Inizio rimescolamento e distribuzione carte..."); // Pulisce il tavolo dalle carte precedenti topRow.getChildren().clear(); centerRow.getChildren().clear(); bottomRow.getChildren().clear(); // 1. Crea una lista con tutti gli indici (da 0 al numero totale di pagine) List deckIndices = new ArrayList<>(); for (int i = 0; i < totalCards; i++) { deckIndices.add(i); } // 2. Mescola la lista (Simula la mescolata del mazzo) Collections.shuffle(deckIndices); // 3. Distribuisci nelle righe (evitando IndexOutOfBounds se il PDF ha meno di 21 pagine) // Riga Top: 8 carte populateRow(topRow, deckIndices, 0, 8); // Riga Center: 6 carte populateRow(centerRow, deckIndices, 8, 6); // Riga Bottom: 7 carte populateRow(bottomRow, deckIndices, 14, 7); logger.info("Distribuzione completata."); } private void populateRow(HBox row, List deckIndices, int startIndex, int numberOfCards) { for (int i = 0; i < numberOfCards; i++) { int actualIndex = startIndex + i; // Se abbiamo esaurito le carte nel PDF, interrompiamo if (actualIndex >= deckIndices.size()) { logger.warn("Il PDF non ha abbastanza carte per riempire questa riga."); break; } int pageNumber = deckIndices.get(actualIndex); ImageView cardImage = createCardImageView(pageNumber); if (cardImage != null) { row.getChildren().add(cardImage); } } } private ImageView createCardImageView(int pageIndex) { try { // Renderizza la pagina. Usiamo 100 DPI invece di 150 per risparmiare RAM, // dato che ora stiamo generando 21 immagini contemporaneamente. BufferedImage bim = pdfRenderer.renderImageWithDPI(pageIndex, 100); Image fxImage = SwingFXUtils.toFXImage(bim, null); ImageView imageView = new ImageView(fxImage); // Impostiamo l'altezza fissa per le carte, in modo che stiano sullo schermo imageView.setFitHeight(180); imageView.setPreserveRatio(true); imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.5), 5, 0, 0, 0);"); return imageView; } catch (IOException e) { logger.error("Errore durante il rendering della pagina {}", pageIndex, e); return null; } } @Override public void stop() throws Exception { if (document != null) { document.close(); logger.info("Documento PDF chiuso correttamente."); } logger.info("Applicazione terminata."); super.stop(); } public static void main(String[] args) { launch(args); } }