"""Studio main window (PySide6) -- Sprint 2.5.
Three areas:
- Sidebar (left) -- user + role + capabilities they hold.
- Central tab area -- Flash Console (Sprint 2.5) + placeholders for the
project configurator that lands in Sprint 4.
- Status bar -- session info + audit log path.
"""
from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QLabel,
QListWidget,
QMainWindow,
QSplitter,
QStatusBar,
QTabWidget,
QTextEdit,
QVBoxLayout,
QWidget,
)
from arautopilot.core.rbac import capabilities_of
from arautopilot.studio.flash_console import FlashConsoleWidget
from arautopilot.studio.session import Session
from arautopilot.version import __version__
class StudioMainWindow(QMainWindow):
"""Top-level Studio window."""
def __init__(self, session: Session) -> None:
super().__init__()
self._session = session
self.setWindowTitle(
f"AR-Autopilot Studio v{__version__} -- "
f"{session.user.display_name} ({session.role.value})"
)
self.resize(1100, 700)
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(self._build_sidebar())
splitter.addWidget(self._build_central())
splitter.setStretchFactor(0, 0)
splitter.setStretchFactor(1, 1)
splitter.setSizes([260, 840])
self.setCentralWidget(splitter)
status = QStatusBar(self)
status.showMessage(f"Audit log: {session.audit.path}")
self.setStatusBar(status)
# ----- UI ------------------------------------------------------------
def _build_sidebar(self) -> QWidget:
w = QWidget()
layout = QVBoxLayout(w)
layout.setContentsMargins(8, 8, 8, 8)
layout.addWidget(QLabel(
f"{self._session.user.display_name}
"
f"{self._session.role.value}"
))
layout.addWidget(QLabel("Capabilities"))
caps = QListWidget()
for cap in sorted(capabilities_of(self._session.role), key=lambda c: c.value):
caps.addItem(cap.value)
layout.addWidget(caps, stretch=1)
return w
def _build_central(self) -> QWidget:
tabs = QTabWidget()
tabs.addTab(self._build_overview_tab(), "Overview")
tabs.addTab(FlashConsoleWidget(self._session), "Flash Console")
tabs.addTab(self._placeholder_tab(
"Project configurator -- Sprint 4.\n\n"
"Will let you create / edit a per-vessel ProjectConfig and "
"compile it into an .appack for deployment."
), "Project")
tabs.addTab(self._placeholder_tab(
"Telemetry -- Sprint 4.\n\n"
"Live Modbus telemetry from the connected AR-NMEA-IO board."
), "Telemetry")
return tabs
def _build_overview_tab(self) -> QWidget:
w = QWidget()
layout = QVBoxLayout(w)
layout.addWidget(QLabel(
"
Welcome. Use the Flash Console tab to compile and " "flash firmware to an AR-NMEA-IO board.
" "The Project tab (Sprint 4) will let you configure a "
"vessel and produce a deployable .appack.
Every action you take is recorded in the audit log " "(see status bar at the bottom).
" )) layout.addStretch(1) return w def _placeholder_tab(self, text: str) -> QWidget: w = QWidget() layout = QVBoxLayout(w) edit = QTextEdit() edit.setReadOnly(True) edit.setPlainText(text) layout.addWidget(edit) return w