Skip to content

Immediate mode

This page matches the current implementation in the FlashBang repo: global ImmediateContext, set_immediate_context per frame, and widget procs in package widgets exposed as flashbang.*.

Per-frame sequence

  1. Clear or rebuild your DrawList for the frame (see draw_list_clear / init patterns in your app).
  2. Feed input into the context after set_immediate_context resets per-frame buffers:
  3. Pointer: you pass mouse_x, mouse_y, mouse_down into set_immediate_context.
  4. Text: flashbang.push_text_input with UTF-8 bytes for the frame.
  5. Keys: flashbang.push_key_event for each key up/down you care about.
  6. Scroll: flashbang.push_scroll_event (widgets read scroll_delta_* from context).
  7. Optional: set_shift_held, set_middle_mouse, set_click_count when your platform provides them.
  8. Call flashbang.set_immediate_context(ctx_draw_list, text_backend, mouse_x, mouse_y, mouse_down) once per frame before drawing widgets. This resets text/key scroll accumulators, widget dimension map, layout rect cache for the frame, theme stack depth, etc., and ensures a default theme exists on first use.
  9. Optional startup-only (not each frame unless backends change): set_platform_backend, set_layout_backend, set_image_backend, set_theme.
  10. Call flashbang.get_imm_ctx() to obtain ^ImmediateContext and pass it to widgets: flashbang.Button(ctx, config), flashbang.Label(ctx, config), …
  11. Submit your DrawList through your render backend.

What ImmediateContext carries

Defined in src/widgets/button.odin (same compilation unit as early immediate-mode widgets):

  • draw_list, text_backend — required for almost all widgets.
  • platform_backend, layout_backend, image_backend — optional; set via set_* helpers.
  • Pointer state: mouse_x, mouse_y, mouse_down, scroll deltas, mouse_click_count, etc.
  • Coordinate origin: origin_x, origin_y — container widgets (e.g. window) adjust these so children use local coordinates.
  • Last sizes: last_widget_w, last_widget_h, and for containers last_content_w, last_content_h — used by GetWidth / GetHeight / GetContentWidth / GetContentHeight helpers.
  • Input buffers: raw text bytes and key events for the frame (consumed by text widgets).
  • Focus: focused_id — hashed widget id; use set_focus / widget-specific helpers as documented per widget.
  • Theme: global_theme plus a small per-frame stack (push_theme / pop_theme reset each frame after set_immediate_context).

Click detection (example: button)

ButtonConfig includes was_active: bool. You must store ButtonState.active from the previous frame and pass it back as was_active next frame. clicked is true when the pointer was down on the widget last frame, released this frame, while still hovering—see check_click in src/widgets/button.odin.

Widget IDs and layout overrides

If id in a config is non-empty, the widget stores dimensions for that id (hashed) so flashbang.GetWidth("id") / GetHeight("id") work. The same hash keys the per-frame layout rect cache populated by an external layout backend, so apply_layout_override can replace x,y,w,h before drawing.

Z order

Use push_z_layer / pop_z_layer (re-exported on flashbang) to bracket draw sections so later ops sort above earlier ones when your backend respects z_index.