Tryst::UI::Handle
The single handle type for a node, valid across both phases - during build you compose/name/record-events on it; live methods (#path, #configure) raise NotRealizedError until the node's realized slot is filled in by the realizer, then the same Handle object drives the real widget through it.
One method is deliberately absent: #on_drag, which CanvasItem's own on_drag/#draggable wait on too - see canvas_item.cr's own doc comment for why both are held back together. The window lifecycle (show/hide/modal/grab_release/on_close) IS ported, alongside the :window widget type it acts on; only its Screens/ModalStack integration is still outstanding.
Resolves this node's own WidgetType#addressing strategy from the registry, falling back to WidgetAddressing for an unregistered type
- the registry now has a real second strategy to resolve (MenuEntryAddressing, for a menu entry with no Tk path of its own), matching ruby's own (WidgetTypes.for_type(node.type)&.addressing || WidgetAddressing).new(node).
Constructors
Instance methods
An arc/pie-slice/chord along the oval inscribed in the bounding box [x1, y1, x2, y2]. Only valid on a ui.canvas handle.
A stipple bitmap anchored at [x, y]. Only valid on a ui.canvas handle.
Mutate the live widget's options - delegated entirely to this node type's addressing strategy, so Handle itself carries no per-type knowledge of how to reach it. Raises NotRealizedError before realize; OptionError (not a bare TclError) for an unknown option - see option_error.cr.
Tears down this node's live widget (and everything under it), releasing its callbacks via tryst's existing <Destroy> cleanup, and unlinks the node from the retained tree so it stops being reachable at all, not just Tk-dead.
A descendant node, or a DIFFERENT node whose Tk window Tk itself destroys (the window manager's own close button, most commonly), gets exactly the same bookkeeping done for it, off the same real Tk <Destroy> this triggers - see Document#node_destroyed, which is the one thing both an explicit #destroy! and an implicit destroy converge on. #perform_destroy! below still does its own node's bookkeeping directly too, redundantly but harmlessly with whatever #node_destroyed also does for that same node - so this stays reliable even for a Handle built against a FakeApp with no real Tk <Destroy> mechanism to fire at all (see handle_spec.cr).
Destroying a widget SYNCHRONOUSLY from inside the click handler of one of its own descendants (a dialog's own "Close" button tearing down the dialog it lives in) is a real Tk hazard: ttk::button (and others) queue their own internal bindings for that SAME click, which then run against a widget that's already gone. defer absorbs this automatically.
defer: nil (the default) auto-detects: defers to the next Tk idle point (Tryst.in_callback? true - the hazard above) so the current click finishes first, or destroys synchronously otherwise (a script/test with no event loop running has nothing to defer TO, and wants "gone when this call returns" semantics). Pass explicitly to override either way.
Safe to call on an already-gone node - whether that's because this same handle's own deferred destroy hasn't run yet, or because the node stopped being realized some other way in the meantime (an ancestor's destroy, or Tk's own doing - e.g. the window manager's close button). Use #configure or another realized-only method instead of #destroy! to actually detect that case; those raise NotRealizedError.
Shorthand for configure(state: :disabled) - greyed out, not interactive/invocable. Raises NotRealizedError before realize.
An ellipse inscribed in the bounding box [x1, y1, x2, y2]. Only valid on a ui.canvas handle.
Shorthand for configure(state: :normal) - Tk's own default state. Raises NotRealizedError before realize.
Every event binding declared on this node so far, in declaration order - on_click/on_key/on_right_click and friends all funnel through here. Meaningful at any phase: before realize these are still queued (nothing wired to Tcl yet), after realize they're the bindings actually in effect.
Release a grab previously taken by #modal. Safe whether or not one was ever held. Only valid on a ui.window handle.
Hide the window again: releases any grab #show took (a no-op if it wasn't modal - grab_release is always safe) and withdraws it. Only valid on a ui.window handle.
A Tk image anchored at [x, y] - which image via image:, named the way every other Tk image option names one:
canvas.image(0, 0, image: photo.name, anchor: :nw)
Takes the image's Tcl name rather than a Tryst::Photo itself, since TclArgValue (what an option value has to be) has no Photo member - Photo#to_s does return the name, so .name and interpolation agree. Only valid on a ui.canvas handle.
Has no counterpart in ruby-tryst's tryst-ui, whose Handle stops at #bitmap: without this there is no way to put a photo on a ui.canvas at all, which rules out anything drawing through Tryst::Photo (a paint layer is a photo canvas item).
A straight line through the given points - [x1, y1, x2, y2, ...], flat or nested, two or more points. Only valid on a ui.canvas handle. Raises ArgumentError if this handle isn't a canvas. Raises NotRealizedError before realize.
Grab all input to this window and focus it - what makes a dialog modal. Release it with #grab_release when the dialog is done; #hide already does. Only valid on a ui.window handle.
The escape hatch for any event the on_* methods above don't curate - a custom virtual event, or a native combo none of them expose. Scoped to this handle's own widget, so no path/target argument is needed the way session.app.bind's would be. event follows the same rules as App#bind: a bare Symbol/Array resolved against Tk's real vocabulary (EventSpec.resolve), or a raw Tk sequence String as its own escape hatch.
Fires when the widget is activated, via Tk's own -command option. Prefer this to #on_click for anything meant to be pressed: -command also fires on keyboard activation of a focused widget (Space on a button), and treats a press dragged off the widget before release as a cancel, where a raw <Button-1> binding has already fired on the way down.
Only for types whose Tk command actually takes -command (see WidgetType#takes_command?) - anything else raises, rather than quietly setting an option Tk will ignore.
Fires on a left click. A literal <Button-1> binding: it fires on the press, wherever the release lands, and never on a keyboard activation - see #on_action for the option most pressable widgets actually want.
ditto, asking for event details alongside it - the same substitutions App#bind takes (:x/:y for widget coordinates, :root_x/:root_y for screen ones, :button, ..., or a raw Tk %-code), arriving in the block's args in the order named.
Without this a click handler knows THAT a click happened and nothing about where, which is unusable on a canvas: one binding on the whole widget plus the coordinates is how a grid of cells gets handled without a callback per cell.
Fires when the window's close button is pressed (titlebar close box, Cmd-W, Alt-F4, ...). tryst's own default - destroy the window
- only applies while nothing else has claimed it, so the block decides whether the window actually closes at all: call #destroy! if that's what you want, or #hide to keep a palette window around for later.
Wired straight away once realized, and queued onto the node otherwise (Realizer picks it up from there), so this reads the same either side of realize - the same before/after pair the other on_* methods here get. Declaring on_close: as a build option does the same thing; this is for setting or replacing one after the fact.
Only valid on a ui.window handle - the root window's own close handler isn't a Handle's to set, since the root has no Handle; reach it through the app instead (session.app.on_close). Raises ArgumentError on any other type.
Fires on a key press. spec is either a friendly Symbol (:enter, :escape, :up, ...) or a "Modifier-Modifier-Key" String ("Ctrl-s", "Ctrl-Shift-s") - see Keysyms.
Fires when the left button is RELEASED. The other half of a press-and-hold interaction: #on_click fires going down, this one coming back up, and only together can a widget offer the classic "drag off before releasing to cancel" behaviour.
ditto, with event substitutions - see #on_click's own overload.
Fires on a right click, however the platform spells it (Button-3 on Linux/Windows, Button-2 or Control-Button-1 on macOS). Handle it yourself with a block, or use the overload below to pop up a menu instead.
ditto, with event substitutions - see #on_click's own overload. Each platform spelling gets the same subs, so a handler reads its coordinates the same way wherever the click came from.
Fires when the selected tab changes (Tk's <<NotebookTabChanged>>). The block is handed the newly selected tab's own name where it has one, and its plain zero-based index where it doesn't - preferring a name over a raw Tk index, the way every other lookup in the DSL does.
Only valid on a ui.tabs handle. Raises ArgumentError otherwise.
What Tk currently thinks this widget's options are right now, straight from a bare configure. Keyed by option name with no leading dash ("text", "state"), values as Tk reports them. Raises NotRealizedError before realize.
This node's live address - the real Tk widget path. Raises NotRealizedError before realize.
A closed shape through the given points - [x1, y1, x2, y2, ...], flat or nested, three or more points. Only valid on a ui.canvas handle.
A rectangle with corners [x1, y1, x2, y2]. Only valid on a ui.canvas handle.
Reveal a declared window (they're created withdrawn - see widget_types/window.cr): positions it just clear of the parent it's nested under, deiconifies, raises it to the front, and - only if it was declared modal: true - grabs input and focuses it via #modal. Only valid on a ui.window handle. Raises ArgumentError otherwise, NotRealizedError before realize.
A handle onto whatever items currently carry tag - zero, one, or many (see CanvasItem, which addresses a tag and an id identically). Doesn't create anything; a shape-creation method (e.g. #line) already returns a single-item handle for its own new item - this is for addressing a shared tags: group (or reaching an item by an id you already have) after the fact. Only valid on a ui.canvas handle.
This widget's content API - insert/get/delete, named formats, markers, search, embedded images. See TextContent for the whole surface. Only valid on a ui.text_area handle.
realized.path, so a text_area wrapped in its own scrollbar hands back the text widget rather than the wrapper frame around it.