Skip to main content

Crate kui_core

Crate kui_core 

Source
Expand description

The headless model behind kui: a per-frame flat tree, flex layout, text shaping, events as data and a quad display list.

A Core owns one window’s worth of state. Each frame the app rebuilds a flat tree of NodeSpecs through a Ui, the core runs a clay-style flex layout over it, shapes the text, and emits a DisplayList of quads for a renderer to draw. Input arrives as InputEvents and comes back out as UiEvents whose payloads are plain-data Values. There is no window, no GPU and no clock in this crate: a driver supplies the viewport, the input, the time and the renderer.

Most Rust apps do not depend on kui-core directly. They use kui-native, the windowed runner, which re-exports all of this crate and pairs it with kui-wgpu, the renderer. Reach for kui-core on its own when you are writing a custom runner, a binding to another language (kui-lua, kui-ffi and kui-node are built on it), or headless tests that build frames and feed input without a window.

§Quick start

A frame built and clicked with no window at all:

use kui_core::{Core, InputEvent, NodeSpec, Size, TextStyle, widgets};

let mut core = Core::new();
core.set_inspect(true); // keep a readable snapshot of each finished frame

// One frame: begin, declare the tree, finish (layout and emission).
let mut ui = core.frame(Size::new(320.0, 200.0), 1.0);
ui.configure_root(NodeSpec::column().fill().pad(16.0).gap(8.0));
ui.text("Hello from kui-core", TextStyle::new(16.0));
widgets::button(&mut ui, "Save", "save");
ui.finish();

// What a renderer draws: a flat list of quads.
let (list, _atlas) = core.output();
assert!(!list.quads.is_empty());

// Input goes in as `InputEvent`s and comes out as `UiEvent`s carrying
// the payload the view declared.
let button = core
    .nodes()
    .into_iter()
    .find(|n| n.label.as_deref() == Some("Save"))
    .expect("the button was laid out");
core.handle_input(InputEvent::CursorMoved(button.rect.center()));
core.handle_input(InputEvent::mouse_down(1));
let events = core.handle_input(InputEvent::mouse_up());
let click = events
    .iter()
    .find(|e| e.payload.as_str() == Some("save"))
    .expect("the click reached the button");
assert_eq!(click.key, button.key);

A real driver repeats the frame whenever input arrives or the core asks for one, hands the display list to a renderer, and calls Core::set_time before each frame so transitions can run.

§Where to look

  • ui::Ui: the frame builder. open/close, with, leaf, text, and the readbacks a view needs (is_hovered, focused, theme).
  • runtime::Core: the per-window state. frame, handle_input, output, set_time, fonts and images, focus and scrolling.
  • spec::NodeSpec and spec::TextStyle: everything a node and a text declare, as plain data with a builder.
  • layout: the flex solver, and what each sizing means.
  • text: shaping, wrapping, measuring and the glyph atlas.
  • input and input::UiEvent: what goes in and what comes out; event has typed readings of the core’s own event payloads.
  • value::Value: the payload type, and message for typed messages over it.
  • display::DisplayList: the renderer boundary.
  • widgets: buttons, toggles, inputs, menus and virtual lists built from the primitives.
  • theme, metrics and tokens: the colours, sizes and named values a view paints with.
  • session: fonts, images and sounds shared between windows.

§Features

  • devtools (default): the inspector panel the core can draw into any app’s frame (Core::set_devtools, or KUI_DEVTOOLS=1).
  • derive: re-exports #[derive(Message)] from kui-derive, a typed Rust enum to and from the payload map.
  • conformance: the scene corpus and the headless test driver (testing). Test infrastructure, off in every shipped binary.

Re-exports§

