Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Splitter

Splitter preview

N-pane split container with draggable, collapsible dividers.

Public types

KindName
structSplitter — An N-pane resizable split container driven by a SplitterModel
structPaneDescriptor — Per-pane configuration passed to SplitterModel::from_panes / SplitterModel::insert_pane
structPaneSnapshot — Immutable per-pane view handed to the pure distribute sizing function (the internal splitter::distribute engine)
structPaneState — Persistable per-pane layout state
structSplitterState — Full serializable snapshot of a SplitterModel's sizes + collapsed flags
structSplitterModel — A shared, cloneable handle to a splitter's layout state

Public functions

Splitter

PaneDescriptor

SplitterModel

ReturnsFunction
Constructors
Selfnew(n: usize, orientation: Orientation)
Selffrom_panes(panes: Vec<PaneDescriptor>, orientation: Orientation)
Methods
usizehandle_count()
set_stored_size(index: usize, size: f32)
set_stored_size_silent(index: usize, size: f32)
set_pair_sizes(index: usize, size_a: f32, size_b: f32)
set_min_size(index: usize, min: f32)
set_max_size(index: usize, max: Option<f32>)
set_stretch(index: usize, stretch: f32)
set_collapsible(index: usize, collapsible: bool)
set_collapsed(index: usize, collapsed: bool)
set_collapsed_immediate(index: usize, collapsed: bool)
toggle_collapsed(index: usize)
set_collapsed_size(index: usize, px: f32)
set_pane_visible(index: usize, visible: bool)
set_pane_visible_immediate(index: usize, visible: bool)
boolis_pane_visible(index: usize)
boolconsume_animate_flag()
insert_pane(index: usize, desc: PaneDescriptor)
remove_pane(index: usize)
replace_pane_desc(index: usize, desc: PaneDescriptor)
set_gutter_thickness(thickness: f32)
set_snap_offset(offset: f32)
set_keyboard_step_px(step: f32)
set_orientation(orientation: Orientation)
usizepane_count()
f32stored_size(index: usize)
f32min_size(index: usize)
Option<f32>max_size(index: usize)
f32stretch(index: usize)
boolis_collapsible(index: usize)
f32collapsed_size(index: usize)
boolis_collapsed(index: usize)
Orientationorientation()
f32gutter_thickness()
f32snap_offset()
f32keyboard_step_px()
Signal<u64>version()
Vec<PaneSnapshot>pane_snapshots()
SplitterStateexport_state()
boolimport_state(state: &SplitterState)

Detailed description

Splitter arranges N ≥ 2 panes along one axis (per Orientation) with N − 1 grabbable handles between them — the Qt QSplitter model. All layout state (per-pane size / min / max / stretch / collapsed) lives in a shared, cloneable SplitterModel; the app holds a clone to read, mutate, persist, and import/export, while the widget renders it and reacts to the model's version signal.

Strengths carried over from the old two-pane SplitView: anti-jump drag, keyboard resize, Role::Splitter accessibility, per-pane content clipping, RTL-correct horizontal layout. New: N panes, per-pane stretch (container-resize policy), animated collapse with four triggers (programmatic / double-click / drag-past-min snap / keyboard), a Tier-3 SplitterStyle, and serializable import/export. It is the building block DockingLayout is built from.

Collapsing and hiding a pane each have an animated door (SplitterModel::set_collapsed, SplitterModel::set_pane_visible) and an instant one (SplitterModel::set_collapsed_immediate, SplitterModel::set_pane_visible_immediate) for restoring a layout.

let model = SplitterModel::from_panes(vec![
    PaneDescriptor::new().size(220.0).min_size(160.0).stretch(0.0).collapsible(true),
    PaneDescriptor::new().stretch(1.0).min_size(320.0),
    PaneDescriptor::new().size(280.0).stretch(0.0).collapsible(true),
], Orientation::Horizontal);

Splitter::new(model.clone())
    .pane(sidebar).pane(editor).pane(inspector)
    .pane_label(0, tr!(sidebar()));

