Module: ui.widget

Source: ./ui/widget.reef


Overview

ui/widget.reef - Widget types and base functionality Part of reef-stdlib UI module

This module defines widget IDs/state and two bases:

  • WidgetBase (struct) — still embedded by checkbox/slider/etc.
  • Widget (passive object) — hierarchy for Label/Button/Panel.

Types

WidgetId

Fields:

Name Type
value int

WidgetState (enum)

Variants:

  • Normal
  • Hovered
  • Pressed
  • Focused
  • Disabled

SizeConstraints

Fields:

Name Type
min_width float
max_width float
min_height float
max_height float

EventResultKind (enum)

D3 (docs/design/2026-09-08-ui-modernization.md): ONE event result for every widget. Before, five widgets each declared their own -- four structs (ButtonEventResult, CheckboxEventResult, SliderEventResult, TextFieldEventResult) plus ScrollViewEventResult as an enum -- each with its own constructors, its own "is it interesting" predicate, and a converter back to this type. The semantic kinds those types added are the three at the bottom of this enum; that was the whole of the difference.

Each of those types also carried the widget itself as a payload, which is why they are gone rather than merged: since widgets are objects and setters mutate (reef-lang#62), the payload was always the receiver the caller already held. It cost an allocation per event to fill -- see the CHANGELOG.

Variants:

  • Ignored
  • Handled
  • RequestFocus
  • ReleaseFocus
  • Clicked
  • Toggled
  • Changed

EventResult

Fields:

Name Type
kind EventResultKind

WidgetBase

Fields:

Name Type
id WidgetId
bounds core.Rect
state WidgetState
visible bool
enabled bool
focusable bool
tab_index int

Objects

Widget

Fields:

Name Type
id WidgetId
bounds core.Rect
wstate WidgetState
visible bool
enabled bool
focusable bool
tab_index int

proc init(id: WidgetId)

Methods:

shared fn kind(): string

exclusive proc set_bounds(bounds: core.Rect)

exclusive proc paint(surf: surface.Surface, th: theme.Theme)

exclusive fn handle_event(e: event.Event): EventResult

Phase 4: virtual, and only possible because D3 gave every widget the same result type. A widget that handles nothing inherits this.


Functions

fn widget_id(id: int): WidgetId

fn widget_id_none(): WidgetId

fn widget_id_is_none(id: WidgetId): bool

fn state_normal(): WidgetState

fn state_hovered(): WidgetState

fn state_pressed(): WidgetState

fn state_focused(): WidgetState

fn state_disabled(): WidgetState

fn is_normal(s: WidgetState): bool

fn is_hovered(s: WidgetState): bool

fn is_pressed(s: WidgetState): bool

fn is_focused(s: WidgetState): bool

fn is_disabled(s: WidgetState): bool

fn constraints_tight(width: float, height: float): SizeConstraints

fn constraints_loose(max_width: float, max_height: float): SizeConstraints

fn constraints_expand(): SizeConstraints

fn constrain_size(c: SizeConstraints, s: core.Size): core.Size

fn event_ignored(): EventResult

fn event_handled(): EventResult

fn event_request_focus(): EventResult

fn event_release_focus(): EventResult

fn event_clicked(): EventResult

fn event_toggled(): EventResult

fn event_changed(): EventResult

fn is_event_handled(r: EventResult): bool

Every kind but Ignored is a handled event. This is what the five deleted converters did -- each mapped its own semantic kind (Clicked, Toggled, Changed, Consumed) onto Handled -- and keeping it here is what stops the collapse from changing behaviour for a caller that only asks "was it handled".

fn requests_focus(r: EventResult): bool

fn releases_focus(r: EventResult): bool

fn is_clicked(r: EventResult): bool

fn is_toggled(r: EventResult): bool

fn is_changed(r: EventResult): bool

fn new_widget_base(id: WidgetId): WidgetBase

fn hit_test(bounds: core.Rect, x: float, y: float): bool

fn widget_kind(w: Widget): string


Procedures

proc widget_base_set_bounds(w: WidgetBase, bounds: core.Rect)

proc widget_base_set_state(w: WidgetBase, state: WidgetState)

proc widget_base_set_visible(w: WidgetBase, visible: bool)

proc widget_base_set_enabled(w: WidgetBase, enabled: bool)


Generated by reefc doc