2025-10-22 18:34:02 +02:00

210 lines
9.4 KiB
Python

from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt6.QtGui import QResizeEvent, QCloseEvent
from PyQt6.QtCore import QSize, QEvent
from app.core.main_manager import MainManager, NotificationType
from app.ui.widgets.tabs_widget import TabsWidget, MenuDirection, ButtonPosition, BorderSide, TabSide
from app.ui.windows.settings_window import SettingsWindow
from app.ui.windows.suggestion_window import SuggestionWindow
from app.ui.windows.activation_window import ActivationWindow
import app.utils.paths as paths, shutil
from typing import Optional
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.main_manager: MainManager = MainManager.get_instance()
self.language_manager = self.main_manager.get_language_manager()
self.theme_manager = self.main_manager.get_theme_manager()
self.settings_manager = self.main_manager.get_settings_manager()
self.observer_manager = self.main_manager.get_observer_manager()
self.observer_manager.subscribe(NotificationType.THEME, self.update_theme)
self.is_maximizing: bool = False
# Initialiser les attributs de taille AVANT setup_ui
app: Optional[QApplication] = QApplication.instance()
size: QSize = app.primaryScreen().size()
self.settings_manager.minScreenSize = min(size.height(), size.width())
# Initialiser les tailles par défaut
window_size: dict = self.settings_manager.get_window_size()
self.current_size: QSize = QSize(window_size["width"], window_size["height"])
self.previous_size: QSize = QSize(window_size["width"], window_size["height"])
# Configuration des tailles de police de référence
self.base_width = 600 # Largeur de référence
self.base_height = 450 # Hauteur de référence
# Cache pour stocker les font-sizes de base de chaque widget
self._base_font_sizes = {}
# UI elements
self.side_menu: TabsWidget
self.settings_window: SettingsWindow
self.suggestion_window: SuggestionWindow
self.setMinimumSize(600, 450)
# Initialiser l'UI immédiatement (sera fait pendant le splash)
self.setup_ui()
# Différer l'application des paramètres de fenêtre jusqu'à l'affichage réel
self._window_state_applied = False
def showEvent(self, event):
"""Applique les paramètres de fenêtre lors du premier affichage"""
super().showEvent(event)
if not self._window_state_applied:
self.apply_saved_window_state()
self._window_state_applied = True
def apply_saved_window_state(self) -> None:
"""Apply saved window size and maximized state"""
window_size: dict = self.settings_manager.get_window_size()
self.current_size = QSize(window_size["width"], window_size["height"])
self.previous_size = QSize(window_size["width"], window_size["height"])
self.resize(self.current_size)
if self.settings_manager.get_maximized():
self.is_maximizing = True
self.showMaximized()
def changeEvent(self, event: QEvent) -> None:
"""Handle window state changes"""
super().changeEvent(event)
if event.type() == event.Type.WindowStateChange:
if self.isMaximized():
# On vient de maximiser
self.is_maximizing = False
else:
# On vient de dé-maximiser, restaurer la taille précédente
if hasattr(self, 'previous_size'):
self.current_size = self.previous_size
self.settings_manager.set_maximized(self.isMaximized())
def resizeEvent(self, a0: QResizeEvent) -> None:
# Ne pas sauvegarder la taille si on est en train de maximiser
if not self.isMaximized() and not self.is_maximizing:
self.previous_size = self.current_size
self.current_size = self.size()
# Ajuster dynamiquement les font-sizes
self.adjust_all_font_sizes()
def adjust_all_font_sizes(self):
"""Ajuste dynamiquement les font-sizes de tous les labels dans toutes les tabs"""
# Calculer le ratio basé sur la largeur ET la hauteur actuelle
current_width = self.width()
current_height = self.height()
# Calculer les ratios séparément
width_ratio = current_width / self.base_width
height_ratio = current_height / self.base_height
# Prendre le ratio le plus petit pour éviter que le texte dépasse
ratio = min(width_ratio, height_ratio)
# Récupérer tous les widgets des tabs
all_widgets = []
if hasattr(self, 'side_menu'):
all_widgets = self.side_menu.widgets
# Parcourir tous les widgets et ajuster leurs labels
for widget in all_widgets:
if widget:
self._adjust_widget_labels(widget, ratio)
def _adjust_widget_labels(self, widget, ratio):
"""Ajuste récursivement tous les QLabel, QPushButton, QLineEdit, QTextEdit et QComboBox d'un widget"""
from PyQt6.QtWidgets import QPushButton, QLineEdit, QTextEdit, QComboBox
# Types de widgets à ajuster
widget_types = [QLabel, QPushButton, QLineEdit, QTextEdit, QComboBox]
font_size_dict = self.extract_base_font_size()
for widget_type in widget_types:
for child in widget.findChildren(widget_type):
# Obtenir l'identifiant unique du widget
widget_id = id(child)
# Si c'est la première fois qu'on voit ce widget, extraire sa font-size de base
if widget_id not in self._base_font_sizes:
base_size = font_size_dict.get(child.__class__.__name__, 14)
self._base_font_sizes[widget_id] = base_size
else:
base_size = self._base_font_sizes[widget_id]
# Calculer la nouvelle taille
new_size = int(base_size * ratio)
# Appliquer le style (en préservant les autres styles existants)
current_style = child.styleSheet()
# Retirer l'ancienne font-size si elle existe
style_parts = [s.strip() for s in current_style.split(';') if s.strip()]
style_parts = [s for s in style_parts if not s.startswith('font-size')]
# Ajouter la nouvelle font-size
style_parts.append(f'font-size: {new_size}px')
new_style = '; '.join(style_parts)
child.setStyleSheet(new_style)
def extract_base_font_size(self) -> dict:
"""Extrait la font-size de base d'un widget depuis son stylesheet"""
base_font_sizes = {}
try:
style = self.theme_manager.get_sheet()
# Chercher "font-size: XXpx" dans le style, puis chercher à quel widget cela correspond
lines = style.splitlines()
component = None
for line in lines:
line = line.strip()
if line.startswith("font-size:"):
size_part = line.split(":")[1].strip().rstrip(";")
if size_part.endswith("px"):
size_value = int(size_part[:-2])
base_font_sizes[component] = size_value
elif line.startswith("Q"):
component = line.split("{")[0].strip()
return base_font_sizes
except Exception:
# En cas d'erreur, retourner une valeur par défaut
return {}
def closeEvent(self, event: QCloseEvent) -> None:
"""Handle application close event"""
super().closeEvent(event)
# si la difference de taille est plus grande que 10 pixels, enregistrer previoussize
if abs(self.current_size.width() - self.previous_size.width()) > 10 or abs(self.current_size.height() - self.previous_size.height()) > 10:
self.current_size = self.previous_size
self.settings_manager.set_window_size(
self.current_size.width(),
self.current_size.height()
)
try:
shutil.rmtree(paths.get_user_temp(self.settings_manager.get_config("app_name")))
except Exception:
pass
def setup_ui(self) -> None:
self.side_menu = TabsWidget(self, MenuDirection.HORIZONTAL, 70, None, 10, 1, BorderSide.BOTTOM, TabSide.TOP)
self.suggestion_window = SuggestionWindow(self)
self.side_menu.add_widget(self.suggestion_window, "", paths.get_asset_svg_path("suggestion"), position=ButtonPosition.CENTER)
self.settings_window = SettingsWindow(self)
self.side_menu.add_widget(self.settings_window, "", paths.get_asset_svg_path("settings"), position=ButtonPosition.CENTER)
# Ajouter la tab d'activation uniquement si le système de licence est activé
if self.settings_manager.get_config("enable_licensing"):
self.activation_window = ActivationWindow(self)
self.side_menu.add_widget(self.activation_window, "", paths.get_asset_svg_path("license"), position=ButtonPosition.END)
self.setCentralWidget(self.side_menu)
def update_theme(self) -> None:
self.setStyleSheet(self.theme_manager.get_sheet())