Density

The picture above is the widget at TargetDensity::Compact, the mouse-and-keyboard ladder. Below is the same subject on the same canvas with only the ladder changed, so what moves is the density and nothing else — where the subject no longer fits, that is what the denser targets cost it at that size. See docs/density-and-targets.md.

Touch

Splitter at Touch density

API reference

📖 Full rustdoc API for this module

pub struct Splitter

Import: use teksilo::widgets::Splitter;

An N-pane resizable split container driven by a SplitterModel.

See the module-level documentation for a usage overview and constructor patterns.

#![allow(unused)]
fn main() {
pub struct Splitter { /* fields */ }
}

Methods

pub fn new(model: SplitterModel) -> Self

Create a Splitter bound to the given model. Panes must be appended with pane in model order.

pub fn pane(mut self, widget: impl teksilo_core::IntoTeksiChild) -> Self

Append a content pane (model order). Call once per pane; the count must match model.pane_count().

pub fn panes(self, iter: impl IntoIterator<Item = impl teksilo_core::IntoTeksiChild>) -> Self

Append several content panes from an iterator, in model order.

The loop form of pane. The total pane count still has to match model.pane_count().

pub fn child(self, widget: impl teksilo_core::IntoTeksiChild) -> Self

teksu! ergonomic alias for pane: a bare child in a Splitter { ... } block lowers to .child(...).

pub fn children( self, iter: impl IntoIterator<Item = impl teksilo_core::IntoTeksiChild>, ) -> Self

teksu! ergonomic alias for panes: a for loop in a Splitter { ... } block lowers to .children(...).

pub fn child_opt(self, widget: Option<impl teksilo_core::IntoTeksiChild>) -> Self

Attach widget when it is Some, and do nothing when it is None.

The conditional-child form. teksu!'s if without an else lowers to this, and it is what cond.then(|| w) is for in a builder chain. None adds no arena node, so nothing is laid out, painted, or published to the accessibility tree, and a stack applies no spacing around it.

pub fn pane_label(mut self, index: usize, label: impl Into<Prop<String>>) -> Self

Set an accessible region name for pane index (locale-reactive). Labeled panes become a named Role::Group; unlabeled panes stay AT-transparent (their content represents itself).

pub fn style(mut self, style: impl SplitterStyle) -> Self

Override the active SplitterStyle for this instance only.

pub fn enabled(mut self, enabled: impl Into<Prop<bool>>) -> Self (default: true)

Enable or disable handle dragging. When false, divider handles are rendered inert — the pane layout is still valid but the user cannot resize panes. Read once at build time: a bound Signal is snapshotted, not tracked.

pub struct PaneDescriptor

Import: none — PaneDescriptor is public in a private module of teksilo-widgets and nothing re-exports it.

Per-pane configuration passed to SplitterModel::from_panes / SplitterModel::insert_pane. Public fields + Default so it can be built with struct-literal ..Default::default() syntax, or via the fluent setters.

#![allow(unused)]
fn main() {
pub struct PaneDescriptor { /* fields */ }
}

