import os from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTreeWidget, QTreeWidgetItem, 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 Tree self.tree = QTreeWidget() self.tree.setHeaderLabel("Pages") self.tree.setFixedWidth(200) self.tree.itemClicked.connect(self.on_page_selected) self.layout.addWidget(self.tree) # Center: Teletext Canvas self.canvas = TeletextCanvas() self.layout.addWidget(self.canvas, 1) # Expand # 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_tree() 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_tree(self): self.tree.clear() # Group by Magazine mags = {} for p in self.service.pages: if p.magazine not in mags: mags[p.magazine] = QTreeWidgetItem([f"Magazine {p.magazine}"]) self.tree.addTopLevelItem(mags[p.magazine]) # Format: PPP-SS (Page-Subcode) # Create Item # Subcode is complicated to display "nicely" without decoding, # let's just show hex or raw for now if not standard 0000. label = f"{p.page_number:02d} (Sub: {p.sub_code:04X})" item = QTreeWidgetItem([label]) item.setData(0, Qt.ItemDataRole.UserRole, p) mags[p.magazine].addChild(item) self.tree.expandAll() def on_page_selected(self, item, column): page = item.data(0, Qt.ItemDataRole.UserRole) if isinstance(page, Page): self.current_page = page self.canvas.set_page(page) # Also set window focus to canvas or handle key events? 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