GUI Architecture¶
This page describes the current high-level structure of the two graphical
applications shipped with pypts:
the runtime application launched with
python -m pyptsthe recipe editor application known as
YamVIEW
The two applications are still separate Qt windows and, when launched from the runtime GUI, separate processes. They now share a common theme layer and a common visual language, but they do not yet share all widgets.
Runtime GUI¶
The runtime GUI is built around pypts.gui.MainWindow. It is a
panelized QMainWindow composed from smaller widgets and helper modules.
Startup path¶
The standard startup path is:
pypts.__main__creates the backend API withrun_pts()pypts.startup.create_and_start_gui()creates theQApplicationandMainWindowthe runtime/event-proxy layer is connected to the window slots
app.exec()starts the Qt event loop
Main window structure¶
MainWindow contains the following major areas:
a menu bar
a top toolbar
a top tab bar representing the current screen state: Idle, Running, Prompt, Results
a recipe label area
a central horizontal splitter with left and right panels
a status bar
The left and right panels are intentionally distinct:
left side: sequence progress and final results
right side: operator interaction and log output
The left side uses a stacked widget so the window can switch between:
an idle placeholder
a live step-status table
a final hierarchical results panel
The right side contains:
an interaction panel for images, prompts, and runtime buttons
a log panel for textual runtime output
Runtime window diagram¶
The runtime window is structured approximately as follows:
+---------------------------------------------------------------+
| Menu Bar |
+---------------------------------------------------------------+
| Toolbar |
+---------------------------------------------------------------+
| Screen Tabs: Idle | Running | Prompt | Results |
+---------------------------------------------------------------+
| Recipe Label / Description |
+-------------------------------+-------------------------------+
| Left Panel | Right Panel |
| | |
| +-------------------------+ | +-------------------------+ |
| | Idle Placeholder | | | Interaction Panel | |
| | or Live Step Table | | | - image | |
| | or Results Panel | | | - prompt text | |
| | | | | - action buttons | |
| +-------------------------+ | +-------------------------+ |
| | |
| | +-------------------------+ |
| | | Log Panel | |
| | +-------------------------+ |
+-------------------------------+-------------------------------+
| Status Bar |
+---------------------------------------------------------------+
Reusable runtime widgets¶
The panelized runtime GUI is assembled from reusable components in
pypts.gui_components:
PtsToolBar: top action barStepTable: live execution tableResultsPanel: hierarchical results tree and summary badgesInteractionPanel: prompt/image/button area for operator interactionLogPanel: formatted runtime log displayresourcesandstyles: assets and base style tokens
This split keeps MainWindow focused on orchestration and screen changes
instead of widget-specific rendering logic.
Theme system¶
The shared theme layer lives in pypts.gui_theme.
It is responsible for:
detecting whether the operating system is currently using a dark color scheme
listening for Qt color-scheme changes where supported
providing shared palette values
exposing the top-level stylesheet used by
YamVIEW
The runtime GUI still uses its existing reusable widgets from
pypts.gui_components, but initial dark-mode state and OS theme synchronization
now come from the shared theme helper instead of a local hardcoded toggle.
YamVIEW / Recipe Editor¶
The recipe editor is still implemented in the pypts.YamVIEW package and is
centered around pypts.YamVIEW.recipe_creator.RecipeEditorMainMenu.
High-level layout¶
The editor window contains:
a menu bar
a toolbar for file/editing actions
a status field for recipe validation state
a main split view with:
a sequencer panel on the left
a YAML editor on the right
a log console at the bottom
a watermark/empty-state screen shown when no recipe is open
The editing widgets are specific to YamVIEW, with deliberately separate
responsibilities:
RecipeEditorMainMenuowns the working text, structural representation, production-parser diagnostics, last-valid recovery state, and file I/O.SequencerWidgetowns selection and emits add, edit, move, reorder, and delete intents identified by sequence, stage, and step identity. It does not define recipe fields or serialize YAML.Step_setupand its mapping rows render controls from the aggregate JSON Schema. Pydantic remains the only owner of variants, required fields, strict types, defaults, and field descriptions.ScintillaYamlEditorowns editable source text and diagnostic highlighting.
The sequencer displays executable sequence documents only. The recipe-header
document (historically labelled Preamble) remains part of the internal
aggregate and is editable in the YAML pane, but is not shown as an inactive
sequencer row.
Editor data flow¶
The structured editing path is:
production Pydantic model -> aggregate JSON Schema -> schema form
-> working aggregate -> recipe_to_yaml() -> YAML editor
-> parse_recipe_text() -> status, diagnostics, and save state
A structured edit is committed once its individual definition is valid. If a cross-document or ordering rule then makes the aggregate invalid, the edit is retained, diagnostics are shown, and Save and Save As are disabled until the recipe is repaired or the last valid state is restored. Malformed JSON in an individual structured field remains in its dialog and is not committed.
Raw YAML editing is intentionally more permissive. Invalid text remains visible and the first diagnostic span is highlighted. The sequencer stays available for structurally valid recipes with semantic diagnostics, but is disabled when the text cannot be represented safely as the aggregate model.
Structured edits and saves use pypts.recipe_parser.recipe_to_yaml().
Consequently, they are deterministic and preserve recipe meaning, but they do
not preserve comments, quoting, or source formatting. Raw text is never
silently lowercased or otherwise migrated.
Relationship Between The Two GUIs¶
Before the refactor, the runtime GUI and YamVIEW were visually and
structurally mostly separate.
Current state:
they are still separate windows
the runtime GUI launches
YamVIEWas a separate process when editing a recipethey now share dark-mode detection and theme tokens
they now use a shared visual palette so they look like the same product family
they still do not share most concrete widgets
In practice, this means:
shared: palette, top-level style rules, OS dark-mode behavior
separate: layout implementation, editor widgets, runtime widgets
Runtime/editor relationship diagram¶
The two GUIs are related like this at a high level:
+-------------------------------+
| pypts runtime process |
| |
| run_pts() |
| -> backend API |
| create_and_start_gui() |
| -> QApplication |
| -> MainWindow |
| |
| MainWindow |
| -> uses pypts.gui_components
| -> uses pypts.gui_theme |
| -> can launch YamVIEW |
+---------------+---------------+
|
| subprocess.Popen(...)
v
+-------------------------------+
| YamVIEW editor process |
| |
| QApplication |
| RecipeEditorMainMenu |
| -> SequencerWidget |
| -> ScintillaYamlEditor |
| -> editor dialogs |
| -> uses pypts.gui_theme |
+-------------------------------+
Both applications therefore share theme behavior, but not the same main widget tree.
This is an intentional intermediate architecture. The UI is already unified at the theme level, while widget-level convergence can happen incrementally later.
Why The Runtime GUI Is Called Panelized¶
The runtime GUI is described as panelized because the window is composed from independent functional panels rather than one monolithic central widget.
Examples:
the interaction area is its own panel widget
the logging area is its own panel widget
the results display is its own panel widget
the live step display is its own panel widget
This provides several practical benefits:
clearer ownership of GUI behavior
easier targeted tests for individual panels
easier theming and visual refreshes
less coupling between execution flow and rendering details