diff --git a/ameba_control_panel/app.py b/ameba_control_panel/app.py index 334858f..f05bad2 100644 --- a/ameba_control_panel/app.py +++ b/ameba_control_panel/app.py @@ -4,20 +4,19 @@ import logging import logging.handlers import sys -from PySide6.QtCore import Qt -from PySide6.QtGui import QFont, QKeySequence, QShortcut +from PySide6.QtCore import QEvent, Qt +from PySide6.QtGui import QFont from PySide6.QtWidgets import ( QApplication, QInputDialog, QMainWindow, - QMenuBar, QMessageBox, QTabWidget, QToolButton, ) from ameba_control_panel import config -from ameba_control_panel.config import DeviceProfile +from ameba_control_panel.config import DeviceProfile, Mode from ameba_control_panel import theme from ameba_control_panel.controllers.device_tab_controller import DeviceTabController from ameba_control_panel.services.session_store import SessionStore @@ -39,10 +38,11 @@ class MainWindow(QMainWindow): self._settings = Settings() self._dut_controllers: list[DeviceTabController] = [] self._next_dut_num = 1 + self._settings_applied = False add_btn = QToolButton() add_btn.setText("+") - add_btn.setToolTip("Add DUT tab (Ctrl+T)") + add_btn.setToolTip("Add DUT tab (Ctrl+N)") add_btn.clicked.connect(self._add_dut_tab_auto) self._tabs.setCornerWidget(add_btn, Qt.TopLeftCorner) @@ -61,21 +61,28 @@ class MainWindow(QMainWindow): else: self._add_dut_tab("dut_1", "DUT 1") + def showEvent(self, event) -> None: # noqa: N802 + super().showEvent(event) + if not self._settings_applied: + self._settings_applied = True + self._apply_settings() + def _build_menu_bar(self) -> None: mb = self.menuBar() view_menu = mb.addMenu("&View") - view_menu.addAction("New Tab", self._add_dut_tab_auto, QKeySequence("Ctrl+T")) - view_menu.addAction("Close Tab", self._close_current_tab, QKeySequence("Ctrl+W")) + view_menu.addAction("New Tab\tCtrl+N", self._add_dut_tab_auto) + view_menu.addAction("Close Tab\tCtrl+W", self._close_current_tab) view_menu.addSeparator() - view_menu.addAction("Clear Log", self._clear_current_log, QKeySequence("Ctrl+L")) - view_menu.addAction("Find", self._focus_find, QKeySequence("Ctrl+F")) + view_menu.addAction("Clear Log\tCtrl+C", self._clear_current_log) + view_menu.addAction("Find\tCtrl+S", self._focus_find) settings_menu = mb.addMenu("&Settings") settings_menu.addAction("Preferences...", self._open_settings) help_menu = mb.addMenu("&Help") help_menu.addAction("About", self._show_about) + help_menu.addAction("Shortcuts", self._show_shortcuts) def _toggle_theme(self) -> None: if self._current_palette.name == "light": @@ -87,6 +94,15 @@ class MainWindow(QMainWindow): for ctrl in self._dut_controllers: ctrl.view.log_view.set_colors(p.log_rx, p.log_tx, p.log_info) + def _toggle_connect(self) -> None: + ctrl = self._current_controller() + if ctrl: + ctrl.view.connect_button.click() + + def _show_shortcuts(self) -> None: + text = "\n".join(f"Ctrl+{lbl}\t{desc}" for lbl, desc in self._shortcut_labels) + QMessageBox.information(self, "Shortcuts", text) + def _show_about(self) -> None: QMessageBox.about(self, config.APP_NAME, f"{config.APP_NAME}\n" @@ -96,14 +112,34 @@ class MainWindow(QMainWindow): f"Licensed under the Apache License, Version 2.0\n" f"All rights reserved. For internal use only.") + _KEY_EVENTS = frozenset({QEvent.KeyPress, QEvent.ShortcutOverride}) + def _setup_shortcuts(self) -> None: - QShortcut(QKeySequence("Ctrl+T"), self, activated=self._add_dut_tab_auto) - QShortcut(QKeySequence("Ctrl+W"), self, activated=self._close_current_tab) - QShortcut(QKeySequence("Ctrl+F"), self, activated=self._focus_find) - QShortcut(QKeySequence("Ctrl+L"), self, activated=self._clear_current_log) - QShortcut(QKeySequence("Ctrl+Return"), self, activated=self._send_current) - QShortcut(QKeySequence("Ctrl+Shift+F"), self, activated=self._flash_current) - QShortcut(QKeySequence("Ctrl+R"), self, activated=self._reset_current) + bindings = ( + ("N", "New DUT tab", Qt.Key_N, self._add_dut_tab_auto), + ("W", "Close current tab", Qt.Key_W, self._close_current_tab), + ("D", "Connect / Disconnect", Qt.Key_D, self._toggle_connect), + ("S", "Find in log", Qt.Key_S, self._focus_find), + ("C", "Clear log", Qt.Key_C, self._clear_current_log), + ("Enter", "Send command", Qt.Key_Return, self._send_current), + ("F", "Flash firmware", Qt.Key_F, self._flash_current), + ("R", "Normal mode", Qt.Key_R, self._reset_current), + ) + self._shortcut_labels = tuple((lbl, desc) for lbl, desc, _, _ in bindings) + self._key_map = {key: handler for _, _, key, handler in bindings} + QApplication.instance().installEventFilter(self) + + def eventFilter(self, obj, event) -> bool: + etype = event.type() + if etype in self._KEY_EVENTS and event.modifiers() == Qt.ControlModifier: + handler = self._key_map.get(event.key()) + if handler: + if etype == QEvent.ShortcutOverride: + event.accept() + return True + handler() + return True + return super().eventFilter(obj, event) def _close_current_tab(self) -> None: self._close_tab(self._tabs.currentIndex()) @@ -146,8 +182,7 @@ class MainWindow(QMainWindow): def _reset_current(self) -> None: ctrl = self._current_controller() if ctrl: - from ameba_control_panel.config import Mode - ctrl.flash.run_mode(Mode.RESET) + ctrl.flash.run_mode(Mode.NORMAL) def _current_controller(self) -> DeviceTabController | None: widget = self._tabs.currentWidget()