Teek::UI::Session Class
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_nameSymbol— 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
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
windowString— 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
See also
choose_dir(initialdir: nil, mustexist: false, title: nil, parent: nil)
Show the native “choose directory” dialog.
@raise NotRealizedError if called before #realize
See also
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
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
pathString— 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
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
See also
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
strictBoolean— seeValidator.validate!
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
strictBoolean— seeValidator.validate!debugBoolean— 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
strictBoolean— seeValidator.validate!debugBoolean— print#debug_info's summary to stderr right after realize
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
See also
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
messageStringdurationInteger— 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