visualdynamics.gui.tables¶
tables
¶
Tables that behave like a spreadsheet.
The tables are model/view, not a widget per cell, so a table costs nothing until it is scrolled, an edit is validated and written straight back to the visualdynamics object under it, and switching display units restates the values without rebuilding anything.
CopyPasteTableView uses Excel's clipboard format (tab-separated cells,
one row per line), so a selection copies straight into a spreadsheet and
a block of spreadsheet cells pastes back in. It also has Batch Edit,
Clear, a fill handle, a copy button for the whole table, and Delete for
whole rows where its owner allows it.
Classes:
| Name | Description |
|---|---|
ItemCheckStyle |
The platform's style, with the check box in a table or list cell |
Column |
One column of a |
TableModel |
A table over a visualdynamics object, described by a list of |
TransposedTableModel |
A |
ChoiceDialog |
Pick one of a column's choices, shown the way its cells show them. |
ChoiceDelegate |
Edit a column that declares |
CopyPasteTableView |
A table view that behaves like a spreadsheet: copy and paste as |
Functions:
| Name | Description |
|---|---|
wear_item_checks |
Put |
trace_units |
Write one line to the units-editor log for an event in a choice |
Classes¶
ItemCheckStyle
¶
Bases: QProxyStyle
The platform's style, with the check box in a table or list cell drawn by Fusion.
Qt 6.12's macOS style draws a checked cell's check box as nothing and an unchecked one as a faint rounded square, so a flag column such as the channel table's Control reads as empty. Everything else is drawn by the platform's style, the check box widget included.
Source code in src/visualdynamics/gui/tables.py
Column
dataclass
¶
Column(title: str, get: Callable, set: Callable | None = None, format: Callable | None = None, decoration: Callable | None = None, background: Callable | None = None, choices: list | None = None, choice_icon: Callable | None = None, row_choices: Callable | None = None, choices_editable: bool = False, checkbox: bool = False, date: bool = False, affects_row: bool = False, affects_table: bool = False, carries: tuple = (), journal: Callable | None = None, does_not_apply: Callable | None = None, alignment: int = int(AlignRight | AlignVCenter))
One column of a TableModel: how to read it, how to show it, and
whether it can be set.
Methods:
| Name | Description |
|---|---|
choices_for |
What one cell offers, which can be narrower than the column's |
why_not |
Why the property does not apply to one item, or '' where it |
text |
The cell's text: |
Attributes:
| Name | Type | Description |
|---|---|---|
editable |
bool
|
Whether the column can be set, which is whether it has a |
Attributes¶
Methods:¶
choices_for
¶
What one cell offers, which can be narrower than the column's list.
A channel the file said was an acceleration offers the acceleration units, not every unit, while the channel below it offers its own.
Source code in src/visualdynamics/gui/tables.py
why_not
¶
Why the property does not apply to one item, or '' where it does.
text
¶
The cell's text: format applied to the value when the column
has one, otherwise a float to six significant figures and '' for
None.
Source code in src/visualdynamics/gui/tables.py
TableModel
¶
TableModel(obj: Any, columns: Sequence[Column], row_count: Callable[[Any], int], parent: QObject | None = None)
Bases: QAbstractTableModel
A table over a visualdynamics object, described by a list of
Column objects.
edit_rejected carries the reason a cell refused a value. For each
successful edit of a journaled column, edit_journaled carries the
replay line's suffix; the window puts project[name] in front of it
and appends it to the journal.
Methods:
| Name | Description |
|---|---|
column_of |
The property a cell belongs to. |
column_number |
The position of a cell's property in |
item_of |
The item a cell belongs to, as the object counts them. |
cell |
The index of an item's cell in a property. |
item_range |
The first and last cells of one item. |
inapplicable |
Why a property does not apply to an item, or '' where it |
refresh_row |
Redraw one item, leaving the selection alone. |
set_cells |
Write a different value into each of many cells, as one change, |
set_many |
Write one value into many cells as one change, and return |
Source code in src/visualdynamics/gui/tables.py
Methods:¶
column_number
¶
item_of
¶
cell
¶
item_range
¶
inapplicable
¶
Why a property does not apply to an item, or '' where it
does (Column.does_not_apply).
refresh_row
¶
Redraw one item, leaving the selection alone.
A full reset clears the selection, which matters when the selection is what the edit applies to: turning a coordinate system would lose the system being turned.
Source code in src/visualdynamics/gui/tables.py
set_cells
¶
Write a different value into each of many cells, as one change, and return (applied, rejected, reason).
cells holds (item, column number, text) for each cell. set_many
is this with one value for every cell. One dataChanged covers all
of them: setData cell by cell would emit once per cell, and each
emission redraws the 3-D view, so setting a column of a few
thousand nodes costs one redraw and not a few thousand.
Cells that refuse their value are left as they are and counted, so a batch that only partly lands is not mistaken for a clean one, and the reason for the first refusal is returned with the counts. A value written where the property does not apply is refused the same way; a blank written there is no edit at all, so a fill carried from one item to another of a different kind writes only what applies.
Source code in src/visualdynamics/gui/tables.py
set_many
¶
Write one value into many cells as one change, and return
(applied, rejected, reason): set_cells with the same text for
every cell.
Source code in src/visualdynamics/gui/tables.py
TransposedTableModel
¶
TransposedTableModel(obj: Any, columns: Sequence[Column], row_count: Callable[[Any], int], parent: QObject | None = None, item_label: Callable[[Any, int], str] | None = None)
Bases: TableModel
A TableModel the other way up: each property a row and each
item a column, with item_label naming the columns. The Element
Groups table is one (Brandon, 2026-10-20): a group's properties
read as a column of entries, and several groups side by side are
edited at once by selecting across them.
Source code in src/visualdynamics/gui/tables.py
ChoiceDialog
¶
ChoiceDialog(parent: QWidget | None, prompt: str, column: Column)
Bases: QDialog
Pick one of a column's choices, shown the way its cells show them.
Batch editing a column of colors offers the same list of colors as editing one cell of it, not a box to type a color name into.
Methods:
| Name | Description |
|---|---|
value |
The choice picked, as text. |
Source code in src/visualdynamics/gui/tables.py
ChoiceDelegate
¶
Bases: QStyledItemDelegate
Edit a column that declares choices with a drop-down, and a date
column with a calendar.
Opening the cell opens the list, because a closed combo box would take a second click to show the choices. Picking one applies it and closes the editor, without waiting for the focus to move. Typing still works, since the model accepts the same values either way, so pasting a column of them from a spreadsheet is unaffected.
Methods:
| Name | Description |
|---|---|
paint |
Mark the selected cell of a choice column with a drop-down arrow. |
Methods:¶
paint
¶
Mark the selected cell of a choice column with a drop-down arrow.
Otherwise nothing shows that a cell has a list behind it until one has been opened. Only the selected cell is marked: an arrow in every cell of a 200k-row column is noise, and a spreadsheet marks the active cell the same way.
The arrow is the platform's own, drawn by the style as a combo box's arrow sub-control, so it is what a real drop-down would draw here.
Source code in src/visualdynamics/gui/tables.py
CopyPasteTableView
¶
Bases: QTableView
A table view that behaves like a spreadsheet: copy and paste as tab-separated text, Batch Edit, Clear, a fill handle, and a copy button for the whole table.
edits_applied reports (cells written, cells refused, the first
refusal's reason) after a paste, a batch edit, a clear or a fill.
rows_deleted carries the whole rows a person asked to remove, and
is emitted only when the owner sets rows_deletable, because only
the owner knows whether a row is an item (a channel, a mode) or just
cells. whole_table_copy is False where the table is a working
surface, as in the geometry editor, and hides the whole-table copy.
Methods:
| Name | Description |
|---|---|
show_rows |
Show only these rows of the model; None shows them all. |
selected_items |
The items any selected cell belongs to, sorted: rows down a |
select_items |
Select whole items, as a click on their headers would. |
row_shown |
Whether |
selected_block |
(rows, columns) covered by the selection, as sorted lists. |
to_tsv |
The selection, or every shown row with |
copy |
Put |
table_cells |
(headers, rows) of the whole table's shown rows, as text. |
copy_table |
Copy the whole table with its headers, as tab-separated text |
cap_columns |
Narrow any column wider than |
cut_short |
Whether cell |
paste |
Paste tab-separated text from the clipboard over the selection's |
editable_selection |
The selected cells that will accept a value. |
inapplicable_selection |
Why each selected cell that does not apply is skipped, one |
shared_choices |
The Column the selection shares, when all of its columns offer |
batch_edit |
Set every selected editable cell to one value, across columns |
whole_rows |
Rows whose every column is selected (a row-header click, or a |
clear_cells |
Empty the selected cells, for the columns that accept empty, and |
fill_handle_rect |
The small square at the bottom-right of the selection, or None. |
fill_from_selection |
Repeat the selected block along the items out to item |
fill_to |
Repeat the selected block over the rectangle from it to the |
mouseDoubleClickEvent |
Double-clicking the handle fills all the way down, as Excel does. |
Source code in src/visualdynamics/gui/tables.py
Methods:¶
show_rows
¶
Show only these rows of the model; None shows them all.
The other rows are out of the table, not only out of sight. They
cannot be selected (selectionChanged deselects them, so Select
All and a drag across the gap reach only what is shown, and the
owner's actions on a selection, such as a highlight or Delete,
never act on a row nobody can see), and copy, paste and the fill
handle skip them. Rows keep their model indices, so code that
reads the selection still reads the model's own rows.
Source code in src/visualdynamics/gui/tables.py
selected_items
¶
The items any selected cell belongs to, sorted: rows down a table, columns across a transposed one.
Source code in src/visualdynamics/gui/tables.py
select_items
¶
Select whole items, as a click on their headers would.
Source code in src/visualdynamics/gui/tables.py
row_shown
¶
selected_block
¶
(rows, columns) covered by the selection, as sorted lists.
Source code in src/visualdynamics/gui/tables.py
to_tsv
¶
The selection, or every shown row with whole_table, as
tab-separated text without headers.
Source code in src/visualdynamics/gui/tables.py
copy
¶
Put to_tsv on the clipboard, and return it.
table_cells
¶
(headers, rows) of the whole table's shown rows, as text.
Source code in src/visualdynamics/gui/tables.py
copy_table
¶
Copy the whole table with its headers, as tab-separated text and as HTML in one clipboard entry, so a spreadsheet pastes cells and a document or an email pastes a table. Returns False when there are no rows to copy.
This is the copy button in the corner. A copy of a selection stays bare cells, which is what pasting back into a sheet needs.
Source code in src/visualdynamics/gui/tables.py
cap_columns
¶
Narrow any column wider than WIDEST_COLUMN_CHARACTERS to it.
A cell cut short this way ends in an ellipsis and shows its whole text on hover; the column is still the person's to drag wider.
Source code in src/visualdynamics/gui/tables.py
cut_short
¶
Whether cell index is too narrow for its text.
Source code in src/visualdynamics/gui/tables.py
paste
¶
Paste tab-separated text from the clipboard over the selection's top-left corner, onto the shown rows, and return (applied, rejected).
Cells that will not accept a value, a cell whose property does
not apply to its item among them, are left as they are and
counted, so a paste that partly lands is not silently half
applied; edits_applied says how it landed. A paste past the table's edge stops there and does not
wrap.
Source code in src/visualdynamics/gui/tables.py
editable_selection
¶
The selected cells that will accept a value.
Source code in src/visualdynamics/gui/tables.py
inapplicable_selection
¶
Why each selected cell that does not apply is skipped, one reason per cell. A batch edit counts them as refused, so a value set across a group of beams and a group of bricks says what it left out.
Source code in src/visualdynamics/gui/tables.py
shared_choices
¶
shared_choices(indexes: Sequence[QModelIndex]) -> Column | None
The Column the selection shares, when all of its columns offer the same list, or None.
A selection spanning a color column and a coordinate column has no common list, so a batch edit of it falls back to typing a value.
Source code in src/visualdynamics/gui/tables.py
batch_edit
¶
Set every selected editable cell to one value, across columns as well, and return (applied, rejected).
The prompt offers the columns' choices when the selection shares
a list, and otherwise asks for text. Pass text to skip the
prompt. Selected cells whose property does not apply to their
item are left blank and counted as refused, with the reason.
Source code in src/visualdynamics/gui/tables.py
whole_rows
¶
Rows whose every column is selected (a row-header click, or a drag across the full width). Delete removes whole rows, where the table allows it, and clears anything less.
Source code in src/visualdynamics/gui/tables.py
clear_cells
¶
Empty the selected cells, for the columns that accept empty, and return (applied, rejected).
A column that cannot be blank (a node id, a connectivity list) refuses and is counted, as it would refuse the same value typed in. The column decides what empty means.
Source code in src/visualdynamics/gui/tables.py
fill_handle_rect
¶
The small square at the bottom-right of the selection, or None.
It is the spreadsheet fill handle, the fastest way to carry one value down a column, or across a row, without selecting the cells first.
Source code in src/visualdynamics/gui/tables.py
fill_from_selection
¶
Repeat the selected block along the items out to item
through, and return (applied, rejected).
This is the fill down a column (across the columns of a
transposed table), which double-clicking the handle does to the
last item; fill_to is the drag, which can also go across.
Source code in src/visualdynamics/gui/tables.py
fill_to
¶
Repeat the selected block over the rectangle from it to the
cell at (row, column), and return (applied, rejected).
This is the drag of the fill handle. The rectangle is the one the selection and that cell span, so a cell level with the selection fills across, one in line with it fills down, and one off both ways fills the whole rectangle between, as a spreadsheet does.
Source code in src/visualdynamics/gui/tables.py
mouseDoubleClickEvent
¶
Double-clicking the handle fills all the way down, as Excel does.
The common case is one unit for every channel, and dragging over 45 rows to say so is slow.
Source code in src/visualdynamics/gui/tables.py
Functions:¶
wear_item_checks
¶
Put ItemCheckStyle on the application when it runs the macOS
style, and say whether it did. Once is enough; a second call, or
any other style, changes nothing.
Source code in src/visualdynamics/gui/tables.py
trace_units
¶
Write one line to the units-editor log for an event in a choice cell's drop-down, with the mouse buttons, the open popup and the focused widget at that moment.
The log is ~/Library/Logs/VisualDynamics-units.log, overwritten by the first line each run writes. A failure to write is ignored.