diff --git a/gui/config_tab.py b/gui/config_tab.py index e0d42f1..f5c2e0b 100644 --- a/gui/config_tab.py +++ b/gui/config_tab.py @@ -1,5 +1,5 @@ """ -Configuration Tab - Handles environment variables and global settings +Configuration Tab - Handles environment variables, global settings, and engine configurations """ import os @@ -8,14 +8,40 @@ from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox, QPushButton, QGroupBox, QLabel, QFileDialog, QMessageBox, QScrollArea, QTextEdit, - QCheckBox, QApplication + QCheckBox, QApplication, QTabWidget, QFrame ) from PyQt5.QtCore import Qt, pyqtSignal from dotenv import load_dotenv, set_key +from gui.rpgmaker_tab import RPGMakerTab +from gui.wolf_tab import WolfTab + + +def create_section_header(title): + """Create a clean section header without boxes.""" + label = QLabel(title) + label.setStyleSheet(""" + QLabel { + font-size: 13px; + font-weight: bold; + color: #007acc; + padding: 8px 0px 5px 0px; + background-color: transparent; + } + """) + return label + +def create_horizontal_line(): + """Create a horizontal separator line.""" + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + line.setStyleSheet("QFrame { color: #555555; margin: 5px 0px; }") + return line + class ConfigTab(QWidget): - """Configuration tab for managing environment variables and global settings.""" + """Configuration tab for managing environment variables, global settings, and engine configs.""" config_changed = pyqtSignal() @@ -26,296 +52,268 @@ class ConfigTab(QWidget): self.load_from_env() def init_ui(self): - """Initialize the user interface.""" + """Initialize the user interface with tabs for different config categories.""" main_layout = QVBoxLayout() + main_layout.setContentsMargins(0, 0, 0, 0) - # Create scroll area - scroll_area = QScrollArea() - scroll_content = QWidget() - scroll_layout = QVBoxLayout() + # Create tab widget for different configuration categories + self.config_tabs = QTabWidget() - # API Configuration Group - api_group = self.create_api_group() - scroll_layout.addWidget(api_group) + # Tab 1: API & Translation Settings + api_tab = self.create_api_translation_tab() + self.config_tabs.addTab(api_tab, "API & Translation") - # Translation Settings Group - translation_group = self.create_translation_group() - scroll_layout.addWidget(translation_group) + # Tab 2: Performance & Formatting + perf_tab = self.create_performance_formatting_tab() + self.config_tabs.addTab(perf_tab, "Performance & Format") - # Performance Settings Group - performance_group = self.create_performance_group() - scroll_layout.addWidget(performance_group) + # Tab 3: RPG Maker MV/MZ Engine + self.mvmz_tab = RPGMakerTab("MVMZ") + self.config_tabs.addTab(self.mvmz_tab, "RPG Maker MV/MZ") - # Text Formatting Group - formatting_group = self.create_formatting_group() - scroll_layout.addWidget(formatting_group) + # Tab 4: RPG Maker Ace Engine + self.ace_tab = RPGMakerTab("ACE") + self.config_tabs.addTab(self.ace_tab, "RPG Maker Ace") - # Custom API Settings Group - custom_api_group = self.create_custom_api_group() - scroll_layout.addWidget(custom_api_group) + # Tab 5: Wolf RPG Engine + self.wolf_tab = WolfTab() + self.config_tabs.addTab(self.wolf_tab, "Wolf RPG") - # UI Settings Group - ui_group = self.create_ui_settings_group() - scroll_layout.addWidget(ui_group) + main_layout.addWidget(self.config_tabs) - # Buttons + # Bottom buttons row button_layout = QHBoxLayout() + button_layout.setSpacing(10) - self.save_button = QPushButton("Save Configuration") + self.save_button = QPushButton("💾 Save Configuration") self.save_button.clicked.connect(self.save_to_env) + self.save_button.setMinimumHeight(35) - self.load_button = QPushButton("Load from File") + self.load_button = QPushButton("📂 Load from File") self.load_button.clicked.connect(self.load_from_file_dialog) + self.load_button.setMinimumHeight(35) - self.reset_button = QPushButton("Reset to Defaults") + self.reset_button = QPushButton("🔄 Reset to Defaults") self.reset_button.clicked.connect(self.reset_to_defaults) + self.reset_button.setMinimumHeight(35) button_layout.addWidget(self.save_button) button_layout.addWidget(self.load_button) button_layout.addWidget(self.reset_button) button_layout.addStretch() - scroll_layout.addLayout(button_layout) - - scroll_content.setLayout(scroll_layout) - scroll_area.setWidget(scroll_content) - scroll_area.setWidgetResizable(True) - - main_layout.addWidget(scroll_area) + main_layout.addLayout(button_layout) self.setLayout(main_layout) + + def create_api_translation_tab(self): + """Create compact API and translation settings tab.""" + widget = QWidget() + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) - def create_api_group(self): - """Create API configuration group.""" - group = QGroupBox("API Configuration") - layout = QFormLayout() + content = QWidget() + layout = QVBoxLayout() + layout.setSpacing(5) + layout.setContentsMargins(10, 10, 10, 10) + + # API Configuration Section + layout.addWidget(create_section_header("🔑 API Configuration")) + api_form = QFormLayout() + api_form.setSpacing(5) + api_form.setContentsMargins(0, 0, 0, 10) - # API URL self.api_url_edit = QLineEdit() self.api_url_edit.setPlaceholderText("Leave blank for OpenAI API") - layout.addRow("API URL:", self.api_url_edit) + api_form.addRow("API URL:", self.api_url_edit) - # API Key self.api_key_edit = QLineEdit() self.api_key_edit.setEchoMode(QLineEdit.Password) self.api_key_edit.setPlaceholderText("Enter your API key") - layout.addRow("API Key:", self.api_key_edit) + api_form.addRow("API Key:", self.api_key_edit) - # Organization self.organization_edit = QLineEdit() - self.organization_edit.setPlaceholderText("Organization key") - layout.addRow("Organization:", self.organization_edit) + self.organization_edit.setPlaceholderText("Optional organization key") + api_form.addRow("Organization:", self.organization_edit) - # Model self.model_combo = QComboBox() self.model_combo.setEditable(True) self.model_combo.addItems([ - "gpt-3.5-turbo", - "gpt-3.5-turbo-1106", - "gpt-4", - "gpt-4-1106-preview", - "gpt-4-turbo", - "claude-3-sonnet-20240229", - "claude-3-opus-20240229" + "gpt-4.1-mini", "gpt-4.1", "gpt-5", + "deepseek-chat", "claude-3-sonnet-20240229", + "gemini-2.0-flash", "gemini-2.5-flash", "gemini-2.5-pro" ]) - layout.addRow("Model:", self.model_combo) + api_form.addRow("Model:", self.model_combo) - group.setLayout(layout) - return group + layout.addLayout(api_form) + layout.addWidget(create_horizontal_line()) - def create_translation_group(self): - """Create translation settings group.""" - group = QGroupBox("Translation Settings") - layout = QFormLayout() + # Translation Settings Section + layout.addWidget(create_section_header("🌐 Translation Settings")) + trans_form = QFormLayout() + trans_form.setSpacing(5) + trans_form.setContentsMargins(0, 0, 0, 10) - # Language self.language_combo = QComboBox() self.language_combo.addItems([ "English", "Spanish", "French", "German", "Italian", "Portuguese", "Russian", "Chinese", "Korean", "Japanese" ]) - layout.addRow("Target Language:", self.language_combo) + trans_form.addRow("Target Language:", self.language_combo) - # Timeout self.timeout_spin = QSpinBox() self.timeout_spin.setRange(30, 300) self.timeout_spin.setValue(120) - self.timeout_spin.setSuffix(" seconds") - layout.addRow("Timeout:", self.timeout_spin) + self.timeout_spin.setSuffix(" sec") + trans_form.addRow("Timeout:", self.timeout_spin) - group.setLayout(layout) - return group + layout.addLayout(trans_form) + layout.addWidget(create_horizontal_line()) - def create_performance_group(self): - """Create performance settings group.""" - group = QGroupBox("Performance Settings") - layout = QFormLayout() + # UI Settings Section + layout.addWidget(create_section_header("🎨 UI Settings")) + ui_form = QFormLayout() + ui_form.setSpacing(5) + ui_form.setContentsMargins(0, 0, 0, 10) - # File Threads - self.file_threads_spin = QSpinBox() - self.file_threads_spin.setRange(1, 10) - self.file_threads_spin.setValue(1) - layout.addRow("File Threads:", self.file_threads_spin) - - # Threads per File - self.threads_spin = QSpinBox() - self.threads_spin.setRange(1, 20) - self.threads_spin.setValue(1) - layout.addRow("Threads per File:", self.threads_spin) - - # Batch Size - self.batch_size_spin = QSpinBox() - self.batch_size_spin.setRange(1, 100) - self.batch_size_spin.setValue(10) - layout.addRow("Batch Size:", self.batch_size_spin) - - # Frequency Penalty - self.frequency_penalty_spin = QDoubleSpinBox() - self.frequency_penalty_spin.setRange(0.0, 2.0) - self.frequency_penalty_spin.setSingleStep(0.1) - self.frequency_penalty_spin.setValue(0.2) - layout.addRow("Frequency Penalty:", self.frequency_penalty_spin) - - group.setLayout(layout) - return group - - def create_formatting_group(self): - """Create text formatting settings group.""" - group = QGroupBox("Text Formatting") - layout = QFormLayout() - - # Dialogue Width - self.width_spin = QSpinBox() - self.width_spin.setRange(20, 200) - self.width_spin.setValue(60) - self.width_spin.setSuffix(" characters") - layout.addRow("Dialogue Width:", self.width_spin) - - # List Width - self.list_width_spin = QSpinBox() - self.list_width_spin.setRange(20, 200) - self.list_width_spin.setValue(100) - self.list_width_spin.setSuffix(" characters") - layout.addRow("List Width:", self.list_width_spin) - - # Note Width - self.note_width_spin = QSpinBox() - self.note_width_spin.setRange(20, 200) - self.note_width_spin.setValue(75) - self.note_width_spin.setSuffix(" characters") - layout.addRow("Note Width:", self.note_width_spin) - - group.setLayout(layout) - return group - - def create_custom_api_group(self): - """Create custom API settings group.""" - group = QGroupBox("Custom API Pricing") - layout = QFormLayout() - - # Input Cost - self.input_cost_spin = QDoubleSpinBox() - self.input_cost_spin.setRange(0.0, 1.0) - self.input_cost_spin.setDecimals(4) - self.input_cost_spin.setSingleStep(0.0001) - self.input_cost_spin.setValue(0.002) - self.input_cost_spin.setSuffix(" per 1K tokens") - layout.addRow("Input Cost:", self.input_cost_spin) - - # Output Cost - self.output_cost_spin = QDoubleSpinBox() - self.output_cost_spin.setRange(0.0, 1.0) - self.output_cost_spin.setDecimals(4) - self.output_cost_spin.setSingleStep(0.0001) - self.output_cost_spin.setValue(0.002) - self.output_cost_spin.setSuffix(" per 1K tokens") - layout.addRow("Output Cost:", self.output_cost_spin) - - group.setLayout(layout) - return group - - def create_ui_settings_group(self): - """Create UI settings group.""" - group = QGroupBox("User Interface Settings") - layout = QFormLayout() - - # Font Scale + font_layout = QHBoxLayout() self.font_scale_spin = QDoubleSpinBox() self.font_scale_spin.setRange(0.5, 3.0) self.font_scale_spin.setSingleStep(0.1) self.font_scale_spin.setValue(1.0) self.font_scale_spin.setDecimals(1) self.font_scale_spin.setSuffix("x") - self.font_scale_spin.setToolTip("Scale factor for all fonts in the GUI (1.0 = normal, 1.5 = 150% larger)") self.font_scale_spin.valueChanged.connect(self.on_font_scale_changed) - - # Font scale presets - font_layout = QHBoxLayout() font_layout.addWidget(self.font_scale_spin) - # Quick preset buttons - small_btn = QPushButton("Small") - small_btn.clicked.connect(lambda: self.font_scale_spin.setValue(0.8)) - small_btn.setMaximumWidth(60) + # Quick preset buttons (smaller) + for label, value in [("S", 0.8), ("M", 1.0), ("L", 1.5), ("XL", 2.0)]: + btn = QPushButton(label) + btn.clicked.connect(lambda checked, v=value: self.font_scale_spin.setValue(v)) + btn.setMaximumWidth(40) + font_layout.addWidget(btn) - normal_btn = QPushButton("Normal") - normal_btn.clicked.connect(lambda: self.font_scale_spin.setValue(1.0)) - normal_btn.setMaximumWidth(60) + ui_form.addRow("Font Scale:", font_layout) - large_btn = QPushButton("Large") - large_btn.clicked.connect(lambda: self.font_scale_spin.setValue(1.5)) - large_btn.setMaximumWidth(60) - - xlarge_btn = QPushButton("X-Large") - xlarge_btn.clicked.connect(lambda: self.font_scale_spin.setValue(2.0)) - xlarge_btn.setMaximumWidth(60) - - font_layout.addWidget(small_btn) - font_layout.addWidget(normal_btn) - font_layout.addWidget(large_btn) - font_layout.addWidget(xlarge_btn) - - layout.addRow("Font Scale:", font_layout) - - # DPI Awareness - self.dpi_aware_cb = QCheckBox("High DPI Scaling") - self.dpi_aware_cb.setToolTip("Enable automatic scaling for high DPI displays") - self.dpi_aware_cb.setChecked(True) - layout.addRow("", self.dpi_aware_cb) - - # Theme selection self.theme_combo = QComboBox() self.theme_combo.addItems(["Dark", "Light", "System"]) self.theme_combo.setCurrentText("Dark") - layout.addRow("Theme:", self.theme_combo) + ui_form.addRow("Theme:", self.theme_combo) - # Show font tip - self.show_font_tip_cb = QCheckBox("Show font size tip on startup") - self.show_font_tip_cb.setToolTip("Display helpful font sizing information when the GUI starts") - self.show_font_tip_cb.setChecked(True) - layout.addRow("", self.show_font_tip_cb) + layout.addLayout(ui_form) + layout.addStretch() - group.setLayout(layout) - return group + content.setLayout(layout) + scroll.setWidget(content) - def on_font_scale_changed(self, value): - """Handle font scale change.""" - self.config_changed.emit() - # Apply font scaling immediately - self.apply_font_scaling(value) + wrapper = QVBoxLayout() + wrapper.setContentsMargins(0, 0, 0, 0) + wrapper.addWidget(scroll) + widget.setLayout(wrapper) + return widget + + def create_performance_formatting_tab(self): + """Create compact performance and formatting settings tab.""" + widget = QWidget() + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) - def apply_font_scaling(self, scale_factor): - """Apply font scaling to the entire application.""" - app = QApplication.instance() - if app: - # Get the default font - font = app.font() - base_size = 9 # Base font size - new_size = int(base_size * scale_factor) - font.setPointSize(new_size) - app.setFont(font) - - # Emit signal to notify other components - self.config_changed.emit() + content = QWidget() + layout = QVBoxLayout() + layout.setSpacing(5) + layout.setContentsMargins(10, 10, 10, 10) + + # Performance Settings Section + layout.addWidget(create_section_header("⚡ Performance Settings")) + perf_form = QFormLayout() + perf_form.setSpacing(5) + perf_form.setContentsMargins(0, 0, 0, 10) + + self.file_threads_spin = QSpinBox() + self.file_threads_spin.setRange(1, 10) + self.file_threads_spin.setValue(1) + perf_form.addRow("File Threads:", self.file_threads_spin) + + self.threads_spin = QSpinBox() + self.threads_spin.setRange(1, 20) + self.threads_spin.setValue(1) + perf_form.addRow("Threads per File:", self.threads_spin) + + self.batch_size_spin = QSpinBox() + self.batch_size_spin.setRange(1, 100) + self.batch_size_spin.setValue(30) + perf_form.addRow("Batch Size:", self.batch_size_spin) + + self.frequency_penalty_spin = QDoubleSpinBox() + self.frequency_penalty_spin.setRange(0.0, 2.0) + self.frequency_penalty_spin.setSingleStep(0.05) + self.frequency_penalty_spin.setValue(0.05) + perf_form.addRow("Frequency Penalty:", self.frequency_penalty_spin) + + layout.addLayout(perf_form) + layout.addWidget(create_horizontal_line()) + + # Text Formatting Section + layout.addWidget(create_section_header("📝 Text Formatting")) + format_form = QFormLayout() + format_form.setSpacing(5) + format_form.setContentsMargins(0, 0, 0, 10) + + self.width_spin = QSpinBox() + self.width_spin.setRange(20, 200) + self.width_spin.setValue(60) + self.width_spin.setSuffix(" chars") + format_form.addRow("Dialogue Width:", self.width_spin) + + self.list_width_spin = QSpinBox() + self.list_width_spin.setRange(20, 200) + self.list_width_spin.setValue(100) + self.list_width_spin.setSuffix(" chars") + format_form.addRow("List Width:", self.list_width_spin) + + self.note_width_spin = QSpinBox() + self.note_width_spin.setRange(20, 200) + self.note_width_spin.setValue(75) + self.note_width_spin.setSuffix(" chars") + format_form.addRow("Note Width:", self.note_width_spin) + + layout.addLayout(format_form) + layout.addWidget(create_horizontal_line()) + + # Custom API Pricing Section + layout.addWidget(create_section_header("💰 Custom API Pricing")) + price_form = QFormLayout() + price_form.setSpacing(5) + price_form.setContentsMargins(0, 0, 0, 10) + + self.input_cost_spin = QDoubleSpinBox() + self.input_cost_spin.setRange(0.0, 100.0) + self.input_cost_spin.setDecimals(4) + self.input_cost_spin.setSingleStep(0.1) + self.input_cost_spin.setValue(2.0) + self.input_cost_spin.setSuffix(" per 1M tokens") + price_form.addRow("Input Cost:", self.input_cost_spin) + + self.output_cost_spin = QDoubleSpinBox() + self.output_cost_spin.setRange(0.0, 100.0) + self.output_cost_spin.setDecimals(4) + self.output_cost_spin.setSingleStep(0.1) + self.output_cost_spin.setValue(8.0) + self.output_cost_spin.setSuffix(" per 1M tokens") + price_form.addRow("Output Cost:", self.output_cost_spin) + + layout.addLayout(price_form) + layout.addStretch() + + content.setLayout(layout) + scroll.setWidget(content) + + wrapper = QVBoxLayout() + wrapper.setContentsMargins(0, 0, 0, 0) + wrapper.addWidget(scroll) + widget.setLayout(wrapper) + return widget def load_from_env(self): """Load configuration from .env file.""" @@ -326,7 +324,7 @@ class ConfigTab(QWidget): self.api_url_edit.setText(os.getenv("api", "")) self.api_key_edit.setText(os.getenv("key", "")) self.organization_edit.setText(os.getenv("organization", "")) - self.model_combo.setCurrentText(os.getenv("model", "gpt-4")) + self.model_combo.setCurrentText(os.getenv("model", "gpt-4.1")) # Load translation settings self.language_combo.setCurrentText(os.getenv("language", "English")) @@ -335,23 +333,21 @@ class ConfigTab(QWidget): # Load performance settings self.file_threads_spin.setValue(int(os.getenv("fileThreads", "1"))) self.threads_spin.setValue(int(os.getenv("threads", "1"))) - self.batch_size_spin.setValue(int(os.getenv("batchsize", "10"))) - self.frequency_penalty_spin.setValue(float(os.getenv("frequency_penalty", "0.2"))) + self.batch_size_spin.setValue(int(os.getenv("batchsize", "30"))) + self.frequency_penalty_spin.setValue(float(os.getenv("frequency_penalty", "0.05"))) # Load formatting settings self.width_spin.setValue(int(os.getenv("width", "60"))) self.list_width_spin.setValue(int(os.getenv("listWidth", "100"))) - self.note_width_spin.setValue(int(os.getenv("noteWidth", "80"))) + self.note_width_spin.setValue(int(os.getenv("noteWidth", "75"))) # Load custom API settings - self.input_cost_spin.setValue(float(os.getenv("input_cost", "0.002"))) - self.output_cost_spin.setValue(float(os.getenv("output_cost", "0.002"))) + self.input_cost_spin.setValue(float(os.getenv("input_cost", "2.0"))) + self.output_cost_spin.setValue(float(os.getenv("output_cost", "8.0"))) # Load UI settings self.font_scale_spin.setValue(float(os.getenv("font_scale", "1.0"))) - self.dpi_aware_cb.setChecked(os.getenv("dpi_aware", "true").lower() == "true") self.theme_combo.setCurrentText(os.getenv("theme", "Dark")) - self.show_font_tip_cb.setChecked(os.getenv("show_font_tip", "true").lower() == "true") # Apply font scaling self.apply_font_scaling(self.font_scale_spin.value()) @@ -390,9 +386,7 @@ class ConfigTab(QWidget): # Save UI settings set_key(self.env_file_path, "font_scale", str(self.font_scale_spin.value())) - set_key(self.env_file_path, "dpi_aware", str(self.dpi_aware_cb.isChecked()).lower()) set_key(self.env_file_path, "theme", self.theme_combo.currentText()) - set_key(self.env_file_path, "show_font_tip", str(self.show_font_tip_cb.isChecked()).lower()) QMessageBox.information(self, "Success", "Configuration saved successfully!") self.config_changed.emit() @@ -434,26 +428,49 @@ class ConfigTab(QWidget): self.file_threads_spin.setValue(1) self.threads_spin.setValue(1) self.batch_size_spin.setValue(30) - self.frequency_penalty_spin.setValue(0.2) + self.frequency_penalty_spin.setValue(0.05) # Formatting settings self.width_spin.setValue(60) - self.list_width_spin.setValue(80) - self.note_width_spin.setValue(85) + self.list_width_spin.setValue(100) + self.note_width_spin.setValue(75) # Custom API settings - self.input_cost_spin.setValue(0.002) - self.output_cost_spin.setValue(0.002) + self.input_cost_spin.setValue(2.0) + self.output_cost_spin.setValue(8.0) # UI settings self.font_scale_spin.setValue(1.0) - self.dpi_aware_cb.setChecked(True) self.theme_combo.setCurrentText("Dark") - self.show_font_tip_cb.setChecked(True) + + # Reset engine tabs + self.mvmz_tab.reset_to_defaults() + self.ace_tab.reset_to_defaults() + self.wolf_tab.reset_to_defaults() # Apply font scaling self.apply_font_scaling(1.0) + def on_font_scale_changed(self, value): + """Handle font scale change.""" + self.config_changed.emit() + # Apply font scaling immediately + self.apply_font_scaling(value) + + def apply_font_scaling(self, scale_factor): + """Apply font scaling to the entire application.""" + app = QApplication.instance() + if app: + # Get the default font + font = app.font() + base_size = 9 # Base font size + new_size = int(base_size * scale_factor) + font.setPointSize(new_size) + app.setFont(font) + + # Emit signal to notify other components + self.config_changed.emit() + def get_config(self): """Get current configuration as dictionary.""" return { @@ -473,9 +490,7 @@ class ConfigTab(QWidget): "input_cost": self.input_cost_spin.value(), "output_cost": self.output_cost_spin.value(), "font_scale": self.font_scale_spin.value(), - "dpi_aware": self.dpi_aware_cb.isChecked(), - "theme": self.theme_combo.currentText(), - "show_font_tip": self.show_font_tip_cb.isChecked() + "theme": self.theme_combo.currentText() } def validate(self): diff --git a/gui/main.py b/gui/main.py index cba02ff..3a18b50 100644 --- a/gui/main.py +++ b/gui/main.py @@ -18,9 +18,6 @@ from PyQt5.QtGui import QIcon, QFont, QPixmap, QScreen # Import configuration widgets from gui.config_tab import ConfigTab -from gui.engine_config_tab import EngineConfigTab -from gui.log_viewer import LogViewer -from gui.file_manager import FileManager from gui.translation_tab import TranslationTab class DazedMTLGUI(QMainWindow): @@ -132,9 +129,6 @@ class DazedMTLGUI(QMainWindow): central_widget = QWidget() self.setCentralWidget(central_widget) - # Create main splitter - main_splitter = QSplitter(Qt.Horizontal) - # Create tab widget self.tab_widget = QTabWidget() self.tab_widget.setTabPosition(QTabWidget.North) @@ -142,20 +136,9 @@ class DazedMTLGUI(QMainWindow): # Add tabs self.setup_tabs() - # Create log viewer - self.log_viewer = LogViewer() - - # Add widgets to splitter - main_splitter.addWidget(self.tab_widget) - main_splitter.addWidget(self.log_viewer) - - # Set proportional sizes instead of fixed pixel sizes - main_splitter.setStretchFactor(0, 2) # Main content gets 2/3 - main_splitter.setStretchFactor(1, 1) # Log viewer gets 1/3 - # Set main layout layout = QVBoxLayout() - layout.addWidget(main_splitter) + layout.addWidget(self.tab_widget) central_widget.setLayout(layout) # Create menu bar @@ -170,32 +153,7 @@ class DazedMTLGUI(QMainWindow): # Translation Execution Tab (includes file management) self.translation_tab = TranslationTab(self) - try: - self.translation_tab.engine_changed.connect(self.show_engine_tab) - except Exception: - pass self.tab_widget.addTab(self.translation_tab, "Translation") - - # Unified Engine Configuration Tab - self.engine_config_tab = EngineConfigTab() - self.tab_widget.addTab(self.engine_config_tab, "Engine Config") - # Default to MV/MZ config on first load - try: - self.show_engine_tab("mvmz") - except Exception: - pass - - def show_engine_tab(self, engine: str): - """Select engine config tab and display appropriate engine sub-widget.""" - try: - # Switch to Engine Config tab - for i in range(self.tab_widget.count()): - if self.tab_widget.tabText(i) == "Engine Config": - self.tab_widget.setCurrentIndex(i) - break - self.engine_config_tab.show_engine(engine) - except Exception: - pass def on_config_changed(self): """Handle configuration changes.""" @@ -307,7 +265,6 @@ class DazedMTLGUI(QMainWindow): try: # Load configuration from file self.config_tab.load_from_file(file_path) - self.rpgmaker_tab.load_from_file(file_path) self.status_label.setText(f"Loaded project: {Path(file_path).name}") except Exception as e: QMessageBox.critical(self, "Error", f"Failed to load project:\n{str(e)}") @@ -324,9 +281,7 @@ class DazedMTLGUI(QMainWindow): if file_path: try: # Save configuration to file - config_data = {} - config_data.update(self.config_tab.get_config()) - config_data.update(self.rpgmaker_tab.get_config()) + config_data = self.config_tab.get_config() import json with open(file_path, 'w', encoding='utf-8') as f: @@ -348,7 +303,6 @@ class DazedMTLGUI(QMainWindow): if reply == QMessageBox.Yes: self.config_tab.reset_to_defaults() - self.rpgmaker_tab.reset_to_defaults() self.status_label.setText("Reset to defaults") def validate_configuration(self): @@ -356,13 +310,12 @@ class DazedMTLGUI(QMainWindow): try: # Validate configuration settings config_valid = self.config_tab.validate() - rpgmaker_valid = self.rpgmaker_tab.validate() - if config_valid and rpgmaker_valid: + if config_valid: QMessageBox.information(self, "Validation", "Configuration is valid!") self.status_label.setText("Configuration validated") else: - QMessageBox.warning(self, "Validation", "Configuration has issues. Check the log for details.") + QMessageBox.warning(self, "Validation", "Configuration has issues. Check the warnings.") except Exception as e: QMessageBox.critical(self, "Validation Error", f"Failed to validate configuration:\n{str(e)}") @@ -433,7 +386,7 @@ def main(): app.setApplicationVersion("1.0") app.setOrganizationName("DazedTranslations") - # Apply dark theme (optional) + # Apply dark theme with cleaner, more compact styling app.setStyleSheet(""" QMainWindow { background-color: #2b2b2b; @@ -446,13 +399,15 @@ def main(): QTabWidget::pane { border: 1px solid #555555; background-color: #3c3c3c; + padding: 5px; } QTabBar::tab { background-color: #555555; color: #ffffff; - padding: 8px 12px; + padding: 8px 16px; margin-right: 2px; border: 1px solid #666666; + border-bottom: none; } QTabBar::tab:selected { background-color: #007acc; @@ -463,26 +418,28 @@ def main(): color: #ffffff; } QGroupBox { - font-weight: bold; - border: 2px solid #555555; - border-radius: 5px; - margin: 10px 0px; - padding-top: 10px; + font-weight: normal; + border: 1px solid #444444; + border-radius: 3px; + margin-top: 8px; + padding: 8px; color: #ffffff; - background-color: #3c3c3c; + background-color: transparent; } QGroupBox::title { subcontrol-origin: margin; - left: 10px; - padding: 0 5px 0 5px; + subcontrol-position: top left; + left: 8px; + padding: 2px 5px; color: #007acc; - background-color: transparent; + background-color: #2b2b2b; + font-weight: bold; } QPushButton { background-color: #0078d4; color: white; border: none; - padding: 6px 12px; + padding: 7px 14px; border-radius: 3px; font-weight: bold; } @@ -492,10 +449,15 @@ def main(): QPushButton:pressed { background-color: #005a9e; } + QPushButton:disabled { + background-color: #404040; + color: #888888; + } QCheckBox { color: #ffffff; - spacing: 5px; + spacing: 6px; background-color: transparent; + padding: 2px; } QCheckBox::indicator { width: 16px; @@ -504,112 +466,142 @@ def main(): QCheckBox::indicator:unchecked { background-color: #404040; border: 1px solid #555555; + border-radius: 2px; } QCheckBox::indicator:checked { background-color: #0078d4; border: 1px solid #0078d4; + border-radius: 2px; } QLabel { color: #ffffff; background-color: transparent; + padding: 2px; } QLineEdit { background-color: #404040; color: #ffffff; border: 1px solid #555555; - padding: 4px; + padding: 5px 8px; border-radius: 2px; + selection-background-color: #007acc; } QLineEdit:focus { - border: 2px solid #007acc; + border: 1px solid #007acc; } QSpinBox, QDoubleSpinBox { background-color: #404040; color: #ffffff; border: 1px solid #555555; - padding: 4px; + padding: 5px 8px; border-radius: 2px; } QSpinBox:focus, QDoubleSpinBox:focus { - border: 2px solid #007acc; + border: 1px solid #007acc; + } + QSpinBox::up-button, QDoubleSpinBox::up-button { + background-color: #555555; + border: none; + border-radius: 0; + } + QSpinBox::down-button, QDoubleSpinBox::down-button { + background-color: #555555; + border: none; + border-radius: 0; } QComboBox { background-color: #404040; color: #ffffff; border: 1px solid #555555; - padding: 4px; + padding: 5px 8px; border-radius: 2px; } QComboBox:focus { - border: 2px solid #007acc; + border: 1px solid #007acc; } QComboBox::drop-down { border: none; background-color: #555555; + width: 20px; } QComboBox::down-arrow { image: none; border-left: 4px solid transparent; border-right: 4px solid transparent; - border-top: 4px solid #ffffff; + border-top: 5px solid #ffffff; + margin-right: 5px; } QComboBox QAbstractItemView { background-color: #404040; color: #ffffff; selection-background-color: #007acc; border: 1px solid #555555; + padding: 3px; } QTextEdit { background-color: #1e1e1e; color: #ffffff; border: 1px solid #555555; selection-background-color: #007acc; + padding: 5px; + } + QTextEdit:focus { + border: 1px solid #007acc; } QScrollArea { - background-color: #2b2b2b; + background-color: transparent; border: none; } QScrollBar:vertical { - background-color: #404040; + background-color: #2b2b2b; width: 12px; - border-radius: 6px; + border: none; } QScrollBar::handle:vertical { - background-color: #666666; + background-color: #555555; border-radius: 6px; + min-height: 20px; margin: 2px; } QScrollBar::handle:vertical:hover { background-color: #007acc; } + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; + } QScrollBar:horizontal { - background-color: #404040; + background-color: #2b2b2b; height: 12px; - border-radius: 6px; + border: none; } QScrollBar::handle:horizontal { - background-color: #666666; + background-color: #555555; border-radius: 6px; + min-width: 20px; margin: 2px; } QScrollBar::handle:horizontal:hover { background-color: #007acc; } - QTreeWidget { + QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + width: 0px; + } + QListWidget { background-color: #1e1e1e; color: #ffffff; border: 1px solid #555555; selection-background-color: #007acc; + padding: 3px; } - QTreeWidget::item { - padding: 4px; + QListWidget::item { + padding: 5px; border-bottom: 1px solid #333333; } - QTreeWidget::item:selected { + QListWidget::item:selected { background-color: #007acc; color: #ffffff; } - QTreeWidget::item:hover { + QListWidget::item:hover { background-color: #404040; } QHeaderView::section { @@ -629,6 +621,7 @@ def main(): border-radius: 3px; text-align: center; color: #ffffff; + height: 20px; } QProgressBar::chunk { background-color: #007acc; @@ -652,16 +645,19 @@ def main(): border: 1px solid #555555; } QMenu::item { - padding: 6px 12px; + padding: 6px 20px; } QMenu::item:selected { background-color: #007acc; } - QFrame[frameShape="4"] { + QFrame[frameShape="4"], QFrame[frameShape="5"] { color: #555555; } - QFrame[frameShape="5"] { - color: #555555; + QSplitter::handle { + background-color: #555555; + } + QSplitter::handle:hover { + background-color: #007acc; } """) diff --git a/gui/translation_tab.py b/gui/translation_tab.py index 0d481e6..94c5f74 100644 --- a/gui/translation_tab.py +++ b/gui/translation_tab.py @@ -24,6 +24,7 @@ from PyQt5.QtWidgets import ( ) from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QThread, QMutex, QProcess from PyQt5.QtGui import QFont +from gui.log_viewer import LogViewer class TranslationWorker(QThread): @@ -475,6 +476,11 @@ class TranslationTab(QWidget): def setup_ui(self): """Set up the user interface.""" + # Create main splitter to separate translation controls from log viewer + main_splitter = QSplitter(Qt.Horizontal) + + # Left side - translation controls + left_widget = QWidget() layout = QVBoxLayout() layout.setSpacing(15) @@ -561,7 +567,24 @@ class TranslationTab(QWidget): button_layout.addWidget(self.stop_button) button_layout.addStretch() layout.addLayout(button_layout) - self.setLayout(layout) + left_widget.setLayout(layout) + + # Right side - translation history log viewer + self.translation_log_viewer = LogViewer() + + # Add both to splitter + main_splitter.addWidget(left_widget) + main_splitter.addWidget(self.translation_log_viewer) + + # Set proportional sizes (translation controls: 60%, log viewer: 40%) + main_splitter.setStretchFactor(0, 3) + main_splitter.setStretchFactor(1, 2) + + # Set main layout for this tab + tab_layout = QVBoxLayout() + tab_layout.addWidget(main_splitter) + tab_layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(tab_layout) def setup_module_list(self): """Set up the module selection list.""" diff --git a/modules/rpgmakerace.py b/modules/rpgmakerace.py index 9f7fbee..35a67c0 100644 --- a/modules/rpgmakerace.py +++ b/modules/rpgmakerace.py @@ -89,7 +89,7 @@ CODE102 = True # Optional CODE101 = False -CODE408 = True +CODE408 = False # Variables CODE122 = False