more improvements

This commit is contained in:
dazedanon 2025-10-25 16:34:21 -05:00
parent f2c6a8ebf1
commit 38a0e8f03a
3 changed files with 393 additions and 335 deletions

View file

@ -130,18 +130,18 @@ class ConfigTab(QWidget):
self.api_url_edit = QLineEdit()
self.api_url_edit.setPlaceholderText("Leave blank for OpenAI API")
self.api_url_edit.setMaximumWidth(400)
self.api_url_edit.setFixedWidth(350) # Large
api_form.addRow("API URL:", self.api_url_edit)
self.api_key_edit = QLineEdit()
self.api_key_edit.setEchoMode(QLineEdit.Password)
self.api_key_edit.setPlaceholderText("Enter your API key")
self.api_key_edit.setMaximumWidth(400)
self.api_key_edit.setFixedWidth(350) # Large
api_form.addRow("API Key:", self.api_key_edit)
self.organization_edit = QLineEdit()
self.organization_edit.setPlaceholderText("Optional organization key")
self.organization_edit.setMaximumWidth(400)
self.organization_edit.setFixedWidth(350) # Large
api_form.addRow("Organization:", self.organization_edit)
self.model_combo = QComboBox()
@ -151,7 +151,7 @@ class ConfigTab(QWidget):
"deepseek-chat", "claude-3-sonnet-20240229",
"gemini-2.0-flash", "gemini-2.5-flash", "gemini-2.5-pro"
])
self.model_combo.setMaximumWidth(400)
self.model_combo.setFixedWidth(200) # Medium
api_form.addRow("Model:", self.model_combo)
left_column.addLayout(api_form)
@ -169,14 +169,15 @@ class ConfigTab(QWidget):
"English", "Spanish", "French", "German", "Italian",
"Portuguese", "Russian", "Chinese", "Korean", "Japanese"
])
self.language_combo.setMaximumWidth(250)
self.language_combo.setFixedWidth(200) # Medium
trans_form.addRow("Target Language:", self.language_combo)
self.timeout_spin = QSpinBox()
self.timeout_spin.setButtonSymbols(QSpinBox.NoButtons)
self.timeout_spin.setRange(30, 300)
self.timeout_spin.setValue(120)
self.timeout_spin.setValue(90)
self.timeout_spin.setSuffix(" sec")
self.timeout_spin.setMaximumWidth(150)
self.timeout_spin.setFixedWidth(90) # Small
trans_form.addRow("Timeout:", self.timeout_spin)
left_column.addLayout(trans_form)
@ -190,28 +191,32 @@ class ConfigTab(QWidget):
perf_form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
self.file_threads_spin = QSpinBox()
self.file_threads_spin.setButtonSymbols(QSpinBox.NoButtons)
self.file_threads_spin.setRange(1, 10)
self.file_threads_spin.setValue(1)
self.file_threads_spin.setMaximumWidth(150)
self.file_threads_spin.setFixedWidth(90) # Small
perf_form.addRow("File Threads:", self.file_threads_spin)
self.threads_spin = QSpinBox()
self.threads_spin.setButtonSymbols(QSpinBox.NoButtons)
self.threads_spin.setRange(1, 20)
self.threads_spin.setValue(1)
self.threads_spin.setMaximumWidth(150)
self.threads_spin.setFixedWidth(90) # Small
perf_form.addRow("Threads per File:", self.threads_spin)
self.batch_size_spin = QSpinBox()
self.batch_size_spin.setButtonSymbols(QSpinBox.NoButtons)
self.batch_size_spin.setRange(1, 100)
self.batch_size_spin.setValue(30)
self.batch_size_spin.setMaximumWidth(150)
self.batch_size_spin.setFixedWidth(90) # Small
perf_form.addRow("Batch Size:", self.batch_size_spin)
self.frequency_penalty_spin = QDoubleSpinBox()
self.frequency_penalty_spin.setButtonSymbols(QDoubleSpinBox.NoButtons)
self.frequency_penalty_spin.setRange(0.0, 2.0)
self.frequency_penalty_spin.setSingleStep(0.05)
self.frequency_penalty_spin.setValue(0.05)
self.frequency_penalty_spin.setMaximumWidth(150)
self.frequency_penalty_spin.setFixedWidth(90) # Small
perf_form.addRow("Frequency Penalty:", self.frequency_penalty_spin)
left_column.addLayout(perf_form)
@ -229,24 +234,27 @@ class ConfigTab(QWidget):
format_form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
self.width_spin = QSpinBox()
self.width_spin.setButtonSymbols(QSpinBox.NoButtons)
self.width_spin.setRange(20, 200)
self.width_spin.setValue(60)
self.width_spin.setSuffix(" chars")
self.width_spin.setMaximumWidth(150)
self.width_spin.setFixedWidth(90) # Small
format_form.addRow("Dialogue Width:", self.width_spin)
self.list_width_spin = QSpinBox()
self.list_width_spin.setButtonSymbols(QSpinBox.NoButtons)
self.list_width_spin.setRange(20, 200)
self.list_width_spin.setValue(100)
self.list_width_spin.setSuffix(" chars")
self.list_width_spin.setMaximumWidth(150)
self.list_width_spin.setFixedWidth(90) # Small
format_form.addRow("List Width:", self.list_width_spin)
self.note_width_spin = QSpinBox()
self.note_width_spin.setButtonSymbols(QSpinBox.NoButtons)
self.note_width_spin.setRange(20, 200)
self.note_width_spin.setValue(75)
self.note_width_spin.setSuffix(" chars")
self.note_width_spin.setMaximumWidth(150)
self.note_width_spin.setFixedWidth(90) # Small
format_form.addRow("Note Width:", self.note_width_spin)
right_column.addLayout(format_form)
@ -266,21 +274,23 @@ class ConfigTab(QWidget):
price_form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
self.input_cost_spin = QDoubleSpinBox()
self.input_cost_spin.setButtonSymbols(QDoubleSpinBox.NoButtons)
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")
self.input_cost_spin.setMaximumWidth(200)
self.input_cost_spin.setFixedWidth(200) # Medium
price_form.addRow("Input Cost:", self.input_cost_spin)
self.output_cost_spin = QDoubleSpinBox()
self.output_cost_spin.setButtonSymbols(QDoubleSpinBox.NoButtons)
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")
self.output_cost_spin.setMaximumWidth(200)
self.output_cost_spin.setFixedWidth(200) # Medium
price_form.addRow("Output Cost:", self.output_cost_spin)
right_column.addLayout(price_form)
@ -314,7 +324,7 @@ class ConfigTab(QWidget):
# Load translation settings
self.language_combo.setCurrentText(os.getenv("language", "English"))
self.timeout_spin.setValue(int(os.getenv("timeout", "120")))
self.timeout_spin.setValue(int(os.getenv("timeout", "90")))
# Load performance settings
self.file_threads_spin.setValue(int(os.getenv("fileThreads", "1")))
@ -397,7 +407,7 @@ class ConfigTab(QWidget):
# Translation settings
self.language_combo.setCurrentText("English")
self.timeout_spin.setValue(120)
self.timeout_spin.setValue(90)
# Performance settings
self.file_threads_spin.setValue(1)

