rust_widgets 2.8.4

Pure Rust cross-platform native GUI library with hardware-adaptive rendering, 180 widgets, touch/gesture support, i18n, and SVG-pipeline-accurate output
# Harmony NAPI Bridge Flow

Use this guide to wire ArkUI/NAPI callbacks into `rust_widgets` with a predictable event flow.

## Step 1: Initialize and Create Widgets

Run this sequence in your app startup:

1. `rw_init()`
2. Create window and controls with `rw_create_*`
3. Store returned `widget_id` values in your native layer

## Step 2: Bind ArkUI Node Handles

When a UI node is created and mapped to a `widget_id`, register it once:

- `rw_harmony_bind_node(node_handle, widget_id)`

When a node is destroyed:

- `rw_harmony_unbind_node(node_handle)`

During app teardown:

- `rw_harmony_clear_node_bindings()`

## Step 3: Forward ArkUI/NAPI Callbacks

Forward native callbacks into `rust_widgets`:

- Click: `rw_harmony_on_node_click(node_handle)`
- Value change: `rw_harmony_on_node_value_changed(node_handle)`
- Menu item: `rw_harmony_on_node_menu_item(node_handle)`
- Generic: `rw_harmony_on_node_widget_event(node_handle, kind_code)`

If you already have a `widget_id`, use direct APIs:

- `rw_harmony_on_click(widget_id)`
- `rw_harmony_on_value_changed(widget_id)`
- `rw_harmony_on_menu_item(menu_item_id)`
- `rw_harmony_on_widget_event(widget_id, kind_code)`

## Step 4: Poll and Dispatch in the App Loop

Consume queued events on each runtime tick:

- `rw_poll_menu_triggered()`
- `rw_poll_widget_trigger_event(widget_id_out)`

Trigger kind mapping:

- `1` = clicked
- `2` = value-changed
- `0` = no event

## Step 5: Minimal Callback Pseudo-Flow

```text
onNodeReady(node, widgetId):
  rw_harmony_bind_node(node, widgetId)
  rw_mount_surface(rootWidgetId, widgetId, x, y, w, h)

onTap(node):
  rw_harmony_on_node_click(node)

onTextChange(node):
  rw_harmony_on_node_value_changed(node)

onAreaChange(w, h):
  // The layout only re-runs if the size reaches the library; OpenHarmony
  // reports it to *this* component, not to the backend.
  rw_report_window_resize(rootWidgetId, w, h)

appTick():
  menuId = rw_poll_menu_triggered()
  kind = rw_poll_widget_trigger_event(&widgetId)
  dispatch(menuId, widgetId, kind)

  // Draw whatever the library says is stale.
  dirty = rw_take_pending_repaint()
  while dirty != 0:
    if rw_render_surface_frame(dirty, w, h, &ow, &oh, &stride, &len, &pixels):
      canvas.blit(pixels, ow, oh, stride)
      rw_free_bytes(pixels, len)
    dirty = rw_take_pending_repaint()

onNodeDispose(node):
  rw_unmount_surface(widgetId)
  rw_harmony_unbind_node(node)
```

## Related Files

- Header: `include/rw_generated.h` (generated by `tools/generate_c_header.py`,
  drift-checked by `tools/check_abi.sh`)
- C bridge sample: `examples/harmony_napi_bridge_sample.c`
- Backend status: `src/platform/harmony/status.md`
- Integration plan: `docs/plans/harmony_integration.md`