SettingsTable
SettingsTable is a QTableWidget subclass that renders a compact,
borderless two-column “Setting / Value” grid. It is the standard
building block for Blackchirp’s configuration surfaces: the hardware
settings widgets, the overlay-configuration panels, the LIF and FTMW
view-dock panels, the experiment-type setup pages, and the
ZoomPanPlot curve-appearance editor all build their
forms by appending rows to one of these tables rather than hand-rolling
a QGridLayout of nested QGroupBox and QFormLayout blocks.
The table is non-selectable, read-only at the item level (value widgets
are still interactive), sizes itself to its contents, and never shows a
vertical scrollbar. Section heading bands are shaded with
ThemeColors so they track the active light or dark
palette. A new configuration UI should reach for SettingsTable
before composing form layouts by hand; doing so keeps spacing, the
borderless contract, and the heading-band styling consistent across
every settings surface.
Row types
Rows are appended in document order and come in three flavors:
Value rows (
addSettingRow) — a left-column label and a value widget in the right column. The two-widget overload places a pair of widgets side by side in the value cell (for example a line edit and a browse button, or a checkbox and a spin box); a horizontally expanding widget fills the cell while a fixed one keeps its hint.Section rows (
addSectionRow) — a bold, centered, theme-shaded band spanning both columns. It replaces the title of a formerQGroupBoxwithout nesting another frame.Checkable section rows (
addCheckableSectionRow) — a section band with a leading checkbox. Value rows bound to it withbindSectionRowscollapse (viasetRowHidden) when the box is unchecked and reappear when it is checked, reproducing a checkable-group-box without the frame.
Checkable sections
A checkable section row is flexible enough that a single row can stand in for several states of the form it replaces:
setSectionCheckableswaps the leading checkbox for a plain centered heading (and back) without destroying the underlyingQCheckBox— so signal/slot connections and the bound-row wiring survive the mode change.setBoundRowsEnabledgreys a section’s rows out in place, the disabled counterpart of the hide-on-uncheck collapse.setSectionVisibleshows or hides a whole section as a unit, and is collapse-aware so a plain container section can wrap nested collapsible sub-sections without fighting their state.sectionCheckBoxreturns the backing checkbox so a caller can drive or observe the collapse directly.
The first user-initiated expand of a section that started collapsed grows the enclosing window by exactly the revealed rows’ height so the new rows are not clipped behind the suppressed scrollbar; the growth happens once and is never reversed, so repeated toggling does not creep the window size.
API Reference
-
class SettingsTable : public QTableWidget
Compact, borderless two-column “Setting / Value” table.
Non-selectable, read-only, sizes to its contents, and never shows a vertical scrollbar. Rows come in three flavors:
a label + value-widget row (single widget, or a pair laid out side by side in the value cell);
a bold, spanned, theme-shaded section/heading row;
a spanned checkable section row whose bound child rows collapse (via setRowHidden) when the box is unchecked.
A checkable section row can be retitled, switched between a checkbox and a plain centered heading, and have its bound rows enabled or disabled without hiding them, so one row can serve both a non-checkable and a checkable state. The backing QCheckBox is created once and outlives every mode change, so external connections to it survive.
Public Functions
-
explicit SettingsTable(QWidget *parent = nullptr)
-
QSize minimumSizeHint() const override
Floor the vertical minimum at the content height.
The table never shows a vertical scrollbar, so it must never be laid out shorter than its (visible) rows or the bottom rows are silently clipped. This matters inside a QMainWindow dock area, where a panel shown next to an existing one is otherwise pinned at the widget minimum. Width still defers to the base class.
-
int addSettingRow(const QString &label, QWidget *value, const QString &tooltip = {})
Append a label + single value widget.
- Returns:
the new row index.
-
int addSettingRow(const QString &label, QWidget *first, QWidget *second, const QString &tooltip = {})
Append a label + two widgets laid side by side in the value cell (e.g. checkbox + spinbox, input + button).
- Returns:
the new row index.
-
int addSectionRow(const QString &title)
Append a bold, spanned, theme-shaded heading row.
Rendered through the same centered cell-widget mechanism as a checkable section row (a plain QLabel instead of a QCheckBox), so the band color is identical for checkable and non-checkable headings. The row is tracked like a checkable section (with a null checkbox) so it can be retitled, have rows bound to it, and be shown/hidden as a unit.
- Returns:
the new row index.
-
int addCheckableSectionRow(const QString &title, bool checked, QCheckBox **outBox = nullptr)
Append a spanned heading row with a leading checkbox.
Rows registered with bindSectionRows() are shown/hidden whenever the box is toggled.
- Parameters:
outBox – optional out-pointer to the created checkbox.
- Returns:
the new row index.
-
void bindSectionRows(int sectionRow, const QList<int> &rows)
Bind value rows to a checkable section row created earlier and apply the box’s current state immediately.
-
void setSectionTitle(int sectionRow, const QString &title)
Retitle a section row in place (works for both the checkbox and the plain-heading rendering).
-
void setSectionCheckable(int sectionRow, bool checkable)
Switch a checkable section row between a leading checkbox and a plain centered heading.
The underlying QCheckBox is kept alive across the change (only the displayed cell content swaps), so connections to it and the bound-row wiring survive. A non-checkable section never collapses; its bound rows’ visibility is left to the caller / bound-row machinery (a plain heading does not itself hide anything).
-
void setBoundRowsEnabled(int sectionRow, bool enabled)
Enable or disable a section’s bound rows (and the section heading itself) without changing visibility — the disabled counterpart of the hide-on-uncheck collapse.
-
void setSectionVisible(int sectionRow, bool visible)
Show or hide a whole section as a unit: the heading row and every bound row.
Collapse-aware: when re-showing, a bound row that also belongs to a nested checkable section whose box is unchecked stays hidden, so a plain container section can wrap nested collapsible sub-sections without fighting their collapse state. Does not grow the enclosing window (used for programmatic context switches, not user toggles).
-
void applySectionVisibility(int sectionRow)
Re-apply the hidden state of a section’s bound rows from the checkbox’s current state, without growing the window.
Used after a signal-blocked programmatic setChecked() so the collapse stays consistent without the user-toggle window growth.
-
QCheckBox *sectionCheckBox(int sectionRow) const
The checkbox backing a checkable section row, or nullptr.
Stable across setSectionCheckable() mode changes.
Private Functions
-
void styleSectionItem(int row)
Paint the section-heading band on the row’s QTableWidgetItem (AlternateBase fill + EmphasisText, bold, centered). Both plain and checkable headings go through this single mechanism so the band is byte-for-byte identical; for a checkable row the transparent cell widget sits on top of this item.
-
void styleSectionText(QWidget *textWidget)
Emphasize a heading’s visible text widget (the QLabel or QCheckBox that sits over the band) to match the item styling.
-
void growEnclosingWindow(int extraHeight)
Add extraHeight px to the enclosing top-level window so newly-shown section rows are not clipped. Grow-only by construction (called only on expand). No-op without a window.
-
struct Section
Public Members
-
QCheckBox *box = nullptr
always alive, even when plain
-
QWidget *wrap = nullptr
centered cell host
-
QLabel *plainLabel = nullptr
shown when non-checkable
-
QString title
-
bool checkable = true
-
QList<int> boundRows
-
bool growPending = false
One-shot: the enclosing window is grown on the first expand only, and only when the section started collapsed. Cleared once consumed so repeated toggling never re-grows.
-
QCheckBox *box = nullptr