Teek API Documentation

The object yielded to (and returned by) Teek::UI.app - owns the build-phase Document and the realize/run lifecycle, and (via WidgetDSL) the ui.<widget> build surface itself.

Building is Tk-free: Teek::UI.app never constructs a Teek::App, so the block runs (and #document is buildable/inspectable) with no interpreter at all. Nothing talks to Tk until #realize (called by #run and #run_async, or directly) actually creates one and walks the tree into it via Realizer.

Inherits: Object

Includes: Teek::UI::WidgetDSL

Instance Methods

add(parent_name)

Build and immediately realize a subtree into the already-running app, as a child of an already-realized widget named parent_name - for dynamic UIs (adding cards/rows/menu entries at runtime), not just the initial build. The block uses the exact same widget DSL as everywhere else (a.button(...), a.column(...) ``, …); new widgets show up immediately, routed through the same Teek::App#command/leak-cleanup path the initial realize uses, so destroying an added widget reclaims its callbacks the normal way.

Unlike the initial #realize, this does not run Validator - it’s already-known-good territory (the session realized once already); validating one small addition on every call would be wasted work.

Parameters
  • parent_name Symbol — an already-realized widget's name

Returns nil

@raise NotRealizedError if the session, or the named parent, isn't realized yet

@raise ArgumentError if no widget is declared under parent_name

@yieldparam ui Session the same builder, block-scoped under parent_name

after(ms, on_error: :raise, &block)

Returns Object, nil — see #every

app

Returns Teek::App — the underlying app - the DSL's escape hatch. Anything the DSL doesn't wrap yet is one call away: `ui.app.command(...)`.

@raise NotRealizedError if called before #realize

busy(window: '.', &block)

Show a busy cursor over window for the duration of the block - Teek::App#busy already restores it even if the block raises, nothing extra to do here for that.

Parameters
  • window String — Tk window path

Returns — the block's return value

@raise NotRealizedError if called before #realize

@yield the work to perform while busy

choose_color(initial: nil, title: nil, parent: nil)

Show the native color picker dialog.

@raise NotRealizedError if called before #realize

choose_dir(initialdir: nil, mustexist: false, title: nil, parent: nil)

Show the native “choose directory” dialog.

@raise NotRealizedError if called before #realize

clipboard

Returns Teek::Clipboard.set(text)/.get/.clear - text widgets don't need this at all for their own copy/cut/paste (Tk wires that to the platform's expected keys already); this is for reading/writing the clipboard directly from app code.

@raise NotRealizedError if called before #realize

debug_info

A live snapshot of currently-registered callbacks, grouped by what registered them - “is my app leaking callbacks, and where.” A tag absent from the result means nothing of that kind is currently registered (not a zero entry). Safe to call any time after realize; see run/run_async’s debug: for printing this automatically instead of calling it yourself.

Returns Hash{Symbol => Integer}:event_bindings, :menu_entries, :canvas_item_binds, :tag_binds, :widget_option_callbacks (-command/-textvariable/etc.), :window_close_handlers

@raise NotRealizedError if called before #realize

emit(event, *args, **kwargs)

Returns void

See also

every(ms, on_error: :raise, &block)

Same queue-then-wire shape as an on_* event binding: called inside the build block, it queues and registers once the tree realizes; called after, it registers immediately - same method, correct behavior either way, so a tick loop can be declared right alongside the UI it drives instead of being forced out to a separate post-run_async step.

Returns Object, nil — the live timer object (`.cancel`-able) once realized; `nil` if queued - there's no live timer to hand back yet, since nothing has registered with Tcl at that point

See also

find_by_path(path)

Reverse lookup: given a real Tk path (from an error message, a winfo query, or poking around in a REPL), find which widget it belongs to - the counterpart to the name-based ui[:name]. See Document#find_by_path for exactly what counts as a match.

Parameters
  • path String — e.g. ".toolbar.save"

Returns Handle, nil

@raise NotRealizedError if called before #realize

initialize(title: nil, scroll: nil, app_opts: {})

Returns Session — a new instance of Session

@api private

message(message:, title: nil, detail: nil, icon: :info, type: :ok, default: nil, parent: nil)

Show a message box with one or more buttons.

@raise NotRealizedError if called before #realize

off(event, block)

Returns void

See also

on(event, &block)

Returns Proc — the block, to pass to a later #off

See also

open_file(filetypes: nil, initialdir: nil, initialfile: nil, title: nil, multiple: false, parent: nil)

Show the native “choose file to open” dialog.

@raise NotRealizedError if called before #realize

realize(strict: false)

Validate the build tree, then create the underlying Teek::App and realize the tree into it, if that hasn’t happened yet. Idempotent - calling it again after the first time just returns the same app.

Atomic in two senses: a validation failure means no interpreter is ever constructed at all, and even once realizing starts, the app’s root window stays withdrawn until the whole tree is realized, so a mid-realize error never leaves a half-built window visible either way. On failure the session is left exactly as if #realize had never been called - it isn’t left half-realized (or half-validated).

Parameters

Returns Teek::App

@raise ValidationError if the build tree has problems

run(strict: false, debug: false)

Realize, show the window, and enter the Tk event loop. Blocks until the app exits.

Parameters
  • strict Boolean — see Validator.validate!
  • debug Boolean — print #debug_info's summary to stderr, once right before entering the event loop and once after it returns - eyeball whether the app leaked any callbacks over its run without writing any diagnostic code yourself.

Returns void

run_async(strict: false, debug: false)

Realize and show the window without entering the event loop. Returns immediately - the caller is responsible for servicing the event loop from then on (e.g. its own timer/callback-driven flow).

Parameters

Returns self

@note Not a substitute for #run in an interactive REPL (IRB/Pry): nothing services the event loop while the REPL blocks waiting for your next line, so the window beachballs between commands on macOS no matter how often you call `ui.app.update` by hand - see Teek::App#mainloop's own REPL warning. Driving a session interactively from IRB/Pry isn't a supported workflow.

save_file(filetypes: nil, initialdir: nil, initialfile: nil, title: nil, defaultextension: nil, confirmoverwrite: true, parent: nil)

Show the native “choose file to save” dialog.

@raise NotRealizedError if called before #realize

toast(message, duration: DEFAULT_TOAST_DURATION_MS)

Briefly flash a message near the bottom of the window - “Saved” after a save action, “Settings” when a modal gains focus, that kind of transient feedback, not a persistent status. Reuses one widget across every call rather than building a new one each time: calling this again while a toast is already showing replaces it (new text, restarted timer) instead of stacking a second one, and the earlier toast’s own pending auto-dismiss is cancelled so it can never fire late and hide the replacement.

Parameters
  • message String
  • duration Integer — milliseconds before it auto-dismisses

Returns void

@raise NotRealizedError if called before #realize

Attributes

document [R]

Returns Document — the build-phase tree - constructible and traversable with no interpreter, before or after realize.

images [R]

Returns Array<Image> — images declared in this build - retained here for the session's whole lifetime, so a widget's `image:` never outlives the Teek::Photo it points at (see Image).

vars [R]

Returns Array<Var> — reactive variables declared in this build