Foundations

Data Binding System

NAppGUI's binding model is runtime-driven. DBind stores type metadata for structs, enums, binary objects, and containers, while the GUI layer attaches that metadata to layouts and cells to keep controls synchronized with C objects.

Relevant Source Files

DBind Registry Model

The core API registers metadata with macros such as dbind(type, mtype, mname), dbind_enum(...), dbind_binary(...), and dbind_alias(...). The runtime then exposes creation, copy, init/remove, compare, read/write, defaults, numeric ranges, precision, increment size, and text suffixes through dbind_* helpers.

This is not code generation. All binding behavior is driven from runtime type lookup and member metadata stored in DBind. The same registry also understands container types such as ArrPt and ArrSt, which are registered during core startup.

Binding Layouts and Cells

The GUI surface has two layers of attachment:

  • layout_dbind(...) associates a layout with a struct type and an optional change listener.
  • layout_dbind_obj(...) attaches a concrete object instance.
  • cell_dbind(...) maps one cell to one struct member.
  • layout_dbind_update(...) refreshes one bound member after programmatic changes.

Nested structs are supported by binding sublayouts or panel-hosted layouts to members. When a cell contains a nested layout and the target member is a basic type, the binding logic propagates that member into the child cells automatically.

Control-to-Object Update Flow

User edits travel through cell helpers such as _cell_update_bool, _cell_update_str, _cell_update_norm32, and _cell_update_incr. Those pass through gbind.c, which uses the member metadata to write the new value into the bound object.

Before the change is finalized, the nearest layout with an object-change listener can receive ekGUI_EVENT_OBJCHANGE. The event carries an EvBind payload and a bool_t result, so the listener can inspect the modified member with evbind_modify(...) and veto or accept the edit.

Object-to-Control Refresh

Refresh in the other direction is handled by _layout_dbind_update() and the internal recursive walker in layout.c. It can update one member or the whole object, and it descends through sublayouts and panel-owned layouts while respecting locally bound subobjects.

Binding also adapts control setup based on metadata. Examples from layout.c include auto-populating enum values into popups or listboxes and enabling edit_autoselect(...) when an edit box is bound to a numeric member.

Metadata-Driven Behavior

Metadata Where It Comes From What The GUI Layer Uses It For
Enum aliases dbind_enum(...) Generates popup/listbox labels and maps selection back to enum values.
Ranges and precision dbind_range, dbind_precision, dbind_increment Normalizes sliders, numeric editors, and increment/decrement controls.
Binary defaults dbind_binary(...) plus defaults Lets image-backed members appear as Image values in the GUI.
String filters DBind string member metadata Applied through _cell_filter_str() for edit validation.

Representative Demo Usage

demo/guihello shows the small-scale patterns: enum registration, member binding, and layout update notifications. demo/bode shows the more complex case with nested parameter structs, range/precision metadata, and panel-switched views.

Those demos are worth reading because they reflect the intended public usage more clearly than the internals alone.