Fields

  • initial_size: Option<f32> — Initial main-axis size in px. None ⇒ take an equal share (the first layout equalizes via the stretch path).
  • min_size: f32 — Hard compression floor in px.
  • max_size: Option<f32> — Optional growth ceiling in px.
  • stretch: f32 — Container-resize slack weight (Qt setStretchFactor). 0.0 ⇒ rigid (keeps its size on resize); >0 ⇒ absorbs slack ∝ weight.
  • collapsible: bool — Whether the user may collapse this pane (drag-snap / double-click / keyboard). Programmatic set_collapsed ignores this flag (it governs interactive collapse only, like Qt's childrenCollapsible).
  • collapsed: bool — Initial collapsed state.
  • collapsed_size: f32 — The main-axis size a collapsed pane folds down to (default 0 ⇒ fully gone). Set this to keep a sliver visible while collapsed — e.g. an accordion's header height, so the pane shrinks to just its header and can be re-expanded from there. The pane restores to its prior size on expand regardless.
  • visible: bool — Whether the pane is present at all. Unlike collapsed (which folds the pane but keeps its grabbable gutter), a hidden pane removes both the pane and an adjacent gutter from the layout — it reads as absent. Toggled reactively via set_pane_visible.

Methods

pub fn new() -> Self

pub fn size(mut self, size: f32) -> Self (default: None)

pub fn min_size(mut self, min: f32) -> Self (default: SPLITTER_MIN_PANE_SIZE)

pub fn max_size(mut self, max: f32) -> Self (default: None)

pub fn stretch(mut self, stretch: f32) -> Self (default: 1.0)

pub fn collapsible(mut self, collapsible: bool) -> Self (default: false)

pub fn collapsed(mut self, collapsed: bool) -> Self (default: false)

pub fn collapsed_size(mut self, px: f32) -> Self

Size a collapsed pane folds down to (default 0). See collapsed_size.

pub fn visible(mut self, visible: bool) -> Self (default: true)

pub struct PaneSnapshot

Import: none — PaneSnapshot is public in a private module of teksilo-widgets and nothing re-exports it.

Immutable per-pane view handed to the pure distribute sizing function (the internal splitter::distribute engine).

#![allow(unused)]
fn main() {
pub struct PaneSnapshot { /* fields */ }
}

Fields

  • stored_size: f32
  • min_size: f32
  • max_size: Option<f32>
  • stretch: f32
  • collapsed: bool
  • collapsed_size: f32
  • visible: bool

pub struct PaneState

Import: none — PaneState is public in a private module of teksilo-widgets and nothing re-exports it.

Persistable per-pane layout state. Captures the user-controllable values (size + collapsed); structural config (min/max/stretch/ collapsible) is app-declared and not serialized — Qt saveState parity.

#![allow(unused)]
fn main() {
pub struct PaneState { /* fields */ }
}

Fields

  • stored_size: f32
  • collapsed: bool

pub struct SplitterState

Import: none — SplitterState is public in a private module of teksilo-widgets and nothing re-exports it.

Full serializable snapshot of a SplitterModel's sizes + collapsed flags. Round-trips through SplitterModel::export_state / import_state and implements Versioned so apps persist it through SettingsFile<SplitterState> + Migrator (TOML).

#![allow(unused)]
fn main() {
pub struct SplitterState { /* fields */ }
}

Fields

  • version: u32
  • panes: Vec<PaneState>

pub struct SplitterModel

Import: none — SplitterModel is public in a private module of teksilo-widgets and nothing re-exports it.

A shared, cloneable handle to a splitter's layout state. Clone = share-by-handle (cheap Rc bump).

#![allow(unused)]
fn main() {
pub struct SplitterModel(Rc<RefCell<SplitterModelInner>>);
}

Methods

pub fn new(n: usize, orientation: Orientation) -> Self

n equal-share panes (each stretch = 1, min = SPLITTER_MIN_PANE_SIZE).

pub fn from_panes(panes: Vec<PaneDescriptor>, orientation: Orientation) -> Self

Build from explicit per-pane descriptors.

pub fn handle_count(&self) -> usize

Number of distinct handles to this model (1 = unshared).

pub fn set_stored_size(&self, index: usize, size: f32)

pub fn set_stored_size_silent(&self, index: usize, size: f32)

Like set_stored_size but without a version bump — for writes made from inside a layout/effect pass that is already relaying out (e.g. capturing the displayed size as the collapse reference), where a bump would re-enter the effect.

pub fn set_pair_sizes(&self, index: usize, size_a: f32, size_b: f32)

Set both sides of handle index (panes index and index+1) in one mutation — a single version bump, so a drag produces exactly one relayout per move.

pub fn set_min_size(&self, index: usize, min: f32)

pub fn set_max_size(&self, index: usize, max: Option<f32>)

pub fn set_stretch(&self, index: usize, stretch: f32)

pub fn set_collapsible(&self, index: usize, collapsible: bool)

pub fn set_collapsed(&self, index: usize, collapsed: bool)

Programmatically collapse/expand pane index, animated. Ignores the collapsible flag (that flag only gates interactive triggers).

pub fn set_collapsed_immediate(&self, index: usize, collapsed: bool)

Collapse/expand pane index instantly (no tween). Used by the drag handlers — the pointer is already the motion.

pub fn toggle_collapsed(&self, index: usize)

Toggle pane index's collapsed state, animated.

pub fn set_collapsed_size(&self, index: usize, px: f32)

Set the size pane index folds down to when collapsed (default 0). See PaneDescriptor::collapsed_size. No version bump on its own — it only affects the next collapse.

pub fn set_pane_visible(&self, index: usize, visible: bool)

Show or hide pane index (animated). A hidden pane removes both the pane and an adjacent gutter from the layout — it reads as absent, unlike a collapsed pane (which keeps its grabbable gutter). The pane must be pre-mounted in the Splitter; this is the reactive "add / remove a pane from a fixed set" trick (no rebuild).

pub fn set_pane_visible_immediate(&self, index: usize, visible: bool)

Show or hide pane index instantly (no tween): the next layout already has the pane removed from, or restored to, the split. The counterpart of Self::set_collapsed_immediate, for a caller that is restoring a layout or reacting to something that is already the motion.

pub fn is_pane_visible(&self, index: usize) -> bool

pub fn consume_animate_flag(&self) -> bool

Read-and-reset the "animate the next collapse change?" latch. The widget's collapse effect calls this once per version bump; it resets to true so the default (programmatic) path animates.

pub fn insert_pane(&self, index: usize, desc: PaneDescriptor)

Insert a pane at index (clamped to [0, len]). A None initial_size takes the average of the existing panes' sizes; the next layout rebalances. The app must rebuild the Splitter widget to supply the new pane's content (retained-mode: changing a container's child set is a rebuild; the model keeps the persistent size/collapse state across it).

pub fn remove_pane(&self, index: usize)

Remove the pane at index (no-op if out of range). The app must rebuild the Splitter widget to drop the corresponding content.

pub fn replace_pane_desc(&self, index: usize, desc: PaneDescriptor)

Replace the metadata of pane index (keeps its current size unless the descriptor specifies one).

pub fn set_gutter_thickness(&self, thickness: f32)

pub fn set_snap_offset(&self, offset: f32)

pub fn set_keyboard_step_px(&self, step: f32)

pub fn set_orientation(&self, orientation: Orientation)

pub fn pane_count(&self) -> usize

pub fn stored_size(&self, index: usize) -> f32

pub fn min_size(&self, index: usize) -> f32

pub fn max_size(&self, index: usize) -> Option<f32>

pub fn stretch(&self, index: usize) -> f32

pub fn is_collapsible(&self, index: usize) -> bool

pub fn collapsed_size(&self, index: usize) -> f32

The size pane index folds to when collapsed (default 0). See PaneDescriptor::collapsed_size.

pub fn is_collapsed(&self, index: usize) -> bool

pub fn orientation(&self) -> Orientation

pub fn gutter_thickness(&self) -> f32

pub fn snap_offset(&self) -> f32

pub fn keyboard_step_px(&self) -> f32

pub fn version(&self) -> Signal<u64>

The reactive version signal. The Splitter widget binds this at BindingLevel::Relayout.

pub fn pane_snapshots(&self) -> Vec<PaneSnapshot>

Immutable per-pane snapshot for the pure sizing engine.

pub fn export_state(&self) -> SplitterState

Snapshot the per-pane sizes + collapsed flags into a serializable SplitterState.

pub fn import_state(&self, state: &SplitterState) -> bool

Restore sizes + collapsed flags from a SplitterState. Returns false (and changes nothing) if the pane count doesn't match — the structural config must be reconstructed first. Restoration is instant (collapsed panes don't animate open on load).