1- import sys
1+ import sys
22import re
3+ import os
34import subprocess
45from pathlib import Path
56from PySide6 .QtWidgets import (
67 QApplication , QMainWindow , QWidget , QVBoxLayout , QHBoxLayout ,
78 QLabel , QLineEdit , QPushButton , QCheckBox , QFileDialog ,
89 QTextEdit , QMessageBox , QTabWidget , QScrollArea , QFrame ,
9- QFormLayout , QGroupBox , QSplitter
10+ QFormLayout , QGroupBox , QSplitter , QTableWidget , QTableWidgetItem ,
11+ QHeaderView , QAbstractItemView
1012)
1113from PySide6 .QtCore import Qt , Signal , QObject , QThread , QSize , QRegularExpression
1214from PySide6 .QtGui import QFont , QColor , QPalette , QIcon , QPixmap , QPainter , QSyntaxHighlighter , QTextCharFormat
@@ -177,6 +179,12 @@ def run(self):
177179 cmd .extend (["--exclude-module" , mod ])
178180 self .output_signal .emit (f"[CONFIG] Excluded modules: { ', ' .join (self .options ['exclude_modules' ])} \n " )
179181
182+ if self .options .get ('add_data' ):
183+ data_separator = os .pathsep
184+ for source , dest in self .options ['add_data' ]:
185+ cmd .extend (["--add-data" , f"{ source } { data_separator } { dest } " ])
186+ self .output_signal .emit (f"[CONFIG] Added data files: { len (self .options ['add_data' ])} \n " )
187+
180188 cmd .append (self .script_path )
181189 self .output_signal .emit (f"[CONFIG] Script: { self .script_path } \n " )
182190 self .output_signal .emit ("\n " + "=" * 80 + "\n " )
@@ -314,7 +322,7 @@ def get_stylesheet(theme_name="light"):
314322 QLabel {{
315323 color: { colors ['text' ]} ;
316324 }}
317- QLineEdit, QTextEdit {{
325+ QLineEdit, QTextEdit, QTableWidget {{
318326 background-color: { colors ['bg_sunken' ]} ;
319327 color: { colors ['text' ]} ;
320328 border: 1px solid { colors ['border' ]} ;
@@ -324,7 +332,7 @@ def get_stylesheet(theme_name="light"):
324332 QTextEdit#logDisplay {{
325333 color: { colors ['text_dim' ]} ;
326334 }}
327- QLineEdit:focus, QTextEdit:focus {{
335+ QLineEdit:focus, QTextEdit:focus, QTableWidget:focus {{
328336 border: 1px solid { colors ['primary' ]} ;
329337 }}
330338 QPushButton {{
@@ -401,6 +409,11 @@ def get_stylesheet(theme_name="light"):
401409 QSplitter::handle:horizontal {{
402410 width: 3px;
403411 }}
412+ QHeaderView::section {{
413+ background-color: { colors ['bg_raised' ]} ;
414+ border: 1px solid { colors ['border' ]} ;
415+ padding: 4px;
416+ }}
404417 """
405418
406419# =================================================================================
@@ -586,6 +599,86 @@ def get_options(self):
586599 'exclude_modules' : exclude_modules ,
587600 }
588601
602+ class AssetsTab (QWidget ):
603+ def __init__ (self ):
604+ super ().__init__ ()
605+ layout = QVBoxLayout (self )
606+ layout .setContentsMargins (20 , 20 , 20 , 20 )
607+ layout .setSpacing (15 )
608+
609+ assets_group = QGroupBox ("Data Files and Assets" )
610+ assets_layout = QVBoxLayout (assets_group )
611+
612+ button_layout = QHBoxLayout ()
613+ self .add_file_button = QPushButton ("Add File(s)..." )
614+ self .add_folder_button = QPushButton ("Add Folder..." )
615+ self .remove_button = QPushButton ("Remove Selected" )
616+
617+ button_layout .addWidget (self .add_file_button )
618+ button_layout .addWidget (self .add_folder_button )
619+ button_layout .addStretch ()
620+ button_layout .addWidget (self .remove_button )
621+
622+ self .assets_table = QTableWidget ()
623+ self .assets_table .setColumnCount (2 )
624+ self .assets_table .setHorizontalHeaderLabels (["Source Path" , "Destination in App (e.g., '.', 'data/')" ])
625+ self .assets_table .horizontalHeader ().setSectionResizeMode (0 , QHeaderView .ResizeMode .Stretch )
626+ self .assets_table .horizontalHeader ().setSectionResizeMode (1 , QHeaderView .ResizeMode .Interactive )
627+ self .assets_table .setColumnWidth (1 , 250 )
628+ self .assets_table .setSelectionBehavior (QAbstractItemView .SelectionBehavior .SelectRows )
629+
630+ self .add_file_button .clicked .connect (self .add_files )
631+ self .add_folder_button .clicked .connect (self .add_folder )
632+ self .remove_button .clicked .connect (self .remove_selected )
633+
634+ assets_layout .addLayout (button_layout )
635+ assets_layout .addWidget (self .assets_table )
636+
637+ layout .addWidget (assets_group )
638+ layout .addStretch ()
639+
640+ def add_files (self ):
641+ files , _ = QFileDialog .getOpenFileNames (self , "Select Asset Files to Add" , "" , "All Files (*)" )
642+ if files :
643+ for file_path in files :
644+ self ._add_row (file_path , "." )
645+
646+ def add_folder (self ):
647+ folder_path = QFileDialog .getExistingDirectory (self , "Select Asset Folder to Add" )
648+ if folder_path :
649+ dest_name = Path (folder_path ).name
650+ self ._add_row (folder_path , dest_name )
651+
652+ def _add_row (self , source_path , dest_path ):
653+ row_position = self .assets_table .rowCount ()
654+ self .assets_table .insertRow (row_position )
655+
656+ source_item = QTableWidgetItem (source_path )
657+ source_item .setFlags (source_item .flags () & ~ Qt .ItemFlag .ItemIsEditable )
658+
659+ dest_item = QTableWidgetItem (dest_path )
660+
661+ self .assets_table .setItem (row_position , 0 , source_item )
662+ self .assets_table .setItem (row_position , 1 , dest_item )
663+
664+ def remove_selected (self ):
665+ selected_rows = sorted (list (set (index .row () for index in self .assets_table .selectionModel ().selectedIndexes ())), reverse = True )
666+ for row in selected_rows :
667+ self .assets_table .removeRow (row )
668+
669+ def get_options (self ):
670+ assets = []
671+ for row in range (self .assets_table .rowCount ()):
672+ source_item = self .assets_table .item (row , 0 )
673+ dest_item = self .assets_table .item (row , 1 )
674+ if source_item and dest_item :
675+ source = source_item .text ()
676+ dest = dest_item .text ().strip ()
677+ if source and dest :
678+ assets .append ((source , dest ))
679+ return {'add_data' : assets }
680+
681+
589682# =================================================================================
590683# Class: PyInstallerGUI (Main Application Window)
591684# =================================================================================
@@ -625,20 +718,23 @@ def _init_ui(self):
625718
626719 # Tabs
627720 self .tabs = QTabWidget ()
628- self .tabs .setMinimumWidth (500 )
721+ self .tabs .setMinimumWidth (530 )
629722 self .basic_tab = BasicOptionsTab ()
630723 self .advanced_tab = AdvancedOptionsTab ()
631724 self .packages_tab = PackagesTab ()
725+ self .assets_tab = AssetsTab ()
632726 self .tabs .addTab (self .basic_tab , "Basic Options" )
633727 self .tabs .addTab (self .advanced_tab , "Advanced Options" )
634728 self .tabs .addTab (self .packages_tab , "Package Management" )
729+ self .tabs .addTab (self .assets_tab , "Assets" )
635730
636731 # Log Panel
637732 log_panel = self ._create_log_panel ()
638733
639734 splitter .addWidget (self .tabs )
640735 splitter .addWidget (log_panel )
641- splitter .setSizes ([500 , 460 ])
736+ splitter .setSizes ([500 , 420 ])
737+ splitter .setCollapsible (0 , False )
642738
643739 def _create_header (self ):
644740 header_widget = QFrame ()
@@ -770,6 +866,7 @@ def start_build(self):
770866 options .update (basic_opts )
771867 options .update (self .advanced_tab .get_options ())
772868 options .update (self .packages_tab .get_options ())
869+ options .update (self .assets_tab .get_options ())
773870
774871 self .build_worker = BuildWorker (script_path , options )
775872 self .build_worker .output_signal .connect (self .append_log )
@@ -822,4 +919,4 @@ def closeEvent(self, event):
822919 app = QApplication (sys .argv )
823920 window = PyInstallerGUI ()
824921 window .show ()
825- sys .exit (app .exec ())
922+ sys .exit (app .exec ())
0 commit comments