spacr.qt.widgets.fold_strip¶
A row of icon buttons, one per module folded into a host screen.
A module that has been folded into another one stops being a tile on Home and becomes a button on its host’s masthead. The button IS the module’s icon: no text beside it, the module’s own one-line description as its tooltip, and the same maturity colour on hover that the tile used to light up in – green-cyan for alpha, magenta for beta, blue for stable.
The hover colour is the reason for a shared class rather than a plain
QPushButton at each site: it shows the maturity of the module behind
the button, and it is read from spacr.qt.theme.STAGE_HOVER through
spacr.qt.app.app_stage() – the same two tables the tiles read. A fold
that hard-coded its colour would keep showing alpha after the module’s
stage changed.
Typical use, from a host screen’s __init__:
from spacr.qt.widgets.fold_strip import FoldStrip
self.folds = FoldStrip([
("train_cellpose", self._open_training),
("model_zoo", self._open_model_zoo),
], parent=self)
masthead_layout.addWidget(self.folds)
Each entry is (app_key, callback), or (app_key, callback, checkable)
when the button is a switch rather than a press. The key is the registry
key the module had as a tile, which is what supplies the icon, the name
and the stage; the callback is what the button does when pressed.
A checkable fold controls a workflow implemented by settings on its host. Timelapse settings are mounted on Mask Generation because tracking extends the segmentation run; its button reveals those categories and enables the corresponding pipeline stage. Motility Assay instead opens from Measure and analyzes existing masks. A checkable button remains active while its workflow is enabled, and its callback receives the new state.
Classes¶
One folded module, drawn as its own icon and nothing else. |
|
The row of |
Functions¶
|
|
|
|
|
Every folded key, as |
|
Mark host categories associated with folded modules. |
|
Mark settings-section headings with a folded module's icon. |
Module Contents¶
- class spacr.qt.widgets.fold_strip.FoldButton(key: str, parent: PySide6.QtWidgets.QWidget | None = None, checkable: bool = False)[source]¶
Bases:
PySide6.QtWidgets.QPushButtonOne folded module, drawn as its own icon and nothing else.
- Parameters:
key – the module this button opens. Also read for the name, description and maturity stage, so it must be a real registry key rather than a caption.
parent – parent widget.
checkable – whether the button is a SWITCH rather than a press. True for a fold whose workflow is implemented by settings on the host module – Timelapse rides on Mask Generation, because tracking extends the segmentation run – so the button stays active while that workflow is enabled and its callback receives the new state. False, the default, is a plain click that opens a module.
Build one fold button: a module’s icon, with its name in the tooltip.
The icon is resolved through the application’s own lookup rather than by filename, because a module that BORROWS another’s picture is resolved wrongly by filename alone – the Cellpose Workbench button drew a dumbbell, since
train_cellpose.pngexists and is the training glyph while the override sends that key to the cell outline. Every other borrower had the same fault. With no icon at all the button falls back to the module’s initial rather than to an empty square.The release stage rides as a Qt property so the stylesheet can select on it, set before the first polish so the first paint is already the right colour, and the name and summary are stored as canonical English so a language switch retranslates rather than translating a translation.
- Parameters:
key – the module this button opens.
parent – parent widget, or
None.checkable – make it a toggle rather than a one-shot button.
- set_stage(stage: str) None[source]¶
Re-state the maturity this button is drawn in.
The stage is read from the app registry when the button is built, and the registry stops answering for a module the day its row is dropped – which is what folding one ends in. Restating it has to move BOTH things the stage decides: the Qt property the shipped hover rule selects on, and the widget-local
:checkedfill, which is a stylesheet computed once from whatever the stage was at construction. Moving only the property left a switch that hovered in its own colour and lit stable-blue when it was on.- Parameters:
stage –
"alpha","beta"or"stable".
- set_verdict(level: str, detail: str = '') None[source]¶
Badge this button with a run’s worst verdict.
The verdict is a dot, not a button colour. The button’s own colour already means maturity – alpha, beta, stable – and a second meaning on the same surface makes both unreadable. The dot is drawn over the corner instead, and the detail goes in the tooltip where the reason can be a sentence.
""clears it, which is what a run that has produced no diagnostics yet must show: no dot rather than a green one, because “not measured” and “measured and fine” are different answers.- Parameters:
level –
"pass","check","fail"or"".detail – the sentence behind the verdict, for the tooltip.
- class spacr.qt.widgets.fold_strip.FoldStrip(folds: Iterable[FoldEntry], parent: PySide6.QtWidgets.QWidget | None = None)[source]¶
Bases:
PySide6.QtWidgets.QWidgetThe row of
FoldButtonfor one host screen.Build one button per fold.
- Parameters:
folds –
(key, callback)for a button that opens something, or(key, callback, True)for one that switches a module on and off. A switch is handed the new state, so the one callback answers both directions; a plain button is called with no arguments, because “pressed” carries no state worth passing on.parent – the masthead the strip is hung on.
- button_for(key: str) FoldButton | None[source]¶
The button for
key, or None if this strip has no such fold.- Parameters:
key – the app key of the folded module whose button is wanted.
- spacr.qt.widgets.fold_strip.fold_label(key: str) Tuple[str, str, str][source]¶
(name, description, stage)for one folded key, from anywhere.For a caller that has a key and needs its name, description and stage, whether or not the key’s host is one
folded_modules()walks. Hosts named only inspacr.qt.app._EXTRA_FOLD_HOSTS– Graph Builder, QC Dashboard and Database Browser – are not walked there, so without this the dock rows of the modules folded onto them would show the raw key, such aslineage,tabulateorcontrol_chart.Adding those hosts here would fix the rows and import three more screen modules while the window is still being built, which is precisely the startup cost this strip exists to avoid. Asking for the words instead of for the host costs nothing.
- Parameters:
key – the folded module’s app key. The registry answers first, then the hosts’ fold fallbacks, then the declared catalogue; an unknown key gets its title-cased name, no description and stage
stable.
- spacr.qt.widgets.fold_strip.folded_fallback(key: str) Tuple[str, str, str][source]¶
(name, description, stage)a folded key kept, or three blanks.The answer for a module that is a button on some host’s masthead rather than a tile on Home. Blank when the key is not folded anywhere, so a caller can tell “folded, and this is what it said” from “never heard of it” – which the registry cannot, because it answers both the same way.
- Parameters:
key – the module’s app key, looked up as a string in
folded_modules().
- spacr.qt.widgets.fold_strip.folded_modules() dict[source]¶
Every folded key, as
key -> (name, description, stage, host).The host is determined by the button list it actually draws, not by the location of fallback text. The latter may be shared: Map Barcodes keeps descriptions for folds owned by Image UMAP, Regression, Mask, and other screens. Treating that shared catalog as membership sends documentation and tutorial links to the wrong screen.
A host’s own fallback record is preferred. If it does not keep one, the other host tables are searched in declaration order. The first host to list a duplicated key still wins, making an accidental double fold deterministic until its invariant test reports the duplication.
The registry is read as well, for a fold that still holds its row. Those modules keep their name, description and maturity in the registry, so their hosts record nothing (Regression notes this beside
investigate_hitandprofiler). Without the registry these modules would be missing from the answer and the dock would show their rows as the raw key. Reading the registry avoids a second copy of the same text in each host.Imported lazily, one host at a time and each guarded: this module is imported while a screen is being built, and the hosts import it back.
The registry part is complete only after registration. Several rows arrive from
spacr.qt.register_self_registering_modules(), so a caller that asks before registration gets the folds whose hosts kept a record and not the ones whose rows have not been added yet. Every caller inside the application asks after the window is built; a test that asks earlier has to register first, and one that does not is testing the order it happened to import in.- Returns:
a fresh dict; callers may keep or mutate it.
- spacr.qt.widgets.fold_strip.mark_folded_categories(sections: Iterable[PySide6.QtWidgets.QWidget], categories: dict) dict[source]¶
Mark host categories associated with folded modules.
- Parameters:
sections – Host settings sections.
categories – Mapping from module key to category titles. Titles are matched case-insensitively.
- Returns:
Mapping from module keys to titles marked successfully.
- spacr.qt.widgets.fold_strip.mark_folded_sections(key: str, sections: Iterable[PySide6.QtWidgets.QWidget]) Tuple[str, ...][source]¶
Mark settings-section headings with a folded module’s icon.
- Parameters:
key – Folded module registry key.
sections – Section widgets containing that module’s settings.
- Returns:
Titles of sections marked successfully. Invalid sections and modules without artwork are skipped.
Nested helpers¶
- _host_declarations._as_string(node)¶
The string an AST node stands for, or
Noneif it is not one.Handles a literal, a constant in this module, and a constant reached through an imported sibling – read from the source rather than by importing the module that defines it.
spacr/qt/widgets/fold_strip.py:270