diff --git a/spanish_trainer.db b/spanish_trainer.db
index 88bd1ed..aecf0c3 100644
Binary files a/spanish_trainer.db and b/spanish_trainer.db differ
diff --git a/tabs/sandbox_tab.py b/tabs/sandbox_tab.py
index 801cf54..2a3fa92 100644
--- a/tabs/sandbox_tab.py
+++ b/tabs/sandbox_tab.py
@@ -14,22 +14,30 @@ import edge_tts
import database
class TextEditorDialog(QDialog):
- """A pop-up modal containing a large text field workspace for copy-pasting extra text blocks."""
+ """A pop-up modal containing a large text field workspace for copy-pasting extra text blocks or drafting HTML content."""
def __init__(self, title, initial_text="", parent=None):
super().__init__(parent)
self.setWindowTitle(title)
- self.resize(500, 350)
+ self.resize(650, 450)
layout = QVBoxLayout(self)
+ info_label = QLabel("Edit text or raw HTML below (supports tables, lists, and inline styles):")
+ info_label.setStyleSheet("color: #7F8C8D; font-size: 12px;")
+ layout.addWidget(info_label)
+
self.editor = QTextEdit()
self.editor.setPlainText(initial_text)
- self.editor.setStyleSheet("font-family: Arial; font-size: 14px; padding: 5px;")
+ # Monospaced font for clean HTML readability
+ self.editor.setStyleSheet("font-family: monospace; font-size: 13px; background-color: #2C3E50; color: #ECF0F1; padding: 8px;")
layout.addWidget(self.editor)
btn_layout = QHBoxLayout()
self.btn_save = QPushButton("Save / Apply")
+ self.btn_save.setStyleSheet("background-color: #27AE60; color: white; font-weight: bold; padding: 6px 14px;")
self.btn_save.clicked.connect(self.accept)
+
self.btn_cancel = QPushButton("Cancel")
+ self.btn_cancel.setStyleSheet("padding: 6px 14px;")
self.btn_cancel.clicked.connect(self.reject)
btn_layout.addStretch()
@@ -63,16 +71,42 @@ class SandboxTab(QWidget):
form_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
form_layout.setSpacing(10)
+ # --- English Input Row ---
+ english_widget = QWidget()
+ english_layout = QHBoxLayout(english_widget)
+ english_layout.setContentsMargins(0, 0, 0, 0)
+ english_layout.setSpacing(8)
+
self.txt_english = QLineEdit()
self.txt_english.setPlaceholderText("Enter English phrase (filters grid real-time)...")
self.txt_english.setStyleSheet("padding: 6px; font-size: 14px;")
self.txt_english.textChanged.connect(self.apply_live_grid_filter)
+ self.btn_edit_english = QPushButton("✏️ Edit English Block")
+ self.btn_edit_english.setStyleSheet("padding: 6px 12px; font-weight: bold; background-color: #34495E; color: white; border-radius: 4px;")
+ self.btn_edit_english.clicked.connect(self.open_english_editor)
+
+ english_layout.addWidget(self.txt_english, stretch=1)
+ english_layout.addWidget(self.btn_edit_english, stretch=0)
+
+ # --- Spanish Input Row ---
+ spanish_widget = QWidget()
+ spanish_layout = QHBoxLayout(spanish_widget)
+ spanish_layout.setContentsMargins(0, 0, 0, 0)
+ spanish_layout.setSpacing(8)
+
self.txt_spanish = QLineEdit()
self.txt_spanish.setPlaceholderText("Enter Spanish phrase (filters grid real-time)...")
self.txt_spanish.setStyleSheet("padding: 6px; font-size: 14px;")
self.txt_spanish.textChanged.connect(self.apply_live_grid_filter)
+ self.btn_edit_spanish = QPushButton("✏️ Edit Spanish Block")
+ self.btn_edit_spanish.setStyleSheet("padding: 6px 12px; font-weight: bold; background-color: #34495E; color: white; border-radius: 4px;")
+ self.btn_edit_spanish.clicked.connect(self.open_spanish_editor)
+
+ spanish_layout.addWidget(self.txt_spanish, stretch=1)
+ spanish_layout.addWidget(self.btn_edit_spanish, stretch=0)
+
self.txt_context = QLineEdit()
self.txt_context.setPlaceholderText("Context e.g., Camino 2027 (filters grid real-time)...")
self.txt_context.setStyleSheet("padding: 6px; font-size: 14px;")
@@ -83,7 +117,7 @@ class SandboxTab(QWidget):
self.txt_tags.setStyleSheet("padding: 6px; font-size: 14px;")
self.txt_tags.textChanged.connect(self.apply_live_grid_filter)
- # Modal Editor Row Buttons
+ # Modal Editor Row Buttons for Extended Notes
editor_buttons_layout = QHBoxLayout()
self.btn_edit_notes = QPushButton("📝 Edit Notes Block")
self.btn_edit_notes.clicked.connect(self.open_notes_editor)
@@ -94,8 +128,9 @@ class SandboxTab(QWidget):
editor_buttons_layout.addWidget(self.btn_edit_notes)
editor_buttons_layout.addWidget(self.btn_edit_anki_notes)
- form_layout.addRow(QLabel("English Phrase:"), self.txt_english)
- form_layout.addRow(QLabel("Spanish Translation:"), self.txt_spanish)
+ # Add container widgets to QFormLayout rows
+ form_layout.addRow(QLabel("English Phrase:"), english_widget)
+ form_layout.addRow(QLabel("Spanish Translation:"), spanish_widget)
form_layout.addRow(QLabel("Source Context:"), self.txt_context)
form_layout.addRow(QLabel("Tags:"), self.txt_tags)
form_layout.addRow(QLabel("Extended Data Fields:"), editor_buttons_layout)
@@ -166,20 +201,29 @@ class SandboxTab(QWidget):
main_layout.addWidget(self.table)
self.reload_table_display()
+ @pyqtSlot()
+ def open_english_editor(self):
+ dlg = TextEditorDialog("Edit English Phrase / HTML Block", self.txt_english.text(), self)
+ if dlg.exec():
+ self.txt_english.setText(dlg.get_text())
+
+ @pyqtSlot()
+ def open_spanish_editor(self):
+ dlg = TextEditorDialog("Edit Spanish Translation / HTML Block", self.txt_spanish.text(), self)
+ if dlg.exec():
+ self.txt_spanish.setText(dlg.get_text())
+
@pyqtSlot()
def open_notes_editor(self):
dlg = TextEditorDialog("Edit Grammar / Core Notes Block", self.current_notes_content, self)
if dlg.exec():
self.current_notes_content = dlg.get_text()
- # print(f"[DEBUG DIALOG CLOSE] Notes Block updated in memory: {self.current_notes_content}")
-
@pyqtSlot()
def open_anki_notes_editor(self):
dlg = TextEditorDialog("Edit Anki Specialized Meta Field", self.current_anki_notes_content, self)
if dlg.exec():
self.current_anki_notes_content = dlg.get_text()
- #print(f"[DEBUG DIALOG CLOSE] Anki Notes Block updated in memory: {self.current_anki_notes_content}")
def clear_form_fields(self):
self.txt_english.blockSignals(True)
@@ -214,19 +258,7 @@ class SandboxTab(QWidget):
if not en_t or not es_t:
QMessageBox.warning(self, "Validation Alert", "English and Spanish phrase properties cannot remain blank.")
return
-
- # print(f"\n[DEBUG DATABASE WRITE]")
- # print(f" ID Selected: {self.selected_translation_id}")
- # print(f" English: {en_t}")
- # print(f" Spanish: {es_t}")
- # print(f" Context: {ctx_t}")
- # print(f" Tags: {tag_t}")
- # print(f" Notes: {self.current_notes_content}")
- # print(f" Anki Notes: {self.current_anki_notes_content}")
- # print(f" Gender: {gender_t}\n")
-
- # Fixed argument sequence to match Beekeeper schema (gender position 7, anki_notes position 8)
if self.selected_translation_id is None:
database.insert_translation_record(es_t, en_t, ctx_t, tag_t, self.current_notes_content, gender_t, self.current_anki_notes_content)
else:
@@ -333,7 +365,6 @@ class SandboxTab(QWidget):
return
settings = database.load_all_settings() or {}
- # Fixed: Changed lookup from "playback_speed_multiplier" to "tts_playback_speed"
config_speed = settings.get("tts_playback_speed", "1.0")
try:
pct = int((float(config_speed) - 1.0) * 100)
@@ -353,18 +384,14 @@ class SandboxTab(QWidget):
if not txt:
return
- # Dynamically switch between neural voices depending on the active form state radio selection
voice = "es-ES-AlvaroNeural" if self.rb_male.isChecked() else "es-ES-ElviraNeural"
settings = database.load_all_settings() or {}
config_speed = settings.get("tts_playback_speed", "1.0")
try:
pct = int((float(config_speed) - 1.0) * 100)
- # print(f"[DEBUG Sandbox Speech] config_speed (Raw String): {config_speed}")
- # print(f"[DEBUG Sandbox Speech] Calculated pct (Integer): {pct}")
rate_string = f"{'+' if pct >= 0 else ''}{pct}%"
except Exception:
- print(f"[DEBUG Sandbox Speech] Failed to parse speed calculation")
rate_string = "+0%"
threading.Thread(