Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ pipeline orchestration, and GUI stay in their own packages.
`uv run ty check`; CI fails on either. Ruff runs with `select = ALL`
and a curated ignore list in `pyproject.toml` — add to that list only with a
one-line reason, as the existing entries do.
- There is no test suite yet (`tests/` is empty, pytest is configured). When
adding tests, put them in `tests/`, add `pytest` to the `dev` group, and keep
them free of Palace, torch training, and network access.
- Tests live in `tests/` and run with `uv run pytest` (`pytest` is in the `dev`

## Simulation and Training

Expand Down
27 changes: 13 additions & 14 deletions .claude/GUI_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,17 +277,16 @@ never the only signal · sentence case, units, tooltip · docs touched.

## 9. Known deviations in the current GUI

To be resolved in one GUI update step, not incrementally by unrelated changes:

- `theme.py` is light-only with Material-blue literals (the file COBRA's theme
started from); it has no tokens, no dark theme, no `ThemeManager`.
- The stylesheet is applied to the main window (`apply_theme(window)` in
`app.py`) rather than the `QApplication`, so dialogs and message boxes miss it.
- `pipeline_window.py` styles the run button with a per-widget `setStyleSheet`
and uses `<h2>` HTML in labels for headings; both become QSS properties
(`primaryAction`, `role="heading"`).
- No `actionState` on the run button, no `progressState` on the progress bar.
- Pipeline success is announced with a modal `QMessageBox`; it should be the
status label plus the `finished` progress state.
- Labels use trailing colons and Title Case ("Select Geometry:", "Geometry Name:").
- No icons, no theme toggle, no persisted appearance setting, no `help_texts.py`.
The GUI update of September 2026 resolved the original list (tokens, both
themes, `ThemeManager`, application-level stylesheet, QSS properties instead of
inline styles, no success modal, sentence-case labels, icons, theme toggle,
`help_texts.py`). What remains, by design rather than by omission:

- No plots, so `theme.py` has no `style_plot` and ORCA does not depend on
pyqtgraph. Add both together with the first plot.
- No pause/stop: `ORCA.run` cannot be interrupted, so the run button only uses
the `start` action state and is disabled while a run is in progress.
- The stage forms are derived from the constructor signatures, so their labels
are the parameter names in sentence case without units; a stage option that
wants a unit or a friendlier label gets it in its `Args:` docstring, which
is what the tooltip shows.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,10 @@ orca
The GUI lets you:

- select a geometry preset or load a custom geometry class,
- configure pipeline stages and parameters,
- monitor simulation and training progress in real time,
- inspect and test the trained model.
- configure pipeline stages and parameters (each field has a tooltip),
- monitor simulation and training progress and the log in real time,
- test the trained model,
- switch between a light and a dark theme, or follow the system setting.

### 2. Python script mode

Expand Down
10 changes: 6 additions & 4 deletions docs/running_orca.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ orca

In GUI mode:

1. Select a geometry class.
2. Configure pipeline stages and parameters.
3. Set Palace executable path.
4. Start the pipeline.
1. Select a geometry preset, or load a custom `.py` file that defines a `BaseGeometry` subclass. The name field sets the output folder (`output/<name>/`).
2. Tick the pipeline stages to run and set their parameters. Every field has a tooltip taken from the stage's documentation; leave an optional field empty (or `None`) to use the default.
3. Set the Palace executable path in the `PalaceSimulator` stage.
4. Click **Run pipeline**. Progress, the current stage, and the outcome show next to the progress bar (green when finished, red text on an error); the log panel mirrors what ORCA prints on the console. Validation problems, such as no geometry selected, appear inline instead of in a dialog. If the output directory already exists you are asked once before it is overwritten.

The button in the top-right corner switches the appearance between *system* (follows the OS colour scheme), *light* (Sandbank) and *dark* (Deepwater). The choice is remembered across sessions.

## 3. Run Script Mode

Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ dependencies = [
"tqdm",
"pandas",
"PySide6",
"qtawesome",
"colorlog",
"matplotlib",
"pebble>=5.2.2",
Expand All @@ -89,10 +90,11 @@ cu126 = ["torch"]
cu130 = ["torch"]

[dependency-groups]
# Installed by `uv sync` (not by `pip install`): the linters CI runs, pinned by uv.lock.
# Installed by `uv sync` (not by `pip install`): the linters and test runner CI uses, pinned by uv.lock.
dev = [
"ruff",
"ty",
"pytest",
]

[tool.uv]
Expand Down
2 changes: 1 addition & 1 deletion src/orca/gui/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
## GUI
This file contains the GUI of ORCA. It allows the user to use the trained models for inference on new data.
PySide6 pipeline window of ORCA: pick a geometry, enable and configure the stages, run them, and follow the log.
7 changes: 4 additions & 3 deletions src/orca/gui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

from PySide6.QtWidgets import QApplication

from orca.gui import theme
from orca.gui.pipeline_window import PipelineWindow
from orca.gui.theme import apply_theme


def run_gui():
app = QApplication(sys.argv)

app.setOrganizationName("ORCA")
app.setApplicationName("ORCA")
theme.manager().apply()
window = PipelineWindow()
apply_theme(window)
window.show()
sys.exit(app.exec())

Expand Down
64 changes: 64 additions & 0 deletions src/orca/gui/help_texts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Tooltips of the ORCA GUI, in one place so wording stays consistent.

Static controls look their text up by key with :func:`tooltip`; the stage
parameter forms, which are derived from the stage constructors, take theirs
from the ``Args:`` section of the constructor docstring via
:func:`parameter_tooltips`, so a stage documents its options once.
"""

from __future__ import annotations

import inspect
import re

TOOLTIPS = {
"theme_btn": "Appearance: {mode} ({theme}). Click to switch between system, light and dark.",
"run_btn": "Run the enabled stages in order on the selected geometry.",
"geometry_combo": "Built-in geometry presets. Loading a custom file replaces the selection.",
"geometry_file_btn": "Browse for a Python file that defines a BaseGeometry subclass.",
"geometry_name_edit": (
"Name of the run. Output goes to output/<name>/; leave the preset name to keep "
"its default."
),
"stage_group": (
"Tick to include this stage in the run. A stage whose inputs are missing "
"reports which earlier stage was skipped."
),
"log_output": "Messages from the pipeline; the same text ORCA prints on the console.",
}

#: ``name (type): text`` or ``name: text`` at the start of an Args entry.
_ARG_LINE = re.compile(r"^(?P<name>\w+)(?:\s*\([^)]*\))?:\s*(?P<text>.*)$")


def tooltip(key: str) -> str:
return TOOLTIPS.get(key, "")


def parameter_tooltips(cls: type) -> dict[str, str]:
"""Per-parameter descriptions from the ``Args:`` section of ``cls.__init__``'s docstring.

Continuation lines are joined with spaces; parameters without an entry are
absent from the result.
"""
doc = inspect.getdoc(cls.__init__)
if not doc:
return {}
tips: dict[str, str] = {}
current: str | None = None
in_args = False
for raw in doc.splitlines():
line = raw.strip()
if not in_args:
in_args = line == "Args:"
continue
if not line or (raw and not raw[0].isspace()):
# A blank line or a new section heading ends the Args block.
break
match = _ARG_LINE.match(line)
if match and not raw.startswith(" "):
current = match.group("name")
tips[current] = match.group("text")
elif current is not None:
tips[current] = f"{tips[current]} {line}".strip()
return tips
Loading
Loading