Skip to main content

Module switch

Module switch 

Source
Expand description

<switch> behavior: an on/off toggle rendered as a pill track with a thumb that slides between the two ends, built on the same shared Toggleable machinery as <checkbox>.

The markup parser spawns <switch> as a track element (tag switch, carrying Toggleable + crate::controls::TrackStyle) with a single absolute- positioned child - the .switch-thumb tile (carrying SwitchThumb). Every visual is design-token / CSS reachable through the skins:

switch            { width: 52; height: 28; bg: ...; }  /* track (off) */
switch:checked    { bg: var(--lumen-accent); }        /* track (on) */
.switch-thumb     { knob-color: ... }                   /* thumb fill */

Behavior reuse - identical to <checkbox>, nothing bespoke:

  • Click anywhere on the track (or the thumb) toggles - crate::controls::flip_toggle_on_click resolves a child hit to the ancestor Toggleable.
  • Space / Enter on the focused switch toggles - lumen_input::activate_focused_on_enter’s press-and-release FSM emits the same ClickEvent (mirrors Slint SwitchBase’s key-pressed: if event.text == " " || "\n" { toggle-checked() } and Qt QAbstractButton’s space-bar activation).
  • bind-checked two-way signal binding comes with Toggleable (apply_checked_bindings / push_toggle_to_signal) - mirrors Slint’s in-out property <bool> checked two-way binding.
  • disabled inserts the generic Disabled marker; interaction is ejected by crate::state_style::eject_interaction_on_disable.

What IS bespoke: the thumb slides between off and on with an implicit animation driven by the shared transition primitive (crate::transition::Transition) rather than snapping - mirroring Slint’s animate ... x { duration: 75ms } on the switch handle and Qt QML Switch’s Behavior on position { NumberAnimation }. The tween is reactive: step_switch_thumb samples it and pings AnimationsActive only while a slide is in flight, then retires the component - no per-frame loop.

The slide’s duration + easing come from a transition: bg <duration> <easing> declaration on the track (see [slide_tween_params]) - the same mechanism crate::hover uses for its hover / press tint tween - falling back to SWITCH_SLIDE_MS / SWITCH_SLIDE_EASING when none is authored. Track / thumb geometry (the inset gap and the thumb’s diameter) come from crate::controls::KnobGeometry, populated from the CSS knob-inset property, with the same today’s-appearance fallback.

Accessibility: <switch> carries an explicit lumen_core::components::A11yRole::Switch, so the a11y tree exposes it as Role::Switch with the Toggled state derived from Toggleable::checked - the Role::Switch analogue of how <checkbox> surfaces Role::CheckBox.

Structs§

SwitchPlugin
Plugin registering the switch visual-sync + thumb-slide systems.
SwitchThumb
Marker for the thumb child spawned inside every <switch>. Absolute-positioned; sync_switch_visuals slides it between the two track ends, animating flips through SwitchThumbSlide.
SwitchThumbSlide
Active thumb-slide tween driving a SwitchThumb’s horizontal inset. Reuses the shared Transition<f32> primitive; step_switch_thumb samples it and removes the component when the slide completes.

Constants§

SWITCH_SLIDE_EASING
Fallback easing for the thumb slide, used under the same condition as SWITCH_SLIDE_MS. Ease-out (fast start, gentle settle) is the Cocoa / Material short-transition curve; the same curve <checkbox> and the hover tints reach for.
SWITCH_SLIDE_MS
Fallback duration of the thumb slide when the switch flips, used when the track carries no transition: bg ... TransitionSpecs (see [slide_tween_params]). 140 ms sits between Slint’s 75 ms handle tween and the 200 ms Qt QML Switch default - long enough to read as motion, short enough to feel instant.

Functions§

register_switch_systems
Register sync_switch_visuals + step_switch_thumb in TickStage::Systems. Called by both SwitchPlugin and crate::ControlsPlugin; system de-duplication makes a double install harmless.
step_switch_thumb
Advance every active SwitchThumbSlide, writing the eased offset into the thumb’s Style::inset.left and marking it dirty so layout repositions it. Pings AnimationsActive while running so the loop keeps ticking without an unrelated OS event; snaps to the endpoint and retires the component when done (or immediately if the thumb is hidden - a display: none subtree runs no animation, matching the CSS transition drivers in crate::transition).
sync_switch_visuals
Place the SwitchThumb child: size + corner radius from the laid-out track height, and the horizontal inset toward the checked/unchecked end. The first placement snaps; a subsequent checked flip starts a SwitchThumbSlide from the thumb’s current position so it glides.