spaCR nightly · Main documentation · Nightly preview
Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
spaCR 1.5.1.4 documentation
Logo
spaCR 1.5.1.4 documentation
  • Installer guide
  • System requirements
  • Choose a workflow after installation
  • Combine measurement tables for plots and gates
  • Installer archive
  • Capabilities
  • Keyboard shortcuts and settings templates
  • Make Masks: editing, detection and measurement
  • Measure: preview checked images and verify mask planes
  • Train a Cellpose model
  • Process images with a point-spread function
  • Recruitment: compartment ratios and channel identity
  • Image quality before segmentation
  • Host–Pathogen Analysis
  • Plaque Assay: fields, figures and reviewed conditions
  • Python API quickstart
  • Export measurements to AnnData
  • Where a setting goes
  • Model zoo
  • Language
  • Setting animation gallery
  • Checkpoint and resume
  • Reproducibility manifests
  • Unified run history
  • Plate and batch-effect correction
  • Classifier evaluation workbench
  • Plate-aware guide permutation analysis
  • Explain CV models and investigate hits
  • Resumable multi-objective UMAP search
  • Remote and distributed execution
  • spaCR plugin SDK
  • Train/test leakage audit
  • Threading and cancellation audit
  • Database concurrency audit
  • API reference
    • spacr
      • spacr.api
      • spacr.core
      • spacr.measure
      • spacr.deep_spacr
      • spacr.sequencing
      • spacr.ml
      • spacr.artifacts
      • spacr.settings
Back to top
View this page
Edit this page

spacr.qt.settings_search¶

Find a setting, and meet a module’s settings a few at a time.

A spaCR module can render a lot of settings. Mask alone renders 190 of them under thirteen collapsed headings, and across the shell there are 1,022. Until now the only way to reach one was to guess which heading somebody filed it under and open headings until it appeared — and the only thing a first-time user saw was those thirteen headings, with nothing to say which two of them they actually had to touch.

This module adds one strip above the settings form:

  • a search box that matches the setting’s key, its label and its description. The description is the only part written in the language a user thinks in, so “touching” finds merge_edge_pathogen_cells and “gpu” finds n_jobs — neither word appears in either name.

  • a Modified filter that shows only what differs from the module’s defaults. It is the fastest possible answer to “what did I change?”, and it shares spacr.qt.settings_diff._values_equal() with the diff dialog and the run journal so all three agree about what an edit is.

  • an Essentials / All switch — the progressive disclosure. Essentials shows the module’s inputs plus the handful of decisions spacr.qt.screens.settings_model.essential_keys() derives from its curated layout, expanded and ready; All restores every heading, collapsed as before. Essentials is the default on a module’s first visit and the choice is remembered per module thereafter, so a returning expert never meets the training wheels twice.

The three compose: with a query typed, Essentials narrows the search rather than fighting it, and the count line always says exactly what is being shown out of how many.

Installation is from outside the screen, deliberately:

from spacr.qt.settings_search import install_window_hooks
install_window_hooks(window)

spacr.qt.shortcuts calls that once from MainWindow.__init__. The installer then follows the screen stack, so a module built later in the session gets its strip when it is first shown rather than needing a line inside the shared screen.

Classes¶

SettingsSearchBar

Search box, Modified filter, Essentials/All switch, and a count line.

Functions¶

disclosure_for(→ str)

The remembered disclosure level for app_key.

forget_disclosure(→ None)

Forget one module's disclosure choice, or every module's.

install(→ Optional[SettingsSearchBar])

Put a search strip above screen's settings form.

install_window_hooks(→ Optional[_StackWatcher])

Follow window's screen stack, adding the strip to each module.

remember_disclosure(→ None)

Persist the disclosure level chosen for app_key.

Module Contents¶

class spacr.qt.settings_search.SettingsSearchBar(screen: PySide6.QtWidgets.QWidget, parent: PySide6.QtWidgets.QWidget | None = None)[source]¶

Bases: PySide6.QtWidgets.QWidget

Search box, Modified filter, Essentials/All switch, and a count line.

Owns no settings state of its own — it reads the screen’s SettingsWidgets model and shows or hides rows that already exist. Hiding rather than rebuilding is what keeps a half-typed value alive across a filter change, which a rebuild would silently discard.

Parameters:
  • screen – the module screen to filter. The bar owns no settings state – it reads that screen’s SettingsWidgets model and shows or hides rows that already exist, which is what keeps a half-typed value alive across a filter change.

  • parent – parent widget.

