spacr.qt.widgets.object_grid_binding¶
Keep the per-object grid and the flat settings form in agreement.
The grid in spacr.qt.widgets.object_settings_grid edits values; the
settings panel is a dictionary of widgets, and the pipeline reads the widgets.
Mounting the grid without a binding would give a screen two answers to the
same question – the table showing what the user typed and collect()
still returning what the widget holds – and the run would silently use the
second one, so the saved settings would differ from what the grid shows.
So the grid never becomes the source of truth. It is a view that writes
through: every edit lands in the widget behind it, and the widget stays what
the pipeline reads. Nothing downstream of collect() learns that the grid
exists, so no settings file, notebook or spacr-run invocation changes.
The panel is duck-typed: the binding asks for two methods – collect and
set_value_for_key – and not for a class. That keeps the binding testable
against a dictionary rather than against a built screen.
Classes¶
Bind a per-object grid to the settings panel behind it. |
Module Contents¶
- class spacr.qt.widgets.object_grid_binding.ObjectGridBinding(grid, panel, parent=None)[source]¶
Bases:
PySide6.QtCore.QObjectBind a per-object grid to the settings panel behind it.
- Parameters:
grid – the
ObjectSettingsGridto drive.panel – anything offering
collect()andset_value_for_key(key, value).parent – parent object.
Bind a per-object grid to the settings panel beside it.
The re-entrancy guard is what stops the table visibly rebuilding under a cursor that is still in a cell: writing a value into a widget makes that widget emit, and a screen that reseeds the grid on every widget change would rebuild it mid-edit. No value depends on the guard – the write reads the grid once, before the first widget moves – so a reseed halfway cannot drop an edit either way.
- Parameters:
grid – the object settings grid.
panel – the settings panel it mirrors.
parent – parent object, or
None.
- follow_the_form() int[source]¶
Make the form’s own fields write into the table.
This is the form-to-grid half of the two-way binding. Without it, a value changed outside the grid – the flat row for an object the table does not claim, a preset, the Live Preview, a loaded settings file – would leave the table showing the old value.
The table is not reseeded:
seedrebuilds the whole table, which takes 30 ms on Mask and 100 ms with ten organelles. On atextChangedthat would run per keystroke and move the cursor out of the cell being edited. One cell is written instead.The magnification field is followed as well: a blank object diameter shows the magnification default, which moves with it (item 696).
- Returns:
how many widgets were newly connected.
- owned_keys() FrozenSet[str][source]¶
The settings keys the grid answers, as the panel now stands.
Read from the panel every time rather than remembered, because a panel hides the settings of an object whose channel names no plane and the grid must not claim a key that is no longer there.
Columns hidden because their channel is unset are still claimed, so their rows stay off the flat form; their channels are not claimed, because a hidden object’s channel on the form is how it is brought back.
- seed() None[source]¶
Show the panel’s current answers in the grid.
Idempotent, and safe to call whenever something else has written the panel – a settings file being loaded, a preset applied, the Live Preview propagating what it tuned.
- write_through() Dict[str, Any][source]¶
Write every changed cell into its widget; return what changed.
Only changed values are written. Setting a widget to the value it already holds still makes it emit, and a panel that re-validates on every emit would do the whole form’s work on each keystroke in the table.