277 lines
13 KiB
Python
277 lines
13 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, TextPosition
|
|
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.observer_manager.subscribe(NotificationType.LANGUAGE, self.update_language)
|
|
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 = 1200 # Largeur de référence (taille par défaut)
|
|
self.base_height = 700 # Hauteur de référence (taille par défaut)
|
|
self.base_tab_height = 70 # Hauteur de base du tab menu
|
|
|
|
# Cache pour stocker les font-sizes de base de chaque widget
|
|
self._base_font_sizes = {}
|
|
self._font_sizes_extracted = False # Flag pour savoir si on a déjà extrait les tailles
|
|
|
|
# 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 avec un ratio
|
|
self.adjust_all_font_sizes()
|
|
|
|
def adjust_all_font_sizes(self):
|
|
"""Ajuste dynamiquement les font-sizes de tous les éléments avec un ratio proportionnel"""
|
|
# 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
|
|
|
|
# Utiliser la moyenne des deux ratios pour un scaling plus naturel
|
|
# Ou utiliser le minimum pour éviter le débordement
|
|
ratio = min(width_ratio,height_ratio) * 1.5
|
|
|
|
# Limiter le ratio pour éviter des tailles extrêmes
|
|
ratio = max(0.5, min(ratio, 2.0)) # Entre 50% et 200%
|
|
|
|
# Récupérer tous les widgets des tabs
|
|
all_widgets = []
|
|
if hasattr(self, 'side_menu'):
|
|
all_widgets = self.side_menu.widgets
|
|
|
|
# Extraire les tailles de base une seule fois
|
|
if not self._font_sizes_extracted:
|
|
self._extract_base_font_sizes(all_widgets)
|
|
self._font_sizes_extracted = True
|
|
|
|
# Parcourir tous les widgets et ajuster leurs tailles
|
|
for widget in all_widgets:
|
|
if widget:
|
|
self._adjust_widget_font_sizes(widget, ratio)
|
|
|
|
def _extract_base_font_sizes(self, widgets):
|
|
"""Extrait les tailles de police de base de tous les widgets une seule fois"""
|
|
from PyQt6.QtWidgets import QPushButton, QLineEdit, QTextEdit, QComboBox
|
|
|
|
widget_types = [QLabel, QPushButton, QLineEdit, QTextEdit, QComboBox]
|
|
# Extraire les tailles des boutons d'onglets du side menu
|
|
if hasattr(self, 'side_menu') and hasattr(self.side_menu, 'buttons'):
|
|
for button in self.side_menu.buttons:
|
|
if button:
|
|
widget_id = id(button)
|
|
current_style = button.styleSheet()
|
|
base_size = self._extract_font_size_from_style(current_style)
|
|
if base_size is None:
|
|
base_size = 14 # Taille par défaut
|
|
self._base_font_sizes[widget_id] = base_size
|
|
|
|
for widget in widgets:
|
|
if not widget:
|
|
continue
|
|
|
|
for widget_type in widget_types:
|
|
for child in widget.findChildren(widget_type):
|
|
widget_id = id(child)
|
|
|
|
# Ignorer les widgets avec un objectName (généralement stylisés spécifiquement)
|
|
if child.objectName() != "":
|
|
continue
|
|
|
|
# Extraire la taille de police depuis le stylesheet
|
|
current_style = child.styleSheet()
|
|
base_size = self._extract_font_size_from_style(current_style)
|
|
|
|
# Si pas trouvé dans le style, utiliser la taille par défaut
|
|
if base_size is None:
|
|
base_size = 14 # Taille par défaut
|
|
|
|
# Stocker la taille de base
|
|
self._base_font_sizes[widget_id] = base_size
|
|
|
|
def _extract_font_size_from_style(self, style: str) -> Optional[int]:
|
|
"""Extrait la taille de police depuis un stylesheet"""
|
|
import re
|
|
|
|
# Chercher "font-size: XXpx"
|
|
match = re.search(r'font-size:\s*(\d+)px', style)
|
|
if match:
|
|
return int(match.group(1))
|
|
|
|
return None
|
|
|
|
def _adjust_widget_font_sizes(self, widget, ratio):
|
|
"""Ajuste les font-sizes de tous les éléments d'un widget avec un ratio proportionnel"""
|
|
from PyQt6.QtWidgets import QPushButton, QLineEdit, QTextEdit, QComboBox
|
|
import re
|
|
|
|
# Ajuster les boutons d'onglets du side menu
|
|
if hasattr(self, 'side_menu') and hasattr(self.side_menu, 'buttons'):
|
|
for button in self.side_menu.buttons:
|
|
if button:
|
|
widget_id = id(button)
|
|
if widget_id in self._base_font_sizes:
|
|
base_size = self._base_font_sizes[widget_id]
|
|
new_size = max(8, int(base_size * ratio))
|
|
current_style = button.styleSheet()
|
|
style_without_font = re.sub(r'font-size:\s*\d+px;?', '', current_style)
|
|
style_without_font = re.sub(r';+', ';', style_without_font)
|
|
style_without_font = style_without_font.strip()
|
|
if style_without_font and not style_without_font.endswith(';'):
|
|
style_without_font += ';'
|
|
new_style = f"{style_without_font} font-size: {new_size}px;"
|
|
button.setStyleSheet(new_style)
|
|
|
|
widget_types = [QLabel, QPushButton, QLineEdit, QTextEdit, QComboBox]
|
|
|
|
for widget_type in widget_types:
|
|
for child in widget.findChildren(widget_type):
|
|
widget_id = id(child)
|
|
|
|
# Récupérer la taille de base
|
|
if widget_id not in self._base_font_sizes:
|
|
continue # Pas de taille de base, ignorer
|
|
|
|
base_size = self._base_font_sizes[widget_id]
|
|
|
|
# Calculer la nouvelle taille avec le ratio
|
|
new_size = max(8, int(base_size * ratio)) # Minimum 8px
|
|
|
|
# Appliquer le style en préservant les autres propriétés
|
|
current_style = child.styleSheet()
|
|
|
|
# Retirer l'ancienne font-size
|
|
style_without_font = re.sub(r'font-size:\s*\d+px;?', '', current_style)
|
|
|
|
# Nettoyer les points-virgules multiples
|
|
style_without_font = re.sub(r';+', ';', style_without_font)
|
|
style_without_font = style_without_font.strip()
|
|
|
|
# Ajouter la nouvelle font-size
|
|
if style_without_font and not style_without_font.endswith(';'):
|
|
style_without_font += ';'
|
|
|
|
new_style = f"{style_without_font} font-size: {new_size}px;"
|
|
child.setStyleSheet(new_style)
|
|
|
|
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, BorderSide.BOTTOM, TabSide.TOP)
|
|
|
|
self.suggestion_window = SuggestionWindow(self)
|
|
self.side_menu.add_widget(self.suggestion_window, self.language_manager.get_text("tab_suggestions"), paths.get_asset_svg_path("suggestion"), position=ButtonPosition.CENTER, text_position=TextPosition.BOTTOM)
|
|
|
|
self.settings_window = SettingsWindow(self)
|
|
self.side_menu.add_widget(self.settings_window, self.language_manager.get_text("tab_settings"), paths.get_asset_svg_path("settings"), position=ButtonPosition.CENTER, text_position=TextPosition.BOTTOM)
|
|
|
|
# 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, self.language_manager.get_text("tab_licensing"), paths.get_asset_svg_path("license"), position=ButtonPosition.END, text_position=TextPosition.BOTTOM)
|
|
|
|
self.setCentralWidget(self.side_menu)
|
|
|
|
def get_tab_widget(self):
|
|
"""Retourne le widget TabsWidget pour permettre le changement d'onglet"""
|
|
return self.side_menu
|
|
|
|
def update_theme(self) -> None:
|
|
self.setStyleSheet(self.theme_manager.get_sheet())
|
|
|
|
def update_language(self) -> None:
|
|
# Mettre à jour les textes des onglets
|
|
self.side_menu.update_button_text(0, self.language_manager.get_text("tab_suggestions"))
|
|
self.side_menu.update_button_text(1, self.language_manager.get_text("tab_settings"))
|
|
if self.settings_manager.get_config("enable_licensing"):
|
|
self.side_menu.update_button_text(2, self.language_manager.get_text("tab_licensing")) |