Build the settings search strip above a module’s form.

Fixed height, explicitly: the strip is two rows tall and the scroll area under it wants everything else, so without a policy the two share the pane by stretch factor and the search box lands 800 pixels high on the first layout.

The key-to-section index is built once from the rendered form, so filtering never has to guess which section a setting ended up in, and which sections the user had open is remembered – clearing the box puts the form back rather than leaving it splayed.

Parameters:
  • screen – the module screen whose settings this filters.

  • parent – parent widget, or None.

add_trailing_widget(widget: PySide6.QtWidgets.QWidget) → None[source]¶

Add widget to the right-hand end of the control row.

The seam other modules use to put a settings-scoped control where the settings are, instead of inventing a second strip. Reparents widget onto the bar.

Parameters:

widget – any widget; it keeps its own size policy.

apply(reopen: bool = True) → None[source]¶

Recompute which rows and sections are shown.

Called on every change to the query, the Modified filter or the disclosure level — one path, so the three can never disagree about what should be on screen. The screen also calls it after each pass of the object rule, so a channel the user commits is judged by the same filter as every other row.

The per-object table has no form rows of its own to count. Its section is counted by the settings it answers for instead, so under Essentials the table stays on screen while it holds the channels, which the flat form no longer shows while the table is on.

A heading that holds only sub-headings has no rows of its own either, so its matches are rolled up out of the headings below it before any section is hidden — see _counting_the_sub_headings().

Parameters:

reopen – while the filter narrows, open every section it keeps. The screen passes False when it re-applies the filter after the object rule or after laying out rows: a section the user shut then stays shut, and only a section this call brings back onto the form is opened.

count_text() → str[source]¶

The sentence under the controls. Public so tests read what users read rather than recomputing it.

indexed_keys() → List[str][source]¶

Every setting key the strip can show or hide.

keys_it_hides() → set[source]¶

The indexed settings apply() would hide right now.

What the object rule asks before it sets rows (SettingsWidgets.rows_the_screen_hides), so a row this strip is about to hide is not shown by the rule first.

level() → str[source]¶

ESSENTIALS or ALL.

minimumSizeHint() → PySide6.QtCore.QSize[source]¶

As narrow as the widest single control, or the Modified switch with its caption, or the box’s own minimum.

Not the whole row: when the strip is narrower than that, the controls move under the box (_fit()). The switch keeps its caption beside it, so the two never wrap apart.

modified_only() → bool[source]¶

True when the Modified filter is on.

query() → str[source]¶

The current search text.

resizeEvent(event) → None[source]¶

Re-decide where the controls go for the new width.

Parameters:

event – the resize event; its new width is read.

reveal(key: str) → bool[source]¶

Show one setting with every other category shut.

WHAT A HELP-SEARCH RESULT NEEDS, and it is deliberately NOT the search filter. Typing the key into the box above would hide every other setting as well, so a user who arrived from the Help search and then wanted to look at the neighbouring rows would first have to work out what had happened to the form. Revealing instead leaves the module whole and only decides which heading is open.

Nothing is rebuilt and no value is read or written: the row was already on the form, and this shows its section and scrolls to it – or, for a category not built yet (indexed with no field), the screen builds it first, as opening it would. That is what makes arriving here from a search safe for a half-typed value – the same property the filter has, for the same reason.

THE DISCLOSURE LEVEL IS CHANGED ONLY IF IT HAS TO BE, AND THE CHANGE IS NEVER REMEMBERED. Switching to All settings unconditionally would work, and it would also rewrite this module’s remembered Essentials/All choice every time anybody arrived here – a setting the user chose, changed as a side effect of looking something up. So the filter is cleared first and the level is raised only when the row is still not on the form afterwards, which is exactly the case where Essentials is what is hiding it; and the raise goes through _show_all_without_remembering(), so the form shows the row while the store still holds the level the user picked. Most settings are not essentials, so a lookup that persisted the raise would move almost every module out of Essentials for good.

Parameters:

key – the setting to reveal.

Returns:

True when the module renders key and it was revealed.

A nested heading is reachable only with every containing heading open, and logical ancestry also crosses bodies parked off the widget tree.

revealed_key() → str[source]¶

The setting reveal() last showed, or "".

section_of(key: str) → PySide6.QtWidgets.QWidget | None[source]¶

The section widget holding key’s row, or None.

Parameters:

key – a setting key.

Returns:

the collapsible section, or None when this module does not render that setting.

