import pygame import re import json import os import config import logging logger = logging.getLogger(__name__) def create_placeholder(width=400): """Crée une image de substitution pour les jeux sans vignette.""" logger.debug(f"Création placeholder: largeur={width}") if config.font is None: # Police de secours si config.font n’est pas initialisé fallback_font = pygame.font.SysFont("arial", 24) text = fallback_font.render("No Image", True, (255, 255, 255)) else: text = config.font.render("No Image", True, (255, 255, 255)) height = int(150 * (width / 200)) placeholder = pygame.Surface((width, height)) placeholder.fill((50, 50, 50)) text_rect = text.get_rect(center=(width // 2, height // 2)) placeholder.blit(text, text_rect) return placeholder def truncate_text_middle(text, font, max_width): """Tronque le texte en insérant '...' au milieu.""" text_width = font.size(text)[0] if text_width <= max_width: return text ellipsis = "..." ellipsis_width = font.size(ellipsis)[0] max_text_width = max_width - ellipsis_width while text_width > max_text_width and len(text) > 0: text = text[:-1] text_width = font.size(text)[0] mid = len(text) // 2 return text[:mid] + ellipsis + text[mid:] def truncate_text_end(text, font, max_width): """Tronque le texte à la fin pour qu'il tienne dans max_width avec la police donnée.""" if not isinstance(text, str): logger.error(f"Texte non valide: {text}") return "" if not isinstance(font, pygame.font.Font): logger.error("Police non valide dans truncate_text_end") return text # Retourne le texte brut si la police est invalide try: if font.size(text)[0] <= max_width: return text truncated = text while len(truncated) > 0 and font.size(truncated + "...")[0] > max_width: truncated = truncated[:-1] return truncated + "..." if len(truncated) < len(text) else text except Exception as e: logger.error(f"Erreur lors du rendu du texte '{text}': {str(e)}") return text # Retourne le texte brut en cas d'erreur def sanitize_filename(name): """Sanitise les noms de fichiers en remplaçant les caractères interdits.""" return re.sub(r'[<>:"/\/\\|?*]', '_', name).strip() def wrap_text(text, font, max_width): """Divise le texte en lignes pour respecter la largeur maximale.""" words = text.split(' ') lines = [] current_line = '' for word in words: # Tester si ajouter le mot dépasse la largeur test_line = current_line + (' ' if current_line else '') + word test_surface = font.render(test_line, True, (255, 255, 255)) if test_surface.get_width() <= max_width: current_line = test_line else: if current_line: lines.append(current_line) current_line = word if current_line: lines.append(current_line) return lines def load_system_image(platform_dict): """Charge une image système depuis le chemin spécifié dans system_image.""" image_path = platform_dict.get("system_image") platform_name = platform_dict.get("platform", "unknown") #logger.debug(f"Chargement de l'image système pour {platform_name} depuis {image_path}") try: if not os.path.exists(image_path): logger.error(f"Image introuvable pour {platform_name} à {image_path}") return None return pygame.image.load(image_path).convert_alpha() except Exception as e: logger.error(f"Erreur lors du chargement de l'image pour {platform_name} : {str(e)}") return None def load_games(platform_id): """Charge les jeux pour une plateforme donnée en utilisant platform_id.""" games_path = f"/userdata/roms/ports/RGSX/games/{platform_id}.json" #logger.debug(f"Chargement des jeux pour {platform_id} depuis {games_path}") try: with open(games_path, 'r', encoding='utf-8') as f: games = json.load(f) return games except Exception as e: logger.error(f"Erreur lors du chargement des jeux pour {platform_id} : {str(e)}") return []