Chore: Stop tracking files based on .gitignore update.

Untracked files matching the following rules:
- Rule "!.vscode/launch.json": 1 file
This commit is contained in:
VALLONGOL 2025-05-12 14:56:09 +02:00
parent 00aea53907
commit 1224daa929
8 changed files with 245 additions and 50 deletions

5
.gitignore vendored
View File

@ -149,4 +149,7 @@ dmypy.json
*.swp
*~
*.txt
*.txt
_dist/
_build/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,39 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['gui_g_converter/__main__.py'],
pathex=['.'],
binaries=[],
# Usa project_icon_filename nella sezione datas
datas=[('GUI_g_converter.ico', '.')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='GUI_g_converter',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
# Usa project_icon_filename per l'opzione icon
icon='GUI_g_converter.ico'
)

46
gui_g_reconverter.spec Normal file
View File

@ -0,0 +1,46 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
import os
a = Analysis(scripts=['gui_g_reconverter\\__main__.py'],
pathex=['gui_g_reconverter'],
binaries=[],
datas=[('GUI_g_reconverter.ico', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=None,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data, cipher=None)
exe = EXE(pyz,
a.scripts,
[], # Binaries/Datas usually handled by Analysis/COLLECT
exclude_binaries=True, # Let COLLECT handle binaries in one-dir
name='GUI_g_converter',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # Use UPX based on config
runtime_tmpdir=None,
console=False, # Set console based on GUI checkbox
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='GUI_g_reconverter.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True, # Match UPX setting
upx_exclude=[],
name='GUI_g_converter')

View File

@ -10,7 +10,7 @@ import sys
# Import the main GUI class from the gui subpackage
from .gui.application_gui import CppConverterGUI
from gui_g_reconverter.gui.application_gui import CppConverterGUI
if __name__ == "__main__":
root = tk.Tk()

View File

@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# File generated by PyInstaller GUI Wrapper. DO NOT EDIT MANUALLY.
# Contains build-time information scraped from Git (if available)
# and a helper function to format version strings.
import re
# --- Version Data (Generated) ---
# This section is automatically generated by the build process.
__version__ = "v.0.0.0.1-2-g537930d-dirty"
GIT_COMMIT_HASH = "537930d65d7e7733d5b39df1e491b58cfeff5126"
GIT_BRANCH = "master"
BUILD_TIMESTAMP = "2025-05-12T12:53:06Z"
IS_GIT_REPO = True
# --- Default Values (for comparison or fallback) ---
DEFAULT_VERSION = "0.0.0+unknown"
DEFAULT_COMMIT = "Unknown"
DEFAULT_BRANCH = "Unknown"
# --- Helper Function ---
def get_version_string(format_string=None):
"""
Returns a formatted string based on the build version information.
Args:
format_string (str, optional): A format string using placeholders.
Defaults to "{{version}} ({{branch}}/{{commit_short}})" if None.
Placeholders:
{{version}}: Full version string (e.g., 'v1.0.0-5-gabcdef-dirty')
{{tag}}: Clean tag part if exists (e.g., 'v1.0.0'), else DEFAULT_VERSION.
{{commit}}: Full Git commit hash.
{{commit_short}}: Short Git commit hash (7 chars).
{{branch}}: Git branch name.
{{dirty}}: '-dirty' if the repo was dirty, empty otherwise.
{{timestamp}}: Full build timestamp (ISO 8601 UTC).
{{timestamp_short}}: Build date only (YYYY-MM-DD).
{{is_git}}: 'Git' if IS_GIT_REPO is True, 'Unknown' otherwise.
Returns:
str: The formatted version string, or an error message if formatting fails.
"""
if format_string is None:
format_string = "{version} ({branch}/{commit_short})" # Sensible default
replacements = {}
try:
# Prepare data dictionary for substitution
replacements['version'] = __version__ if __version__ else DEFAULT_VERSION
replacements['commit'] = GIT_COMMIT_HASH if GIT_COMMIT_HASH else DEFAULT_COMMIT
replacements['commit_short'] = GIT_COMMIT_HASH[:7] if GIT_COMMIT_HASH and len(GIT_COMMIT_HASH) >= 7 else DEFAULT_COMMIT
replacements['branch'] = GIT_BRANCH if GIT_BRANCH else DEFAULT_BRANCH
replacements['timestamp'] = BUILD_TIMESTAMP if BUILD_TIMESTAMP else "Unknown"
replacements['timestamp_short'] = BUILD_TIMESTAMP.split('T')[0] if BUILD_TIMESTAMP and 'T' in BUILD_TIMESTAMP else "Unknown"
replacements['is_git'] = "Git" if IS_GIT_REPO else "Unknown"
replacements['dirty'] = "-dirty" if __version__ and __version__.endswith('-dirty') else ""
# Extract clean tag using regex (handles versions like v1.0.0, 1.0.0)
tag = DEFAULT_VERSION
if __version__ and IS_GIT_REPO:
# Match optional 'v' prefix, then major.minor.patch
match = re.match(r'^(v?([0-9]+)\.([0-9]+)\.([0-9]+))', __version__)
if match:
tag = match.group(1) # Get the full tag (e.g., 'v1.0.0')
replacements['tag'] = tag
# Perform substitution using regex to find placeholders {placeholder}
output_string = format_string
# Iterate through placeholders and replace them in the format string
for placeholder, value in replacements.items():
# Compile regex pattern for {placeholder}, allowing for whitespace inside braces
pattern = re.compile(r'{\s*' + re.escape(placeholder) + r'\s*}')
# Substitute found patterns with the corresponding string value
output_string = pattern.sub(str(value), output_string)
# Optional: Check if any placeholders remain unsubstituted (could indicate typo)
if re.search(r'{\s*[\w_]+\s*}', output_string):
# You might want to log this or handle it, for now, we return the string as is
# print(f"Warning: Unsubstituted placeholders remain in version string: {output_string}")
pass
return output_string
except Exception as e:
# Return a simple error message in case of unexpected formatting issues
# Avoid printing directly from this generated function
return f"[Formatting Error: {e}]"

View File

@ -1,3 +1,4 @@
import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox, ttk
import subprocess
@ -9,7 +10,7 @@ import datetime
import sys # Needed for sys.platform in open_gui_log_file
# Import the runner function from the core module
from ..core.g_reconvert_runner import run_g_reconvert
from gui_g_reconverter.core.g_reconvert_runner import run_g_reconvert
# --- Constants ---
DEFAULT_GUI_LOG_FILE = "gui_execution_log.txt"
@ -22,6 +23,28 @@ DEFAULT_PROFILE_FILE = "default_launch_profile.json"
BIN_FILE_EXTENSION = ".rec"
BIN_FILETYPES = [("REC files", f"*{BIN_FILE_EXTENSION}"), ("All files", "*.*")]
# Polling interval for the output queue in milliseconds
OUTPUT_QUEUE_POLLING_INTERVAL = 50 # Reduced from 100ms for potentially faster updates
# --- Import Version Info FOR THE WRAPPER ITSELF ---
try:
# Use absolute import based on package name
from gui_g_reconverter import _version as wrapper_version
WRAPPER_APP_VERSION_STRING = f"{wrapper_version.__version__} ({wrapper_version.GIT_BRANCH}/{wrapper_version.GIT_COMMIT_HASH[:7]})"
WRAPPER_BUILD_INFO = f"Wrapper Built: {wrapper_version.BUILD_TIMESTAMP}"
except ImportError:
# This might happen if you run the wrapper directly from source
# without generating its _version.py first (if you use that approach for the wrapper itself)
WRAPPER_APP_VERSION_STRING = "(Dev Wrapper)"
WRAPPER_BUILD_INFO = "Wrapper build time unknown"
# --- End Import Version Info ---
# --- Constants for Version Generation ---
DEFAULT_VERSION = "0.0.0+unknown"
DEFAULT_COMMIT = "Unknown"
DEFAULT_BRANCH = "Unknown"
# --- End Constants ---
class CppConverterGUI:
"""
@ -37,7 +60,7 @@ class CppConverterGUI:
master_window: The main Tkinter window.
"""
self.master_window = master_window
self.master_window.title("g_reconvert.exe Interface")
self.master_window.title(f"g_reconvert.exe Interface - {WRAPPER_APP_VERSION_STRING}")
# Adjusted initial window size - Further reduced height for more compact layout
self.master_window.geometry("950x650") # Adjusted height, might need tweaking based on content
@ -129,6 +152,11 @@ class CppConverterGUI:
# Ensure generated paths are updated after potential profile load
self._update_generated_file_paths()
# Trace changes to output_dir_var to update button state
self.output_dir_var.trace_add("write", lambda *args: self._update_go_to_output_button_state())
# Initial update of the button state
self._update_go_to_output_button_state()
def _load_default_profile(self):
"""Attempts to load the default profile file on application startup."""
@ -507,6 +535,50 @@ class CppConverterGUI:
self._generated_log_file_path = ""
self.g_reconvert_log_file_var.set("Generated log file path will appear here.")
# Update the state of the "Go to Output Folder" button
self._update_go_to_output_button_state()
def _update_go_to_output_button_state(self):
"""Enables or disables the 'Go to Output Folder' button."""
output_dir = self.output_dir_var.get().strip()
# Enable the button only if output_dir is not empty AND it's a valid directory path
if output_dir and os.path.isdir(output_dir):
if hasattr(self, 'go_to_output_button'): # Check if button exists
self.go_to_output_button.config(state=tk.NORMAL)
else:
if hasattr(self, 'go_to_output_button'): # Check if button exists
self.go_to_output_button.config(state=tk.DISABLED)
def _open_output_folder(self):
"""Opens the selected output directory in the system's file explorer."""
output_dir = self.output_dir_var.get().strip()
if not output_dir or not os.path.isdir(output_dir):
messagebox.showwarning("Invalid Output Directory", "The specified output directory is empty or does not exist.")
self._update_status_bar("Warning: Cannot open invalid output directory.")
return
try:
# Use os.startfile on Windows
if os.name == 'nt':
os.startfile(output_dir)
# Use subprocess for macOS and Linux
elif sys.platform == 'darwin': # macOS
subprocess.run(['open', output_dir], check=True)
else: # Linux and other Unix-like
subprocess.run(['xdg-open', output_dir], check=True)
self._log_message_to_gui_log(f"Opened output directory: {output_dir}")
self._update_status_bar(f"Opened output directory: {os.path.basename(output_dir)}")
except FileNotFoundError:
messagebox.showerror("Error", f"Could not find an application to open the directory.\nPlease open it manually: {output_dir}")
self._log_message_to_gui_log(f"Error opening output directory with system default (app not found): {output_dir}")
self._update_status_bar("Error opening output directory.")
except Exception as e:
messagebox.showerror("Error", f"Could not open output directory: {e}\nPath: {output_dir}")
self._log_message_to_gui_log(f"Error opening output directory: {e}. Path: {output_dir}")
self._update_status_bar("Error opening output directory.")
def _select_bin_file(self):
"""Open a dialog to select the source binary file (binfile), filtered for .rec."""
@ -515,12 +587,23 @@ class CppConverterGUI:
def _setup_control_buttons(self, parent_frame):
"""Create and arrange control buttons within a frame using grid."""
# Use grid for centering the button within the frame
parent_frame.columnconfigure(0, weight=1) # Make the column expandable to center
# Configure grid for two columns to place buttons side-by-side
parent_frame.columnconfigure(0, weight=1) # Column for Run button (will still center it)
parent_frame.columnconfigure(1, weight=1) # Column for Go to Output button
# Run button centered
# Run button
self.run_button = tk.Button(parent_frame, text="Run g_reconvert.exe", command=self.run_cpp_application, width=25, height=2, bg="#4CAF50", fg="white", font=('Helvetica', 10, 'bold'))
self.run_button.grid(row=0, column=0, padx=10, pady=10)
# Use sticky='E' to push it to the right in its column (relative to the center if column weight > 0)
# Or just use a fixed column and place it. Let's keep it simple and centered in its column for now.
self.run_button.grid(row=0, column=0, padx=10, pady=10, sticky=tk.E) # Sticky East
# Go to Output Folder button
self.go_to_output_button = tk.Button(parent_frame, text="Go to Output Folder", command=self._open_output_folder, width=25, height=2, bg="#FFD700", fg="black", font=('Helvetica', 10, 'bold'))
# Place it in the second column, sticky='W' to push it to the left
self.go_to_output_button.grid(row=0, column=1, padx=10, pady=10, sticky=tk.W)
# Ensure the button is initially disabled until a valid directory is selected
self._update_go_to_output_button_state()
def _setup_output_area(self, parent_frame):
@ -736,6 +819,7 @@ class CppConverterGUI:
self._update_status_bar(f"Running g_reconvert.exe...")
self.run_button.config(state=tk.DISABLED, bg="#cccccc") # Disable button while running
self.go_to_output_button.config(state=tk.DISABLED) # Disable Go To button while running
self.process_running = True
# Run the core runner function in a separate thread
@ -750,7 +834,7 @@ class CppConverterGUI:
# Start polling the output queue
# Check queue every 100 milliseconds (adjust as needed)
self.master_window.after(100, self._process_output_queue)
self.master_window.after(OUTPUT_QUEUE_POLLING_INTERVAL, self._process_output_queue)
def _process_output_queue(self):
@ -758,8 +842,13 @@ class CppConverterGUI:
Checks the output queue for messages from the core runner thread
and updates the GUI. This runs in the main GUI thread.
"""
# Process a limited number of messages at a time to avoid blocking the GUI
MAX_MESSAGES_TO_PROCESS = 10 # Adjust this number as needed for responsiveness vs update frequency
messages_processed = 0
try:
while True: # Process all messages currently in the queue
# Process up to MAX_MESSAGES_TO_PROCESS from the queue
while messages_processed < MAX_MESSAGES_TO_PROCESS:
# Use get_nowait() to avoid blocking the GUI thread
item = self.output_queue.get_nowait()
@ -769,6 +858,8 @@ class CppConverterGUI:
self.run_button.config(state=tk.NORMAL, bg="#4CAF50") # Re-enable button
self.process_running = False
self._update_status_bar("g_reconvert.exe finished. Ready.")
# Re-enable Go To Output button if directory is valid
self._update_go_to_output_button_state()
return # Stop polling the `after` loop
else: # It's a message dictionary {'text': ..., 'type': ...}
@ -776,14 +867,18 @@ class CppConverterGUI:
# Decide whether to log the message to the GUI log based on its source or content
# For now, log everything coming from the runner thread
self._log_message_to_gui_log(item['text'].strip(), include_timestamp=False) # Log to file
messages_processed += 1 # Increment counter
except queue.Empty:
# No new messages in queue, just continue polling if process is still running
pass
# If process is still marked as running, schedule the next check
# Schedule the next check regardless of whether messages were processed this time
if self.process_running:
self.master_window.after(100, self._process_output_queue)
self.master_window.after(OUTPUT_QUEUE_POLLING_INTERVAL, self._process_output_queue)
# If process_running is False, the 'None' signal would have caused the function to return
def _insert_output_text(self, message, tag='INFO'):