set_level(level: str) → None[source]¶

Switch disclosure level and remember the choice.

Parameters:

level – disclosure level: 'all' shows every setting; any other value selects 'essentials'.

set_modified_only(on: bool) → None[source]¶

Turn the Modified filter on or off.

Parameters:

on – True to show only settings changed from their defaults; coerced with bool().

set_query(text: str) → None[source]¶

Type text into the search box, filtering as it goes.

Parameters:

text – search text for the box; None or empty clears it.

sizeHint() → PySide6.QtCore.QSize[source]¶

The one-line hint, or, with the controls under the box, the height every wrapped line needs at the current width.

The strip’s height is fixed at its hint, so a hint that did not follow the wrapping would let the lines overlap the count below.

visible_keys() → List[str][source]¶

Setting keys whose form row is currently shown.

Row visibility, not widget visibility: a collapsed section makes every widget inside it invisible, and “you collapsed that heading” is a different statement from “the filter excluded that setting”.

spacr.qt.settings_search.disclosure_for(app_key: str) → str[source]¶

The remembered disclosure level for app_key.

Defaults to ESSENTIALS, which is the whole point: a module is met a few settings at a time until its user says otherwise.

Parameters:

app_key – the module’s app key.

spacr.qt.settings_search.forget_disclosure(app_key: str | None = None) → None[source]¶

Forget one module’s disclosure choice, or every module’s.

Parameters:

app_key – the module to forget, or None for all of them.

spacr.qt.settings_search.install(screen: PySide6.QtWidgets.QWidget) → SettingsSearchBar | None[source]¶

Put a search strip above screen’s settings form.

The form is a QScrollArea sitting directly in the screen’s splitter. The strip goes outside the scroll area, in a container that takes its place: a search box that scrolls away with the results it is filtering is a search box you have to scroll back up to reach.

Returns the strip, or None when the screen has no settings form (a bespoke screen), the form failed to build, or one is already installed. Never raises — a missing search box must not cost anyone a module.

Parameters:

screen – an AppScreen.

spacr.qt.settings_search.install_window_hooks(window: PySide6.QtWidgets.QMainWindow) → _StackWatcher | None[source]¶

Follow window’s screen stack, adding the strip to each module.

Called once from spacr.qt.shortcuts.install(). Screens are built lazily on first navigation, so this cannot be a one-shot sweep; it connects to the stack and also installs into anything already built.

Parameters:

window – the main window; nothing is installed unless it has a _stack screen stack, and a watcher already on it is returned.

Returns:

the watcher, kept alive by the window, or None.

spacr.qt.settings_search.remember_disclosure(app_key: str, level: str) → None[source]¶

Persist the disclosure level chosen for app_key.

Parameters:
  • app_key – application key the level is stored under.

  • level – disclosure level; 'all' is stored as is and any other value as 'essentials'.

Nested helpers¶

SettingsSearchBar._mark._unmark() → None¶

Put the field back the way it was found.

spacr/qt/settings_search.py:475

SettingsSearchBar._wanted_now.narrowed(keys: set) → set¶

keys less whatever the query, Modified and level exclude.

spacr/qt/settings_search.py:713

Copyright © 2025-2026, Einar Birnir Olafsson
Made with Sphinx and @pradyunsg's Furo
On this page
  • spacr.qt.settings_search
    • Classes
    • Functions
    • Module Contents
      • SettingsSearchBar
        • SettingsSearchBar.add_trailing_widget()
        • SettingsSearchBar.apply()
        • SettingsSearchBar.count_text()
        • SettingsSearchBar.indexed_keys()
        • SettingsSearchBar.keys_it_hides()
        • SettingsSearchBar.level()
        • SettingsSearchBar.minimumSizeHint()
        • SettingsSearchBar.modified_only()
        • SettingsSearchBar.query()
        • SettingsSearchBar.resizeEvent()
        • SettingsSearchBar.reveal()
        • SettingsSearchBar.revealed_key()
        • SettingsSearchBar.section_of()
        • SettingsSearchBar.set_level()
        • SettingsSearchBar.set_modified_only()
        • SettingsSearchBar.set_query()
        • SettingsSearchBar.sizeHint()
        • SettingsSearchBar.visible_keys()
      • disclosure_for()
      • forget_disclosure()
      • install()
      • install_window_hooks()
      • remember_disclosure()
    • Nested helpers
      • SettingsSearchBar._mark._unmark()
      • SettingsSearchBar._wanted_now.narrowed()