Files
Teletext-Editor/src/teletext/ui.py

196 lines
6.8 KiB
Python
Raw Normal View History

import os
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QListWidget, QListWidgetItem, QComboBox, QLabel, QFileDialog, QMenuBar, QMenu, QMessageBox)
from PyQt6.QtGui import QAction, QKeyEvent
from PyQt6.QtCore import Qt
from .io import load_t42, save_t42
from .renderer import TeletextCanvas
from .models import TeletextService, Page, Packet
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Teletext Editor")
self.resize(1024, 768)
self.service = TeletextService()
self.current_page: Page = None
# UI Components
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QHBoxLayout(self.central_widget)
# Left Panel: Page List
left_layout = QVBoxLayout()
left_label = QLabel("Pages")
left_layout.addWidget(left_label)
self.page_list = QListWidget()
self.page_list.setFixedWidth(150)
self.page_list.itemClicked.connect(self.on_page_selected)
left_layout.addWidget(self.page_list)
self.layout.addLayout(left_layout)
# Center Area Layout (Top Bar + Canvas)
center_layout = QVBoxLayout()
# Top Bar: Subpage Selector
top_bar = QHBoxLayout()
self.subpage_label = QLabel("Subpage:")
self.subpage_combo = QComboBox()
self.subpage_combo.setMinimumWidth(250)
self.subpage_combo.currentIndexChanged.connect(self.on_subpage_changed)
top_bar.addWidget(self.subpage_label)
top_bar.addWidget(self.subpage_combo)
top_bar.addStretch()
center_layout.addLayout(top_bar)
# Canvas
self.canvas = TeletextCanvas()
center_layout.addWidget(self.canvas, 1) # Expand
self.layout.addLayout(center_layout, 1)
# Menus
self.create_menus()
def create_menus(self):
menu_bar = self.menuBar()
file_menu = menu_bar.addMenu("File")
open_action = QAction("Open T42...", self)
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)
save_action = QAction("Save T42...", self)
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)
exit_action = QAction("Exit", self)
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
view_menu = menu_bar.addMenu("View")
lang_menu = view_menu.addMenu("Language")
langs = ["English", "German", "Swedish/Finnish", "Italian", "French", "Portuguese/Spanish", "Turkish", "Romania"]
for i, lang in enumerate(langs):
action = QAction(lang, self)
action.setData(i)
action.triggered.connect(self.set_language)
lang_menu.addAction(action)
def set_language(self):
action = self.sender()
if action:
idx = action.data()
self.canvas.subset_idx = idx
self.canvas.redraw()
self.canvas.update()
def open_file(self):
fname, _ = QFileDialog.getOpenFileName(self, "Open T42", "", "Teletext Files (*.t42);;All Files (*)")
if fname:
try:
self.service = load_t42(fname)
self.populate_list()
QMessageBox.information(self, "Loaded", f"Loaded {len(self.service.pages)} pages.")
except Exception as e:
QMessageBox.critical(self, "Error", f"Failed to load file: {e}")
def save_file(self):
fname, _ = QFileDialog.getSaveFileName(self, "Save T42", "", "Teletext Files (*.t42);;All Files (*)")
if fname:
try:
save_t42(fname, self.service)
QMessageBox.information(self, "Saved", "File saved successfully.")
except Exception as e:
QMessageBox.critical(self, "Error", f"Failed to save file: {e}")
def populate_list(self):
self.page_list.clear()
# Group pages by Mag+PageNum
# We want unique list items
self.page_groups = {} # Key: (mag, page_num) -> List[Page]
for p in self.service.pages:
key = (p.magazine, p.page_number)
if key not in self.page_groups:
self.page_groups[key] = []
self.page_groups[key].append(p)
# Sort keys
sorted_keys = sorted(self.page_groups.keys())
for mag, pnum in sorted_keys:
label = f"{mag}{pnum:02d}"
item = QListWidgetItem(label)
item.setData(Qt.ItemDataRole.UserRole, (mag, pnum))
self.page_list.addItem(item)
def on_page_selected(self, item):
mag, pnum = item.data(Qt.ItemDataRole.UserRole)
pages = self.page_groups.get((mag, pnum), [])
# Populate Subpage Combo
self.subpage_combo.blockSignals(True)
self.subpage_combo.clear()
for i, p in enumerate(pages):
# Display format: Index or Subcode?
# Subcode is often 0000. Index 1/N is clearer for editing.
label = f"{i+1}/{len(pages)} (Sub {p.sub_code:04X})"
self.subpage_combo.addItem(label, p)
self.subpage_combo.blockSignals(False)
if pages:
self.subpage_combo.setCurrentIndex(0)
# Trigger update (manual because blockSignals)
self.on_subpage_changed(0)
def on_subpage_changed(self, index):
if index < 0: return
page = self.subpage_combo.itemData(index)
if isinstance(page, Page):
self.current_page = page
self.canvas.set_page(page)
self.canvas.setFocus()
# Input Handling (Editor Logic)
def keyPressEvent(self, event: QKeyEvent):
if not self.current_page:
return
key = event.key()
text = event.text()
# Navigation
if key == Qt.Key.Key_Up:
self.canvas.move_cursor(0, -1)
elif key == Qt.Key.Key_Down:
self.canvas.move_cursor(0, 1)
elif key == Qt.Key.Key_Left:
self.canvas.move_cursor(-1, 0)
elif key == Qt.Key.Key_Right:
self.canvas.move_cursor(1, 0)
else:
# Typing
# Filter non-printable
if text and len(text) == 1 and 32 <= ord(text) <= 126:
self.canvas.handle_input(text)
elif key == Qt.Key.Key_Backspace:
# Move back and delete
self.canvas.move_cursor(-1, 0)
self.canvas.handle_input(' ')
self.canvas.move_cursor(-1, 0) # Compensate for the auto-advance logic if any