Add SRPG Studio to GUI
This commit is contained in:
parent
52e23c12aa
commit
da7b3a7bd1
4 changed files with 171 additions and 1 deletions
|
|
@ -17,6 +17,7 @@ from dotenv import load_dotenv, set_key
|
||||||
from gui.rpgmaker_tab import RPGMakerTab
|
from gui.rpgmaker_tab import RPGMakerTab
|
||||||
from gui.wolf_tab import WolfTab
|
from gui.wolf_tab import WolfTab
|
||||||
from gui.csv_tab import CSVTab
|
from gui.csv_tab import CSVTab
|
||||||
|
from gui.srpg_tab import SRPGTab
|
||||||
|
|
||||||
|
|
||||||
def create_section_header(title):
|
def create_section_header(title):
|
||||||
|
|
@ -113,6 +114,12 @@ class ConfigTab(QWidget):
|
||||||
btn_csv.clicked.connect(lambda: self.switch_page(4))
|
btn_csv.clicked.connect(lambda: self.switch_page(4))
|
||||||
nav_layout.addWidget(btn_csv)
|
nav_layout.addWidget(btn_csv)
|
||||||
self.nav_buttons.append(btn_csv)
|
self.nav_buttons.append(btn_csv)
|
||||||
|
|
||||||
|
# SRPG Studio button
|
||||||
|
btn_srpg = self.create_nav_button("⚔️", "SRPG Studio")
|
||||||
|
btn_srpg.clicked.connect(lambda: self.switch_page(5))
|
||||||
|
nav_layout.addWidget(btn_srpg)
|
||||||
|
self.nav_buttons.append(btn_srpg)
|
||||||
|
|
||||||
nav_layout.addStretch()
|
nav_layout.addStretch()
|
||||||
nav_bar.setLayout(nav_layout)
|
nav_bar.setLayout(nav_layout)
|
||||||
|
|
@ -139,6 +146,10 @@ class ConfigTab(QWidget):
|
||||||
# Page 5: CSV Settings
|
# Page 5: CSV Settings
|
||||||
self.csv_tab = CSVTab()
|
self.csv_tab = CSVTab()
|
||||||
self.content_stack.addWidget(self.csv_tab)
|
self.content_stack.addWidget(self.csv_tab)
|
||||||
|
|
||||||
|
# Page 6: SRPG Studio Engine
|
||||||
|
self.srpg_tab = SRPGTab()
|
||||||
|
self.content_stack.addWidget(self.srpg_tab)
|
||||||
|
|
||||||
# Add navigation bar and content to main layout
|
# Add navigation bar and content to main layout
|
||||||
main_layout.addWidget(nav_bar)
|
main_layout.addWidget(nav_bar)
|
||||||
|
|
|
||||||
155
gui/srpg_tab.py
Normal file
155
gui/srpg_tab.py
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
"""SRPG Studio configuration tab.
|
||||||
|
|
||||||
|
Provides toggles for configurable flags in srpg.py so users can
|
||||||
|
enable/disable text-wrap fixing and skip-already-translated behaviour.
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QWidget, QVBoxLayout, QCheckBox, QPushButton, QMessageBox, QLabel, QHBoxLayout
|
||||||
|
)
|
||||||
|
from PyQt5.QtCore import pyqtSignal
|
||||||
|
import re
|
||||||
|
|
||||||
|
try:
|
||||||
|
import set_defaults
|
||||||
|
CANONICAL_DEFAULTS = getattr(set_defaults, 'DEFAULTS', None)
|
||||||
|
except Exception:
|
||||||
|
CANONICAL_DEFAULTS = None
|
||||||
|
|
||||||
|
|
||||||
|
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 SRPGTab(QWidget):
|
||||||
|
config_changed = pyqtSignal()
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"FIXTEXTWRAP": True,
|
||||||
|
"IGNORETLTEXT": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
defaults = CANONICAL_DEFAULTS if CANONICAL_DEFAULTS is not None else self.DEFAULT_CONFIG
|
||||||
|
self.set_config(defaults)
|
||||||
|
self.connect_auto_apply()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""Initialize the user interface."""
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
main_layout.setContentsMargins(15, 15, 15, 15)
|
||||||
|
main_layout.setSpacing(10)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
title = QLabel("SRPG Studio Translation Settings")
|
||||||
|
title.setStyleSheet("font-size: 15px; font-weight: bold; color: #007acc;")
|
||||||
|
main_layout.addWidget(title)
|
||||||
|
|
||||||
|
description = QLabel(
|
||||||
|
"Configure translation options for SRPG Studio projects. "
|
||||||
|
"Changes are applied directly to modules/srpg.py."
|
||||||
|
)
|
||||||
|
description.setWordWrap(True)
|
||||||
|
description.setStyleSheet("color: #888888; font-size: 10px; margin-bottom: 8px;")
|
||||||
|
main_layout.addWidget(description)
|
||||||
|
|
||||||
|
# --- Text Formatting ---
|
||||||
|
main_layout.addWidget(create_section_label("📝 Text Formatting"))
|
||||||
|
|
||||||
|
self.fixtextwrap_cb = QCheckBox("Fix Text Wrap")
|
||||||
|
self.fixtextwrap_cb.setToolTip(
|
||||||
|
"Re-wrap translated text to fit the configured dialogue width (WIDTH setting)"
|
||||||
|
)
|
||||||
|
main_layout.addWidget(self.fixtextwrap_cb)
|
||||||
|
|
||||||
|
# --- Translation Behaviour ---
|
||||||
|
main_layout.addWidget(create_section_label("🔄 Translation Behaviour"))
|
||||||
|
|
||||||
|
self.ignoretltext_cb = QCheckBox("Ignore Already-Translated Text")
|
||||||
|
self.ignoretltext_cb.setToolTip(
|
||||||
|
"Skip lines that appear to have already been translated"
|
||||||
|
)
|
||||||
|
main_layout.addWidget(self.ignoretltext_cb)
|
||||||
|
|
||||||
|
main_layout.addStretch()
|
||||||
|
|
||||||
|
# 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(180)
|
||||||
|
self.reset_btn.setMinimumHeight(32)
|
||||||
|
|
||||||
|
button_layout.addWidget(self.reset_btn)
|
||||||
|
button_layout.addStretch()
|
||||||
|
|
||||||
|
main_layout.addLayout(button_layout)
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Public API
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def get_config(self) -> dict:
|
||||||
|
"""Return current configuration as a dictionary."""
|
||||||
|
return {
|
||||||
|
"FIXTEXTWRAP": self.fixtextwrap_cb.isChecked(),
|
||||||
|
"IGNORETLTEXT": self.ignoretltext_cb.isChecked(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_config(self, config: dict):
|
||||||
|
"""Set configuration from dictionary (does not write to module)."""
|
||||||
|
self.fixtextwrap_cb.setChecked(config.get("FIXTEXTWRAP", True))
|
||||||
|
self.ignoretltext_cb.setChecked(config.get("IGNORETLTEXT", False))
|
||||||
|
|
||||||
|
def connect_auto_apply(self):
|
||||||
|
"""Connect widget changes to auto-apply to srpg.py."""
|
||||||
|
self.fixtextwrap_cb.stateChanged.connect(lambda: self.apply_to_module(False))
|
||||||
|
self.ignoretltext_cb.stateChanged.connect(lambda: self.apply_to_module(False))
|
||||||
|
|
||||||
|
def reset_to_defaults(self):
|
||||||
|
"""Reset all settings to defaults without showing a message."""
|
||||||
|
defaults = (
|
||||||
|
CANONICAL_DEFAULTS
|
||||||
|
if 'CANONICAL_DEFAULTS' in globals() and CANONICAL_DEFAULTS is not None
|
||||||
|
else self.DEFAULT_CONFIG
|
||||||
|
)
|
||||||
|
self.set_config(defaults)
|
||||||
|
self.apply_to_module(False)
|
||||||
|
|
||||||
|
def reset_to_defaults_with_message(self):
|
||||||
|
"""Reset to defaults and show a 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: bool = False):
|
||||||
|
"""Write current configuration back to modules/srpg.py."""
|
||||||
|
module_path = Path(__file__).parent.parent / 'modules' / 'srpg.py'
|
||||||
|
if not module_path.exists():
|
||||||
|
if show_message:
|
||||||
|
QMessageBox.critical(self, 'Error', 'srpg.py not found in modules directory.')
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
content = module_path.read_text(encoding='utf-8')
|
||||||
|
for key, value in self.get_config().items():
|
||||||
|
pattern = rf'^{key}\s*=\s*.*$'
|
||||||
|
content = re.sub(pattern, f'{key} = {value}', content, flags=re.MULTILINE)
|
||||||
|
module_path.write_text(content, encoding='utf-8')
|
||||||
|
self.config_changed.emit()
|
||||||
|
if show_message:
|
||||||
|
QMessageBox.information(self, 'Applied', 'SRPG Studio configuration applied to srpg.py.')
|
||||||
|
except Exception as e:
|
||||||
|
if show_message:
|
||||||
|
QMessageBox.critical(self, 'Error', f'Failed to apply settings: {e}')
|
||||||
|
|
@ -1078,6 +1078,7 @@ class TranslationTab(QWidget):
|
||||||
from modules.images import handleImages
|
from modules.images import handleImages
|
||||||
from modules.rpgmakerplugin import handlePlugin
|
from modules.rpgmakerplugin import handlePlugin
|
||||||
from modules.aquedi4 import handleAquedi4
|
from modules.aquedi4 import handleAquedi4
|
||||||
|
from modules.srpg import handleSRPG
|
||||||
|
|
||||||
self.modules = [
|
self.modules = [
|
||||||
["RPG Maker MV/MZ", [".json"], handleMVMZ],
|
["RPG Maker MV/MZ", [".json"], handleMVMZ],
|
||||||
|
|
@ -1097,6 +1098,7 @@ class TranslationTab(QWidget):
|
||||||
["Images", [".png", ".jpg", ".jpeg"], handleImages],
|
["Images", [".png", ".jpg", ".jpeg"], handleImages],
|
||||||
["RPG Maker Plugin", [".js"], handlePlugin],
|
["RPG Maker Plugin", [".js"], handlePlugin],
|
||||||
["Aquedi4 Prepared JSON", [".json"], handleAquedi4],
|
["Aquedi4 Prepared JSON", [".json"], handleAquedi4],
|
||||||
|
["SRPG Studio", [".json"], handleSRPG],
|
||||||
]
|
]
|
||||||
|
|
||||||
for module in self.modules:
|
for module in self.modules:
|
||||||
|
|
@ -1121,6 +1123,8 @@ class TranslationTab(QWidget):
|
||||||
self.engine_changed.emit("wolf")
|
self.engine_changed.emit("wolf")
|
||||||
elif "mv/mz" in lowered:
|
elif "mv/mz" in lowered:
|
||||||
self.engine_changed.emit("mvmz")
|
self.engine_changed.emit("mvmz")
|
||||||
|
elif "srpg" in lowered:
|
||||||
|
self.engine_changed.emit("srpg")
|
||||||
|
|
||||||
# Update mode dropdown based on engine
|
# Update mode dropdown based on engine
|
||||||
current_mode = self.mode_combo.currentText()
|
current_mode = self.mode_combo.currentText()
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ FIXTEXTWRAP = True
|
||||||
# IGNORETLTEXT: Skip Translated Text.
|
# IGNORETLTEXT: Skip Translated Text.
|
||||||
IGNORETLTEXT = False
|
IGNORETLTEXT = False
|
||||||
# TLSYSTEMVARIABLES: Translate System Variables. (Optional but sometimes necessary. Can break stuff.)
|
# TLSYSTEMVARIABLES: Translate System Variables. (Optional but sometimes necessary. Can break stuff.)
|
||||||
TLSYSTEMVARIABLES = True
|
TLSYSTEMVARIABLES = False
|
||||||
# TLSYSTEMSWITCHES: Translate System Switches. (Optional. Translates switch names in System.json.)
|
# TLSYSTEMSWITCHES: Translate System Switches. (Optional. Translates switch names in System.json.)
|
||||||
TLSYSTEMSWITCHES = False
|
TLSYSTEMSWITCHES = False
|
||||||
# Join 408 codes into a single string like 401.
|
# Join 408 codes into a single string like 401.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue