Class rtk.Widget

Base class for all widgets. Not intended to be directly used, but rather subclassed to create specific widgets. However all widgets provide at least this interface.

Alignment Constants

Used with the halign and valign fields to control horizontal and vertical alignment of a widget's contents within its own box.

Lowercase strings of these constants can be used for convenience (e.g. 'center' instead of rtk.Widget.CENTER). These strings, noted in the middle columns below, are automatically converted to the appropriate numeric constants.

rtk.Widget.LEFT

'left'

Align contents to widget's left edge (for halign)

rtk.Widget.TOP

'top'

Align contents to widget's top edge (for valign)

rtk.Widget.CENTER

'center'

Center align contents within widget boundary (used for both valign and halign)

rtk.Widget.RIGHT

'right'

Align contents to widget's right edge (for halign)

rtk.Widget.BOTTOM

'bottom'

Align contents to widget's bottom edge (for valign)

Position Constants

Used with the position field to control how containers will position and scroll widgets in relation to other widgets in the window.

Lowercase strings of these constants can be used, e.g. 'relative' instead of rtk.Widget.RELATIVE, or 'fixed-flow' instead of rtk.Widget.FIXED_FLOW. These strings are automatically converted to the appropriate numeric constants.

Like CSS

If you're familiar with the position property in CSS, your intuitions here should mostly apply.

rtk.Widget.RELATIVE

'relative'

Widget is positioned normally by its parent container and respects the widget's x and y coordinates, and scrolls within any viewport it belongs to.

Widgets with non-zero x and y coordinates modify their drawing position relative to their parent but don't affect layout relative to siblings. For example, a widget in an rtk.VBox with y=50 will spill into its siblings' space, while the overall VBox layout is unchanged.

If you do want to modify the widget's position and also affect sibling layout, use margin or container cell padding (they are equivalent) instead of the x and y attributes.

rtk.Widget.ABSOLUTE

'absolute'

Widget is positioned normally by its parent container and respects the widget's x and y coordinates, but no space is created for the widget in the container layout (which applies to containers that arrange children relative to one another like rtk.Box, but not rtk.Container which treats each child independently). This means that in boxes, the sibling immediately following will share the same position and overlap.

z order across siblings in a box container is respected, so it's possible to draw an absolute positioned widget above or below its siblings.

rtk.Widget.FIXED

'fixed'

Widget is positioned initially according to absolute positioning, but then is fixed on the screen even as the parent viewport is scrolled. As with absolute positioning, z order between siblings applies.

Note that if a fixed widget is a child of a non-fixed container and that container scrolls out of view, the fixed widget will not be drawn.

rtk.Widget.FIXED_FLOW

'fixed-flow'

Like FIXED but the dimensions of the widget are incorporated in the overall flow of the parent container.

Scalability Constants

Used with the scalability field to control how the widget should respond to changes to the global scale level.

Lowercase strings of these constants can be used (e.g. 'box' instead of rtk.Widget.BOX). These strings are automatically converted to the appropriate numeric constants.

rtk.Widget.BOX

'box'

Scales box model properties (padding, margin, etc) as well as the inner contents (e.g. images and font sizes) of the widget, but fixed dimensions are not scaled.

rtk.Widget.FULL

'full'

Everything from BOX, plus user-specified static widget and height will also be scaled. Fractional relative dimensions (e.g. 0.5) are not however scaled. This allows a fixed-dimension widget to scale up and down with rtk.scale.

This is the default scalability of all widgets.

Reflow Constants

Used with attr() and queue_reflow() to influence reflow behavior.

A reflow is the process of calculating the geometry of one or more widgets within the window. See reflow() for more explanation.

rtk.Widget.REFLOW_DEFAULT

Use a sensible default, which is further described by the individual methods using these constants.

rtk.Widget.REFLOW_NONE

Do not perform any reflow at all, regardless of whether the default behavior would have performed one.

rtk.Widget.REFLOW_PARTIAL

Only do a partial reflow, which means only the specific widget in question will be reflowed, not the entire window. This is done when the widget's own size won't change, but it may need to rearrange the contents within it. For example, changing halign doesn't affect the widget's box but may affect where internal contents are positioned, so a partial reflow is needed.

rtk.Widget.REFLOW_FULL

Recalculate the geometry of all visible widgets in the window. This includes widgets that are offscreen (for example in a viewport below the fold): unless visible is false, they will be reflowed. This is the most expensive type of reflow.

Widget Attributes

The appearance and behavior of widgets in rtk is managed mostly through attributes. Attributes are special fields in widgets that, apart from the attribute values themselves, carry associated metadata, such as details about what should happen internally when the attribute is updated, or how it should be animated. (These are largely internal details but you can read more about how rtk.Attribute works.)

Attributes that are read/write can be set to influence appearance or behavior, while read-only attributes are only a reflection of current state.

The proper way to set an attribute is via the attr() method that is provided by the base rtk.Widget class.

local button = container:add(rtk.Button{'Nuke it from orbit'})
-- After 0.5 seconds, this changes the button color attribute to red,
-- and modifies the label.
rtk.callafter(1.5, function()
   button:attr('color', 'red')
   button:attr('label', "It's the only way to be sure")
end)

Reading back attributes that you previously set is just a matter of access the attribute field directly on the widget. Following the above example:

-- This will display 'red' from above
log.info('Button color is: %s', button.color)
-- This will display "It's the only way to be sure" (again from above)
log.info('Button label is: %s', button.label)

Calculated Attributes

When you set the value of a read/write attribute, it is ultimately translated into a low-level calculated value. These calculated values can be fetched via the calc() method. In the above code example:

-- This returns the 4-element {r,g,b,a} table holding the calculated color
-- used internally during drawing.
local c = button:calc('color')
log.info('Calculated color table: %s', table.tostring(c))

Similarly, if you set halign='center' the stringified value of the alignment constant is translated to rtk.Widget.CENTER, which would be returned by widget:calc('halign'). Or, suppose you set w=0.5 to assign a 50% relative width to the widget (more on that later), then once the widget reflows widget:calc('w') will return the calculated width in pixels.

In most cases the value you store in the attribute -- what rtk calls the exterior value -- remains the way you set it, and rtk internally uses the calculated variants. However, whenever a user interacts with a widget in that affects an attribute, the new value is synced back to both the calculated value and the exterior value. For example, rtk.Entry.caret is modified when the user moves where the caret is positioned. Or rtk.Window.w is updated when the user resizes the width of the window.

Geometry and Positioning Attributes

Positioning widgets on the screen in rtk is done by adding widgets to containers. There are different containers that provide varying types of layouts. You generally want to let the container dictate the widget's positioning, but you can define it more explicitly if you need to.

x and y coordinates are relative to the parent container and can be negative. If you're familiar with HTML, this is equivalent to position: relative in CSS. These coordinates don't affect the layout of the parent container at all, nor do they affect the geometry of any siblings in the same container, but rather they only affect this widget's position relative to where the parent container would have normally placed it.

Consequently, in boxes, setting x/y coordinates on a widget can cause it to shift into the cells of siblings (or even outside the container's own box). Sometimes this is what you want, for example to produce certain effects, but usually not. However for the base rtk.Containers, since this simple type of container doesn't impose any positioning on its children, it makes more sense to specify x/y, although they are usually combined with halign and valign cell attributes. For example, you might set the widget to x=-20 and then add it to an rtk.Container with a cell attribute of halign='right' in which case it will cause the right edge of the widget to be positioned 20 pixels from the right edge of its parent container.

But even in the above example, it's more idiomatic to use an rpadding=20 cell attribute in combination with halign='right' and leave the widget's x attribute at 0.

All that's to say, you almost never need or want to specify x or y. You can, but there are probably more robust and more readable positioning options by combining container cell alignment with cell padding. (Because remember that x and y do not affect the position of siblings in the same container, whereas cell padding does.) See rtk.Container for more on cell attributes.

Width and height are unspecified by default, which means they will choose an appropriate size based on the parent-supplied bounding box, and the widget's natural desired size (called the intrinsic size).

If w and h are between 0.0 and 1.0 or negative, they are relative sizes. If between 0.0 and 1.0, they indicate a fraction of the bounding box imposed by our parent. For example, w=0.6 means 60% of the parent-specified bounding box. If they're negative, then they are relative to the far edge of the bounding box, so e.g. w=-50 means the widget will extend to 50px left of the right edge of the bounding box.

When using relative sizes in widgets placed within an rtk.Viewport, the size will be relative to viewport's bounding box even though the widget may technically be allowed an unconstrained size (if the viewport can scroll in that direction). For example, if an rtk.VBox called "box" is the immediate child of a viewport, you could do box:add(rtk.Button{w=0.8}, {halign='center'}) which would create a button 80% of the viewport's width and center-align it within the viewport's bounding box. Meanwhile, box:add(rtk.Button{w=800}) would add a button with a fixed width of 800 pixels, which may require scrolling the viewport horizontally to see it all.

The geometry attributes mentioned above all have read-only calculated variants as determined by rtk.Widget:reflow() stored in the calc table, which indicate the final geometry of the widget relative to its parent container's outer (border) coordinates. This includes padding per the border-box style box model (see padding).

So for example if w=nil, after the window is reflowed, calc.w will hold the final calculated width in pixels, at least until the next reflow. These calculated values are guaranteed never to be nil when the widget has been realized.

Synopsis

Attributes
x number

read/write

Left position of widget relative to parent in pixels (default 0)

y number

read/write

Top position of widget relative to parent in pixels (default 0)

w number or nil

read/write

Width of widget in pixels, or as a fraction of parent's width (default nil)

h number or nil

read/write

Like w but for widget height (default nil)

z number

read/write

The z-index, or "stack level" that defines what the order the widget will be drawn in relation to its immediate siblings (default 0)

minw number or nil

read/write

The minimum width in pixels the widget is allowed to have, or nil for no minimum (default nil)

minh number or nil

read/write

Like minw but for height (default nil)

maxw number or nil

read/write

The maximum width in pixels the widget is allowed to have, or nil for no maximum (default nil)

maxh number or nil

read/write

Like maxw but for height (default nil)

halign alignmentconst

read/write

Horizontal alignment of contents within the widget's calculated width (default LEFT)

valign alignmentconst

read/write

Vertical alignment of contents within the widget's calculated height (default TOP)

scalability scaleconst

read/write

A bitmap of scale constants that defines how the widget will behave with respect to rtk.scale (default FULL)

position positionconst

read/write

Controls how the widget reacts when the parent viewport is scrolled (default RELATIVE)

box table

read-only

Bounding box geometry supplied from parent on last reflow()

offx number

read-only

The x coordinate within our drawing target that we should offset our position as requested by our parent container in its last invocation of draw

offy number

read-only

Like offx but for the y coordinate

clientx number

read-only

The x client coordinate of the widget as of last draw

clienty number

read-only

Like clientx but for the y coordinate

rtk.Widget.x number read/write

Left position of widget relative to parent in pixels (default 0)

rtk.Widget.y number read/write

Top position of widget relative to parent in pixels (default 0)

rtk.Widget.w number or nil read/write

Width of widget in pixels, or as a fraction of parent's width (default nil). Where:

  • values between 0.0 and 1.0 (inclusive) are considered a ratio of the parent width
  • negative values are relative to the right edge of the parent
  • while nil means widget does not define a width and will use its intrisic width (up to the parent-imposed width).

Because 1.0 means 100% of the parent's width it does mean that you can't explicitly specify a widget width of 1px. If you think you need to do this, you're probably doing something wrong. But if for some reason you desperately need a widget 1px in size, you can use 1.01 as the value. It will get rounded down to 1 pixel during rendering.

This attribute is animatable, where animating toward relative sizes (0.0 - 1.0) or nil (intrinsic size) is supported.

The calculated value (widget:calc('w')) is also adjusted to account for rtk.scale, provided the scalability attribute is set to FULL (as is the default).

rtk.Widget.h number or nil read/write

Like w but for widget height (default nil)

rtk.Widget.z number read/write

The z-index, or "stack level" that defines what the order the widget will be drawn in relation to its immediate siblings (default 0). Widgets with a higher z-index will be drawn after lower z-index widgets (and therefore appear above them), and their events will be handled before lower z-index widgets.

rtk.Widget.minw number or nil read/write

The minimum width in pixels the widget is allowed to have, or nil for no minimum (default nil). When this is specified, the widget will disregard any bounding box contraints by its parent, causing the parent container to overflow its own bounding box if necessary, which may result in needing to scroll if within an rtk.Viewport.

rtk.Widget.minh number or nil read/write

Like minw but for height (default nil)

rtk.Widget.maxw number or nil read/write

The maximum width in pixels the widget is allowed to have, or nil for no maximum (default nil). This will constrain a widget's width if it is added to a container with the fillw=true cell attribute, or if the widget has a relative width (e.g. w=0.5). In either case the widget will not exceed maxw.

rtk.Widget.maxh number or nil read/write

Like maxw but for height (default nil)

rtk.Widget.halign alignmentconst read/write

Horizontal alignment of contents within the widget's calculated width (default LEFT). See alignment constants.

rtk.Widget.valign alignmentconst read/write

Vertical alignment of contents within the widget's calculated height (default TOP). See alignment constants.

rtk.Widget.scalability scaleconst read/write

A bitmap of scale constants that defines how the widget will behave with respect to rtk.scale (default FULL). See scalability constants.

rtk.Widget.position positionconst read/write

Controls how the widget reacts when the parent viewport is scrolled (default RELATIVE). See position constants.

rtk.Widget.box table read-only

Bounding box geometry supplied from parent on last reflow(). Primarily maintained so that reflow() can be called without any arguments and still produce a useful result. The fields of this table correspond exactly to reflow()'s arguments.

rtk.Widget.offx number read-only

The x coordinate within our drawing target that we should offset our position as requested by our parent container in its last invocation of draw.

If the child is parented within a rtk.Viewport, this will not represent client coordinates. For client coordinates, use clientx instead.

rtk.Widget.offy number read-only

Like offx but for the y coordinate

rtk.Widget.clientx number read-only

The x client coordinate of the widget as of last draw. Client coordinates are always relative to the window (where the window's top-left point is 0,0), regardless of whether the widget is within a viewport.

Client coordinates are used when interacting with the mouse: the widget might be placed at the very end of a 5000px height container, but if the viewport holding that container is scrolled down such that the widget is at the very top of the screen, its clienty coordinate will be 0.

Another use case is when popping up an OS-native context menu (rtk.NativeMenu), where we want the menu to popup relative to the widget's current position on screen.

rtk.Widget.clienty number read-only

Like clientx but for the y coordinate

Box Model Attributes

rtk's box model allows defining margin, border, and padding around the inner content of all widgets. When the widget's dimensions aren't explicitly defined, its intrinsic size will include padding and border, in addition to the widget's internal content.

Similar to CSS

If you're familiar with web design, rtk's notion of inner content, padding, border, and margin are the same as CSS's box model, specifically the border-box box sizing model where padding and border sizes are included in the widget's dimensions. That is, if either w or h attributes are specified, then it implicitly includes padding and border (but not margin), and the inner content will shrink accordingly.

Widget padding affects the amount of space between the widget's border (based on its own dimensions) and its internal content. For example, an rtk.Button with a padding of 10px and no explicit dimensions (i.e. it will use its intrinsic size) will ensure the width and height of the button surface fits its icon and/or label with a 10px gap to the button's edges.

Meanwhile, margin affects the amount of space around the widget's own box. It is used by parent containers to determine how to place the widget within a container cell. Widget margin is exactly equivalent to cell padding which can be specified when you add the widget to a container. In fact, if both margin and cell padding are defined, they sum together during layout. See here for more on cell attributes.

Synopsis

Attributes
padding number, table or string

read/write

Shorthand to set padding on all 4 sides of the widget at once (default 0)

tpadding number

read/write

Top padding in pixels; if specified, overrides padding for the top edge (default 0)

rpadding number

read/write

Right padding in pixels; if specified, overrides padding for the right edge (default 0)

bpadding number

read/write

Bottom padding in pixels; if specified, overrides padding for the bottom edge (default 0)

lpadding number

read/write

Left padding in pixels; if specified, overrides padding for the left edge (default 0)

margin number, table or string

read/write

Shorthand to set margin on all 4 sides of the widget at once (default 0)

tmargin number

read/write

Top margin in pixels; if specified, overrides margin for the top edge (default 0)

rmargin number

read/write

Right margin in pixels; if specified, overrides margin for the right edge (default 0)

bmargin number

read/write

Bottom margin in pixels; if specified, overrides margin for the bottom edge (default 0)

lmargin number

read/write

Left margin in pixels; if specified, overrides margin for the left edge (default 0)

border table or string

read/write

Border to be drawn around the widget's box (default nil)

tborder table or string

read/write

Top border; if specified overrides border for the top edge (default nil)

rborder table or string

read/write

Right border; if specified overrides border for the right edge (default nil)

bborder table or string

read/write

Bottom border; if specified overrides border for the bottom edge (default nil)

lborder table or string

read/write

Left border; if specified overrides border for the left edge (default nil)

rtk.Widget.padding number, table or string read/write

Shorthand to set padding on all 4 sides of the widget at once (default 0).

Like CSS, this can be a string in one of these forms:

  1. '5px' - padding of 5 pixels on all sides
  2. '10px 5px' - padding of 10 pixels on top and bottom, and 5 pixels on left and right
  3. '10px 5px 15px' - top, horizontal (left/right), and bottom padding
  4. '5px 10px 2px 4px' - top, right, bottom, left

Alternatively, a table of 1 to 4 numeric values can be passed as well, with the same element ordering as above for strings.

Supported units

The "px" unit suffix is optional. Pixels are assumed and no other unit is currently supported. Other units may be supported in the future.

rtk.Widget.tpadding number read/write

Top padding in pixels; if specified, overrides padding for the top edge (default 0). Must be numeric.

rtk.Widget.rpadding number read/write

Right padding in pixels; if specified, overrides padding for the right edge (default 0). Must be numeric.

rtk.Widget.bpadding number read/write

Bottom padding in pixels; if specified, overrides padding for the bottom edge (default 0). Must be numeric.

rtk.Widget.lpadding number read/write

Left padding in pixels; if specified, overrides padding for the left edge (default 0). Must be numeric.

rtk.Widget.margin number, table or string read/write

Shorthand to set margin on all 4 sides of the widget at once (default 0). The format is the same as for padding.

rtk.Widget.tmargin number read/write

Top margin in pixels; if specified, overrides margin for the top edge (default 0). Must be numeric.

rtk.Widget.rmargin number read/write

Right margin in pixels; if specified, overrides margin for the right edge (default 0). Must be numeric.

rtk.Widget.bmargin number read/write

Bottom margin in pixels; if specified, overrides margin for the bottom edge (default 0). Must be numeric.

rtk.Widget.lmargin number read/write

Left margin in pixels; if specified, overrides margin for the left edge (default 0). Must be numeric.

rtk.Widget.border table or string read/write

Border to be drawn around the widget's box (default nil). Borders can be defined as a CSS-like string that takes border width and/or color (e.g. '1px #ff0000' or '#ffff00') or a 2-element table holding {color, numeric width}.

rtk.Widget.tborder table or string read/write

Top border; if specified overrides border for the top edge (default nil).

rtk.Widget.rborder table or string read/write

Right border; if specified overrides border for the right edge (default nil).

rtk.Widget.bborder table or string read/write

Bottom border; if specified overrides border for the bottom edge (default nil).

rtk.Widget.lborder table or string read/write

Left border; if specified overrides border for the left edge (default nil).

Appearance and Behavior Attributes

Synopsis

Attributes
visible boolean

read/write

Indicates whether the widget should be rendered by its parent (default true)

disabled boolean

read/write

If true and the widget is interactive, it will not respond to user input and render itself in a way to indicate it's inert (usually with a lower opacity) (default false)

ghost boolean

read/write

A ghost widget is one that takes up space in terms of layout and will have its geometry calculated in reflow() but is otherwise not drawn (default false)

tooltip string

read/write

A tooltip that pops up when the mouse hovers over the widget and remains still for rtk.tooltip_delay seconds

cursor cursorconst or nil

read/write

The mouse cursor to display when the mouse is within the widget's region (i.e. mouseover is true)

alpha number

read/write

Alpha channel (opacity) level of this widget from 0.0 to 1.0 (default 1.0)

autofocus boolean or nil

read/write

Whether the widget is allowed to automatically receive focus in response to a mouse button pressed event (default nil)

bg colortype or nil

read/write

The widget's background color (semantics vary by widget) or nil to have no background color (default nil)

hotzone number, table or string

read/write

Shorthand to set the extended "hot zone" on all 4 sides of the widget at once (default 0)

thotzone number

read/write

Top hot zone extension in pixels; if specified, overrides hotzone for the top edge (default 0)

rhotzone number

read/write

Right hot zone extension in pixels; if specified, overrides hotzone for the right edge (default 0)

bhotzone number

read/write

Bottom hot zone extension in pixels; if specified, overrides hotzone for the bottom edge (default 0)

lhotzone number

read/write

Left hot zone extension in pixels; if specified, overrides hotzone for the left edge (default 0)

scroll_on_drag boolean

read/write

If true, dragging this widget will cause the parent rtk.Viewport (if any) to scroll when the mouse is click-dragged against the viewport's edge (default true)

show_scrollbar_on_drag boolean

read/write

If true, dragging this widget will cause the parent rtk.Viewport (if any) to display the scrollbar while the child is dragging, even if the viewport's scrollbar mode would normally have it hidden

touch_activate_delay number

read/write

The amount of time in seconds a mouse button must be pressed and held over the widget before onmousedown() is fired, and before ondragstart() is eligible to be fired, where nil is adaptive based on the current value of rtk.touchscroll (default nil)

realized boolean

read-only

True if the widget is ready for _draw(), and also ready to handle events (i.e. it is initialized and reflowed and its geometry is fully known)

drawn boolean

read-only

True if the widget was drawn (which also implies both realized and visible)

viewport rtk.Viewport

read-only

The widget's closest ancestor viewport as of last reflow, which is nil if there is no containing viewport

window rtk.Window

read-only

The rtk.Window the widget belongs to as of the last reflow

mouseover boolean

read-only

Set to true if the mouse is within the widget's region (which is extended according to hotzone) and not occluded by a higher z-index widget, and false otherwise

hovering boolean

read-only

Set to true if the mouse is within the widget's region (extended according to hotzone) and if onmouseenter() had returned a non-false value

rtk.Widget.visible boolean read/write

Indicates whether the widget should be rendered by its parent (default true). If false, this is equivlent to CSS's display:none where it is not considered as part of layout during reflow(). Parent containers will not attempt to draw invisible widgets.

rtk.Widget.disabled boolean read/write

If true and the widget is interactive, it will not respond to user input and render itself in a way to indicate it's inert (usually with a lower opacity) (default false).

rtk.Widget.ghost boolean read/write

A ghost widget is one that takes up space in terms of layout and will have its geometry calculated in reflow() but is otherwise not drawn (default false). This is similar to CSS's visibility:hidden. Also, unlike visible=false, parent containers will invoke the draw method on ghost widgets, allowing them to implement a specific visual, but most of the time drawing ghost widgets simply returns as a no-op.

rtk.Widget.tooltip string read/write

A tooltip that pops up when the mouse hovers over the widget and remains still for rtk.tooltip_delay seconds. The tooltip is styled according to the current theme. Explicit newlines are supported, and the tooltip will be wrapped if necessary to fit within the window.

rtk.Widget.cursor cursorconst or nil read/write

The mouse cursor to display when the mouse is within the widget's region (i.e. mouseover is true). If nil, the default window cursor is used.

rtk.Widget.alpha number read/write

Alpha channel (opacity) level of this widget from 0.0 to 1.0 (default 1.0)

rtk.Widget.autofocus boolean or nil read/write

Whether the widget is allowed to automatically receive focus in response to a mouse button pressed event (default nil). When nil, autofocus will not occur unless you have attached a custom onclick handler to the widget, in which case it assume autofocus behavior in order to ensure the onclick handler fires. If this attribute is explicitly false, then it will never autofocus regardless of whether there's a custom onclick handler.

rtk.Widget.bg colortype or nil read/write

The widget's background color (semantics vary by widget) or nil to have no background color (default nil)

rtk.Widget.hotzone number, table or string read/write

Shorthand to set the extended "hot zone" on all 4 sides of the widget at once (default 0).

The hot zone defines an extended area around the widget's natural boundary where mouseover events and clicks will be recognized, allowing you to extend the interactable area of a widget beyond what it visually depicts. This can be useful when constructing a rtk.Box with spacing between cells, but you want the widgets occupying those cells to be clickable even within the inter-cell spacing. Another use case is extending the area that small widgets can be clicked, improving the UX for touch devices.

The hot zone defines an extension relative to the widget's normal size, so, for example, a value of 5 will extend the clickable area 5 pixels beyond the widget's edge.

The format of this attribute is the same as margin and padding.

Supported units

The "px" unit suffix is optional. Pixels are assumed and no other unit is currently supported. Other units may be supported in the future.

rtk.Widget.thotzone number read/write

Top hot zone extension in pixels; if specified, overrides hotzone for the top edge (default 0). Must be numeric.

rtk.Widget.rhotzone number read/write

Right hot zone extension in pixels; if specified, overrides hotzone for the right edge (default 0). Must be numeric.

rtk.Widget.bhotzone number read/write

Bottom hot zone extension in pixels; if specified, overrides hotzone for the bottom edge (default 0). Must be numeric.

rtk.Widget.lhotzone number read/write

Left hot zone extension in pixels; if specified, overrides hotzone for the left edge (default 0). Must be numeric.

rtk.Widget.scroll_on_drag boolean read/write

If true, dragging this widget will cause the parent rtk.Viewport (if any) to scroll when the mouse is click-dragged against the viewport's edge (default true).

rtk.Widget.show_scrollbar_on_drag boolean read/write

If true, dragging this widget will cause the parent rtk.Viewport (if any) to display the scrollbar while the child is dragging, even if the viewport's scrollbar mode would normally have it hidden. (default true)

rtk.Widget.touch_activate_delay number read/write

The amount of time in seconds a mouse button must be pressed and held over the widget before onmousedown() is fired, and before ondragstart() is eligible to be fired, where nil is adaptive based on the current value of rtk.touchscroll (default nil).

When rtk.touchscroll is false, touch_activate_delay is effectively 0 (i.e. onmousedown() is invoked immediately when the mouse button is pressed), however when touch scrolling is enabled the default is rtk.touch_activate_delay, except for rtk.Viewport where the default is 0ms in order to respond to touch-scrolling.

rtk.Widget.realized boolean read-only

True if the widget is ready for _draw(), and also ready to handle events (i.e. it is initialized and reflowed and its geometry is fully known)

rtk.Widget.drawn boolean read-only

True if the widget was drawn (which also implies both realized and visible)

rtk.Widget.viewport rtk.Viewport read-only

The widget's closest ancestor viewport as of last reflow, which is nil if there is no containing viewport

rtk.Widget.window rtk.Window read-only

The rtk.Window the widget belongs to as of the last reflow. It is safe to assume this is set in rtk.Widget._draw() and event handlers.

rtk.Widget.mouseover boolean read-only

Set to true if the mouse is within the widget's region (which is extended according to hotzone) and not occluded by a higher z-index widget, and false otherwise.

rtk.Widget.hovering boolean read-only

Set to true if the mouse is within the widget's region (extended according to hotzone) and if onmouseenter() had returned a non-false value. The semantics of "hovering" is that the widget is interactive and responsive to the mouse entering the widget's geometry, and so the return value of onmouseenter() indicates this interactivity.

Normally hovering implies mouseover, but one exception is that if the widget is being dragged and the mouse is outside the widget's current region, hovering could be true even while mouseover is false.

Other Attributes

Synopsis

Attributes
debug boolean

read/write

If true, a translucent box will be drawn over the widget visually indicating the widget's geometry and padding, which is useful for debugging layout (default false)

id string

read-only

An automatically generated identifier for the widget, which is guaranteed to be unique across the life of the program and will not be reused

ref string

read/write-once

A name for this widget that can be accessed via the refs table (default nil)

refs table

read-only

A table through which widget ref names can be dynamically accessed

rtk.Widget.debug boolean read/write

If true, a translucent box will be drawn over the widget visually indicating the widget's geometry and padding, which is useful for debugging layout (default false).

rtk.Widget.id string read-only

An automatically generated identifier for the widget, which is guaranteed to be unique across the life of the program and will not be reused. Widgets will get the same id assigned between program executions as long as the overall scene graph doesn't change.

The value currently happens to be a stringified numeric value, but this may change in the future and should not be assumed by applications. Treat this value as an opaque string.

rtk.Widget.ref string read/write-once

A name for this widget that can be accessed via the refs table (default nil).

Note that once the ref name is set it cannot be changed.

rtk.Widget.refs table read-only

A table through which widget ref names can be dynamically accessed.

ref names are resolved based on fellow children (or grandchildren) of the widget's parent container(s). For example, given self.refs.foo, whichever child (however nested) of the parent container has the ref name foo will be returned. If there's no match, the parent's parent is consulted, and so on up the widget hierarchy.

local box = rtk.HBox{
    valign='center', spacing=10,
    -- Use the ref name 'label' for later access
    rtk.Text{w=40, ref='label'},
    rtk.Slider{
        onchange=function(self)
            -- Fetch the label via its ref name in order to update it.
            self.refs.label:attr('text', self.value)
        end
    },
}
window:add(box)

Ref names don't need to be globally unique: the context of which widget's refs table is being accessed dicates how the name is resolved. If you try to access an ambiguous ref name -- that is, the nearest parent container which knows about the ref name actually has multiple child descendents with the same ref name -- you can't be sure which widget you'll get (and in fact you may not get any at all). The specific behavior in this case is undefined. So just make sure that when you access a ref name via a widget's refs table, there is a level at or above the widget where there is only one such ref name.

Resolving references generally requires both the widget whose refs table is being accessed and the widget being looked up to be nested somewhere under the same container. It is possible to resolve an unparented reference as there is a last-ditch global lookup table that's consulted, but in this case global uniqueness of the ref name is required.

Because accessing fields on this table involves an upward traversal of the widget's parent hierarchy, there is a cost in accessing distant refs compared to standard Lua table accesses. Consequently, if repeatedly accessing a distant ref, you may want to assign it to a temporary local variable first.

Refs are weak, which means that in order to access a widget by its ref name there must be some other reference to the widget object in Lua. Any widget added to a container widget is covered (provided a reference to the container itself exists, of course). Once the Lua garbage collector frees a widget, it can no longer be accessed by its ref name.

Public Methods

These methods are intended to be used to control rtk's built-in widgets, in contrast to the subclass API which is used to implement custom widgets.

Synopsis

Methods
attr()

Set an attribute on the widget to the given value

calc()

Returns the calculated value of the given attribute

move()

Moves the widget to explicit coordinates relative to its parent

resize()

Resizes the widget

scrolltoview()

Ensures the widget is fully visible within its rtk.Viewport

hide()

Hides the widget, removing it from the layout flow and not drawing it

show()

Shows the widget after it was hidden

toggle()

Toggles the widget's visibility

focused()

Check if the widget currently has focus

focus()

Makes the widget focused

blur()

Removes focus from the widget

animate()

Begin an animation against one of the widget's attributes

cancel_animation()

Cancels any ongoing animation for the given attribute

get_animation()

Gets the current ongoing animation for the given attribute, if any

setcolor()

Sets the graphic context to the given color while respecting the widget's alpha

queue_draw()

Requests a full redraw from the widget's rtk.Window on next update

queue_reflow()

Requests a reflow by the widget's rtk.Window on next update

reflow()

Calculates and returns the widget's geometry given the bounding box

rtk.Widget:attr(attr, value, trigger, reflow)

Set an attribute on the widget to the given value.

This method is the proper way to dynamically modify any of the widget's fields to ensure they are properly reflected. In most cases the value is immediately calculated and the calculated form is accessible via the calc() method. (The exception is attributes that depend on parent geometry, in which case the value will not be calculated until next reflow.)

Setting a different value will cause the onattr handler to fire, in addition to any other widget-specific handlers if applicable (for example onchange if setting the selected attribute on a rtk.OptionMenu). However if the given value is the same as the current value, this will be a no-op unless trigger is true, in which case all the event handlers associated with attr are forced and will fire whether or not the value changed.

Meanwhile, setting trigger to false will suppress event handlers (except for onattr which always fires if the value has changed), which can be useful if setting the attribute in another on* handler to prevent circular calls.

Parameters
attr (string)

the attribute name

value (any)

the target value for the attribute. A special value rtk.Attribute.DEFAULT restores the attribute to rtk's built-in default.

trigger (bool or nil)

if false, event handlers that would normally fire will be suppressed even if the value changed (except for onattr which is always fired if the value changes); conversely, if true, all handlers will fire even if the value hasn't changed. If nil, the default behavior will be used, which is typically that handlers will only fire if the value changed (unless indicated otherwise by the event handler's documentation).

reflow (reflowconst or nil)

controls how the widget should be reflowed after the attribute is set. If nil, then REFLOW_DEFAULT is used, where either a partial reflow or a full reflow will be performed, depending on what is appropriate for attr. Most of the time you want to leave this as nil, but if you're changing an attribute that normally affects geometry but, due to external constraints the widget may not know about, the geometry actually can't change as a result of modifying this attribute, passing false here will nontrivially improve performance as the costly reflow can be avoided.

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:calc(attr, instant)

Returns the calculated value of the given attribute.

Calculated attributes have been parsed and transformed into efficient values that are used for internal operations.

local b = rtk.Button{"Don't Panic", halign='right', padding='10px 30px'}
log.info('halign=%s is calculated as %s', b.halign, b:calc('halign'))
log.info('padding=%s is calculated as %s', b.padding, table.tostring(b:calc('padding')))
b:attr('color', 'indigo')
log.info('color=%s is calculated as %s', b.color, table.tostring(b:calc('color')))

The above example outputs something along these lines:

17:32:30.292 [INFO]  halign=right is calculated as 2
17:32:30.292 [INFO]  padding=10px 30px is calculated as {10,30,10,30}
17:32:30.292 [INFO]  color=indigo is calculated as {0.29411764705882,0.0,0.50980392156863,1}
Calculated Geometry

In the example above, the calculated attributes were all available immediately after setting, but most attributes related to geometry first require a reflow() before they're available. Consider:

local text = rtk.Text{"They've gone to plaid!", wrap=true}
-- What should this output?
log.info('calculated width is %s', text:calc('w'))

Here the size of the rtk.Text widget depends on its bounding box, but it hasn't been added to a container yet, and even if it were, that container may not yet have been added to its own container yet, and so on, until this rtk.Text widget ultimately descends from rtk.Window. So widget geometry is not calculated until reflow has occurred. It is always safe to access in drawing handlers, however.

More on attributes here.

Note that calc can also be accessed as a table. For example, instead of widget:calc('attr') you can access widget.calc.attr. This means of access is much faster as it bypasses the abstractions provided when invoking as a method, but is also more limited: attribute getters are not taken into account, and the table value is always the current point-in-time value of an attribute being animated.

Due to the significant performance benefit which can be useful in certain cases, table access is a supported API, but be aware of its limitations. When in doubt, invoke calc() as a method.

Parameters
attr (string)

the name of the attribute whose calculated value to return

instant (bool or nil)

if true, the point-in-time calculated value of the attribute is returned even if it's in the middle of an animation. False (or nil) will return the ultimate target value of the attribute if it's animating.

Return Values
(any)

the target value of the attribute if animating, or current value otherwise

rtk.Widget:move(x, y)

Moves the widget to explicit coordinates relative to its parent.

This is just a shorthand for calling attr() on the x and y attributes.

Parameters
x (number)

the x position relative to parent in pixels

y (number)

the y position relative to parent in pixels

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:resize(w, h)

Resizes the widget.

This is just a shorthand for calling attr() on the w and h attributes, so fractional values (0.0 to 1.0) and negative values can be used for relative sizing, as well as nil to have the widget pick its own size.

Parameters
w (number)

the width of the widget

h (number)

the height of the widget

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:scrolltoview(margin, allowh, allowv, smooth)

Ensures the widget is fully visible within its rtk.Viewport.

If the widget is not placed within a viewport then this function is a no-op.

The margin argument ensure the widget is visible plus the supplied margin as a buffer, depending which direction the viewport is being scrolled.

Example
-- Allow scrolling in any directions with 0 margin.
widget:scrolltoview()

-- Allow scrolling in any direction with a 15 pixel margin if scrolling
-- vertically, and a 10 pixel margin if scrolling horizontally.
widget:scrolltoview{15, 10}

-- Only allow vertical scrolling with a 50 pixel top margin if scrolling
-- up, and a 20 pixel bottom margin if scrolling down.
widget:scrolltoview({50, 0, 20}, false)
Parameters
margin (number, table, string or nil)

amount of space to leave on the side of the widget opposite the direction being scrolled, which takes the same format as the padding attribute. If nil, 0 margin is assumed for all sides.

allowh (bool or nil)

if false, horizontal scrolling will be prevented, otherwise any other value allows it

allowv (bool or nil)

if false, vertical scrolling will be prevented, otherwise any other value allows it

smooth (boolean or nil)

true to force smooth scrolling even if the containing viewport's smoothscroll attribute is false; false to force-disable smooth scrolling even if rtk.Viewport.smoothscroll is true, or nil to use whatever smooth scrolling behavior is default for the viewport (or globally via rtk.smoothscroll).

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:hide()

Hides the widget, removing it from the layout flow and not drawing it.

This is mainly a shorthand for calling attr() on the visible attribute but includes a small optimization, which makes it preferred for performance and readability.

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:show()

Shows the widget after it was hidden.

This is mainly a shorthand for calling attr() on the visible attribute but includes a small optimization, which makes it preferred for performance and readability.

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:toggle()

Toggles the widget's visibility.

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:focused(event)

Check if the widget currently has focus.

This simply just checks is this widget is the same as rtk.focused. In rtk, exactly one (or zero) widgets can grab focus. A container that holds a focused widget is not itself considered focused, but depending on the type of event, it may invoke event handlers for certain events when one of its children has focus.

A widget obtains focus when it is autofocus and the mouse clicks on it (and the widget is using the default onmousedown() handler), or if focus() is explicitly called.

Parameters
event (rtk.Event or nil)

if specified, is the event which will be dispatched to event handlers if this functions returns true. This is ignored by rtk.Widget, but subclasses can override. For example, rtk.Container overrides this and considers itself focused for rtk.Event.KEY events when one of its children has focus.

Return Values
(bool)

true if focused, false otherwise

rtk.Widget:focus(event)

Makes the widget focused.

The semantics of a focused widget varies by subclass. For example, with rtk.Entry it means that the widget will render an accented border, the cursor will blink, and keyboard events will be captured by the widget.

If another widget currently has focus, blur() will be called on it. If that widget's onblur() handler returns false, it will block the focus, in which case this function will return false. This condition is fairly rare but it can occur, for example, when the currently-focused widget is modal.

If the request to blur the currently-focused widget was successful (or there wasn't any focused widget to begin with), then our onfocus() handler is called to determine if focus should be accepted. If that returns anything other than false, focus is accepted. The default implementation is to accept the focus.

Note that the autofocus attribute doesn't come into play here. That attribute controls whether focus occurs on a mouse down, but if focus() is explicitly called on a widget, the only deciding factor is the return value from the onfocus() handler.

Parameters
event (rtk.Event or nil)

when focus() is called as a result of some event (usually a mouse click) then the event should be included here so it can be passed along to the onfocus() handler. But when no event was involved, this argument can be excluded.

Return Values
(bool)

true if the focus succeeded, false otherwise

rtk.Widget:blur(event, other)

Removes focus from the widget.

Our onblur() handler is first called to determine if focus should be relinquished. If that returns anything other than false then focus is surrendered.

Parameters
event (rtk.Event or nil)

when blur() is called as a result of some event, then the event should be included here so it can be passed along to the onblur() handler. When no event was involved, this argument can be excluded

other (rtk.Widget or nil)

when we are being asked to be blurred because some other widget wants focus, then this parameter is set to that other widget

Return Values
(bool)

true if focus was relinquished and the blur succeeded, false otherwise

rtk.Widget:animate(kwargs)

Begin an animation against one of the widget's attributes.

All numeric attributes can be animated, as well as tables containing numeric values. This means that colors can be animated, as colors are calculated as their 4-element rgba values.

All other attributes are animatable only where indicated.

Multiple attributes can be animated in parallel using successive calls to animate().

The argument is a key/value table that describes the animation. Valid fields are as follows, with mandatory fields in bold:

  • attr (string): the name of the attribute to animate. This can optionally be passed as the first positional argument without the need to specify the attr field.
  • dst (number|table|nil): the destination value to animate toward. If nil, 0 is usually assumed, but if attr is w or h then the widget's intrinsic size will be calculated and animated toward. (This also supports fractional values.)
  • src (number|table): the starting value of the attribute. Default is the current attribute's calculated value as the starting value.
  • easing (string): the name of an easing function that controls the contour of the animation.
  • duration (number): the amount of time in seconds the animation should occur over. Fractional values are fine. Default is 0.5. Frame timing isn't guaranteed so the animation not complete in exactly this amount, but the margin of error is typically below 50ms.
  • reflow (reflowconst): by default, a full window reflow() will occur if attr is one that could affect the geometry of the widget, and a partial reflow will be done for all other attributes. Specifying rtk.Widget.REFLOW_FULL here will force a full reflow at each step of the animation; conversely, specifying rtk.Widget.REFLOW_PARTIAL will force a partial reflow even if the attribute is one that would normally warrant a full reflow.

This function returns an rtk.Future so you can attach callbacks to be invoked when the animation is finished (via done()) or when it's cancelled (via cancelled()).

You can also cancel a running animation by calling cancel() on the rtk.Future.

If there is an existing animation for the given attribute, it will be replaced only if the dst value has changed, in which case the animation will be restarted from its current mid-animation value toward the new dst value. If the dst is the same, then the in-flight animation will continue to run without interruption.

During an animation, the attribute's calculated value is updated to reflect each individual step of the animation, and this can be fetched by calling calc() with the instant argument set to true. However, the exterior value -- that is, the direct fields of the widget object, such as button.color or box.alpha -- are not updated during the animation. Exterior attributes are updated either at the start of end of the animation, depending on what makes sense in the context of the attribute.

-- This example causes the button width to animate back and forth between
-- 300px and its intrinsic size with different speeds each time it's clicked.
-- For good measure, we also animate the opacity via the alpha attribute.
button.onclick = function()
   if not button.w then
       -- Use a bouncing effect for the width animation
       button:animate{'w', dst=300, duration=1, easing='out-bounce'}
       button:animate{'alpha', dst=0.5, duration=1}
   else
       button:animate{'w', dst=nil, duration=0.25, easing='out-bounce'}
       button:animate{'alpha', dst=1, duration=0.25}
           :done(function()
               log.info('widget opacity is returned to normal')
           end)
   end
end
Parameters
kwargs (table)

the table describing the animation as above

Return Values
(rtk.Future)

a Future object tracking the state of the asynchronous animation

rtk.Widget:cancel_animation(attr)

Cancels any ongoing animation for the given attribute.

If there are no animations currently running for the attribute, then this function is a no-op.

You can also call cancel() on the rtk.Future returned by animate() but if you don't have a reference to the rtk.Future you can call this function.

Parameters
attr (string)

the attribute name to stop animating

Return Values
(table or nil)

nil if no animation was cancelled, otherwise it's the animation state table (see get_animation()).

rtk.Widget:get_animation(attr)

Gets the current ongoing animation for the given attribute, if any.

This can also be used to easily test if the attribute is currently animating, as the return value's truthiness behaves like a boolean.

Parameters
attr (string)

the attribute name to check if animating

Return Values
(table or nil)

nil if no animation is running for the attribute, otherwise it's a table containing the current animation state, which includes everything passed to animate() (including any user-custom keys).

rtk.Widget:setcolor(color, amul)

Sets the graphic context to the given color while respecting the widget's alpha.

This is considered a low-level function but is useful when implementing custom widget drawing under/overlays via ondrawpre() and ondraw().

See rtk.color.set() for more information, which this method wraps.

Parameters
color (colortype)

the color value to set

amul (number or nil)

alpha muliplier to apply to alpha

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:queue_draw()

Requests a full redraw from the widget's rtk.Window on next update.

It's usually not necessary to call this function as widgets know when to redraw themselves, but if you're doing any custom drawing over widgets and need to trigger a redraw based on some event rtk doesn't know about, this can be explicitly called.

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:queue_reflow(mode, widget)

Requests a reflow by the widget's rtk.Window on next update.

As with queue_draw(), this method also usually doesn't need to be directly invoked as it is done automatically when attributes are changed via attr().

If the reflow is expected to change the widget's geometry then mode must be rtk.Widget.REFLOW_FULL or else sibling and ancestor widgets that may be affected by this widget's geometry will not properly readjust. However, if no geometry change has occurred, a partial reflow is preferred as it's much faster.

Parameters
mode (reflowconst or nil)

the type of reflow to occur, where the default is REFLOW_PARTIAL

widget (rtk.Widget or nil)

for partial reflows, this is the widget requesting the reflow (nil implies self)

Return Values
(rtk.Widget)

returns self for method chaining

rtk.Widget:reflow(boxx, boxy, boxw, boxh, fillw, fillh, clampw, clamph, uiscale, viewport, window, greedyw, greedyh)

Calculates and returns the widget's geometry given the bounding box.

This is called by parent containers on their children and usually does not need to be directly invoked.

A reflow is required when the widget's geometry could be affected due to a geometry change of a parent (this is called a full reflow because every visible widget must be reflowed at the same time) or when some attribute of a widget changes that, while not affecting its geometry, may affect its internal layout (called a partial reflow because only the affected widgets need to be reflowed). Reflows are not needed when viewports are scrolled.

The bounding box is our maximum allowed geometry as dictated by the parent container. Our parent itself has its own bounding box (dictated by its parent container, and so on) and its job is to manage our position, relative to all our siblings, such that we collectively fit within the parent's box. Parents will clamp any offered boxes based on minw/maxw and minh/maxh.

If fillw or fillh is specified, it requests that the widget consume the entirety of the bounding box in that dimension. The semantics of this varies by widget. For example, buttons will stretch their surface to fit, while labels will render normally but consider the filled dimension for alignment purposes.

This function will set calc.x, calc.y, calc.w, and calc.h for the widget (i.e. the calculated geometry) and also returns them.

The box model is akin to CSS's border-box which means that any explicitly provided width and height (and their calculated counterparts) includes the widget's padding and border.

If the function is invoked with no parameters, then the parameters used in the previous invocation will be reused (as cached in rtk.Widget.box). This is needed to implement partial reflows, in which the widget recalculates its own internal content positioning within its previously calculated geometry. In contrast, a full reflow starts at the rtk.Window and recalculates the entire widget tree.

Parameters
boxx (number)

bounding box of widget relative to parent's left edge

boxy (number)

bounding box of widget relative to parent's top edge

boxw (number)

bounding box width imposed by parent

boxh (number)

bounding box height imposed by parent

fillw (bool)

if true, widget should fill the full bounding box width

fillh (bool)

if true, widget should fill the full bounding box height

clampw (bool)

if true, the widget will clamp to the bounding box width; false implies the widget can overflow the bounding box width, usually because it is parented within an rtk.Viewport that allows horizontal scrolling

clamph (bool)

like clampw, but applies in the vertical direction

uiscale (number)

the current rtk.scale.value at the time of reflow

viewport (rtk.Viewport)

the viewport the widget is rendered into

window (rtk.Window)

the window the widget is ultimately parented within

greedyw (bool)

if false avoid greedily expanding up to boxw even if fillw is true, while if true (as is usually the case), allow expansion. Greediness is disabled when windows are doing an autosize reflow.

greedyh (bool)

like greedyw but for height

Return Values
1. (number)

calculated x position of widget relative to parent

2. (number)

calculated y position of widget relative to parent

3. (number)

calculated width of widget

4. (number)

calculated height of widget

5. (bool)

true if the widget expanded to use all of boxw, which information is used by parent containers for more robust positioning. If fillw is true, then it implies true here as well, but there are cases when fillw is false but the widget decides to use all offered space anyway (e.g. for boxes with expand=1).

6. (bool)

true if the widget expanded to use all of boxh

Event Handlers

These are special methods that are automatically dispatched when certain events occur, such as mouse or keyboard actions. This is the primary mechanism by which user logic is hooked into rtk widgets, allowing the user to modify a widget's default behavior or appearance.

These methods are designed to be replaced wholesale by your own functions. In most cases, returning false from a handler prevents the widget's default behavior.

local b = rtk.Button{label='Click me'}
b.onclick = function(button, event)
    log.info('Button %s was clicked', button)
end
Beware the first parameter

When you assign a custom function to an event handler as in the above example, take note that the first parameter is always the widget itself, even though the handler function signatures documented below don't explicitly include it.

While it is possible to rewrite the above example using implicit receiver passing ...

function b:onclick(event)
   log.info('Button %s was clicked', button)
end

... this is not considered idiomatic for event handlers and should be avoided, in part because if the handler body is defined within some other method (as is typical), the handler will mask the outer receiver (as there can be only one self).

Synopsis

Methods
onattr()

Called when an attribute is set via attr(), which is the proper way to modify any attribute on a widget

ondrawpre()

Called before any drawing from within the internal draw method

ondraw()

Called after the widget is finished drawing from within the internal draw method

onmousedown()

Called when any mouse button is pressed down over the widget

onmouseup()

Called when any mouse button is released over the widget

onmousewheel()

Called when the mousewheel is moved while the mouse cursor is over the widget

onclick()

Called when the mouse button is pressed and subsequently released over a widget quickly enough that it's not considered a long press

ondoubleclick()

Called after two successive onclick events occur within rtk.double_click_delay over a widget

onlongpress()

Called after the mouse has been consistently held down for rtk.long_press_delay over a widget

onmouseenter()

Called once when the mouse is moved within the widget's region

onmouseleave()

Called once when the mouse was previously hovering over a widget but then moves outside its geometry

onmousemove()

Called when the mouse is moved within a hovering widget

onkeypress()

Called when a key is pressed while the widget is focused

onfocus()

Called when a widget is about to be focused where the handler can decide whether to accept the focus request

onblur()

Called when a widget is about to lose focus where the handler can decide whether or not to relinquish focus

ondragstart()

Called when a widget is dragged and dictates the widget's draggability

ondragend()

Called on a dragging widget when the mouse button is released

ondragmousemove()

Called on a dragging widget while the button is being held

ondropfocus()

Called when some other dragging widget has moved within our boundary

ondropmousemove()

Called when some other dragging widget has moved within our boundary after we previously accepted being a potential drop target in ondropfocus()

ondropblur()

Called when some other dragging widget has left our boundary after we previously accepted being a potential drop target in ondropfocus()

ondrop()

Called when some other dragging widget has been dragged over us and the mouse button was released, after having accepted being a potential drop target in ondropfocus()

onreflow()

Called after a reflow occurs on the widget, for example when the geometry of the widget (or any of its parents) changes, or the widget's visibility is toggled

ondropfile()

Called when files are dropped over the widget from outside the application

rtk.Widget:onattr(attr, value, oldval, trigger, sync)

Called when an attribute is set via attr(), which is the proper way to modify any attribute on a widget.

The default implementation ensures that appropriate reflow and redraw behavior is preserved depending on which attribute was updated.

Parameters
attr (string)

the name of the changed attribute

value (any)

the attribute's new calculated value

oldval (any)

the attribute's previous calculated value

trigger (bool)

if true, we are expected to emit any other on*() handlers even if the value did not actually change.

sync (bool)

if true, the attribute was set via sync(). This implies the attribute value was set from within the widget in response to a user interaction as opposed to programmatically.

Return Values
(bool or nil)

if false, suppresses the default behavior. Any other value will execute default behavior.

rtk.Widget:ondrawpre(offx, offy, alpha, event)

Called before any drawing from within the internal draw method.

There is no default implementation.

User-provided handlers can use this to customize the widget's appearance by drawing underneath the widget's standard rendering. The offx and offy arguments indicate the widget's top left corner that all manual drawing operations must explicitly take into account.

Parameters
offx (number)

the same value per _draw()

offy (number)

the same value per _draw()

alpha (number)

the same value per _draw()

event (rtk.Event)

the same value per _draw()

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondraw(offx, offy, alpha, event)

Called after the widget is finished drawing from within the internal draw method.

There is no default implementation.

User-provided handlers can use this to customize the widget's appearance by drawing over top of the widget's standard rendering.

Parameters
offx (number)

the same value per _draw()

offy (number)

the same value per _draw()

alpha (number)

the same value per _draw()

event (rtk.Event)

the same value per _draw()

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:onmousedown(event)

Called when any mouse button is pressed down over the widget.

The default implementation focuses the widget if autofocus is true and returns true if the focus was accepted to indicate the event is considered handled.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEDOWN event, where rtk.Event.button will indicate which mouse button was pressed.

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets. Returning false will suppress the default behavior.

rtk.Widget:onmouseup(event)

Called when any mouse button is released over the widget.

The default implementation does nothing.

This event will fire even if the mouse button wasn't previously pressed over the same widget (in other words, onmousedown() was never called). The widget doesn't have to be focused. The only condition for this event is that the mouse button was released over top of the widget.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEUP event, where rtk.Event.button will indicate which mouse button was released.

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets.

rtk.Widget:onmousewheel(event)

Called when the mousewheel is moved while the mouse cursor is over the widget.

The default implementation does nothing.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEWHEEL event, where rtk.Event.wheel will indicate the wheel direction and distance.

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets, including (and especially) parent viewports.

rtk.Widget:onclick(event)

Called when the mouse button is pressed and subsequently released over a widget quickly enough that it's not considered a long press.

The default implementation does nothing.

Parameters
event (rtk.Event)

an rtk.Event.MOUSEUP event, where rtk.Event.button will indicate which mouse button was pressed.

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets.

rtk.Widget:ondoubleclick(event)

Called after two successive onclick events occur within rtk.double_click_delay over a widget.

The default implementation does nothing.

Parameters
event (rtk.Event)

the rtk.Event.MOUSEUP event that triggered the double click

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets.

rtk.Widget:onlongpress(event)

Called after the mouse has been consistently held down for rtk.long_press_delay over a widget.

The default implementation does nothing.

Parameters
event (rtk.Event)

an rtk.Event.MOUSEDOWN event that triggered the long press

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets and also onclick() will not fire after the mouse button is released.

rtk.Widget:onmouseenter(event)

Called once when the mouse is moved within the widget's region.

The default implementation returns true if autofocus is set to true.

If the mouse moves while the pointer stays within the widget's geometry this handler isn't retriggered. It will fire again once the mouse exits and re-enters the widget's region.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets, and moreover the widget will be considered hovering. Returning false suppresses the default behavior.

rtk.Widget:onmouseleave(event)

Called once when the mouse was previously hovering over a widget but then moves outside its geometry.

The default implementation does nothing.

If onmouseenter() hadn't returned true such that the widget isn't marked as hovering, then this handler won't be called.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

Return Values
(bool or nil)

returning true indicates the event is to be marked as handled and it will not propagate to lower z-index widgets, and moreover the widget will be considered hovering.

rtk.Widget:onmousemove(event)

Called when the mouse is moved within a hovering widget.

The default implementation does nothing.

If onmouseenter() hadn't returned true such that the widget isn't marked as hovering, then this handler won't be called.

Unlike most other event handlers, the return value has no significance.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

rtk.Widget:onkeypress(event)

Called when a key is pressed while the widget is focused.

Parameters
event (rtk.Event)

a rtk.Event.KEY event

Return Values
(bool)

if true, the event is considered handled; if false, the default behavior of the widget is circumvented; any other value will perform the default behavior.

rtk.Widget:onfocus(event)

Called when a widget is about to be focused where the handler can decide whether to accept the focus request.

The default implementation always returns true, accepting the focus. Rejecting focus largely means the widget is non-interactive, and events that depend on focus (such as onclick() or onkeypress()) won't fire.

Parameters
event (rtk.Event or nil)

if defined, is the event that caused the focus to be requested (usually a mouse click). But it can be nil if focus() was directly called by the user.

Return Values
(bool)

if true, focus is accepted. False rejects the focus.

rtk.Widget:onblur(event, other)

Called when a widget is about to lose focus where the handler can decide whether or not to relinquish focus.

The default implementation always returns true, relinquishing focus.

Parameters
event (rtk.Event or nil)

if defined, is the event that caused the focus to be requested (usually a mouse click). But it can be nil if blur() was directly called by the user.

other (rtk.Widget or nil)

if we are being blurred because another widget wants focus, this will be that other widget.

Return Values
(bool)

if true, we relinquish focus, while false hangs onto it.

rtk.Widget:ondragstart(event, x, y, t)

Called when a widget is dragged and dictates the widget's draggability.

The default implementation returns false, indicating that it is not draggable.

This event fires when any mouse button is clicked on a widget, the button is held down, and the mouse is moved.

The callback's return value controls whether the drag operation should occur, and whether the widget is considered droppable. (An example of a draggable-but-not-droppable widget is rtk.Viewport, which uses the drag-and-drop system for its scrollbar implementation.)

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

x (number)

the x position of the mouse pointer when the mousedown first occurred. This is different from event.x because the latter reflects the new mouse position where the change in position is what caused the drag to occur, while the x parameter is the original position. math.abs(event.x - x) represents the delta.

y (number)

like x, but for the y coordinate

t (number)

the original rtk.Event.time when the mousedown first occurred

Return Values
1. (any)

if the first return value is truthy value (i.e. neither false nor nil), then the widget is considered dragging and this return value is the user-provided drag argument that will be supplied to other ondrag* and ondrop* handlers as dragarg.

2. (bool or nil)

if false, the widget will not be droppable and the ondrop* handlers of widgets this one hovers over will not be triggered, while with any other value (including nil), ondrop* handlers will be called on widgets we hover over.

rtk.Widget:ondragend(event, dragarg)

Called on a dragging widget when the mouse button is released.

The default implementation does nothing.

A widget is dragging when ondragstart() returned true when a drag was attempted.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

dragarg (any)

the first value returned by ondragstart().

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondragmousemove(event, dragarg)

Called on a dragging widget while the button is being held.

In order to support scroll_on_drag, this event is fired periodically on a dragging widget even if the mouse didn't actually move. When this happens, the simulated field on the event will be true.

The default implementation does nothing.

Note

While the widget is dragging, its cursor (if set) will always be active even if the mouse moves over another widget that defines its own cursor. If you want a particular mouse cursor to appear while dragging a widget that's different from the dragging widget's cursor you can call rtk.Window:request_mouse_cursor() from this handler.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

dragarg (any)

the first value returned by ondragstart().

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondropfocus(event, source, dragarg)

Called when some other dragging widget has moved within our boundary.

This event determines if we are a potential drop target for the dragging widget. If so, we return true to subscribe to future ondropmousemove(), ondropblur(), or ondrop() events for this drag operation from the other widget.

The default implementation returns false, refusing being a drop target.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

source (rtk.Widget)

the other widget that is the source of drag operation

dragarg (any)

the first value returned by ondragstart().

Return Values
(bool)

true if we are a potential drop target, and false otherwise.

rtk.Widget:ondropmousemove(event, source, dragarg)

Called when some other dragging widget has moved within our boundary after we previously accepted being a potential drop target in ondropfocus().

The default implementation does nothing.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

source (rtk.Widget)

the other widget that is the source of drag operation

dragarg (any)

the first value returned by ondragstart().

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondropblur(event, source, dragarg)

Called when some other dragging widget has left our boundary after we previously accepted being a potential drop target in ondropfocus().

The default implementation does nothing.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

source (rtk.Widget)

the other widget that is the source of drag operation

dragarg (any)

the first value returned by ondragstart().

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondrop(event, source, dragarg)

Called when some other dragging widget has been dragged over us and the mouse button was released, after having accepted being a potential drop target in ondropfocus().

The default implementation returns false, refusing the drop.

Parameters
event (rtk.Event)

a rtk.Event.MOUSEMOVE event

source (rtk.Widget)

the other widget that is the source of drag operation

dragarg (any)

the first value returned by ondragstart().

Return Values
(bool or nil)

returning true indicates the drop was accepted, and the event is to be marked as handled so it will not propagate to lower z-index widgets.

rtk.Widget:onreflow()

Called after a reflow occurs on the widget, for example when the geometry of the widget (or any of its parents) changes, or the widget's visibility is toggled.

The default implementation does nothing.

Return Values
(nil)

Return value has no significance. This is a notification event only.

rtk.Widget:ondropfile(event)

Called when files are dropped over the widget from outside the application.

The rtk.Event.files field holds the list of file paths that were dropped. If the callback returns a non-false value then the event is considered handled.

Parameters
event (rtk.Event)

a rtk.Event.DROPFILE event, where rtk.Event.files will hold the list of file paths that were dropped.

Return Values
(bool or nil)

returning true indicates the drop was accepted, and the event is to be marked as handled so it will not propagate to lower z-index widgets.

Subclass API

These methods are internal (as denoted by the prefixed underscore), but comprise the subclass API that can be used to implement custom widgets.

Quite a lot of customization can be accomplished without creating a custom widget subclass by using event handlers. If you're looking for some modest change in appearance of behavior of an existing widget, you might find it more easily accomplished by hooking one or more event handlers, such as ondraw().

Otherwise, for more sophisticated or complete widget implementations, you can subclass rtk.Widget (or any other widget you want to build on top of) and use this subclass API (or any public method as needed) for the implementation.

Warning

These methods are considered somewhat less stable than the public methods and are more subject to change as rtk approaches 1.0.

Event Handling for Custom Widgets

Subclasses must not use any of the on* event handlers as a means of implementing custom behavior, as these methods are intended to be replaced wholesale by users for their own custom behaviors.

Instead, subclasses should override the internal _handle_* methods. For every onfoo() event handler there is a corresponding _handle_foo() (with the same arguments) that's called first and which dispatches to onfoo(). Subclasses can call up to the superclass implementations for the default behavior.

The most common such method is _handle_attr() which subclasses commonly implement to perform some customizations when some attribute is set. For example:

-- Create a custom widget subclassed directly from rtk.Widget
local MyWidget = rtk.class('MyWidget', rtk.Widget)
function MyWidget:_handle_attr(attr, value, oldval, trigger)
    -- First delegate to the superclass implementation.  This example assumes
    -- MyWidget subclasses directly from rtk.Widget.
    local ok = rtk.Widget._handle_attr(self, attr, value, oldval, trigger)
    -- We test for false explicitly because the superclass could return nil,
    -- which means we would still be ok to proceed with our own logic.
    if ok == false then
       -- User-supplied onattr() handler returned false to bypass default behavior.
       return ok
    end
    if attr == 'myattr' then
       -- Just riffing here ...
       self._whatever = value * 2
    end
    -- Indicates that we handled the event
    return true
end

Synopsis

Methods
_get_padding()

Returns padding from all 4 sides

_get_border_sizes()

Returns the border thickness from all 4 sides

_get_padding_and_border()

Returns combined padding and border thickness

_get_box_pos()

Returns the top left position of the widget's box relative to its parent based on the given bounding box position

_get_content_size()

Returns the dimensions allowed for the widget's inner content based on the w and h attributes (if defined), but ignoring min/max size attributes

_reflow()

Internal implementation of reflow(), using the same arguments and return values

_realize_geometry()

Invoked by parent containers after the child's reflow() was called, and after any parent-controlled geometry modifications (if any)

_is_mouse_over()

Tests to see if the mouse is currently over the widget

_draw()

Draws the widget

_draw_bg()

Draws the widget background

_draw_tooltip()

Draws the widget's tooltip according to the tooltip attribute and the current theme

_draw_borders()

Draws borders around the widget

_handle_event()

Process an event

_unrealize()

Called when the widget (or one of its ancestors) is hidden

_release_modal()

Called by the parent window when the widget is being asked to give up its modal state

rtk.Widget:_get_padding()

Returns padding from all 4 sides.

Return Values
1. (number)

top padding

2. (number)

right padding

3. (number)

bottom padding

4. (number)

left padding

rtk.Widget:_get_border_sizes()

Returns the border thickness from all 4 sides.

Return Values
1. (number)

top border thickness

2. (number)

right border thickness

3. (number)

bottom border thickness

4. (number)

left border thickness

rtk.Widget:_get_padding_and_border()

Returns combined padding and border thickness.

Return Values
1. (number)

top border and padding thickness

2. (number)

right border and padding thickness

3. (number)

bottom border and padding thickness

4. (number)

left border and padding thickness

rtk.Widget:_get_box_pos(boxx, boxy)

Returns the top left position of the widget's box relative to its parent based on the given bounding box position.

This method is usually called from _reflow() and it expects the boxx and boxy parameters that were provided there. And the return value is almost certainly what custom widgets should assign to calc.x and calc.y.

Subclasses are expected to draw widget content relative to these coordinates, and need to explicitly account for lpadding and tpadding as offsets from these coordinates.

rtk.Widget:_get_content_size(boxw, boxh, fillw, fillh, clampw, clamph, scale, greedyw, greedyh)

Returns the dimensions allowed for the widget's inner content based on the w and h attributes (if defined), but ignoring min/max size attributes.

This method is usually called from _reflow() as part of calculating the widget's geometry, where the box, fill, and clamp parameters are those that were passed to _reflow(). This is also where relative sizes (i.e. when w or h is between 0.0 and 1.0) are resolved into pixels.

If this method returns nil for either dimension, then the widget is not constrained in that dimension and the widget implementation must calculate its intrinsic size in that dimension (which varies by widget type).

The minw/maxw and minh/maxh attributes are ignored by this method. It is up to the caller to subsequently clamp the resulting calculated width and height based on these attributes.

Note

Remember that in rtk's box model any padding and border thickness is subtracted from w and h which results in the size available for content. In other words, non-nil values returned here will exclude any padding in that dimension.

Parameters
boxw (number)

as in reflow()

boxh (number)

as in reflow()

fillw (bool)

as in reflow()

fillh (bool)

as in reflow()

clampw (bool)

as in reflow()

clamph (bool)

as in reflow()

scale (number or nil)

if the widget instance's scalability flags permit scaling dimensions then non-nil return values will be multipled by this amount (in addition to rtk.scale.value which is implcitly included even when this argument is nil).

greedyw (bool)

as in reflow()

greedyh (bool)

as in reflow()

Return Values
1. (number or nil)

the content width, or nil if caller should use intrinsic width

2. (number or nil)

the content height, or nil if caller should use intrinsic height

3. (number)

the combined top padding and border size in pixels

4. (number)

the combined right padding and border size in pixels

5. (number)

the combined bottom padding and border size in pixels

6. (number)

the combined left padding and border size in pixels

7. (number or nil)

the minimum width, resolved from relative size if applicable, less padding, or nil if minw is nil

8. (number or nil)

as above, except maximum width

9. (number or nil)

as above, except minimum height

10. (number or nil)

as above, except maximum height

rtk.Widget:_reflow(boxx, boxy, boxw, boxh, fillw, fillh, clampw, clamph, uiscale, viewport, window, greedyw, greedyh)

Internal implementation of reflow(), using the same arguments and return values. Subclasses override and there is no need to call up to this method: the default rtk.Widget implementation merely sets the calculated box geometry based on sane defaults, but widget implementations almost always need something slightly different.

Parent containers may directly modify a child's geometry (e.g. for alignment purposes) after calling reflow(). This means that subclass implementations of _reflow() must not precompute any values to be used by _draw() that depend on geometry. Use _realize_geometry() for that instead, as the parent will invoke that method after laying out the child (whether or not any modifications were made)

rtk.Widget:_realize_geometry()

Invoked by parent containers after the child's reflow() was called, and after any parent-controlled geometry modifications (if any).

This is where subclasses should do any precalculations for _draw() that depend on its geometry. They mustn't do this within _reflow() because parent containers can make direct modifications to the widget's calculated geometry after _reflow() was called, for example to arrange the widget within a box relative to siblings, or to implement cell alignment.

The default implementation simply sets realized to true.

rtk.Widget:_is_mouse_over(clparentx, clparenty, event)

Tests to see if the mouse is currently over the widget.

The given coordinates is current the client position of the widget's parent, which is identical to the arguments of the same name from _handle_event() because this method is called from there.

You probably don't ever need to call this method directly and should instead test the mouseover attribute instead as that takes into account any occluding widgets.

That said, subclasses may need to override this method if they implement non-default shapes, such as circular buttons.

Parameters
clparentx (number)

the x client coordinate of our parent's position

clparenty (number)

the y client coordinate of our parent's position

event (rtk.Event)

a mouse event that contains current mouse coordinates

Return Values
(bool)

true if the mouse is currently over the widget's area, false otherwise.

rtk.Widget:_draw(offx, offy, alpha, event, clipw, cliph, cltargetx, cltargety, parentx, parenty)

Draws the widget.

This is an internal function not meant to be called directly but rather implemented by subclasses. It is invoked by parent containers, and the widget is expected to paint itself on the current drawing target as setup by the parent (via rtk.pushdest()).

The default implementation simply sets offx and offy, calculates clientx and clienty, and sets drawn to true.

Note that unlike _handle_event() which deals with client coordinates, implementations of _draw() typically just need to use the given offsets (offx and offy) as they refer to the widget's intended drawing location on the current drawing target.

However, if client coordinates are needed by implementations, once you call up to the superclass method, clientx and clienty will be available for use. (You can always calculate this explicitly by summing cltargetx/cltargety with offx/offy, which provides our client position less our own x/y position. But it's usually easier to just use clientx and clienty.)

Parameters
offx (number)

the x coordinate on the current drawing target that the widget should offset its position as requested by the parent container.

offy (number)

like offx but the y coordinate

alpha (number)

the opacity (from 0.0 to 1.0) as imposed by the parent container, which must be multiplied with rtk.Widget.alpha for drawing

event (rtk.Event)

the event that occurred at the time of the redraw

clipw (number)

the width of the drawing target beyond which anything the widget draws will be automatically clipped. This can be used by subclass implementations for optimizations, not bothering to draw elements that won't be visible.

cliph (number)

like clipw but for height

cltargetx (number)

the x coordinate of the current drawing target (typically a rtk.Viewport backing store) relative to the window (where 0 indicates the left edge of the rtk.Window).

cltargety (number)

like cltargetx but the y coordinate

parentx (number)

the x coordinate of our parent's position relative to the current drawing target. Rarely needed, but useful in certain limited cases (for example when drawing fixed position widgets).

parenty (number)

like parentx but the y coordinate

rtk.Widget:_draw_bg(offx, offy, alpha, event)

Draws the widget background.

This isn't called by the default _draw() method and is left up to direct subclasses of rtk.Widget to call explicitly at the appropriate time.

All arguments are the same as _draw().

rtk.Widget:_draw_tooltip(clientx, clienty, clientw, clienth, tooltip)

Draws the widget's tooltip according to the tooltip attribute and the current theme.

Parameters
clientx (number)

the client x coordinate of the requested tooltip position

clienty (number)

the client y coordinate of the requested tooltip position

clientw (number)

the maximum width of the client area which the tootip must not exceed. The clientx value should also be adjusted if necessary to ensure the tooltip doesn't exceed the width.

clienth (number)

like clientw except for height

tooltip (string)

the text of the tooltip to draw

rtk.Widget:_draw_borders(offx, offy, alpha, all)

Draws borders around the widget.

All arguments are the same as _draw().

rtk.Widget:_handle_event(clparentx, clparenty, event, clipped, listen)

Process an event.

This is an internal function not meant to be called directly, but rather it is invoked by our parent container to handle an event, usually some user interaction, but may be a generated event based on some timed action.

Subclasses can override, but most of the time subclasses will want to use one of the _handle_* events that are internal analogues to the user-facing event handlers.

May be called before draw

Our parent will not invoke this method before a reflow and so calculated geometry is guaranteed to be available, but it may call us before we're drawn, so event handlers should be cautious about using clientx and clienty as they may not be calculated yet, depending on the event. (Specifically, when handling simulated events, widgets should not expect fields set during draw to be valid.)

The parent will also call us even if the event was already handled by some other widget so that we have the opportunity to perform any necessary finalization actions (for example firing the onmouseleave handler). It's our responsibility to determine if we should handle this event, and if so, to dispatch to the appropriate internal _handle_* method (which in turn calls the user-facing on* handlers), declare the event handled by calling rtk.Event:set_handled(), and queuing a draw if necessary.

clparentx and clparenty refer to our parent's position relative to top-left of the client window (in other words, these are client coordinates).

If clipped is true, it means the rtk.Viewport we belong to has indicated that the mouse is currently outside the viewport bounds. This can be used to filter mouse events -- we must not fire onmouseenter() for a clipped event, for example -- but it can be used to fire onmouseleave(). (This is the reason that our parent even bothers to call us for handled events.)

The listen parameter is somewhat the opposite of clipped. If true, the event is processed as normal. If false, the event will propagate to children but otherwise will be ignored unless the widget is modal, in which case listen is flipped to true for us and our children.

When an event is marked as handled, a redraw is automatically performed. If a redraw is required when an event isn't explicitly marked as handled, such as in the case of a blur event, then queue_draw() must be called.

Parameters
clparentx (number)

the x client coordinate of our parent's position

clparenty (number)

the y client coordinate of our parent's position

event (rtk.Event)

the event to handle

clipped (bool)

whether the mouse is outside our rtk.Viewport's bounds

listen (bool)

whether we should handle the event at all, or blindly propagate the event to children

Return Values
(bool)

whether we determined we should listen to this event. Subclasses can use this return value in their implementations.

rtk.Widget:_unrealize()

Called when the widget (or one of its ancestors) is hidden.

Subclasses should use this to release resources that aren't needed when the widget isn't being rendered, such as image buffers.

rtk.Widget:_release_modal(event)

Called by the parent window when the widget is being asked to give up its modal state.

When the widget was previously registered with rtk.add_modal() and the user either clicks somewhere else within the window or if the window's focus is lost, then this method is invoked.

It's not required that implementations honor the request, but if it does it can call rtk.reset_modal(). For example, a popup menu probably should close itself and release its hijacking of input events when the user clicks outside of the popup area.

Parameters
event (rtk.Event or nil)

the event, if any, that was the cause of the invocation