5555 QGridLayout ,
5656 QFrame ,
5757 QSplitter ,
58+ QTabWidget ,
5859)
5960from PySide6 .QtGui import QIcon , QAction , QFont , QPixmap
6061
6566)
6667from Core .engines_loader .validator import check_engine_compatibility
6768from Core .allversion import get_core_version , get_engine_sdk_version
69+ import Core .engines_loader as engines_loader
6870
6971
7072class EnginesStandaloneGui (QMainWindow ):
@@ -182,35 +184,25 @@ def _setup_ui(self):
182184 config_layout = QGridLayout (config_widget )
183185 config_layout .setSpacing (15 )
184186
185- # === Section Moteur ===
187+ # === Section Moteur (Tabs) ===
186188 engine_group = QGroupBox ("Engine Configuration" )
187- engine_layout = QGridLayout ()
189+ engine_layout = QVBoxLayout ()
188190
189- engine_label = QLabel ("Engine:" )
190- engine_layout .addWidget (engine_label , 0 , 0 )
191+ # Ajout du QTabWidget pour les moteurs (comme dans l'application principale)
192+ self .compiler_tabs = QTabWidget ()
193+ self .compiler_tabs .setDocumentMode (False )
194+ self .compiler_tabs .setTabsClosable (False )
195+ self .compiler_tabs .setMovable (False )
196+ engine_layout .addWidget (self .compiler_tabs )
191197
192- self .engine_combo = QComboBox ()
193- self .engine_combo .setMinimumWidth (200 )
194- self .engine_combo .currentIndexChanged .connect (self ._on_engine_changed )
195- engine_layout .addWidget (self .engine_combo , 0 , 1 )
196-
197- self .engine_version_label = QLabel ("Version: -" )
198- self .engine_version_label .setStyleSheet ("color: #888;" )
199- engine_layout .addWidget (self .engine_version_label , 0 , 2 )
200-
201- engine_layout .addWidget (QLabel ("Required Core:" ), 1 , 0 )
202- self .core_version_label = QLabel ("-" )
203- self .core_version_label .setStyleSheet ("color: #888;" )
204- engine_layout .addWidget (self .core_version_label , 1 , 1 , 1 , 2 )
205-
206- # Bouton vérifier compatibilité
198+ # Bouton vérifier compatibilité (sélectionne l'onglet courant)
207199 compat_btn = QPushButton ("Check Compatibility" )
208200 compat_btn .clicked .connect (self ._check_compatibility )
209- engine_layout .addWidget (compat_btn , 2 , 0 )
201+ engine_layout .addWidget (compat_btn )
210202
211203 self .compat_status_label = QLabel ("" )
212204 self .compat_status_label .setStyleSheet ("font-weight: bold;" )
213- engine_layout .addWidget (self .compat_status_label , 2 , 1 , 1 , 2 )
205+ engine_layout .addWidget (self .compat_status_label )
214206
215207 engine_group .setLayout (engine_layout )
216208 config_layout .addWidget (engine_group , 0 , 0 )
@@ -338,13 +330,6 @@ def _setup_ui(self):
338330 self .setStatusBar (self .statusBar )
339331 self .statusBar .showMessage ("Ready" )
340332
341- # Initialiser les dimensions des groupes
342- self ._init_group_dimensions ()
343-
344- def _init_group_dimensions (self ):
345- """Initialise les dimensions minimales des groupes."""
346- self .engine_combo .setMinimumContentsLength (15 )
347-
348333 def _center_window (self ):
349334 """Centre la fenêtre sur l'écran."""
350335 screen_geometry = QApplication .primaryScreen ().geometry ()
@@ -513,62 +498,145 @@ def _apply_language(self, lang_code: str):
513498 child .setTitle (tr ["log" ])
514499
515500 def _refresh_engines (self ):
516- """Rafraîchit la liste des moteurs disponibles."""
517- self .engine_combo .clear ()
501+ """Rafraîchit la liste des moteurs disponibles et crée leurs onglets."""
502+ # Nettoyer les onglets existants
503+ self .compiler_tabs .clear ()
518504 self .engines_info = {}
519505
520506 engine_ids = available_engines ()
521507
522- for eid in engine_ids :
523- try :
524- engine_cls = get_engine (eid )
525- if engine_cls :
526- name = getattr (engine_cls , "name" , eid )
527- version = getattr (engine_cls , "version" , "1.0.0" )
528- required_core = getattr (
529- engine_cls , "required_core_version" , "1.0.0"
530- )
508+ if not engine_ids :
509+ # Pas de moteurs : afficher un message
510+ no_engine_widget = QWidget ()
511+ no_engine_layout = QVBoxLayout ()
512+ no_engine_label = QLabel ("No engines available.\n Please check ENGINES folder." )
513+ no_engine_label .setStyleSheet ("color: #888; font-size: 14px;" )
514+ no_engine_label .setAlignment (Qt .AlignmentFlag .AlignCenter )
515+ no_engine_layout .addWidget (no_engine_label )
516+ no_engine_widget .setLayout (no_engine_layout )
517+ self .compiler_tabs .addTab (no_engine_label , "No Engines" )
518+ self ._log ("No engines available. Please check ENGINES folder." )
519+ self .statusBar .showMessage ("No engines available" )
520+ return
531521
532- self .engine_combo .addItem (f"{ name } ({ eid } )" , eid )
533- self .engines_info [eid ] = {
534- "name" : name ,
535- "version" : version ,
536- "required_core" : required_core ,
537- "class" : engine_cls ,
538- }
539- except Exception as e :
540- self ._log (f"Error loading engine { eid } : { e } " )
541-
542- if engine_ids :
522+ # Utiliser le mécanisme standard de bind_tabs comme dans l'application principale
523+ try :
524+ engines_loader .registry .bind_tabs (self )
543525 self ._log (f"Loaded { len (engine_ids )} engine(s)" )
544526 self .statusBar .showMessage (f"Ready - { len (engine_ids )} engines loaded" )
545- else :
546- self ._log ("No engines available. Please check ENGINES folder." )
547- self .statusBar .showMessage ("No engines available" )
527+ except Exception as e :
528+ self ._log (f"Error binding engine tabs: { e } " )
529+ # Fallback : créer les onglets manuellement
530+ for eid in engine_ids :
531+ try :
532+ engine_cls = get_engine (eid )
533+ if engine_cls :
534+ name = getattr (engine_cls , "name" , eid )
535+ version = getattr (engine_cls , "version" , "1.0.0" )
536+ required_core = getattr (
537+ engine_cls , "required_core_version" , "1.0.0"
538+ )
539+
540+ self .engines_info [eid ] = {
541+ "name" : name ,
542+ "version" : version ,
543+ "required_core" : required_core ,
544+ "class" : engine_cls ,
545+ }
546+
547+ # Essayer de créer l'onglet via create_tab
548+ create_tab = getattr (engine_cls , "create_tab" , None )
549+ if callable (create_tab ):
550+ result = create_tab (self )
551+ if result :
552+ widget , label = result
553+ self .compiler_tabs .addTab (widget , label )
554+ else :
555+ # Pas de create_tab : créer un onglet par défaut
556+ default_widget = self ._create_default_engine_widget (
557+ eid , name , version , required_core
558+ )
559+ self .compiler_tabs .addTab (default_widget , name )
560+
561+ except Exception as e :
562+ self ._log (f"Error loading engine { eid } : { e } " )
548563
549564 def _on_engine_changed (self , index ):
550- """Appelé lorsque l'utilisateur sélectionne un moteur."""
565+ """Appelé lorsque l'utilisateur sélectionne un moteur via l'onglet ."""
551566 if index < 0 :
552567 return
553568
554- engine_id = self .engine_combo .currentData ()
555- self .selected_engine_id = engine_id
569+ # Récupérer l'ID du moteur depuis le registry
570+ try :
571+ engine_id = engines_loader .registry .get_engine_for_tab (index )
572+ self .selected_engine_id = engine_id
573+ if engine_id and engine_id in self .engines_info :
574+ info = self .engines_info [engine_id ]
575+ self ._log (f"Selected engine: { info ['name' ]} v{ info ['version' ]} " )
576+ except Exception as e :
577+ self ._log (f"Error getting engine for tab { index } : { e } " )
578+
579+ def _create_default_engine_widget (
580+ self , engine_id : str , name : str , version : str , required_core : str
581+ ) -> QWidget :
582+ """Crée un widget par défaut pour un moteur sans create_tab."""
583+ widget = QWidget ()
584+ layout = QGridLayout ()
585+
586+ layout .addWidget (QLabel (f"<b>Engine:</b> { name } ({ engine_id } )" ), 0 , 0 , 1 , 2 )
587+ layout .addWidget (QLabel (f"<b>Version:</b> { version } " ), 1 , 0 )
588+ layout .addWidget (QLabel (f"<b>Required Core:</b> { required_core } " ), 1 , 1 )
589+
590+ # Info label
591+ info_label = QLabel (
592+ "This engine uses default configuration.\n "
593+ "Configure options in the main application for full functionality."
594+ )
595+ info_label .setStyleSheet ("color: #888; font-style: italic;" )
596+ info_label .setAlignment (Qt .AlignmentFlag .AlignCenter )
597+ layout .addWidget (info_label , 2 , 0 , 1 , 2 )
556598
557- if engine_id in self .engines_info :
558- info = self .engines_info [engine_id ]
559- self .engine_version_label .setText (f"Version: { info ['version' ]} " )
560- self .core_version_label .setText (info ["required_core" ])
561- self ._log (f"Selected engine: { info ['name' ]} v{ info ['version' ]} " )
599+ widget .setLayout (layout )
600+ return widget
562601
563602 def _check_compatibility (self ):
564- """Vérifie la compatibilité du moteur sélectionné."""
565- engine_id = self .engine_combo .currentData ()
603+ """Vérifie la compatibilité du moteur de l'onglet courant."""
604+ # Récupérer l'ID du moteur depuis l'onglet courant
605+ current_index = self .compiler_tabs .currentIndex ()
606+ if current_index < 0 :
607+ QMessageBox .warning (self , "Warning" , "No engine tab selected" )
608+ return
609+
610+ try :
611+ engine_id = engines_loader .registry .get_engine_for_tab (current_index )
612+ if not engine_id :
613+ # Essayer le fallback avec engines_info
614+ if self .engines_info :
615+ engine_id = list (self .engines_info .keys ())[current_index ]
616+ else :
617+ QMessageBox .warning (self , "Warning" , "No engine available" )
618+ return
619+ except Exception :
620+ engine_id = None
621+
566622 if not engine_id :
567- QMessageBox .warning (self , "Warning" , "Please select an engine first " )
623+ QMessageBox .warning (self , "Warning" , "No engine available " )
568624 return
569625
570626 try :
571- engine_cls = self .engines_info [engine_id ]["class" ]
627+ # Récupérer la classe du moteur
628+ engine_cls = None
629+ if engine_id in self .engines_info :
630+ engine_cls = self .engines_info [engine_id ].get ("class" )
631+ if not engine_cls :
632+ engine_cls = get_engine (engine_id )
633+
634+ if not engine_cls :
635+ QMessageBox .warning (
636+ self , "Warning" , f"Engine class not found: { engine_id } "
637+ )
638+ return
639+
572640 result = check_engine_compatibility (
573641 engine_cls ,
574642 get_core_version (),
@@ -619,16 +687,49 @@ def _browse_workspace(self):
619687 self .workspace_dir = workspace_dir
620688
621689 def _run_compilation (self ):
622- """Exécute la compilation."""
623- engine_id = self .engine_combo .currentData ()
690+ """Exécute la compilation avec le moteur de l'onglet courant."""
691+ # Récupérer l'ID du moteur depuis l'onglet courant
692+ current_index = self .compiler_tabs .currentIndex ()
693+ if current_index < 0 :
694+ QMessageBox .warning (
695+ self ,
696+ "Warning" ,
697+ (
698+ "Please select an engine tab first"
699+ if self .language == "en"
700+ else "Veuillez sélectionner un onglet de moteur d'abord"
701+ ),
702+ )
703+ return
704+
705+ try :
706+ engine_id = engines_loader .registry .get_engine_for_tab (current_index )
707+ if not engine_id :
708+ # Fallback avec engines_info
709+ if self .engines_info :
710+ engine_id = list (self .engines_info .keys ())[current_index ]
711+ else :
712+ QMessageBox .warning (
713+ self ,
714+ "Warning" ,
715+ (
716+ "No engine available"
717+ if self .language == "en"
718+ else "Aucun moteur disponible"
719+ ),
720+ )
721+ return
722+ except Exception :
723+ engine_id = None
724+
624725 if not engine_id :
625726 QMessageBox .warning (
626727 self ,
627728 "Warning" ,
628729 (
629- "Please select an engine first "
730+ "No engine available "
630731 if self .language == "en"
631- else "Veuillez sélectionner un moteur d'abord "
732+ else "Aucun moteur disponible "
632733 ),
633734 )
634735 return
@@ -671,8 +772,8 @@ def _run_compilation(self):
671772 # Créer le moteur
672773 engine = create_engine (engine_id )
673774
674- # Préparer les arguments
675- result = engine .program_and_args (None , file_path )
775+ # Préparer les arguments avec le GUI pour accéder aux options
776+ result = engine .program_and_args (self , file_path )
676777
677778 if result :
678779 program , args = result
@@ -760,10 +861,27 @@ def _run_compilation(self):
760861 self .compile_btn .setEnabled (True )
761862
762863 def _dry_run (self ):
763- """Affiche la commande sans l'exécuter."""
764- engine_id = self .engine_combo .currentData ()
864+ """Affiche la commande sans l'exécuter en utilisant l'onglet courant."""
865+ # Récupérer l'ID du moteur depuis l'onglet courant
866+ current_index = self .compiler_tabs .currentIndex ()
867+ if current_index < 0 :
868+ QMessageBox .warning (self , "Warning" , "Please select an engine tab first" )
869+ return
870+
871+ try :
872+ engine_id = engines_loader .registry .get_engine_for_tab (current_index )
873+ if not engine_id :
874+ # Fallback avec engines_info
875+ if self .engines_info :
876+ engine_id = list (self .engines_info .keys ())[current_index ]
877+ else :
878+ QMessageBox .warning (self , "Warning" , "No engine available" )
879+ return
880+ except Exception :
881+ engine_id = None
882+
765883 if not engine_id :
766- QMessageBox .warning (self , "Warning" , "Please select an engine first " )
884+ QMessageBox .warning (self , "Warning" , "No engine available " )
767885 return
768886
769887 file_path = self .file_path_edit .text ()
@@ -773,7 +891,7 @@ def _dry_run(self):
773891
774892 try :
775893 engine = create_engine (engine_id )
776- result = engine .program_and_args (None , file_path )
894+ result = engine .program_and_args (self , file_path )
777895
778896 if result :
779897 program , args = result
@@ -828,3 +946,4 @@ def launch_engines_gui(
828946
829947if __name__ == "__main__" :
830948 sys .exit (launch_engines_gui ())
949+
0 commit comments