pub use access::AccessAction;
pub use access::AccessNode;
pub use access::AccessRequest;
pub use access::AccessRun;
pub use access::AccessTree;
pub use access::Announcement;
pub use access::Live;
pub use access::Orientation;
pub use access::Role;
pub use access::ScrollState;
pub use access::TextPos;
pub use anim::Bounce;
pub use anim::Easing;
pub use anim::MAX_BOUNCE;
pub use anim::Repeat;
pub use anim::Transition;
pub use audio::AudioCommand;
pub use audio::AudioSpec;
pub use audio::AudioStore;
pub use audio::PlayOptions;
pub use audio::PlaybackId;
pub use audio::Why;
pub use calc::Calc;
pub use calc::Expr as SizeExpr;
pub use cells::Cell;
pub use cells::CellGrid;
pub use cells::CellStore;
pub use cells::CellsId;
pub use cells::CursorShape as CellCursor;
pub use color::Color;
pub use cursor::CursorShape;
pub use depart::DepartStore;
pub use diag::Warning;
pub use dialog::FileDialog;
pub use dialog::FileDialogMode;
pub use dialog::FileFilter;
pub use display::Clip;
pub use display::ClipId;
pub use display::DisplayList;
pub use display::FragmentDraw;
pub use display::FragmentImage;
pub use display::NO_CLIP;
pub use display::NO_CLIP_ID;
pub use display::Quad;
pub use display::QuadKind;
pub use edit::EditOptions;
pub use edit::MAX_UNDECLARED_EDITS;
pub use enter::Enter;
pub use env::Appearance;
pub use env::Assistive;
pub use env::AudioDevice;
pub use env::AudioEnv;
pub use env::Env;
pub use env::Locale;
pub use env::MotionPref;
pub use env::SystemEnv;
pub use event::ButtonEvent;
pub use event::ButtonPhase;
pub use event::Drag;
pub use event::DragPhase;
pub use event::Hover;
pub use event::HoverBy;
pub use event::HoverPhase;
pub use event::Layout;
pub use event::Scroll;
pub use event::TextInput;
pub use fragment::FragmentDrawId;
pub use fragment::FragmentList;
pub use fragment::FragmentRef;
pub use geom::Edges;
pub use geom::Rect;
pub use geom::Size;
pub use geom::Vec2;
pub use gradient::Gradient;
pub use gradient::Side;
pub use gradient::Stop as GradientStop;
pub use input::ScrollAxis;
pub use input::Buttons;
pub use input::ClipboardMarks;
pub use input::EditKey;
pub use input::InputEvent;
pub use input::KeyCode;
pub use input::KeyLocation;
pub use input::KeyLocks;
pub use input::KeyMods;
pub use input::KeyPhase;
pub use input::KeyPress;
pub use input::LayoutScript;
pub use input::Mods;
pub use input::MouseButton;
pub use input::OptionAsAlt;
pub use input::UiEvent;
pub use key::Key;
pub use keyframes::Keyframe;
pub use line::Dash;
pub use line::LineId;
pub use line::LineStore;
pub use line::Stroke;
pub use menu::Accel;
pub use menu::BarMenu;
pub use menu::Menu;
pub use menu::MenuAction;
pub use menu::MenuBar;
pub use menu::MenuItem;
pub use menu::MenuRole;
pub use message::MessageError;
pub use message::MessageField;
pub use metrics::Metrics;
pub use path::FillRule;
pub use path::Path;
pub use path::PathError;
pub use path::PathId;
pub use path::PathOp;
pub use path::PathStore;
pub use path::Turn;
pub use resources::FontId;
pub use resources::FragmentId;
pub use resources::ImageBacking;
pub use resources::ImageFit;
pub use resources::ImageId;
pub use resources::ImageOpts;
pub use resources::Resources;
pub use resources::Sampling;
pub use resources::SessionId;
pub use resources::SoundId;
pub use resources::SystemFont;
pub use runtime::cause::FrameCause;
pub use runtime::cause::FrameHolder;
pub use runtime::cause::FrameRequest;
pub use runtime::cause::OwedBy;
pub use runtime::devtools;
pub use runtime::devtools::Dock as DevtoolsDock;
pub use runtime::inspect::NodeInfo;
pub use runtime::inspect::NodeKind;
pub use runtime::Content;
pub use runtime::Core;
pub use runtime::Extension;
pub use runtime::Owed;
pub use scroll::MAX_UNDECLARED_SCROLLS;
pub use scroll::ScrollGeometry;
pub use select::CellEnd;
pub use select::CellSelection;
pub use select::CopyRequest;
pub use select::Endpoint;
pub use select::Grain;
pub use select::RangeEnd;
pub use select::Selection;
pub use session::Session;
pub use session::SharedAudio;
pub use session::SharedResources;
pub use slot::ANY_SLOT;
pub use slot::Extensions;
pub use slot::Fill;
pub use slot::NAMESPACE_SEPARATOR;
pub use slot::ROOT_SLOT;
pub use slot::Slot;
pub use slot::full_name;
pub use slot::split_name;
pub use spec::Align;
pub use spec::Bound;
pub use spec::Dir;
pub use spec::FLOAT_PRESETS;
pub use spec::FloatAnchor;
pub use spec::FloatConfig;
pub use spec::FontFamily;
pub use spec::FontFeatures;
pub use spec::Min;
pub use spec::NodeSpec;
pub use spec::OVERFLOW_CLIP;
pub use spec::OVERFLOW_SCROLL_X;
pub use spec::OVERFLOW_SCROLL_Y;
pub use spec::Overscroll;
pub use spec::PadShorthand;
pub use spec::ScrollAxes;
pub use spec::Scrollbar;
pub use spec::ScrollbarMode;
pub use spec::Shadow;
pub use spec::Sizing;
pub use spec::TextStyle;
pub use spec::TextWrap;
pub use spec::UnderlineStyle;
pub use spec::Vec2Offset;
pub use spec::corner;
pub use stats::FrameSample;
pub use stats::FrameStats;
pub use text::DEFAULT_TEXT_CACHE_BYTES;
pub use text::LONG_LINE_BYTES;
pub use text::Span;
pub use text::TextHit;
pub use text::TextMetrics;
pub use theme::Theme;
pub use theme::ThemeSource;
pub use tokens::ColorOp;
pub use tokens::ColorToken;
pub use tokens::NameRefs;
pub use tokens::OpRange;
pub use tokens::TokenError;
pub use tokens::TokenKind;
pub use tokens::TokenLookup;
pub use tokens::TokenRef;
pub use tokens::Tokens;
pub use tokens::Unresolved;
pub use tree::OriginId;
pub use ui::Ui;
pub use value::Handles;
pub use value::Value;
pub use window::Backdrop;
pub use window::DismissReason;
pub use window::WindowButton;
pub use window::WindowCommand;
pub use window::WindowConfig;
pub use window::WindowEnv;
pub use window::WindowId;
pub use window::WindowKind;
pub use window::WindowRole;