View file

@ -7,7 +7,7 @@ from pathlib import Path
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QCheckBox,
QPushButton, QGroupBox, QLabel, QMessageBox, QScrollArea,
QTextEdit, QSpinBox, QFrame
QTextEdit, QSpinBox, QFrame, QGridLayout
)
from PyQt5.QtCore import Qt, pyqtSignal
@ -18,6 +18,21 @@ except ImportError:
ConfigIntegration = None
def create_section_label(text):
"""Create a section label for grouping checkboxes."""
label = QLabel(text)
label.setStyleSheet("""
QLabel {
font-size: 12px;
font-weight: bold;
color: #007acc;
padding: 5px 0px 3px 0px;
background-color: transparent;
}
""")
return label
class RPGMakerTab(QWidget):
"""RPG Maker MV/MZ & Ace configuration tab.
@ -154,232 +169,148 @@ class RPGMakerTab(QWidget):
self.reset_to_defaults()
def init_ui(self):
"""Initialize the user interface."""
"""Initialize the user interface with compact two-column layout."""
main_layout = QVBoxLayout()
# Create scroll area
scroll_area = QScrollArea()
scroll_content = QWidget()
scroll_layout = QVBoxLayout()
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.setSpacing(10)
# Title and description
title = "RPG Maker MV/MZ" if self.engine != "ACE" else "RPG Maker Ace"
title_label = QLabel(f"{title} Translation Settings")
title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #007acc;")
scroll_layout.addWidget(title_label)
title_label.setStyleSheet("font-size: 14px; font-weight: bold; color: #007acc;")
main_layout.addWidget(title_label)
description_label = QLabel(
"Configure which RPG Maker event codes to translate and additional options. "
"Each code represents a specific type of game content."
"Enable event codes to translate. Only enable what you need to reduce translation time and costs."
)
description_label.setWordWrap(True)
description_label.setStyleSheet("color: #cccccc; margin-bottom: 10px;")
scroll_layout.addWidget(description_label)
description_label.setStyleSheet("color: #888888; font-size: 11px; margin-bottom: 5px;")
main_layout.addWidget(description_label)
# General Config Group
general_group = self.create_general_config_group()
scroll_layout.addWidget(general_group)
# Two-column layout for checkboxes
columns_layout = QHBoxLayout()
columns_layout.setSpacing(30)
# Main Dialogue Codes Group
dialogue_group = self.create_dialogue_codes_group()
scroll_layout.addWidget(dialogue_group)
# LEFT COLUMN
left_column = QVBoxLayout()
left_column.setSpacing(3)
# Optional Codes Group
optional_group = self.create_optional_codes_group()
scroll_layout.addWidget(optional_group)
# Variable Codes Group
variable_group = self.create_variable_codes_group()
scroll_layout.addWidget(variable_group)
# Other Codes Group
other_group = self.create_other_codes_group()
scroll_layout.addWidget(other_group)
# Buttons
button_layout = QHBoxLayout()
self.reset_button = QPushButton("Reset to Defaults")
self.reset_button.clicked.connect(self.reset_to_defaults_with_message)
self.validate_button = QPushButton("Validate Settings")
self.validate_button.clicked.connect(self.validate_and_show_report)
button_layout.addWidget(self.reset_button)
button_layout.addWidget(self.validate_button)
button_layout.addStretch()
scroll_layout.addLayout(button_layout)
# Add separator
separator = QFrame()
separator.setFrameShape(QFrame.HLine)
separator.setFrameShadow(QFrame.Sunken)
scroll_layout.addWidget(separator)
# Add note about performance
note_text = QTextEdit()
note_text.setMaximumHeight(100)
note_text.setReadOnly(True)
note_text.setHtml("""
<b>Performance Notes:</b><br>
Enable only the codes you need to reduce translation time and costs<br>
CODE408 can significantly increase costs as it translates comments<br>
Main dialogue codes (401, 405, 102) are typically required for story content<br>
Test with a small file first to verify settings work correctly
""")
scroll_layout.addWidget(note_text)
scroll_content.setLayout(scroll_layout)
scroll_area.setWidget(scroll_content)
scroll_area.setWidgetResizable(True)
main_layout.addWidget(scroll_area)
self.setLayout(main_layout)
def create_general_config_group(self):
"""Create general configuration group."""
group = QGroupBox("General Configuration")
layout = QVBoxLayout()
# FIRSTLINESPEAKERS
# General Configuration
left_column.addWidget(create_section_label("⚙️ General Options"))
self.first_line_speakers_cb = QCheckBox("First Line Speakers")
self.first_line_speakers_cb.setToolTip(
"If the first line of event code 401 contains a speaker name, enable this option"
)
layout.addWidget(self.first_line_speakers_cb)
self.first_line_speakers_cb.setToolTip("Enable if first line of CODE401 contains speaker name")
left_column.addWidget(self.first_line_speakers_cb)
# FACENAME101
self.facename_101_cb = QCheckBox("Find Speakers in 101 Codes based on Face Name")
self.facename_101_cb.setToolTip(
"Use character face names to identify speakers in event code 101"
)
layout.addWidget(self.facename_101_cb)
self.facename101_cb = QCheckBox("Face Name in CODE101")
self.facename101_cb.setToolTip("Enable to translate face names in CODE101")
left_column.addWidget(self.facename101_cb)
# NAMES
self.names_cb = QCheckBox("Output Character Names List")
self.names_cb.setToolTip(
"Generate a list of all character names found during translation"
)
layout.addWidget(self.names_cb)
self.names_cb = QCheckBox("Translate Names")
self.names_cb.setToolTip("Enable to translate character names")
left_column.addWidget(self.names_cb)
# BRFLAG
self.br_flag_cb = QCheckBox("Use <br> Tags")
self.br_flag_cb.setToolTip(
"Use <br> HTML tags instead of newlines for line breaks"
)
layout.addWidget(self.br_flag_cb)
self.brflag_cb = QCheckBox("Line Break Flag")
self.brflag_cb.setToolTip("Enable line break handling")
left_column.addWidget(self.brflag_cb)
# FIXTEXTWRAP
self.fix_textwrap_cb = QCheckBox("Fix Text Wrapping")
self.fix_textwrap_cb.setToolTip(
"Automatically fix text wrapping for better display"
)
layout.addWidget(self.fix_textwrap_cb)
self.fixtextwrap_cb = QCheckBox("Fix Text Wrap")
self.fixtextwrap_cb.setToolTip("Automatically fix text wrapping issues")
left_column.addWidget(self.fixtextwrap_cb)
# IGNORETLTEXT
self.ignore_tl_text_cb = QCheckBox("Ignore Already Translated Text")
self.ignore_tl_text_cb.setToolTip(
"Skip text that appears to already be translated"
)
layout.addWidget(self.ignore_tl_text_cb)
self.ignoretltext_cb = QCheckBox("Ignore TL Text")
self.ignoretltext_cb.setToolTip("Ignore already translated text")
left_column.addWidget(self.ignoretltext_cb)
group.setLayout(layout)
return group
left_column.addSpacing(8)
def create_dialogue_codes_group(self):
"""Create dialogue codes group."""
group = QGroupBox("Main Dialogue Codes (Recommended)")
layout = QVBoxLayout()
# Main Dialogue Codes
left_column.addWidget(create_section_label("💬 Main Dialogue (Recommended)"))
self.code401_cb = QCheckBox("CODE401 - Show Text")
left_column.addWidget(self.code401_cb)
# CODE401
self.code_401_cb = QCheckBox("CODE 401 - Show Text")
self.code_401_cb.setToolTip(
"Translate dialogue text displayed in message windows. Essential for story content."
)
layout.addWidget(self.code_401_cb)
self.code405_cb = QCheckBox("CODE405 - Show Text (line 4+)")
left_column.addWidget(self.code405_cb)
# CODE405
self.code_405_cb = QCheckBox("CODE 405 - Show Text (Scrolling)")
self.code_405_cb.setToolTip(
"Translate scrolling text messages. Used for longer dialogue passages."
)
layout.addWidget(self.code_405_cb)
self.code102_cb = QCheckBox("CODE102 - Show Choices")
left_column.addWidget(self.code102_cb)
# CODE102
self.code_102_cb = QCheckBox("CODE 102 - Show Choices")
self.code_102_cb.setToolTip(
"Translate choice options presented to the player."
)
layout.addWidget(self.code_102_cb)
left_column.addSpacing(8)
group.setLayout(layout)
return group
# Optional Dialogue Codes
left_column.addWidget(create_section_label("📝 Optional Dialogue"))
self.code101_cb = QCheckBox("CODE101 - Show Text (face)")
left_column.addWidget(self.code101_cb)
def create_optional_codes_group(self):
"""Create optional codes group."""
group = QGroupBox("Optional Codes")
layout = QVBoxLayout()
self.code408_cb = QCheckBox("CODE408 - Show Text (continuation)")
self.code408_cb.setToolTip("Can significantly increase costs")
left_column.addWidget(self.code408_cb)
# CODE101
self.code_101_cb = QCheckBox("CODE 101 - Character Names")
self.code_101_cb.setToolTip(
"Translate character names. Enable only when names are stored in code 101."
)
layout.addWidget(self.code_101_cb)
self.code122_cb = QCheckBox("CODE122 - Control Variables")
left_column.addWidget(self.code122_cb)
# CODE408
self.code_408_cb = QCheckBox("CODE 408 - Comments (Warning: High Cost)")
self.code_408_cb.setToolTip(
"Translate comment text. WARNING: This can significantly increase translation costs!"
)
self.code_408_cb.setStyleSheet("QCheckBox { color: #ff6b6b; }")
layout.addWidget(self.code_408_cb)
left_column.addStretch()
group.setLayout(layout)
return group
# RIGHT COLUMN
right_column = QVBoxLayout()
right_column.setSpacing(3)
def create_variable_codes_group(self):
"""Create variable codes group."""
group = QGroupBox("Variable Codes")
layout = QVBoxLayout()
# Event Codes (compact grid layout)
right_column.addWidget(create_section_label("🎮 Event Codes"))
# CODE122
self.code_122_cb = QCheckBox("CODE 122 - Control Variables")
self.code_122_cb.setToolTip(
"Translate text stored in game variables."
)
layout.addWidget(self.code_122_cb)
# Create a grid for better space usage
event_grid = QGridLayout()
event_grid.setSpacing(2)
event_grid.setHorizontalSpacing(15)
group.setLayout(layout)
return group
def create_other_codes_group(self):
"""Create other codes group."""
group = QGroupBox("Other Event Codes")
layout = QVBoxLayout()
codes_info = [
("355655", "Scripts", "Translate text within script commands"),
("357", "Picture Text", "Translate text displayed on pictures"),
("657", "Picture Text Extended", "Extended picture text translation"),
("356", "Plugin Commands", "Translate plugin command parameters"),
("320", "Change Name Input", "Translate name input prompts"),
("324", "Change Nickname", "Translate nickname changes"),
("111", "Conditional Branch", "Translate conditional text"),
("108", "Comments", "Translate comment blocks")
# Event codes in a more compact format
event_codes = [
("CODE103", "Input Number"), ("CODE104", "Select Item"),
("CODE111", "Conditional Branch"), ("CODE117", "Common Event"),
("CODE119", "Set Movement"), ("CODE121", "Control Switches"),
("CODE125", "Change Gold"), ("CODE126", "Change Items"),
("CODE127", "Change Weapons"), ("CODE128", "Change Armors"),
("CODE129", "Change Party"), ("CODE201", "Transfer Player"),
("CODE202", "Set Vehicle Loc"), ("CODE203", "Set Event Loc"),
("CODE211", "Change Transparency"), ("CODE212", "Show Animation"),
("CODE213", "Show Balloon"), ("CODE214", "Erase Event"),
("CODE221", "Fadeout Screen"), ("CODE222", "Fadein Screen"),
("CODE231", "Show Picture"), ("CODE232", "Move Picture"),
("CODE241", "Play BGM"), ("CODE242", "Fadeout BGM"),
]
self.other_code_checkboxes = {}
self.event_checkboxes = {}
for idx, (code, label) in enumerate(event_codes):
cb = QCheckBox(f"{code} - {label}")
cb.setStyleSheet("QCheckBox { font-size: 10px; }")
event_grid.addWidget(cb, idx // 2, idx % 2)
self.event_checkboxes[code] = cb
for code, name, tooltip in codes_info:
cb = QCheckBox(f"CODE {code} - {name}")
cb.setToolTip(tooltip)
layout.addWidget(cb)
self.other_code_checkboxes[code] = cb
right_column.addLayout(event_grid)
right_column.addStretch()
group.setLayout(layout)
return group
# Add both columns
columns_layout.addLayout(left_column, 1)
columns_layout.addLayout(right_column, 1)
main_layout.addLayout(columns_layout)
# Bottom buttons
button_layout = QHBoxLayout()
button_layout.setSpacing(10)
self.reset_button = QPushButton("🔄 Reset to Defaults")
self.reset_button.clicked.connect(self.reset_to_defaults_with_message)
self.reset_button.setMaximumWidth(200)
self.apply_button = QPushButton("✓ Apply Settings")
self.apply_button.clicked.connect(self.apply_to_module)
self.apply_button.setMaximumWidth(200)
button_layout.addWidget(self.reset_button)
button_layout.addWidget(self.apply_button)
button_layout.addStretch()
main_layout.addLayout(button_layout)
self.setLayout(main_layout)
def reset_to_defaults(self):
"""Reset all settings to default values."""
@ -388,31 +319,27 @@ class RPGMakerTab(QWidget):
# Apply default values from the DEFAULT_CONFIG constant
self.first_line_speakers_cb.setChecked(self.DEFAULT_CONFIG["FIRSTLINESPEAKERS"])
self.facename_101_cb.setChecked(self.DEFAULT_CONFIG["FACENAME101"])
self.facename101_cb.setChecked(self.DEFAULT_CONFIG["FACENAME101"])
self.names_cb.setChecked(self.DEFAULT_CONFIG["NAMES"])
self.br_flag_cb.setChecked(self.DEFAULT_CONFIG["BRFLAG"])
self.fix_textwrap_cb.setChecked(self.DEFAULT_CONFIG["FIXTEXTWRAP"])
self.ignore_tl_text_cb.setChecked(self.DEFAULT_CONFIG["IGNORETLTEXT"])
self.brflag_cb.setChecked(self.DEFAULT_CONFIG["BRFLAG"])
self.fixtextwrap_cb.setChecked(self.DEFAULT_CONFIG["FIXTEXTWRAP"])
self.ignoretltext_cb.setChecked(self.DEFAULT_CONFIG["IGNORETLTEXT"])
# Main dialogue codes
self.code_401_cb.setChecked(self.DEFAULT_CONFIG["CODE401"])
self.code_405_cb.setChecked(self.DEFAULT_CONFIG["CODE405"])
self.code_102_cb.setChecked(self.DEFAULT_CONFIG["CODE102"])
self.code401_cb.setChecked(self.DEFAULT_CONFIG["CODE401"])
self.code405_cb.setChecked(self.DEFAULT_CONFIG["CODE405"])
self.code102_cb.setChecked(self.DEFAULT_CONFIG["CODE102"])
# Optional codes
self.code_101_cb.setChecked(self.DEFAULT_CONFIG["CODE101"])
self.code_408_cb.setChecked(self.DEFAULT_CONFIG["CODE408"])
self.code101_cb.setChecked(self.DEFAULT_CONFIG["CODE101"])
self.code408_cb.setChecked(self.DEFAULT_CONFIG["CODE408"])
# Variable codes
self.code_122_cb.setChecked(self.DEFAULT_CONFIG["CODE122"])
self.code122_cb.setChecked(self.DEFAULT_CONFIG["CODE122"])
# Other codes - apply defaults from the constant
for code, cb in self.other_code_checkboxes.items():
default_key = f"CODE{code}"
if default_key in self.DEFAULT_CONFIG:
cb.setChecked(self.DEFAULT_CONFIG[default_key])
else:
cb.setChecked(False) # Fallback to False if not in defaults
# Event codes
for code, cb in self.event_checkboxes.items():
cb.setChecked(self.DEFAULT_CONFIG.get(code, False))
# Reconnect signals and apply changes once
self.connect_auto_apply()
@ -432,26 +359,26 @@ class RPGMakerTab(QWidget):
try:
# General settings checkboxes
self.first_line_speakers_cb.stateChanged.disconnect()
self.facename_101_cb.stateChanged.disconnect()
self.facename101_cb.stateChanged.disconnect()
self.names_cb.stateChanged.disconnect()
self.br_flag_cb.stateChanged.disconnect()
self.fix_textwrap_cb.stateChanged.disconnect()
self.ignore_tl_text_cb.stateChanged.disconnect()
self.brflag_cb.stateChanged.disconnect()
self.fixtextwrap_cb.stateChanged.disconnect()
self.ignoretltext_cb.stateChanged.disconnect()
# Main dialogue codes
self.code_401_cb.stateChanged.disconnect()
self.code_405_cb.stateChanged.disconnect()
self.code_102_cb.stateChanged.disconnect()
self.code401_cb.stateChanged.disconnect()
self.code405_cb.stateChanged.disconnect()
self.code102_cb.stateChanged.disconnect()
# Optional codes
self.code_101_cb.stateChanged.disconnect()
self.code_408_cb.stateChanged.disconnect()
self.code101_cb.stateChanged.disconnect()
self.code408_cb.stateChanged.disconnect()
# Variable codes
self.code_122_cb.stateChanged.disconnect()
self.code122_cb.stateChanged.disconnect()
# Other codes
for cb in self.other_code_checkboxes.values():
# Event codes
for cb in self.event_checkboxes.values():
cb.stateChanged.disconnect()
except TypeError:
# Ignore if signals are not connected
@ -461,26 +388,26 @@ class RPGMakerTab(QWidget):
"""Connect all checkboxes to auto-apply changes when modified."""
# General settings checkboxes
self.first_line_speakers_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.facename_101_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.facename101_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.names_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.br_flag_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.fix_textwrap_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.ignore_tl_text_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.brflag_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.fixtextwrap_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.ignoretltext_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
# Main dialogue codes
self.code_401_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code_405_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code_102_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code401_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code405_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code102_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
# Optional codes
self.code_101_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code_408_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code101_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code408_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
# Variable codes
self.code_122_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
self.code122_cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
# Other codes
for cb in self.other_code_checkboxes.values():
# Event codes
for cb in self.event_checkboxes.values():
cb.stateChanged.connect(lambda: self.apply_to_module(show_messages=False))
def get_config(self):
@ -488,28 +415,28 @@ class RPGMakerTab(QWidget):
config = {
# General settings
"FIRSTLINESPEAKERS": self.first_line_speakers_cb.isChecked(),
"FACENAME101": self.facename_101_cb.isChecked(),
"FACENAME101": self.facename101_cb.isChecked(),
"NAMES": self.names_cb.isChecked(),
"BRFLAG": self.br_flag_cb.isChecked(),
"FIXTEXTWRAP": self.fix_textwrap_cb.isChecked(),
"IGNORETLTEXT": self.ignore_tl_text_cb.isChecked(),
"BRFLAG": self.brflag_cb.isChecked(),
"FIXTEXTWRAP": self.fixtextwrap_cb.isChecked(),
"IGNORETLTEXT": self.ignoretltext_cb.isChecked(),
# Main dialogue codes
"CODE401": self.code_401_cb.isChecked(),
"CODE405": self.code_405_cb.isChecked(),
"CODE102": self.code_102_cb.isChecked(),
"CODE401": self.code401_cb.isChecked(),
"CODE405": self.code405_cb.isChecked(),
"CODE102": self.code102_cb.isChecked(),
# Optional codes
"CODE101": self.code_101_cb.isChecked(),
"CODE408": self.code_408_cb.isChecked(),
"CODE101": self.code101_cb.isChecked(),
"CODE408": self.code408_cb.isChecked(),
# Variable codes
"CODE122": self.code_122_cb.isChecked(),
"CODE122": self.code122_cb.isChecked(),
}
# Other codes
for code, cb in self.other_code_checkboxes.items():
config[f"CODE{code}"] = cb.isChecked()
# Event codes
for code, cb in self.event_checkboxes.items():
config[code] = cb.isChecked()
return config
@ -517,27 +444,27 @@ class RPGMakerTab(QWidget):
"""Set configuration from dictionary."""
# General settings
self.first_line_speakers_cb.setChecked(config.get("FIRSTLINESPEAKERS", False))
self.facename_101_cb.setChecked(config.get("FACENAME101", False))
self.facename101_cb.setChecked(config.get("FACENAME101", False))
self.names_cb.setChecked(config.get("NAMES", False))
self.br_flag_cb.setChecked(config.get("BRFLAG", False))
self.fix_textwrap_cb.setChecked(config.get("FIXTEXTWRAP", True))
self.ignore_tl_text_cb.setChecked(config.get("IGNORETLTEXT", False))
self.brflag_cb.setChecked(config.get("BRFLAG", False))
self.fixtextwrap_cb.setChecked(config.get("FIXTEXTWRAP", True))
self.ignoretltext_cb.setChecked(config.get("IGNORETLTEXT", False))
# Main dialogue codes
self.code_401_cb.setChecked(config.get("CODE401", True))
self.code_405_cb.setChecked(config.get("CODE405", True))
self.code_102_cb.setChecked(config.get("CODE102", True))
self.code401_cb.setChecked(config.get("CODE401", True))
self.code405_cb.setChecked(config.get("CODE405", True))
self.code102_cb.setChecked(config.get("CODE102", True))
# Optional codes
self.code_101_cb.setChecked(config.get("CODE101", False))
self.code_408_cb.setChecked(config.get("CODE408", False))
self.code101_cb.setChecked(config.get("CODE101", False))
self.code408_cb.setChecked(config.get("CODE408", False))
# Variable codes
self.code_122_cb.setChecked(config.get("CODE122", False))
self.code122_cb.setChecked(config.get("CODE122", False))
# Other codes
for code, cb in self.other_code_checkboxes.items():
cb.setChecked(config.get(f"CODE{code}", False))
# Event codes
for code, cb in self.event_checkboxes.items():
cb.setChecked(config.get(code, False))
def load_from_file(self, file_path):
"""Load configuration from file."""
@ -555,20 +482,20 @@ class RPGMakerTab(QWidget):
# Check if any main dialogue codes are enabled
main_codes_enabled = (
self.code_401_cb.isChecked() or
self.code_405_cb.isChecked() or
self.code_102_cb.isChecked()
self.code401_cb.isChecked() or
self.code405_cb.isChecked() or
self.code102_cb.isChecked()
)
if not main_codes_enabled:
warnings.append("No main dialogue codes are enabled. You may not get any translated content.")
# Check for high-cost options
if self.code_408_cb.isChecked():
if self.code408_cb.isChecked():
warnings.append("CODE 408 (Comments) is enabled. This can significantly increase translation costs!")
# Check for conflicting options
if self.br_flag_cb.isChecked() and self.fix_textwrap_cb.isChecked():
if self.brflag_cb.isChecked() and self.fixtextwrap_cb.isChecked():
warnings.append("Both BR tags and text wrapping are enabled. This might cause formatting issues.")
return len(errors) == 0, warnings, errors

View file

@ -5,11 +5,17 @@ what gets translated. This can be expanded later.
"""
from pathlib import Path
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QGroupBox, QCheckBox, QPushButton, QMessageBox, QLabel, QHBoxLayout, QScrollArea
QWidget, QVBoxLayout, QCheckBox, QPushButton, QMessageBox, QLabel, QHBoxLayout, QGridLayout
)
from PyQt5.QtCore import pyqtSignal
import re
def create_section_label(text):
"""Create a styled section header label."""
label = QLabel(text)
label.setStyleSheet("font-size: 12px; font-weight: bold; color: #007acc; padding: 2px 0px;")
return label
class WolfTab(QWidget):
config_changed = pyqtSignal()
@ -45,67 +51,183 @@ class WolfTab(QWidget):
self.reset_to_defaults()
def init_ui(self):
"""Initialize the user interface with compact two-column layout."""
main_layout = QVBoxLayout()
scroll = QScrollArea()
content = QWidget()
v = QVBoxLayout()
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.setSpacing(10)
# Title and description
title = QLabel("Wolf RPG Editor Translation Settings")
title.setStyleSheet("font-size: 14px; font-weight: bold; color: #007acc;")
main_layout.addWidget(title)
title = QLabel("Wolf RPG Settings")
title.setStyleSheet("font-size:16px;font-weight:bold;color:#007acc")
v.addWidget(title)
desc = QLabel("Toggle which parts of Wolf RPG data are translated. This is a minimal first pass; more options can be added later.")
desc.setWordWrap(True)
desc.setStyleSheet("color:#cccccc")
v.addWidget(desc)
# Groups
self.checkboxes = {}
self.add_group(v, "Dialogue / Choices", ["CODE101", "CODE102"])
self.add_group(v, "Pictures / Variables", ["CODE150", "CODE122"])
self.add_group(v, "Other Event Codes", ["CODE210", "CODE300", "CODE250"])
self.add_group(v, "Database Sections", [
"SCENARIOFLAG", "OPTIONSFLAG", "NPCFLAG", "DBNAMEFLAG", "DBVALUEFLAG",
"ITEMFLAG", "STATEFLAG", "ENEMYFLAG", "ARMORFLAG", "WEAPONFLAG", "SKILLFLAG"
])
# Buttons
btn_row = QHBoxLayout()
self.reset_btn = QPushButton("Reset")
self.reset_btn.clicked.connect(self.reset_to_defaults)
self.apply_btn = QPushButton("Apply Now")
self.apply_btn.clicked.connect(self.apply_to_module)
btn_row.addWidget(self.reset_btn)
btn_row.addWidget(self.apply_btn)
btn_row.addStretch()
v.addLayout(btn_row)
content.setLayout(v)
scroll.setWidget(content)
scroll.setWidgetResizable(True)
main_layout.addWidget(scroll)
description = QLabel(
"Enable translation options for Wolf RPG Editor projects. Only enable what you need."
)
description.setWordWrap(True)
description.setStyleSheet("color: #888888; font-size: 11px; margin-bottom: 5px;")
main_layout.addWidget(description)
# Two-column layout for checkboxes
columns_layout = QHBoxLayout()
columns_layout.setSpacing(30)
# LEFT COLUMN
left_column = QVBoxLayout()
left_column.setSpacing(3)
# Dialogue & Choices
left_column.addWidget(create_section_label("💬 Dialogue & Choices"))
self.code101_cb = QCheckBox("CODE101 - Show Text")
self.code101_cb.setToolTip("Enable translation of dialogue text")
left_column.addWidget(self.code101_cb)
self.code102_cb = QCheckBox("CODE102 - Show Choices")
self.code102_cb.setToolTip("Enable translation of choice options")
left_column.addWidget(self.code102_cb)
left_column.addSpacing(8)
# Pictures & Variables
left_column.addWidget(create_section_label("🖼️ Pictures & Variables"))
self.code150_cb = QCheckBox("CODE150 - Show Picture")
self.code150_cb.setToolTip("Enable translation of picture-related text")
left_column.addWidget(self.code150_cb)
self.code122_cb = QCheckBox("CODE122 - String Operations")
self.code122_cb.setToolTip("Enable translation of string variables")
left_column.addWidget(self.code122_cb)
left_column.addSpacing(8)
# Other Event Codes
left_column.addWidget(create_section_label("🎮 Other Event Codes"))
self.code210_cb = QCheckBox("CODE210 - Conditional Branch")
left_column.addWidget(self.code210_cb)
self.code300_cb = QCheckBox("CODE300 - Set Variable")
left_column.addWidget(self.code300_cb)
self.code250_cb = QCheckBox("CODE250 - Sound Effect")
left_column.addWidget(self.code250_cb)
left_column.addStretch()
# RIGHT COLUMN
right_column = QVBoxLayout()
right_column.setSpacing(3)
# Database Sections
right_column.addWidget(create_section_label("📚 Database Sections"))
# Database flags in compact 2-column grid
db_grid = QGridLayout()
db_grid.setSpacing(2)
db_grid.setHorizontalSpacing(10)
database_flags = [
("SCENARIOFLAG", "Scenario Text"),
("OPTIONSFLAG", "Options"),
("NPCFLAG", "NPC Data"),
("DBNAMEFLAG", "Database Names"),
("DBVALUEFLAG", "Database Values"),
("ITEMFLAG", "Items"),
("STATEFLAG", "States"),
("ENEMYFLAG", "Enemies"),
("ARMORFLAG", "Armor"),
("WEAPONFLAG", "Weapons"),
("SKILLFLAG", "Skills"),
]
self.db_checkboxes = {}
for idx, (key, label) in enumerate(database_flags):
cb = QCheckBox(label)
cb.setStyleSheet("QCheckBox { font-size: 10px; }")
db_grid.addWidget(cb, idx // 2, idx % 2)
self.db_checkboxes[key] = cb
right_column.addLayout(db_grid)
right_column.addStretch()
# Add both columns
columns_layout.addLayout(left_column, 1)
columns_layout.addLayout(right_column, 1)
main_layout.addLayout(columns_layout)
# Bottom buttons
button_layout = QHBoxLayout()
button_layout.setSpacing(10)
self.reset_btn = QPushButton("🔄 Reset to Defaults")
self.reset_btn.clicked.connect(self.reset_to_defaults_with_message)
self.reset_btn.setMaximumWidth(200)
self.apply_btn = QPushButton("✓ Apply Settings")
self.apply_btn.clicked.connect(lambda: self.apply_to_module(True))
self.apply_btn.setMaximumWidth(200)
button_layout.addWidget(self.reset_btn)
button_layout.addWidget(self.apply_btn)
button_layout.addStretch()
main_layout.addLayout(button_layout)
self.setLayout(main_layout)
# Connect auto-apply
self.code101_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code102_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code150_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code122_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code210_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code300_cb.stateChanged.connect(lambda: self.apply_to_module(False))
self.code250_cb.stateChanged.connect(lambda: self.apply_to_module(False))
for cb in self.db_checkboxes.values():
cb.stateChanged.connect(lambda: self.apply_to_module(False))
def add_group(self, parent_layout, title, keys):
box = QGroupBox(title)
v = QVBoxLayout()
for k in keys:
cb = QCheckBox(k)
cb.stateChanged.connect(lambda _=None: self.apply_to_module(False))
v.addWidget(cb)
self.checkboxes[k] = cb
box.setLayout(v)
parent_layout.addWidget(box)
def get_config(self):
return {k: cb.isChecked() for k, cb in self.checkboxes.items()}
"""Get current configuration as dictionary."""
config = {
"CODE101": self.code101_cb.isChecked(),
"CODE102": self.code102_cb.isChecked(),
"CODE150": self.code150_cb.isChecked(),
"CODE122": self.code122_cb.isChecked(),
"CODE210": self.code210_cb.isChecked(),
"CODE300": self.code300_cb.isChecked(),
"CODE250": self.code250_cb.isChecked(),
}
# Add database checkboxes
for key, cb in self.db_checkboxes.items():
config[key] = cb.isChecked()
return config
def reset_to_defaults(self):
for k, val in self.DEFAULT_CONFIG.items():
if k in self.checkboxes:
self.checkboxes[k].setChecked(val)
self.apply_to_module()
"""Reset all settings to default values without showing message."""
self.code101_cb.setChecked(self.DEFAULT_CONFIG["CODE101"])
self.code102_cb.setChecked(self.DEFAULT_CONFIG["CODE102"])
self.code150_cb.setChecked(self.DEFAULT_CONFIG["CODE150"])
self.code122_cb.setChecked(self.DEFAULT_CONFIG["CODE122"])
self.code210_cb.setChecked(self.DEFAULT_CONFIG["CODE210"])
self.code300_cb.setChecked(self.DEFAULT_CONFIG["CODE300"])
self.code250_cb.setChecked(self.DEFAULT_CONFIG["CODE250"])
for key, cb in self.db_checkboxes.items():
cb.setChecked(self.DEFAULT_CONFIG.get(key, False))
self.apply_to_module(False)
def reset_to_defaults_with_message(self):
"""Reset to defaults and show confirmation message."""
self.reset_to_defaults()
QMessageBox.information(
self,
"Reset Complete",
"All settings have been reset to their default values."
)
def apply_to_module(self, show_message=False):
"""Apply current configuration to wolf.py module."""
module_path = Path(__file__).parent.parent / 'modules' / 'wolf.py'
if not module_path.exists():
if show_message:
@ -123,4 +245,3 @@ class WolfTab(QWidget):
except Exception as e:
if show_message:
QMessageBox.critical(self, 'Error', f'Failed to apply settings: {e}')