Modules§

access
Accessibility as data: the semantic tree of a frame, derived from what nodes do and from the role and label props a view declares.
anim
Transitions: retained tweens keyed by node identity.
atlas
CPU-side glyph atlas: a single RGBA page with shelf packing. Renderers mirror it to a texture; dirty/epoch tell them when to re-upload.
audio
Audio as data: sounds are session resources, and playing one is a command the frame driver drains and applies to the device.
calc
Size expressions: CSS’s min(), max() and clamp() over lengths and percentages, resolved by layout against the parent’s content box (the same box a Percent sizing takes its cut of).
cells
A cell grid: a terminal’s screen as one node, rows × cols cells each with a character, a foreground, a background and attribute bits.
color
Color: straight-alpha sRGB with f32 channels, plus the small amount of colour arithmetic a palette needs (mixing, luminance, WCAG contrast).
cursor
Pointer shape as declared data. A view says what the pointer is over a node with the cursor prop — a button is a hand because it declared one, a handle a grab because it declared one — and the core resolves which declaration is under the pointer per frame (crate::runtime::Core::cursor_shape), which the frame driver hands to the real window. Nothing is inferred from what a node does: an on_click node with no cursor is the plain arrow, as a native button is, and so is an on_drag node. The one shape the core implies is the I-beam over an editor or a selection scope, the way every desktop marks text that can be taken. The stock button declares Pointer for itself, so <button> is a hand in every binding without the app saying so.
deco
Decoration lines that are not a rect: the wavy and dotted underlines a text, a span or a cell asks for. A solid line is one Solid quad, as it always was; these are runs of QuadKind::Segment — the capsule the backend already draws for a line node — so no backend, header or protocol learns a kind. A wave is a zigzag of short pieces whose round caps soften the corners; a dotted line is a row of zero-length pieces, which the capsule SDF draws as dots. Both are sized from the stroke the face recommends, so they scale with the text and the display.
depart
Exit transitions: a subtree the view stopped declaring, kept as a picture and played out.
diag
Warnings as data: misconfigurations the core notices, drained through crate::Core::take_warnings.
dialog
File dialogs as an ask: the app describes an Open, Save or folder dialog, the host shows the platform’s own, and the answer comes back as one {kind:"files", paths, tag} event (paths empty when cancelled).
display
The renderer boundary: a flat list of quads in physical pixels.
edit
Editable text: the retained state of every text_edit node, keyed by node Key, built on cosmic-text’s editor.
enter
Entrance transitions: where a node’s animatable slots start on the first frame it is seen.
env
Env: the host facts a frame driver pushes into the core, which a view reads back with ui.env().
event
Typed readings of the core’s own event payloads: drags, buttons, scrolls, hovers, layouts, key presses and text input.
fragment
A fragment: WGSL an app registers, validated here so a frame never sees a source that cannot compile.
geom
Plain geometry in logical pixels: Vec2, Size, Rect and Edges.
gradient
Gradients: what a box’s gradient row paints (docs/adr/0042-a-gradient-is-an-image-the-core-paints.md).
input
Input in, events out.
key
Key: stable node identity across frames.
keyframes
Keyframes: CSS @keyframes for a node’s animatable slots.
layout
The flex solver: clay-style layout over the flat tree, run by compute once per frame.
line
Strokes: what a line node draws.
menu
Menus as data: the rows of a context menu or the application menu bar, what the window has open, and what a host still has to do after a row is chosen.
message
Typed messages over the plain-data payload.
metrics
Metrics: the sizes the stock widgets are built from, one struct beside the palette.
path
Paths: what a path node draws (docs/adr/0040-a-path-is-a-mask-in-the-atlas.md).
resources
Long-lived, host-registered resources: fonts, images, sounds and fragment shaders, behind typed handles.
runtime
Core: one window’s runtime, the state machine a runner drives frame by frame.
schema
The prop schema: the one table of node props, elements, events and readings that every kui binding is generated from or checked against.
scroll
Retained scroll state: the offset of every scroll container, keyed by node Key, and the geometry the last layout resolved for it.
select
The window’s text selection outside an editor: what a selectable node scopes, what a press-drag across it produces, and what a copy reads.
session
Session: what a set of windows shares.
slider
A slider’s arithmetic: what value a pointer position, an arrow, a Page key or Home / End means on a node whose role is Slider and that declared on_change.
slot
Slots: the places a host declares in its own view for an extension to fill, with parameters in and replies out.
slots
The animatable slots an entrance or a keyframe stop may name (width, height, bg, radius, opacity) as one value.
spec
NodeSpec and TextStyle: everything a node and a text declare, as plain data with a builder.
stats
Frame timing samples for the latency graph. The core only stores data — whoever drives the frame loop (the runner, an FFI host) measures and pushes; widgets::latency_graph renders it with ordinary primitives.
text
Core-owned text stack. Shaping and line layout run through cosmic-text and are cached across frames keyed by (content, style, scale) — the layout pass measures through this cache, so shaping survives resizes and static text costs a hash lookup per frame. Rasterization feeds the shared glyph atlas; renderers only ever see positioned atlas quads.
theme
Theme: the named colours a view and the stock widgets paint with, derived from the OS’s appearance and accent.
tokens
Tokens: named colours and lengths an app declares beside the theme and references by name ($peach, $sidebar) in any colour or length prop.
tree
Tree: the per-frame flat tree the core builds, lays out and emits.
ui
Ui: the frame builder a Rust view declares its tree through.
value
Value: the plain-data payload type for everything that crosses an event or binding boundary.
widgets
Stock widgets built from the primitives: buttons, toggles, text input, select, slider, splitter, tooltips, menus, a titlebar and virtual lists.
window
Windows as data: what a frame declares about the OS windows it wants, and the commands a frame driver applies to the real ones.