kui_ffi/types.rs
1//! Opaque handles and the repr(C) mirrors of the core's spec structs —
2//! what `include/kui.h` declares, field for field. See the ABI notes in
3//! `abi` for which side may write which struct.
4
5use super::*;
6
7/// A C callback that builds into a context: `kui_run`'s view, and the body
8/// of a `kui_titlebar_with` / `kui_tooltip_with`. Here rather than in
9/// `run`, because the widgets take one whether or not this build has a
10/// windowed runner.
11pub(crate) type ViewFn = extern "C" fn(user: *mut c_void, ctx: *mut KuiCtx);
12/// A C callback that receives one event: `kui_run`'s, and only its — so
13/// unlike `ViewFn` it is not here in a build without the runner.
14#[cfg(feature = "runner")]
15pub(crate) type EventFn = extern "C" fn(user: *mut c_void, ev: *const KuiEvent);
16/// A C callback that hears the window go: `kui_on_teardown`'s, with
17/// `kui_run`'s `user`. Runner-only, as `EventFn` is.
18#[cfg(feature = "runner")]
19pub(crate) type TeardownFn = extern "C" fn(user: *mut c_void);
20
21// ---------------------------------------------------------------------------
22// Opaque + repr(C) types
23
24/// The opaque context every `kui_*` call takes: a core plus its pending
25/// event queue.
26///
27/// A standalone context from [`kui_ctx_new`] owns its core and lives until
28/// [`kui_ctx_free`]. The context handed to a `kui_run` view callback or a
29/// plugin's `kui_ext_view` borrows the runner's frame instead and is valid
30/// for that call only; the builder entry points work the same on both,
31/// while input, polling and draw data belong to the owning side.
32pub struct KuiCtx {
33 pub(crate) core: *mut Core,
34 /// Keep-alive for standalone contexts; never read directly.
35 pub(crate) _owned: Option<Box<Core>>,
36 pub(crate) events: Vec<UiEvent>,
37 /// Payload most recently handed out by kui_poll_event; freed on the next
38 /// poll (or context free) so C never manages event payload lifetime.
39 pub(crate) last_payload: Option<Box<KuiValue>>,
40 /// Text most recently handed out by kui_edit_text; freed on the next call.
41 pub(crate) last_edit_text: Option<String>,
42 /// The WGSL module most recently handed out by `kui_fragment_source`;
43 /// valid until the next call, like every other borrowed string here.
44 pub(crate) fragment_source: String,
45 /// This frame's fragment draws, in `KuiFragmentDraw` form, so
46 /// `kui_draw_data` can hand out a pointer that outlives the call.
47 pub(crate) fragment_draws: Vec<KuiFragmentDraw>,
48 /// `kui_draw_data`'s transcription of the frame's texture draws.
49 pub(crate) texture_draws: Vec<KuiTextureDraw>,
50 /// Whether the two above are this frame's: `kui_draw_data` transcribes
51 /// once a frame, so a second call in the same frame hands out the same
52 /// arrays rather than freeing the ones the first call handed out.
53 /// Cleared by `kui_frame_begin`, which is where kui.h ends them, and
54 /// by `kui_frame_finish`, so a call while the frame built does not
55 /// stand for the frame it finished.
56 pub(crate) draws_current: bool,
57 /// What `kui_image_pixels` last handed out, so the pointer outlives
58 /// the call.
59 pub(crate) image_pixels: Option<std::sync::Arc<Vec<u8>>>,
60 /// Warnings most recently handed out by kui_take_warnings; their strings
61 /// stay valid until the next call.
62 pub(crate) last_warnings: Vec<kui_core::Warning>,
63 /// Warnings drained from the core and not handed out yet: a `cap`
64 /// shorter than what was raised leaves the rest here.
65 pub(crate) pending_warnings: Vec<kui_core::Warning>,
66 /// Access tree most recently handed out by kui_access_tree; its strings
67 /// stay valid until the next call.
68 pub(crate) last_access: kui_core::AccessTree,
69 /// The runs most recently handed out by kui_access_runs, held apart
70 /// from `last_access` so reading an editor's runs leaves the strings
71 /// kui_access_tree handed out alone.
72 pub(crate) last_runs: Vec<kui_core::AccessRun>,
73 /// Announcements most recently handed out by kui_take_announcements;
74 /// their strings stay valid until the next call.
75 pub(crate) last_announcements: Vec<kui_core::Announcement>,
76 /// Window commands taken from the core and not yet handed out one at a
77 /// time by `kui_take_window_command`.
78 pub(crate) window_commands: VecDeque<WindowCommand>,
79 /// The same for the menu actions `kui_take_menu_action` hands out, and
80 /// the text of the one most recently handed out — borrowed by the
81 /// caller until the next call, like every other string here.
82 pub(crate) menu_actions: VecDeque<kui_core::MenuAction>,
83 pub(crate) menu_text: String,
84 pub(crate) menu_html: String,
85 /// The label most recently read back by `kui_menu_bar_menu`,
86 /// `kui_menu_bar_item` or `kui_menu_item`, and the accelerator beside
87 /// it: their own, so reading a menu leaves a taken action's `text`
88 /// alone, as kui.h says it is (borrowed until the next
89 /// `kui_take_menu_action`).
90 pub(crate) row_text: String,
91 pub(crate) menu_accel: String,
92 /// What `kui_request_copy` most recently handed out, on the same terms.
93 pub(crate) copy_text: String,
94 /// The chord most recently handed out by `kui_devtools_key`, on the
95 /// same terms.
96 pub(crate) devtools_key: String,
97 /// The file dialog `kui_take_file_request` most recently handed out,
98 /// whose strings — and the filter `kui_file_request_filter` read,
99 /// its extensions joined — are borrowed until the next call.
100 pub(crate) file_request: Option<kui_core::FileDialog>,
101 pub(crate) file_filter_text: String,
102 /// The tab name most recently handed out by `kui_devtools_current_tab`,
103 /// on the same terms.
104 pub(crate) devtools_tab: String,
105 /// The selection most recently handed out by `kui_selection_text` /
106 /// `kui_selection_html`; valid until the next such call, like every
107 /// other borrowed string here.
108 pub(crate) selection_text: String,
109 pub(crate) selection_html: String,
110 /// The family names most recently handed out by `kui_font_families`,
111 /// held so the `KuiStr`s written into the host's array stay valid
112 /// until the next call.
113 pub(crate) font_families: Vec<String>,
114 /// The families most recently handed out by `kui_system_fonts`, held
115 /// for the same reason: their names and weights are what the
116 /// `KuiSystemFont`s written into the host's array point at.
117 pub(crate) system_fonts: Vec<kui_core::SystemFont>,
118 /// The node list most recently handed out by `kui_nodes`; borrowed
119 /// until the next call, like every other reading here.
120 pub(crate) nodes: Option<Box<KuiValue>>,
121 /// The name most recently handed out by kui_ctx_window_name; valid
122 /// until the next call.
123 pub(crate) last_window_name: Option<Rc<str>>,
124 /// Which slot this context is a C extension's fill of, and the params
125 /// the host passed it: what `kui_slot_name` / `kui_slot_params`
126 /// answer. `None` on every other context - a standalone one, a C host's
127 /// view callback - where they answer false and NULL.
128 pub(crate) slot_name: Option<String>,
129 pub(crate) slot_namespace: Option<String>,
130 pub(crate) slot_params: Option<KuiValue>,
131 /// The extensions this context hosts, in origin order.
132 /// `kui_ctx_add_extension` fills it, `kui_slot` fills *them* in place,
133 /// `kui_frame_finish` lets them take `ns/root` and warn about slots
134 /// nobody declared, and an event whose origin names one is delivered to
135 /// it rather than queued for the host. `kui_run_with` moves it into
136 /// the window's runner. Empty on a borrowing context: an extension
137 /// does not host extensions, and a host's under the runner is the
138 /// runner's.
139 pub(crate) extensions: kui_core::Extensions,
140 /// Why the last `kui_ctx_add_extension` said false. Valid until the
141 /// next call, like every other borrowed string here.
142 pub(crate) last_ext_error: String,
143 /// Set only for the length of a `kui_run_with` view callback: the
144 /// runner's own `Ui`, erased to a pointer because `KuiCtx` is what C
145 /// holds and has no lifetime to carry one.
146 ///
147 /// It exists because under the windowed runner the extension list is
148 /// the *runner's*, not this context's — `kui_native::Launcher` owns it, and
149 /// the `Ui` it built the frame with is what knows how to fill a slot.
150 /// So `kui_slot` hands the declaration to that `Ui` when this is set,
151 /// and fills from `extensions` when it is not. Null on every other
152 /// context: a standalone one, and an extension's own.
153 pub(crate) host_ui: *mut c_void,
154}
155
156impl KuiCtx {
157 pub(crate) fn core(&mut self) -> &mut Core {
158 unsafe { &mut *self.core }
159 }
160
161 /// Takes the core a standalone context owns, for `kui_run_with` to
162 /// open the window on, and leaves the context a fresh
163 /// one so that it stays a context — still the caller's to free, and
164 /// to use, as one that has registered nothing. `None` on a borrowing
165 /// context, whose core is someone else's frame.
166 #[cfg(any(feature = "runner", test))]
167 pub(crate) fn take_core(&mut self) -> Option<Box<Core>> {
168 let taken = self._owned.take()?;
169 let mut fresh = Box::new(Core::new());
170 fresh.set_diagnostics(false);
171 self.core = &mut *fresh;
172 self._owned = Some(fresh);
173 Some(taken)
174 }
175
176 /// A context that borrows someone else's frame instead of owning a
177 /// `Core`: what `kui_run`'s view callback and a C extension's both get.
178 /// Only the builder entry points are meaningful on one - the queues
179 /// below stay empty, because the runner owns event delivery.
180 ///
181 /// The borrow is not in the type (`KuiCtx` is what C holds, and it has
182 /// no lifetime), so the caller keeps it: use the context inside the
183 /// scope this `&mut Core` came from and let it go at the end of it.
184 pub(crate) fn borrowing(core: &mut Core) -> Self {
185 Self {
186 core,
187 _owned: None,
188 events: Vec::new(),
189 last_payload: None,
190 last_edit_text: None,
191 fragment_source: String::new(),
192 fragment_draws: Vec::new(),
193 texture_draws: Vec::new(),
194 draws_current: false,
195 image_pixels: None,
196 last_warnings: Vec::new(),
197 pending_warnings: Vec::new(),
198 last_access: Default::default(),
199 last_runs: Vec::new(),
200 last_announcements: Vec::new(),
201 window_commands: VecDeque::new(),
202 menu_actions: VecDeque::new(),
203 menu_text: String::new(),
204 row_text: String::new(),
205 menu_accel: String::new(),
206 copy_text: String::new(),
207 devtools_key: String::new(),
208 file_request: None,
209 file_filter_text: String::new(),
210 devtools_tab: String::new(),
211 menu_html: String::new(),
212 selection_text: String::new(),
213 selection_html: String::new(),
214 font_families: Vec::new(),
215 system_fonts: Vec::new(),
216 nodes: None,
217 last_window_name: None,
218 slot_name: None,
219 slot_namespace: None,
220 slot_params: None,
221 extensions: Default::default(),
222 last_ext_error: String::new(),
223 host_ui: std::ptr::null_mut(),
224 }
225 }
226
227 /// [`Self::borrowing`] for the windowed runner's view callback, which
228 /// has a whole `Ui` rather than a bare `Core`: same context, plus the
229 /// pointer `kui_slot` needs to reach the runner's extensions. Valid
230 /// for the callback and not one instruction longer, like the borrow
231 /// itself.
232 pub(crate) fn borrowing_in(ui: &mut kui_core::Ui<'_>) -> Self {
233 // `borrowing` keeps the core as a raw pointer, so the borrow of
234 // `ui` it takes ends when it returns and the `Ui` can be kept too.
235 let mut this = Self::borrowing(ui.core());
236 this.host_ui = std::ptr::from_mut(ui).cast();
237 this
238 }
239
240 /// Takes a batch of events the core just produced: the host's own are
241 /// queued for `kui_poll_event`, and one whose origin names a loaded
242 /// extension is delivered to it instead, its replies queued in its
243 /// place. `Extensions::route` is the walk, the
244 /// same one the Rust runner's `route_events` takes.
245 pub(crate) fn absorb(&mut self, events: impl IntoIterator<Item = UiEvent>) {
246 let out = &mut self.events;
247 self.extensions.route(events, |ev| out.push(ev));
248 }
249
250 /// Records a just-opened node's hover hint: the core floats it on
251 /// `kui_close` while the node is hovered (`Core::hint`).
252 pub(crate) fn push_tooltip(&mut self, key: kui_core::Key, hint: KuiStr) {
253 if let Some(h) = opt_str(hint) {
254 self.core().hint(key, h.into_owned());
255 }
256 }
257}
258
259/// An opaque dynamic value: null, bool, int, float, string, list or map.
260///
261/// Payloads a host attaches to nodes (`on_click` and the other tags) and
262/// the payloads events carry back are values. Build one with
263/// `kui_value_*` and read one with [`kui_value_get`], [`kui_value_at`],
264/// [`kui_value_as_str`] and friends. One you built is yours until a call
265/// documented as consuming it takes it; otherwise free it with
266/// [`kui_value_free`]. One the library hands out is borrowed.
267#[repr(transparent)]
268pub struct KuiValue(pub(crate) Value);
269
270/// A borrowed string: `len` bytes of UTF-8 at `ptr`, not NUL-terminated.
271///
272/// `KUI_STR("literal")` makes one in C and `kui_str_eq` compares one to a
273/// C string. A string the library hands out points into memory it owns and
274/// is valid until the next call of the same function on that context.
275/// Invalid UTF-8 going in is replaced. The layout is frozen.
276#[repr(C)]
277#[derive(Clone, Copy)]
278pub struct KuiStr {
279 pub ptr: *const u8,
280 pub len: usize,
281}
282
283/// One axis of a node's size: a `KUI_*` tag and its value.
284#[repr(C)]
285#[derive(Clone, Copy)]
286pub struct KuiSizing {
287 /// `KUI_FIT` (0), `KUI_GROW` (1, `value` the weight), `KUI_FIXED` (2,
288 /// logical px), `KUI_PERCENT` (3, `value` 0..1) or `KUI_CALC` (4,
289 /// `value` an expression number from `kui_size_*`).
290 pub tag: u32,
291 pub value: f32,
292}
293
294/// `KuiSpec.min_w` / `min_h` as the node's own fit size (`KUI_MIN_FIT`).
295pub const KUI_MIN_FIT: f32 = -1.0;
296/// `KuiSpec.min_w` / `min_h` as a declared floor of 0: no floor at all,
297/// not even the content's that a share in an overflowing row gets for an
298/// undeclared (0) one; CSS's `min-width: 0`.
299pub const KUI_MIN_NONE: f32 = -2.0;
300/// Which of a `KuiKeyframe`'s fields are set (its `set` bits).
301pub const KUI_KF_AT: u32 = 1 << 0;
302pub const KUI_KF_WIDTH: u32 = 1 << 1;
303pub const KUI_KF_HEIGHT: u32 = 1 << 2;
304pub const KUI_KF_BG: u32 = 1 << 3;
305pub const KUI_KF_RADIUS: u32 = 1 << 4;
306pub const KUI_KF_OPACITY: u32 = 1 << 5;
307pub const KUI_KF_ROTATE: u32 = 1 << 6;
308pub const KUI_KF_SCALE: u32 = 1 << 7;
309pub const KUI_KF_OFFSET: u32 = 1 << 8;
310
311/// One keyframe stop (`KuiSpec.keyframes`): a zeroed stop sets nothing.
312/// `set` says which fields count, so 0 stays a legal value for each.
313#[repr(C)]
314#[derive(Clone, Copy)]
315pub struct KuiKeyframe {
316 pub set: u32,
317 /// 0..1 (KUI_KF_AT); unset stops spread evenly, a lone one sits at 1.
318 pub at: f32,
319 pub width: KuiSizing,
320 pub height: KuiSizing,
321 /// 0xRRGGBBAA
322 pub bg: u32,
323 pub radius: f32,
324 /// Group opacity 0..1 (KUI_KF_OPACITY).
325 pub opacity: f32,
326 /// A turn in turns clockwise (KUI_KF_ROTATE), ADR 0043. ABI 27.
327 pub rotate: f32,
328 /// A uniform scale about the node's pivot (KUI_KF_SCALE). ABI 27.
329 pub scale: f32,
330 /// Logical px from where layout put the node (KUI_KF_OFFSET, both
331 /// together; backlog F132). ABI 27.
332 pub dx: f32,
333 pub dy: f32,
334}
335
336/// `KuiGradient.kind`: along a line, or out from a centre.
337pub const KUI_GRADIENT_LINEAR: u32 = 0;
338pub const KUI_GRADIENT_RADIAL: u32 = 1;
339
340/// One stop of a `KuiGradient`: a colour and where along the gradient
341/// it sits, 0..1 — or a negative `at` for a stop spaced evenly between
342/// its neighbours that have one.
343#[repr(C)]
344#[derive(Clone, Copy)]
345pub struct KuiGradientStop {
346 /// 0xRRGGBBAA
347 pub color: u32,
348 pub at: f32,
349}
350
351/// A box's gradient (`KuiSpec.gradient`,
352/// `docs/adr/0042-a-gradient-is-an-image-the-core-paints.md`): linear
353/// along `angle` — turns clockwise from east, in the box's unit square —
354/// or radial out from (`at_x`, `at_y`), fractions of the box, to its
355/// farthest corner. `stops_len` stops, two or more.
356#[repr(C)]
357#[derive(Clone, Copy)]
358pub struct KuiGradient {
359 /// `KUI_GRADIENT_*`.
360 pub kind: u32,
361 pub angle: f32,
362 pub at_x: f32,
363 pub at_y: f32,
364 pub stops: *const KuiGradientStop,
365 pub stops_len: usize,
366}
367
368/// Which of a `KuiEnter`'s fields are set (its `set` bits); 0 = no entrance.
369/// `KuiSpec.float_mode`: in flow, or which rect the float attaches to. The
370/// non-zero values are `kui_core::FLOAT_PRESETS` indices plus one, so zero
371/// can still mean "no float".
372pub const KUI_FLOAT_NONE: u32 = 0;
373pub const KUI_FLOAT_PARENT: u32 = 1;
374pub const KUI_FLOAT_VIEWPORT: u32 = 2;
375
376pub const KUI_ENTER_OFFSET: u32 = 1 << 0;
377pub const KUI_ENTER_WIDTH: u32 = 1 << 1;
378pub const KUI_ENTER_HEIGHT: u32 = 1 << 2;
379pub const KUI_ENTER_BG: u32 = 1 << 3;
380pub const KUI_ENTER_RADIUS: u32 = 1 << 4;
381pub const KUI_ENTER_OPACITY: u32 = 1 << 5;
382pub const KUI_ENTER_ROTATE: u32 = 1 << 6;
383pub const KUI_ENTER_SCALE: u32 = 1 << 7;
384
385/// Where a node starts the first frame it is seen (`KuiSpec.enter`): the
386/// slots `set` names ease in from these values over `transition_ms`
387/// instead of snapping. A zeroed struct is no entrance.
388#[repr(C)]
389#[derive(Clone, Copy)]
390pub struct KuiEnter {
391 pub set: u32,
392 /// Logical px the node slides in from (KUI_ENTER_OFFSET).
393 pub dx: f32,
394 pub dy: f32,
395 pub width: KuiSizing,
396 pub height: KuiSizing,
397 /// 0xRRGGBBAA
398 pub bg: u32,
399 pub radius: f32,
400 /// Group opacity 0..1 (KUI_ENTER_OPACITY); 0 fades the subtree in.
401 pub opacity: f32,
402 /// A turn in turns clockwise (KUI_ENTER_ROTATE), ADR 0043. ABI 27.
403 pub rotate: f32,
404 /// A uniform scale (KUI_ENTER_SCALE); 0 scales the subtree in from
405 /// nothing. ABI 27.
406 pub scale: f32,
407}
408
409/// Everything a box node is built from: size, layout, paint, behaviour
410/// tags and accessibility, as the `kui_open*` family and the stock
411/// widgets read it.
412///
413/// Zero-initialize it and set what you need; a zeroed field is its
414/// documented default. The library reads the whole struct, so build
415/// against the header that matches `kui_abi_version()`. Pointers (`KuiStr`
416/// and `KuiValue`) are borrowed while the node opens and never retained.
417#[repr(C)]
418#[derive(Clone, Copy)]
419pub struct KuiSpec {
420 pub width: KuiSizing,
421 pub height: KuiSizing,
422 /// Clamps applied after sizing resolves; 0 for max means unconstrained,
423 /// 0 for min is undeclared, `KUI_MIN_FIT` the node's own fit size and
424 /// `KUI_MIN_NONE` a declared 0.
425 pub min_w: f32,
426 pub max_w: f32,
427 pub min_h: f32,
428 pub max_h: f32,
429 /// `KUI_COLUMN` (0), `KUI_ROW` (1) or `KUI_TABLE` (2): a column whose
430 /// rows' children line up in columns.
431 pub dir: u32,
432 pub pad_l: f32,
433 pub pad_r: f32,
434 pub pad_t: f32,
435 pub pad_b: f32,
436 pub gap: f32,
437 /// 0 = start, 1 = center, 2 = end
438 pub main_align: u32,
439 pub cross_align: u32,
440 /// 0xRRGGBBAA; 0 = transparent
441 pub bg: u32,
442 pub border_color: u32,
443 pub border_w: f32,
444 pub radius: f32,
445 /// `KUI_CLIP` | `KUI_SCROLL_X` | `KUI_SCROLL_Y`; the same bits the
446 /// binary protocol carries, applied by `NodeSpec::overflow_bits`.
447 pub overflow: u32,
448 /// `KUI_FLOAT_NONE` (in flow), `KUI_FLOAT_PARENT` or `KUI_FLOAT_VIEWPORT`.
449 /// `kui_spec_float_preset` fills this and the fields below from one of
450 /// the named presets.
451 pub float_mode: u32,
452 /// Attach points as align values (0 start, 1 center, 2 end).
453 pub float_anchor_x: u32,
454 pub float_anchor_y: u32,
455 pub float_self_x: u32,
456 pub float_self_y: u32,
457 pub float_dx: f32,
458 pub float_dy: f32,
459 /// Non-zero: flip across the anchor / clamp to stay in the viewport.
460 pub float_fit: u32,
461 /// Non-zero: hover-track this node (kui_is_hovered) without a payload.
462 pub hoverable: u32,
463 /// Window-chrome role: 0 = none, 1 = drag, 2 = close button,
464 /// 3 = minimize button, 4 = maximize button. Chrome nodes emit window
465 /// commands (kui_take_window_command), never events.
466 pub window_role: u32,
467 /// Positive: ease sizing/colors/radius changes over this many ms (the
468 /// node needs a stable key, i.e. kui_open_keyed). Needs kui_set_time.
469 pub transition_ms: f32,
470 /// KUI_EASE_* curve for `transition_ms`.
471 pub easing: u32,
472 /// Non-zero (with `transition_ms`): also ease the node's position, so
473 /// reordered siblings slide into place.
474 pub slide: u32,
475 /// 0xRRGGBBAA background while hovered (or while any node in the same
476 /// hover group is); 0 = none. Implies hover tracking; eases with
477 /// `transition_ms`.
478 pub hover_bg: u32,
479 /// 0xRRGGBBAA background while pressed; 0 = none. Implies hover tracking.
480 pub pressed_bg: u32,
481 /// Hover group name (empty = none): members show hover_bg / pressed_bg
482 /// together. Hashed by the core; the string is not retained.
483 pub hover_group: KuiStr,
484 /// Non-zero: `radius_tl..radius_bl` are the four corner radii and
485 /// `radius` is ignored (zero = uniform `radius` on every corner).
486 pub per_corner: u32,
487 pub radius_tl: f32,
488 pub radius_tr: f32,
489 pub radius_br: f32,
490 pub radius_bl: f32,
491 /// KUI_REPEAT_* direction for `keyframes` (CSS animation-direction).
492 pub repeat: u32,
493 /// Holds the keyframe cycle back by this many ms (CSS animation-delay).
494 pub delay_ms: f32,
495 /// CSS-style stops (`keyframes_len` of them; NULL/0 = none): the slots
496 /// they name cycle over `transition_ms`, forever, without the view
497 /// redrawing. Read while the node opens; not retained.
498 pub keyframes: *const KuiKeyframe,
499 pub keyframes_len: usize,
500 /// Entrance: with `set` non-zero, the named slots ease in from these
501 /// values on the node's first sight (see `KuiEnter`).
502 pub enter: KuiEnter,
503 /// Registered sounds (`kui_sound_add`) played when the node is clicked /
504 /// the pointer enters it; 0 = none. Either makes the node hover-tracked.
505 pub click_sound: u64,
506 pub hover_sound: u64,
507 /// Layout tag (NULL = none): the node's laid-out rect arrives as
508 /// `{kind="layout", x, y, w, h, parent, tag}` on its first frame and
509 /// whenever it changes. Borrowed — cloned while the node opens, so the
510 /// caller keeps ownership and frees it as usual; `kui_value_null()`
511 /// asks for the events without a tag.
512 pub on_layout: *const KuiValue,
513 /// KUI_ROLE_* (0 = unset: the core derives one). What the node is to
514 /// assistive technology; KUI_ROLE_NONE hides it and its subtree.
515 pub role: u32,
516 /// Accessible name (empty = none). Copied while the node opens.
517 pub label: KuiStr,
518 /// Non-zero: a checkbox / radio / switch role is on.
519 pub checked: u32,
520 /// KUI_VALUE_NOW / MIN / MAX bits saying which of the three below are
521 /// set (a slider role's position and range).
522 pub value_set: u32,
523 pub value_now: f32,
524 pub value_min: f32,
525 pub value_max: f32,
526 /// On a KUI_ROLE_LINE of a custom editor: the caret's byte offset into
527 /// the line's text, and the selection's other end (KUI_VALUE_CARET /
528 /// KUI_VALUE_ANCHOR in `value_set` say which are present).
529 /// KUI_VALUE_CARET_SOLID beside KUI_VALUE_CARET says the caret is
530 /// solid — a block caret in a modal editor's normal mode — so
531 /// `kui_has_caret` leaves it out and no blink clock is armed on it,
532 /// while it still anchors the IME and reads to assistive technology.
533 pub caret: u32,
534 pub selection_anchor: u32,
535 /// Non-zero: reachable by Tab (and focused by a click) without a click
536 /// payload or a control role.
537 pub focusable: u32,
538 /// Non-zero: inert — no click, drag or key sink, no hover / pressed /
539 /// focus background, skipped by Tab, reported disabled to assistive
540 /// technology; hover tracking stays so a tooltip can say why.
541 pub disabled: u32,
542 /// 0xRRGGBBAA background while the node holds keyboard-visible focus
543 /// (Tab or assistive technology put it there); 0 = the core's default
544 /// ring.
545 pub focus_bg: u32,
546 /// Hover hint (empty = none), the `tooltip` prop of the other
547 /// bindings: makes the node hover-tracked, becomes its accessible
548 /// description, and floats `kui_core::widgets::tooltip` below it while
549 /// the pointer is over it: as its last child for the `kui_open*`
550 /// family and the `kui_fragment*` doors (backlog RG124), which
551 /// `kui_close` draws, and beside a leaf, anchored to it,
552 /// for the leaf doors (`leaf_spec_of`, backlog RG113).
553 pub tooltip: KuiStr,
554 /// Modal surface (NULL = none): while this node is declared the Tab
555 /// ring is its subtree, everything outside it is inert to the pointer,
556 /// the wheel and assistive technology, and Escape or a press outside
557 /// emits `{kind="dismiss", reason, tag}` on it — the app stops opening
558 /// the node. The last one declared wins (a confirm inside a dialog);
559 /// a modal that must cover the app is a float. Borrowed — cloned
560 /// while the node opens, so the caller keeps ownership;
561 /// `kui_value_null()` asks for the behaviour without a tag.
562 pub modal: *const KuiValue,
563 /// Context menu (NULL = none): a secondary-button press over this node
564 /// emits `{kind="contextmenu", x, y, tag}` on it, at the logical point
565 /// to open the menu at. The press moves no focus, places no caret and
566 /// produces no click. Borrowed — cloned while the node opens, so the
567 /// caller keeps ownership; `kui_value_null()` asks for the behaviour
568 /// without a tag.
569 pub on_context_menu: *const KuiValue,
570 /// KUI_CURSOR_* (0 = unset: the I-beam over text, the arrow otherwise
571 /// — a clickable or draggable node included). The pointer shape while
572 /// the pointer is over this node; a node with only a cursor is
573 /// hover-tracked so it can be found.
574 pub cursor: u32,
575 /// Non-zero: this node is the current one of its set — the shown tab,
576 /// the picked row, the link for the page you are on. A KUI_ROLE_TAB
577 /// reports the state either way; a row or a link reports it only when
578 /// this is set.
579 pub selected: u32,
580 /// KUI_EXPANDED_* (0 = unset: the node does not expand and says
581 /// nothing about it). What a twisty, an accordion header or a menu
582 /// button reads as.
583 pub expanded: u32,
584 /// Non-zero: `opacity` is the node's group opacity (0 without this bit
585 /// means "not set", so a fully transparent subtree stays expressible).
586 pub opacity_set: u32,
587 /// Group opacity 0..1 with `opacity_set`: fades this node and its whole
588 /// subtree. A per-quad alpha multiply, not an offscreen composite, so
589 /// overlapping pieces of one subtree show their seams through the fade;
590 /// layout, hit-testing and the access tree are untouched. Eases with
591 /// `transition_ms`.
592 pub opacity: f32,
593 /// 0xRRGGBBAA drop-shadow color; 0 = no shadow, and nothing else here
594 /// draws without it. The shadow is the node's rounded rect moved by
595 /// `shadow_x`/`shadow_y`, grown by `shadow_spread` and blurred over
596 /// `shadow_blur`, painted behind the node. Outer shadows only, and the
597 /// shape is not knocked out of the middle.
598 pub shadow_color: u32,
599 /// Blur radius (logical px): the edge ramps over this distance and
600 /// reaches this far past the shape. 0 = a hard edge.
601 pub shadow_blur: f32,
602 /// Offset (logical px); positive `shadow_y` casts downward.
603 pub shadow_x: f32,
604 pub shadow_y: f32,
605 /// Grows (negative: shrinks) the shape before blurring (logical px).
606 pub shadow_spread: f32,
607 /// Non-zero: children that don't fit the main axis start a new line
608 /// instead of overflowing or shrinking. Rows only — a column, or a row
609 /// with KUI_OVERFLOW_SCROLL_X, lays out as if this were 0 and raises a
610 /// `wrap-ignored` warning.
611 pub wrap_children: u32,
612 /// Space between wrap lines, across the main axis (`gap` stays the
613 /// space between children along it).
614 pub cross_gap: f32,
615 /// Non-zero: where focus lands when the enclosing `modal` scope is
616 /// entered - the first node in the modal's Tab ring declaring it,
617 /// instead of the ring's first, so a destructive confirm opens on its
618 /// Cancel. Read on entry only; nothing declaring it (or only nodes
619 /// the ring skips) keeps the ring's first node.
620 pub initial_focus: u32,
621 /// Exit: with `set` non-zero and a `transition_ms`, the frame after the
622 /// view stops declaring this node its subtree is copied out of the last
623 /// frame that had it and replayed — frozen where layout left it, on top
624 /// of everything and inert — while the named slots ease from where they
625 /// were to these values (see `KuiEnter`, which an exit reuses: an exit
626 /// is an entrance read the other way).
627 pub exit: KuiEnter,
628 /// KUI_LIVE_* (0 = KUI_LIVE_OFF, the default): when the text inside
629 /// this node changes, a screen reader reads the change without being
630 /// asked. A node that declares it is semantic, so a plain box marked
631 /// live is not elided from the access tree. For a one-off with no node
632 /// behind it, `kui_announce` is the other half.
633 pub live: u32,
634 /// Non-zero, with a non-NULL `on_key` on `kui_open_with`: the sink hears
635 /// releases too, as the same `{kind="key"}` payload with `phase="up"`
636 /// (`text` null, `repeat` false) — for a held-key interaction (WASD,
637 /// press-and-hold, a key that arms a mode while it is down). A key only
638 /// comes up where it went down, and focus leaving while a key is held
639 /// delivers the `up` first. Zero: presses only, which is what a keymap
640 /// wants — one that heard both halves would run every binding twice.
641 pub key_up: u32,
642 /// What a slider role's position reads as, empty for none (ARIA's
643 /// `aria-valuetext`). Without one a reader has only `value_now` and the
644 /// range and says a percentage — 25 in [5..60] is "36 percent" — so a
645 /// value whose unit carries the meaning says it here: "25 minutes". It
646 /// replaces the number in the reading rather than joining it, and a
647 /// nudge announces the new text. Copied while the node opens. It
648 /// arrives back as `KuiAccessNode.value` (KUI_ACCESS_HAS_VALUE), the
649 /// one string slot a node has.
650 pub value_text: KuiStr,
651 /// The accessible description (empty = none): the extra sentence a
652 /// reader says after the name, for what the name cannot say on its own
653 /// — what a button will do, why a control is disabled, what format a
654 /// field wants. `tooltip` is the shorthand that also draws the string
655 /// and hover-tracks the node; this is the description alone, for a hint
656 /// that is spoken and never drawn. Both write the one slot and this one
657 /// is applied second, so it wins over a `tooltip` on the same node. It
658 /// reads only on a node that reaches the access tree — a role, a label,
659 /// a control — since a plain box is elided and takes its description
660 /// with it. Borrowed while the node opens.
661 pub description: KuiStr,
662 /// Non-zero: ask for another frame after this one, every frame this
663 /// node is declared (`animate`). What a `kui_fragment` reading `time`
664 /// needs. Opt-in, because it takes the loop off input-driven; one node
665 /// asking is enough for the window.
666 pub animate: u32,
667 /// Non-zero: paint this node's background in the OS accent colour
668 /// (`kui_env_set_system`), keeping `bg` where the host never said what
669 /// it is. On `kui_button_with` it takes the hover and pressed shades
670 /// and the label colour with it.
671 pub accent: u32,
672 /// Non-zero: this node is a selection scope. The text of every node
673 /// inside it selects as one run, and a press-drag across them takes
674 /// the lot. Declared on the container, not on each label.
675 pub selectable: u32,
676 /// Force-click tag (`on_force_click`): a press that deepens past the
677 /// second stage of a Force Touch trackpad over this node emits
678 /// `{kind:"forceclick", x, y, tag}` on it. Borrowed while the node
679 /// opens, like every other tag.
680 pub on_force_click: *const KuiValue,
681 /// Non-zero: this node's subtree is a focus region, a Tab ring of its
682 /// own that the ring outside never enters and that never leaves.
683 /// Entered on purpose: `kui_focus_region`, a press inside it, or a
684 /// focus on a node in it. Nothing else about the node changes.
685 pub focus_region: u32,
686 /// When this node's scrollbars are drawn: `KUI_SCROLLBAR_*` (the
687 /// `scrollbar` row's index plus one), 0 for the default, which is
688 /// `KUI_SCROLLBAR_VISIBLE`.
689 pub scrollbar: u32,
690 /// The thumb's width at rest, logical px; 0 for the stock 4. Under
691 /// the pointer or dragged it is 2 px wider.
692 pub scrollbar_width: f32,
693 /// The thumb at rest and under the pointer, `0xRRGGBBAA`; 0 (fully
694 /// transparent, like every unset colour) for the theme's `scrollbar`
695 /// and `scrollbar_active`.
696 pub scrollbar_color: u32,
697 pub scrollbar_active_color: u32,
698 /// Non-zero: scroll anchoring on this scrolling node (CSS's
699 /// `overflow-anchor`): the first child in view keeps its place on
700 /// screen when the content before it changes size.
701 pub anchor: u32,
702 /// Scroll tag (`on_scroll`): the wheel over this node emits
703 /// `{kind:"scroll", x, y, dx, dy, lines, tag}` on it instead of
704 /// scrolling anything (`lines` the whole lines a `cells` grid's delta
705 /// covers, null elsewhere), and a drag-select held past a grid's edge
706 /// arrives the same way once a frame. Borrowed while the node opens,
707 /// like every other tag.
708 pub on_scroll: *const KuiValue,
709 /// Drop-zone tag (`on_drop`): files dragged in from the OS over this
710 /// node emit `{kind:"drop", phase, paths, x, y, tag}` on it, `phase`
711 /// one of `enter`, `move`, `leave`, `drop`. A node inside a zone is
712 /// the zone's; a node that is no zone is looked past. Borrowed while
713 /// the node opens, like every other tag. ABI 18.
714 pub on_drop: *const KuiValue,
715 /// Background while dragged files are over this node, `0xRRGGBBAA`;
716 /// 0 for none. Wins over `pressed_bg`, `focus_bg` and `hover_bg`;
717 /// eases with `transition`. ABI 18.
718 pub drop_bg: u32,
719 /// Non-zero: a `KUI_FLOAT_PARENT` float takes its parent's clip, as a
720 /// child does, instead of escaping every ancestor's: cut at a `clip`
721 /// canvas's edge and not hit past it. Read with the parent anchor
722 /// only; still painted as a layer over its in-flow siblings. ABI 19.
723 pub float_clip: u32,
724 /// Width over height (`aspectRatio`); 0 for none. It sizes the axis
725 /// whose sizing is fit: a fit height from the final width, a fit width
726 /// from a fixed height. ABI 19.
727 pub aspect_ratio: f32,
728 /// A checkbox that is neither on nor off (`mixed`): read as mixed
729 /// whatever `checked` says, drawn as a dash by `kui_checkbox`. ABI 19.
730 pub mixed: u32,
731 /// A slider's step (`valueStep`), present when `KUI_VALUE_STEP` is in
732 /// `value_set`. ABI 19.
733 pub value_step: f32,
734 /// A slider's change tag (`onChange`): the core turns a press, a drag,
735 /// the arrows, PageUp / PageDown and Home / End into
736 /// `{kind:"change", value, phase, tag}`. Borrowed while the node
737 /// opens, like every other tag. ABI 19.
738 pub on_change: *const KuiValue,
739 /// Non-zero: paint the background, border, shadow and fragment with each edge
740 /// on a whole physical pixel (`pixelSnap`), so snapped boxes that
741 /// share an edge in layout, and one beside a text's background, meet
742 /// without a seam. A zeroed field is a box drawn where layout put it.
743 /// ABI 20.
744 pub pixel_snap: u32,
745 /// Non-zero: a press on this node or inside it leaves keyboard focus
746 /// where it was (`keepFocus`). ABI 20.
747 pub keep_focus: u32,
748 /// Focus entering or leaving this node's subtree emits `{kind:"focus",
749 /// phase, by, tag}` (`onFocus`). Borrowed while the node opens, like
750 /// every other tag. ABI 20.
751 pub on_focus: *const KuiValue,
752 /// A table's grid rules (`rules`), 0xRRGGBBAA; 0 draws none. ABI 20.
753 pub rules: u32,
754 /// Their width in logical px (`ruleWidth`); 0 is 1. ABI 20.
755 pub rule_w: f32,
756 /// The non-primary buttons as `{kind:"button", phase, button, x, y,
757 /// clicks, tag}` events on the node that claims them, captured from
758 /// press to release (`onButton`). Borrowed while the node opens, like
759 /// every other tag. ABI 20.
760 pub on_button: *const KuiValue,
761 /// Which buttons `on_button` claims, as `KUI_BUTTONS_*` bits; 0 is all
762 /// three. ABI 20.
763 pub buttons: u32,
764 /// Whether a scroll gesture starting over this scroller at its limit
765 /// goes on to the one around it (`overscroll`): `KUI_OVERSCROLL_*`,
766 /// the row's index plus one; 0 is `auto`. ABI 20.
767 pub overscroll: u32,
768 /// Which axes `on_scroll` takes (`scrollAxes`): `KUI_SCROLL_AXES_*`,
769 /// the row's index plus one; 0 is both. ABI 20.
770 pub scroll_axes: u32,
771 /// Non-zero, with `on_key`: the modifier and lock keys arrive as keys
772 /// of their own (`modifierKeys`), with codes "shift", "ctrl", "alt",
773 /// "super", "capslock", "numlock", "scrolllock" and the side in
774 /// `location`. Zero: a modifier is only ever held. ABI 21.
775 pub modifier_keys: u32,
776 /// The clamps as size expressions: a `KUI_FIXED`, `KUI_PERCENT` or
777 /// `KUI_CALC` sizing (`kui_size_*`) here replaces the float of the
778 /// same name, resolved by layout against the parent's content box;
779 /// zeroed (`KUI_FIT`), the float holds. ABI 22.
780 pub min_w_size: KuiSizing,
781 pub max_w_size: KuiSizing,
782 pub min_h_size: KuiSizing,
783 pub max_h_size: KuiSizing,
784 /// How far a spring overshoots (`bounce`), in place of a spring
785 /// easing's own, and making a timed easing a spring; 0 is the
786 /// easing's own, since a spring with none is `KUI_EASE_SMOOTH`.
787 /// ABI 23.
788 pub bounce: f32,
789 /// A gradient painted over `bg`, under the border and the children;
790 /// NULL for none. Read during the call. ABI 24.
791 pub gradient: *const KuiGradient,
792 /// The modifiers `on_scroll` is for (`scrollMods`), as `KUI_KMOD_*`
793 /// bits: with any set, the node hears only a scroll gesture begun
794 /// with one of them held, ahead of every scroller under the pointer.
795 /// 0 is none: a handler like any other. ABI 25.
796 pub scroll_mods: u32,
797 /// Blur what was drawn beneath the node, inside its rounded box, by
798 /// this radius in logical px (`backdropBlur`, backlog F129); 0 is
799 /// none. ABI 26.
800 pub backdrop_blur: f32,
801 /// A turn of the node and everything under it, in turns clockwise,
802 /// about its pivot, after layout (`rotate`, ADR 0043); 0 is none.
803 /// ABI 27.
804 pub rotate: f32,
805 /// A uniform scale about the pivot (`scale`); 0, the zeroed spec, is
806 /// 1 — a scale of nothing is `opacity`'s job. ABI 27.
807 pub scale: f32,
808 /// `KUI_PIVOT_X` / `KUI_PIVOT_Y` bits saying which of `pivot_x` /
809 /// `pivot_y` hold — fractions of the box (`pivotX` / `pivotY`); an
810 /// axis not set keeps the centre, so a pivot on the top edge or at
811 /// the top-left corner stays expressible. ABI 27.
812 pub pivot_set: u32,
813 pub pivot_x: f32,
814 pub pivot_y: f32,
815 /// How many times the `keyframes` cycle runs (`iterations`, backlog
816 /// F133); 0, the zeroed spec, is for ever. A finite cycle plays from
817 /// the first frame the node is declared with it and rests where its
818 /// last iteration ended. ABI 27.
819 pub iterations: f32,
820}
821
822/// `KuiSpec.pivot_set` bits: which of `pivot_x` / `pivot_y` hold.
823pub const KUI_PIVOT_X: u32 = 1 << 0;
824pub const KUI_PIVOT_Y: u32 = 1 << 1;
825
826/// One laid-out run of an editor's text (`kui_access_runs`): what a
827/// screen reader reads by character and word. `text` ends with `"\n"`
828/// (counted as a zero-width character) when the line continues into
829/// another. Character positions are relative to `x`. Arrays and strings
830/// are borrowed until the next `kui_access_tree` / `kui_access_runs` on
831/// the context.
832#[repr(C)]
833#[derive(Clone, Copy)]
834pub struct KuiAccessRun {
835 /// The run's own id (a `KuiAccessNode.anchor_run` / `focus_run`, and
836 /// what `kui_input_access_text` takes).
837 pub key: u64,
838 /// The line it belongs to (a buffer line, or a KUI_ROLE_LINE ordinal
839 /// for a custom editor) and its byte range in that line's text.
840 pub line: u32,
841 pub start: u32,
842 pub end: u32,
843 pub text: KuiStr,
844 pub x: f32,
845 pub y: f32,
846 pub w: f32,
847 pub h: f32,
848 pub char_count: u32,
849 pub char_lengths: *const u8,
850 pub char_positions: *const f32,
851 pub char_widths: *const f32,
852 pub word_start_count: u32,
853 pub word_starts: *const u8,
854 pub rtl: u32,
855}
856
857pub const KUI_VALUE_CARET: u32 = 1 << 3;
858pub const KUI_VALUE_ANCHOR: u32 = 1 << 4;
859pub const KUI_VALUE_CARET_SOLID: u32 = 1 << 5;
860pub const KUI_ACCESS_HAS_TEXT_SELECTION: u32 = 1 << 9;
861
862/// One node of the access tree (`kui_access_tree`): what assistive
863/// technology sees. `role` is KUI_ROLE_*, `flags` KUI_ACCESS_HAS_* /
864/// FOCUSED / CHECKED bits saying which optional fields hold, `actions`
865/// the KUI_ACCESS_* bits the node accepts through `kui_input_access`.
866/// Strings are borrowed until the next `kui_access_tree` on the context.
867#[repr(C)]
868#[derive(Clone, Copy)]
869pub struct KuiAccessNode {
870 pub key: u64,
871 /// The nearest semantic ancestor; 0 for the root.
872 pub parent: u64,
873 pub origin: u32,
874 pub role: u32,
875 pub flags: u32,
876 pub actions: u32,
877 pub name: KuiStr,
878 pub description: KuiStr,
879 /// The node's one string value (KUI_ACCESS_HAS_VALUE): an editor's
880 /// text, or a slider's `value_text` — the platform has one slot, and a
881 /// slider that named its reading reads as that instead of its number.
882 pub value: KuiStr,
883 /// Logical px, viewport coordinates, cut to the node's clip (zero-size
884 /// on the clip's edge when wholly clipped).
885 pub x: f32,
886 pub y: f32,
887 pub w: f32,
888 pub h: f32,
889 /// Byte offsets into `value` (KUI_ACCESS_HAS_VALUE / HAS_SELECTION).
890 pub caret: u32,
891 pub selection_start: u32,
892 pub selection_end: u32,
893 /// A slider's position and range (KUI_ACCESS_HAS_NUMBER / MIN / MAX).
894 pub value_now: f32,
895 pub value_min: f32,
896 pub value_max: f32,
897 /// A scroll view's offsets and range (KUI_ACCESS_HAS_SCROLL).
898 pub scroll_x: f32,
899 pub scroll_y: f32,
900 pub scroll_max_x: f32,
901 pub scroll_max_y: f32,
902 /// An editor's caret (`focus_*`) and the selection's other end
903 /// (`anchor_*`) as run positions (KUI_ACCESS_HAS_TEXT_SELECTION):
904 /// a run key from `kui_access_runs` and a character index into it.
905 pub anchor_run: u64,
906 pub anchor_char: u32,
907 pub focus_run: u64,
908 pub focus_char: u32,
909 /// How many runs `kui_access_runs` returns for this node.
910 pub run_count: u32,
911 /// "3 of 7" (KUI_ACCESS_HAS_POS_IN_SET / HAS_SET_SIZE): the item's
912 /// zero-based ordinal among its list's or tab list's items, and the
913 /// count on that container.
914 pub pos_in_set: u32,
915 pub set_size: u32,
916 /// KUI_ORIENTATION_* (0 = unset: this node is not a composite
917 /// container). How the container arranges its items, from its own
918 /// `dir`.
919 pub orientation: u32,
920}
921
922pub const KUI_ACCESS_HAS_VALUE: u32 = 1 << 0;
923pub const KUI_ACCESS_HAS_SELECTION: u32 = 1 << 1;
924pub const KUI_ACCESS_FOCUSED: u32 = 1 << 2;
925pub const KUI_ACCESS_CHECKED_SET: u32 = 1 << 3;
926pub const KUI_ACCESS_CHECKED: u32 = 1 << 4;
927pub const KUI_ACCESS_HAS_NUMBER: u32 = 1 << 5;
928pub const KUI_ACCESS_HAS_MIN: u32 = 1 << 6;
929pub const KUI_ACCESS_HAS_MAX: u32 = 1 << 7;
930pub const KUI_ACCESS_HAS_SCROLL: u32 = 1 << 8;
931/// The node is `disabled`: inert, not a Tab stop (bit 9 is
932/// KUI_ACCESS_HAS_TEXT_SELECTION).
933pub const KUI_ACCESS_DISABLED: u32 = 1 << 10;
934/// The node is the frame's `modal` surface (`aria-modal`): focus and input
935/// are confined to it.
936pub const KUI_ACCESS_MODAL: u32 = 1 << 11;
937/// The node has a selected state at all, and what it is: every
938/// KUI_ROLE_TAB, and a row or link the view marked (see `KuiSpec.selected`).
939pub const KUI_ACCESS_SELECTED_SET: u32 = 1 << 12;
940pub const KUI_ACCESS_SELECTED: u32 = 1 << 13;
941/// The node expands, and whether it is open (see `KuiSpec.expanded`).
942pub const KUI_ACCESS_EXPANDED_SET: u32 = 1 << 14;
943pub const KUI_ACCESS_EXPANDED: u32 = 1 << 15;
944/// `pos_in_set` holds (on an item), `set_size` holds (on its container).
945pub const KUI_ACCESS_HAS_POS_IN_SET: u32 = 1 << 16;
946pub const KUI_ACCESS_HAS_SET_SIZE: u32 = 1 << 17;
947/// A checkbox that is neither on nor off (`KuiSpec.mixed`); set beside
948/// `KUI_ACCESS_CHECKED_SET`, whose `KUI_ACCESS_CHECKED` it outranks.
949pub const KUI_ACCESS_MIXED: u32 = 1 << 20;
950/// The node declared `live` (see `KuiSpec.live`), and which politeness.
951/// Two bits rather than a field, because `KuiAccessNode` is an array the
952/// host allocates and appending to it would be an ABI break.
953pub const KUI_ACCESS_LIVE_POLITE: u32 = 1 << 18;
954pub const KUI_ACCESS_LIVE_ASSERTIVE: u32 = 1 << 19;
955
956/// KUI_ORIENTATION_* is the position in `Orientation::ALL` plus one
957/// (0 = unset: the node is not a composite container).
958pub const KUI_ORIENTATION_HORIZONTAL: u32 = 1;
959pub const KUI_ORIENTATION_VERTICAL: u32 = 2;
960
961pub(crate) fn orientation_code(o: Option<kui_core::Orientation>) -> u32 {
962 o.and_then(|o| kui_core::Orientation::ALL.iter().position(|x| *x == o))
963 .map_or(0, |i| i as u32 + 1)
964}
965
966/// KUI_EXPANDED_* is the position in `schema::EXPANDED` plus one (0 = unset:
967/// the node does not expand).
968pub const KUI_EXPANDED_COLLAPSED: u32 = 1;
969pub const KUI_EXPANDED_EXPANDED: u32 = 2;
970
971/// KUI_SCROLLBAR_* is the position in `schema::SCROLLBARS` plus one (0 =
972/// unset, which is the stock visible bar).
973pub const KUI_SCROLLBAR_VISIBLE: u32 = 1;
974pub const KUI_SCROLLBAR_HIDDEN: u32 = 2;
975pub const KUI_SCROLLBAR_AUTO: u32 = 3;
976
977/// KUI_OVERSCROLL_* is the position in `schema::OVERSCROLLS` plus one (0 =
978/// unset, which is `auto`).
979pub const KUI_OVERSCROLL_AUTO: u32 = 1;
980pub const KUI_OVERSCROLL_CONTAIN: u32 = 2;
981
982/// KUI_SCROLL_AXES_* is the position in `schema::SCROLL_AXES` plus one (0
983/// = unset, which is both).
984pub const KUI_SCROLL_AXES_BOTH: u32 = 1;
985pub const KUI_SCROLL_AXES_X: u32 = 2;
986pub const KUI_SCROLL_AXES_Y: u32 = 3;
987
988/// KUI_LIVE_* is the position in `schema::LIVE` itself, not the position
989/// plus one: unlike a disclosure, a live region's zero *is* a value —
990/// "not a live region" is what an unset field already means, so there is
991/// no unset state to reserve zero for.
992pub const KUI_LIVE_OFF: u32 = 0;
993pub const KUI_LIVE_POLITE: u32 = 1;
994pub const KUI_LIVE_ASSERTIVE: u32 = 2;
995
996/// One queued announcement (`kui_take_announcements`): something to say
997/// once, with no node behind it. `live` is KUI_LIVE_POLITE or
998/// KUI_LIVE_ASSERTIVE — never KUI_LIVE_OFF, which `kui_announce` drops.
999/// `text` borrows the context's buffer and stays valid until the next
1000/// `kui_take_announcements` on the same context.
1001#[repr(C)]
1002#[derive(Clone, Copy)]
1003pub struct KuiAnnouncement {
1004 pub text: KuiStr,
1005 pub live: u32,
1006}
1007
1008pub const KUI_VALUE_NOW: u32 = 1 << 0;
1009pub const KUI_VALUE_MIN: u32 = 1 << 1;
1010pub const KUI_VALUE_MAX: u32 = 1 << 2;
1011/// `KuiSpec.value_step` holds.
1012pub const KUI_VALUE_STEP: u32 = 1 << 6;
1013
1014/// KUI_ROLE_* is the position in `Role::ALL` plus one (0 = unset).
1015pub(crate) fn role_code(role: kui_core::Role) -> u32 {
1016 kui_core::Role::ALL
1017 .iter()
1018 .position(|r| *r == role)
1019 .map_or(0, |i| i as u32 + 1)
1020}
1021
1022pub(crate) fn role_of_code(code: u32) -> Option<kui_core::Role> {
1023 (code > 0)
1024 .then(|| kui_core::Role::ALL.get(code as usize - 1).copied())
1025 .flatten()
1026}
1027
1028/// What a piece of text measures (`kui_measure_text`), logical px at the
1029/// scale of the current or last frame.
1030#[repr(C)]
1031#[derive(Clone, Copy)]
1032pub struct KuiTextMetrics {
1033 /// `[out]` reservation; see `KUI_TEXT_METRICS_INIT`.
1034 pub size: u32,
1035 pub width: f32,
1036 pub height: f32,
1037 /// Lines after wrapping (capped by `max_lines`).
1038 pub lines: u32,
1039}
1040
1041// Hand-written rather than derived: a derived `Default` would zero `size`,
1042// and a zero `size` is the one value the handshake refuses.
1043impl Default for KuiTextMetrics {
1044 fn default() -> Self {
1045 Self {
1046 size: std::mem::size_of::<Self>() as u32,
1047 width: 0.0,
1048 height: 0.0,
1049 lines: 0,
1050 }
1051 }
1052}
1053
1054// SAFETY: `repr(C)` with `size: u32` first.
1055unsafe impl OutParam for KuiTextMetrics {
1056 const ABI_V1_SIZE: u32 = abi_through!(KuiTextMetrics, lines, u32);
1057 fn size_mut(&mut self) -> &mut u32 {
1058 &mut self.size
1059 }
1060}
1061
1062/// The palette a frame paints with: one `0xRRGGBBAA` per role, derived
1063/// from what the host reported through `kui_env_set_system` unless it
1064/// pinned something else. Written by `kui_theme` (`[out]`, so start from
1065/// `KUI_THEME_INIT`) and read whole by `kui_theme_set` (`[in]`).
1066///
1067/// The roles are `kui_core::schema::THEME_ROLES` field for field, in that
1068/// order; a test pins the two together, and an append here bumps
1069/// `KUI_ABI_VERSION`.
1070#[repr(C)]
1071#[derive(Clone, Copy)]
1072pub struct KuiTheme {
1073 /// `[out]` reservation; see `KUI_THEME_INIT`. Ignored by
1074 /// `kui_theme_set`, which reads the struct the host filled.
1075 pub size: u32,
1076 /// Which base this came from: `KUI_APPEARANCE_UNKNOWN` (0, the dark
1077 /// base without claiming the user chose it) / `_LIGHT` / `_DARK`.
1078 pub appearance: u32,
1079 /// What a disabled control's opacity is multiplied by.
1080 pub disabled_opacity: f32,
1081 pub bg: u32,
1082 pub surface: u32,
1083 pub raised: u32,
1084 pub sunken: u32,
1085 pub border: u32,
1086 pub border_strong: u32,
1087 pub fg: u32,
1088 pub muted: u32,
1089 pub faint: u32,
1090 pub accent: u32,
1091 pub accent_hover: u32,
1092 pub accent_pressed: u32,
1093 pub on_accent: u32,
1094 pub accent_soft: u32,
1095 pub selection: u32,
1096 pub focus_ring: u32,
1097 pub hover: u32,
1098 pub pressed: u32,
1099 pub success: u32,
1100 pub warning: u32,
1101 pub danger: u32,
1102 pub scrollbar: u32,
1103 pub scrollbar_active: u32,
1104}
1105
1106// Hand-written for the same reason `KuiTextMetrics`'s is: a zeroed `size`
1107// is the one value the handshake refuses.
1108impl Default for KuiTheme {
1109 fn default() -> Self {
1110 Self {
1111 size: std::mem::size_of::<Self>() as u32,
1112 appearance: 0,
1113 disabled_opacity: 0.0,
1114 bg: 0,
1115 surface: 0,
1116 raised: 0,
1117 sunken: 0,
1118 border: 0,
1119 border_strong: 0,
1120 fg: 0,
1121 muted: 0,
1122 faint: 0,
1123 accent: 0,
1124 accent_hover: 0,
1125 accent_pressed: 0,
1126 on_accent: 0,
1127 accent_soft: 0,
1128 selection: 0,
1129 focus_ring: 0,
1130 hover: 0,
1131 pressed: 0,
1132 success: 0,
1133 warning: 0,
1134 danger: 0,
1135 scrollbar: 0,
1136 scrollbar_active: 0,
1137 }
1138 }
1139}
1140
1141// SAFETY: `repr(C)` with `size: u32` first.
1142unsafe impl OutParam for KuiTheme {
1143 const ABI_V1_SIZE: u32 = abi_through!(KuiTheme, scrollbar_active, u32);
1144 fn size_mut(&mut self) -> &mut u32 {
1145 &mut self.size
1146 }
1147}
1148
1149/// The sizes the stock widgets are built from (`kui_metrics`,
1150/// `kui_metrics_set`), in logical px before the scale factor:
1151/// `kui_core::schema::METRIC_ROLES` field for field, in that order. An
1152/// append here bumps `KUI_ABI_VERSION`.
1153#[repr(C)]
1154#[derive(Clone, Copy)]
1155pub struct KuiMetrics {
1156 /// `[out]` reservation; see `KUI_METRICS_INIT`. Ignored by
1157 /// `kui_metrics_set`, which reads the struct the host filled.
1158 pub size: u32,
1159 pub control_text: f32,
1160 pub chrome_text: f32,
1161 pub hint_text: f32,
1162 pub radius: f32,
1163 pub radius_inner: f32,
1164 pub control_pad_x: f32,
1165 pub control_pad_y: f32,
1166 pub field_pad_x: f32,
1167 pub field_pad_y: f32,
1168 pub hint_pad_x: f32,
1169 pub hint_pad_y: f32,
1170 pub menu_pad_x: f32,
1171 pub menu_pad_y: f32,
1172 pub menu_width: f32,
1173 pub menu_bar_h: f32,
1174 pub titlebar_h: f32,
1175}
1176
1177impl Default for KuiMetrics {
1178 fn default() -> Self {
1179 Self::of(&kui_core::Metrics::default())
1180 }
1181}
1182
1183impl KuiMetrics {
1184 /// A core `Metrics` as the host reads it, through the role table so
1185 /// the two cannot disagree on a field.
1186 pub(crate) fn of(m: &kui_core::Metrics) -> Self {
1187 let mut out = Self {
1188 size: std::mem::size_of::<Self>() as u32,
1189 control_text: 0.0,
1190 chrome_text: 0.0,
1191 hint_text: 0.0,
1192 radius: 0.0,
1193 radius_inner: 0.0,
1194 control_pad_x: 0.0,
1195 control_pad_y: 0.0,
1196 field_pad_x: 0.0,
1197 field_pad_y: 0.0,
1198 hint_pad_x: 0.0,
1199 hint_pad_y: 0.0,
1200 menu_pad_x: 0.0,
1201 menu_pad_y: 0.0,
1202 menu_width: 0.0,
1203 menu_bar_h: 0.0,
1204 titlebar_h: 0.0,
1205 };
1206 for role in kui_core::schema::METRIC_ROLES {
1207 *out.field_mut(role.name) = (role.get)(m);
1208 }
1209 out
1210 }
1211
1212 /// The host's struct as a core `Metrics`, through the same table.
1213 pub(crate) fn to_core(self) -> kui_core::Metrics {
1214 let mut m = kui_core::Metrics::default();
1215 for role in kui_core::schema::METRIC_ROLES {
1216 (role.set)(&mut m, *self.field(role.name));
1217 }
1218 m
1219 }
1220
1221 fn field(&self, name: &str) -> &f32 {
1222 match name {
1223 "control_text" => &self.control_text,
1224 "chrome_text" => &self.chrome_text,
1225 "hint_text" => &self.hint_text,
1226 "radius" => &self.radius,
1227 "radius_inner" => &self.radius_inner,
1228 "control_pad_x" => &self.control_pad_x,
1229 "control_pad_y" => &self.control_pad_y,
1230 "field_pad_x" => &self.field_pad_x,
1231 "field_pad_y" => &self.field_pad_y,
1232 "hint_pad_x" => &self.hint_pad_x,
1233 "hint_pad_y" => &self.hint_pad_y,
1234 "menu_pad_x" => &self.menu_pad_x,
1235 "menu_pad_y" => &self.menu_pad_y,
1236 "menu_width" => &self.menu_width,
1237 "menu_bar_h" => &self.menu_bar_h,
1238 "titlebar_h" => &self.titlebar_h,
1239 other => panic!("METRIC_ROLES names a metric KuiMetrics lacks: {other}"),
1240 }
1241 }
1242
1243 fn field_mut(&mut self, name: &str) -> &mut f32 {
1244 match name {
1245 "control_text" => &mut self.control_text,
1246 "chrome_text" => &mut self.chrome_text,
1247 "hint_text" => &mut self.hint_text,
1248 "radius" => &mut self.radius,
1249 "radius_inner" => &mut self.radius_inner,
1250 "control_pad_x" => &mut self.control_pad_x,
1251 "control_pad_y" => &mut self.control_pad_y,
1252 "field_pad_x" => &mut self.field_pad_x,
1253 "field_pad_y" => &mut self.field_pad_y,
1254 "hint_pad_x" => &mut self.hint_pad_x,
1255 "hint_pad_y" => &mut self.hint_pad_y,
1256 "menu_pad_x" => &mut self.menu_pad_x,
1257 "menu_pad_y" => &mut self.menu_pad_y,
1258 "menu_width" => &mut self.menu_width,
1259 "menu_bar_h" => &mut self.menu_bar_h,
1260 "titlebar_h" => &mut self.titlebar_h,
1261 other => panic!("METRIC_ROLES names a metric KuiMetrics lacks: {other}"),
1262 }
1263 }
1264}
1265
1266// SAFETY: `repr(C)` with `size: u32` first.
1267unsafe impl OutParam for KuiMetrics {
1268 const ABI_V1_SIZE: u32 = abi_through!(KuiMetrics, titlebar_h, f32);
1269 fn size_mut(&mut self) -> &mut u32 {
1270 &mut self.size
1271 }
1272}
1273
1274/// One diagnostic (`kui_take_warnings`): a silent misconfiguration the
1275/// core noticed. `code` is stable (`grow-weight-ignored`,
1276/// `transition-auto-key`, `duplicate-key`); the strings are borrowed until
1277/// the next `kui_take_warnings` on the same context.
1278#[repr(C)]
1279#[derive(Clone, Copy)]
1280pub struct KuiWarning {
1281 pub code: KuiStr,
1282 pub key: u64,
1283 pub message: KuiStr,
1284}
1285
1286/// One installed or loaded font family (`kui_system_fonts`), as the font
1287/// database read its faces. `family` and `weights` are borrowed until the
1288/// next `kui_system_fonts` on the same context.
1289#[repr(C)]
1290#[derive(Clone, Copy)]
1291pub struct KuiSystemFont {
1292 /// The name `kui_font_add_system` takes.
1293 pub family: KuiStr,
1294 /// The weights its faces come in (400 regular, 700 bold), sorted,
1295 /// each once; `weight_count` of them.
1296 pub weights: *const u16,
1297 pub weight_count: u32,
1298 /// 1 when every face says it is fixed-pitch.
1299 pub monospaced: u32,
1300 /// 1 when it has an italic or an oblique face.
1301 pub italic: u32,
1302}
1303
1304/// Options for `kui_play`. NULL means defaults; a given struct is read
1305/// literally (so `volume` must be set — `KUI_PLAY_INIT` in kui.h does).
1306#[repr(C)]
1307#[derive(Clone, Copy)]
1308pub struct KuiPlay {
1309 /// Linear amplitude, 0..1.
1310 pub volume: f32,
1311 pub looped: u32,
1312 pub fade_in_ms: f32,
1313}
1314
1315/// What a `kui_audio` node declares; read literally (`KUI_AUDIO_INIT`).
1316#[repr(C)]
1317#[derive(Clone, Copy)]
1318pub struct KuiAudio {
1319 /// A registered sound (`kui_sound_add`).
1320 pub src: u64,
1321 /// Linear amplitude, 0..1.
1322 pub volume: f32,
1323 pub looped: u32,
1324 pub paused: u32,
1325 /// Removal releases the playback instead of stopping it: it plays to
1326 /// its end. Zero stops it.
1327 pub finish: u32,
1328}
1329
1330/// One audio command for a host that drives its own device
1331/// (`kui_take_audio_commands`); `kind` is `KUI_AUDIO_*` and says which of
1332/// the other fields mean anything.
1333#[repr(C)]
1334#[derive(Clone, Copy, Default)]
1335pub struct KuiAudioCommand {
1336 pub kind: u32,
1337 pub playback: u64,
1338 pub sound: u64,
1339 /// Linear amplitude (play, set_volume, master_volume).
1340 pub volume: f32,
1341 /// Fade / tween duration in ms (fade-in for play).
1342 pub ms: f32,
1343 pub looped: u32,
1344}
1345
1346/// How a run of text is set: size, line height, colour, family or font,
1347/// wrapping and decoration. A zeroed struct is the default style at size
1348/// 0, so set at least `size`; NULL where a style pointer is taken is the
1349/// default style.
1350#[repr(C)]
1351#[derive(Clone, Copy)]
1352pub struct KuiTextStyle {
1353 pub size: f32,
1354 /// <= 0 picks the default (size * 1.35).
1355 pub line_height: f32,
1356 /// 0xRRGGBBAA; 0 = default foreground
1357 pub color: u32,
1358 /// KUI_FONT_SANS (0, default) / KUI_FONT_SERIF / KUI_FONT_MONO.
1359 pub family: u32,
1360 /// A registered font handle (kui_font_add / kui_font_add_system);
1361 /// non-zero overrides `family`.
1362 pub font: u64,
1363 /// KUI_WRAP_WORD (0, default) / KUI_WRAP_GLYPH / KUI_WRAP_NONE /
1364 /// KUI_WRAP_BREAK_SPACES.
1365 pub wrap: u32,
1366 /// Lay out at most this many lines; 0 = unlimited.
1367 pub max_lines: u32,
1368 /// Non-zero: end the last line with an ellipsis when the text is cut
1369 /// off (a single line unless `max_lines` says otherwise).
1370 pub ellipsis: u32,
1371 /// OpenType features for the shaper, in the spelling every binding
1372 /// shares: `tag=value` pairs separated by spaces or commas, a bare
1373 /// tag meaning 1 and `-tag` 0 (`"liga=0 calt=0"`, `"tnum"`). Empty
1374 /// (a zeroed `KuiStr`) is the font's defaults.
1375 pub features: KuiStr,
1376 /// `KUI_DECO_UNDERLINE` | `KUI_DECO_STRIKETHROUGH`: lines where the
1377 /// face puts them, over every glyph. Paint only.
1378 pub decoration: u32,
1379 /// The underline's own colour as `0xRRGGBBAA`, 0 for the text's;
1380 /// non-zero implies `KUI_DECO_UNDERLINE`. ABI 17.
1381 pub underline_color: u32,
1382 /// `KUI_UNDERLINE_SOLID` / `_WAVY` / `_DOTTED`; a non-solid style
1383 /// implies `KUI_DECO_UNDERLINE`. ABI 17.
1384 pub underline_style: u32,
1385}
1386
1387/// One styled run of a rich-text paragraph (`kui_rich_text`,
1388/// `kui_measure_rich_text`): its text and what differs from the base
1389/// style. Travels as an array, so an append here is an ABI bump.
1390#[repr(C)]
1391#[derive(Clone, Copy)]
1392pub struct KuiSpan {
1393 pub text: KuiStr,
1394 /// 0xRRGGBBAA; 0 = inherit the paragraph color
1395 pub color: u32,
1396 /// `KUI_SPAN_BOLD` | `KUI_SPAN_ITALIC` | `KUI_SPAN_UNDERLINE` |
1397 /// `KUI_SPAN_STRIKETHROUGH`
1398 pub flags: u32,
1399 /// 0xRRGGBBAA behind the span's glyphs alone, one rect per line the
1400 /// span covers; 0 = none. ABI 8.
1401 pub bg: u32,
1402 /// The underline's own colour, 0 for the span's; non-zero implies
1403 /// `KUI_SPAN_UNDERLINE`. ABI 17.
1404 pub underline_color: u32,
1405 /// `KUI_UNDERLINE_*`; non-solid implies `KUI_SPAN_UNDERLINE`. ABI 17.
1406 pub underline_style: u32,
1407 /// The background's corner radius, logical px; 0 is the square
1408 /// background. Above zero, `bg` is joined into one shape with
1409 /// every rounded background of the same colour and radius it meets —
1410 /// on the line above or below, or end to end on its own line, in this
1411 /// text or another — rounded outside where a line reaches past its
1412 /// neighbour and filleted inside where it falls short: a selection
1413 /// over rows is one outline. ABI 20.
1414 pub bg_radius: f32,
1415 /// With `KUI_SPAN_FAMILY` in `flags`, the span's own face, a
1416 /// `KUI_FONT_*`; without it the paragraph's. ABI 26.
1417 pub family: u32,
1418 /// The span's own size, logical px; 0 is the paragraph's. ABI 26.
1419 pub size: f32,
1420 /// A registered font handle, the span's face; non-zero overrides
1421 /// `family`. ABI 26.
1422 pub font: u64,
1423}
1424
1425/// One colour token as `kui_tokens_set` reads it: a name and a value per
1426/// base, `0xRRGGBBAA` each (the same value twice for a colour that does
1427/// not follow the appearance). Travels as an array, so an append here is
1428/// an ABI bump.
1429#[repr(C)]
1430#[derive(Clone, Copy)]
1431pub struct KuiColorToken {
1432 pub name: KuiStr,
1433 pub light: u32,
1434 pub dark: u32,
1435}
1436
1437/// One length token: a name and logical px, before the scale factor.
1438/// Array-carried like `KuiColorToken`.
1439#[repr(C)]
1440#[derive(Clone, Copy)]
1441pub struct KuiLengthToken {
1442 pub name: KuiStr,
1443 pub value: f32,
1444}
1445
1446/// One step of a derived colour token's recipe as `kui_tokens_derive`
1447/// reads it: the verb as one of the `KUI_OP_*` numbers, the number it
1448/// takes, and (for `KUI_OP_MIX` and `KUI_OP_READABLE` only) the colour
1449/// token or role the verb names, empty otherwise. Array-carried, so an
1450/// append here is an ABI bump.
1451#[repr(C)]
1452#[derive(Clone, Copy)]
1453pub struct KuiColorOp {
1454 pub op: u8,
1455 pub t: f32,
1456 pub other: KuiStr,
1457}
1458
1459/// One derived colour token: a name, the colour token or theme role it
1460/// derives from, and its chain of ops in order (none for an alias).
1461/// Array-carried like `KuiColorToken`.
1462#[repr(C)]
1463#[derive(Clone, Copy)]
1464pub struct KuiDerivedToken {
1465 pub name: KuiStr,
1466 pub from: KuiStr,
1467 pub ops: *const KuiColorOp,
1468 pub op_count: usize,
1469}
1470
1471/// The verbs of `KuiColorOp.op`, numbered as `kui_core::ColorOp::VERBS`
1472/// lists them.
1473pub const KUI_OP_LIFT: u8 = 0;
1474pub const KUI_OP_DARKEN: u8 = 1;
1475pub const KUI_OP_RAISE: u8 = 2;
1476pub const KUI_OP_ALPHA: u8 = 3;
1477pub const KUI_OP_MIX: u8 = 4;
1478pub const KUI_OP_READABLE: u8 = 5;
1479
1480/// Where a `kui_reply` from inside `kui_ext_on_event` sends its value: an
1481/// opaque handle the library puts on the event for the callback and takes
1482/// back when it returns. Never allocate, dereference or store one.
1483///
1484/// It carries a function pointer into the host's copy of this library, so
1485/// a plugin linked against a different copy (which a Windows DLL must be)
1486/// still reaches the host. `push` is cleared when the callback returns, so
1487/// a plugin that stored the event and replies later gets `false`.
1488#[repr(C)]
1489pub struct KuiReplySink {
1490 /// Called with the sink and the value; false if the sink is closed.
1491 pub(crate) push: Option<unsafe extern "C" fn(*mut KuiReplySink, *const KuiValue) -> bool>,
1492}
1493
1494/// One event from the UI, as `kui_poll_event` writes it and `kui_run`'s
1495/// `on_event` receives it.
1496///
1497/// `key` is the node that emitted it, `payload` the tag the node was
1498/// declared with plus what the event adds (its `kind`, a pointer
1499/// position, a key's `code`), `origin` 0 for the host's own nodes and an
1500/// extension's index otherwise, `window` which window it came from. An
1501/// `[out]` struct: start from `KUI_EVENT_INIT` so `size` is set.
1502#[repr(C)]
1503pub struct KuiEvent {
1504 /// Set to `sizeof(KuiEvent)` before the call (`KUI_EVENT_INIT` does);
1505 /// comes back as the number of bytes the library filled.
1506 pub size: u32,
1507 pub origin: u16,
1508 pub key: u64,
1509 /// Borrowed until the next `kui_poll_event`/`kui_ctx_free`; NULL if none.
1510 pub payload: *const KuiValue,
1511 /// Which window the event came from; 0 (`KUI_WINDOW_MAIN`) until a
1512 /// second one is opened. Appended in ABI 4; a host reserving the older
1513 /// layout gets a shorter write and never sees it.
1514 pub window: u32,
1515 /// Where `kui_reply` sends a reply to this event, or NULL when there is
1516 /// nowhere to send one (every event a host polls itself). A host has no
1517 /// use for it: it is the library's channel to a plugin, which passes
1518 /// the event straight back. See [`KuiReplySink`]. Appended in ABI 10.
1519 pub reply_sink: *mut KuiReplySink,
1520 /// The key of the slot whose fill drew the node (what `kui_key_of`
1521 /// answers for the slot's full name), or 0 for a node the host drew
1522 /// itself. Appended after `reply_sink` without a bump: a host
1523 /// reserving the older layout never sees it.
1524 pub slot: u64,
1525}
1526
1527impl Default for KuiEvent {
1528 fn default() -> Self {
1529 Self {
1530 size: std::mem::size_of::<Self>() as u32,
1531 origin: 0,
1532 key: 0,
1533 payload: std::ptr::null(),
1534 window: 0,
1535 reply_sink: std::ptr::null_mut(),
1536 slot: 0,
1537 }
1538 }
1539}
1540
1541// SAFETY: `repr(C)` with `size: u32` first.
1542unsafe impl OutParam for KuiEvent {
1543 /// Through `payload`: the last field ABI 1 shipped, and so still the
1544 /// floor now that `window` follows it.
1545 const ABI_V1_SIZE: u32 = abi_through!(KuiEvent, payload, *const KuiValue);
1546 fn size_mut(&mut self) -> &mut u32 {
1547 &mut self.size
1548 }
1549}
1550
1551/// What a declared window is (`kui_window_declare`), and what an `Open`
1552/// command carries back out inside [`KuiWindowCommand`]. Read literally,
1553/// so start from `KUI_WINDOW_CONFIG_INIT` (a normal, activating 640x480
1554/// window) or pass NULL for exactly that.
1555#[repr(C)]
1556#[derive(Clone, Copy, Default)]
1557pub struct KuiWindowConfig {
1558 /// `KUI_WINDOW_KIND_*`; 0 is a normal window.
1559 pub kind: u32,
1560 /// Initial inner size, logical px. Zero means the default.
1561 pub width: f32,
1562 pub height: f32,
1563 /// Whether opening it takes OS focus. Start a popup from
1564 /// `KUI_WINDOW_POPUP_INIT`, which clears it: a popup that takes focus
1565 /// blurs the field that opened it.
1566 pub activates: u32,
1567 /// `KUI_WINDOW_KIND_POPUP` only: the rect the popup is placed against,
1568 /// in the **declaring window's** logical coordinates — the `x`/`y`/`w`/
1569 /// `h` an `onLayout` event already reports for the field or button the
1570 /// menu belongs to. The host resolves it to screen coordinates against
1571 /// that window's own position. Ignored by a normal window, and read on
1572 /// the opening edge with the rest of the config.
1573 pub anchor_x: f32,
1574 pub anchor_y: f32,
1575 pub anchor_w: f32,
1576 pub anchor_h: f32,
1577}
1578
1579/// `KUI_WINDOW_KIND_NORMAL`: a regular top-level window.
1580pub const KUI_WINDOW_KIND_NORMAL: u32 = 0;
1581/// `KUI_WINDOW_KIND_POPUP`: a borderless, taskbar-less menu surface owned
1582/// by the window that declared it, placed against `anchor_*` in screen
1583/// coordinates and closed when its owner closes.
1584pub const KUI_WINDOW_KIND_POPUP: u32 = 1;
1585
1586pub(crate) fn window_config_of(c: Option<&KuiWindowConfig>) -> WindowConfig {
1587 let Some(c) = c else {
1588 return WindowConfig::default();
1589 };
1590 let size = if c.width > 0.0 && c.height > 0.0 {
1591 Size::new(c.width, c.height)
1592 } else {
1593 WindowConfig::DEFAULT_SIZE
1594 };
1595 WindowConfig {
1596 // A kind this build does not have reads as a normal window, so a
1597 // host built against a later header degrades to a window rather
1598 // than to nothing. `kui_window_declare` raises `unknown-window-kind`
1599 // on the way past, so the degradation is reported and not silent.
1600 kind: match c.kind {
1601 KUI_WINDOW_KIND_POPUP => WindowKind::Popup,
1602 _ => WindowKind::Normal,
1603 },
1604 size,
1605 activates: c.activates != 0,
1606 anchor: Rect::new(c.anchor_x, c.anchor_y, c.anchor_w, c.anchor_h),
1607 }
1608}
1609
1610/// How `kui_run_with` opens its window: the options a Rust host's
1611/// `Launcher` has, as one struct. Read literally, so start from
1612/// `KUI_RUN_CONFIG_INIT` (every zero) or pass NULL for exactly that: a
1613/// 960x640 native window, unbounded, antialiasing chosen by the GPU,
1614/// diagnostics as the build has them.
1615#[repr(C)]
1616#[derive(Clone, Copy, Default, Debug, PartialEq)]
1617pub struct KuiRunConfig {
1618 /// Initial inner size, logical px; zero is the default. Clamped into
1619 /// the bounds below, as the OS would. `KUI_WINDOW=WxH` in the
1620 /// environment still overrides.
1621 pub width: f32,
1622 pub height: f32,
1623 /// Smallest and largest inner size the user may resize to, logical
1624 /// px; a zero side is unbounded, so a lone `min_h` stands. A max
1625 /// below its min loses to it, as on the OS side.
1626 pub min_w: f32,
1627 pub min_h: f32,
1628 pub max_w: f32,
1629 pub max_h: f32,
1630 /// `KUI_CHROME_*`: native decorations, the custom titlebar a
1631 /// `kui_titlebar` draws, or none.
1632 pub chrome: u32,
1633 /// `KUI_TEXT_AA_*`; `KUI_TEXT_AA=gray|subpixel` in the environment
1634 /// still overrides, for an A/B by hand.
1635 pub text_aa: u32,
1636 /// `KUI_DIAG_*`: whether the core runs its checks and the runner
1637 /// prints them to stderr. The window's setting, over whatever
1638 /// `kui_set_diagnostics` set on the context handed in; the default is
1639 /// the build's — on in a debug build, off in release — as `kui_run`
1640 /// always had it.
1641 pub diagnostics: u32,
1642 /// Frames queued ahead of the one on screen; zero is the default.
1643 /// `KUI_FRAME_LATENCY` in the environment still overrides. ABI 19.
1644 pub frame_latency: u32,
1645 /// `KUI_BACKDROP_*`: what shows through the window's transparent
1646 /// pixels where the platform can (`Launcher::backdrop`); 0 is opaque.
1647 /// What the window got is `kui_ctx_backdrop`. ABI 26.
1648 pub backdrop: u32,
1649}
1650
1651/// `KUI_CHROME_NATIVE`: the OS's decorations.
1652pub const KUI_CHROME_NATIVE: u32 = 0;
1653/// `KUI_CHROME_CUSTOM`: undecorated; the view draws a `kui_titlebar` and
1654/// the runner synthesizes edge resizing and double-click maximize.
1655pub const KUI_CHROME_CUSTOM: u32 = 1;
1656/// `KUI_CHROME_BORDERLESS`: no decorations and no chrome expectations.
1657pub const KUI_CHROME_BORDERLESS: u32 = 2;
1658/// `KUI_TEXT_AA_AUTO`: LCD subpixel coverage when the GPU can blend per
1659/// channel, grayscale otherwise.
1660pub const KUI_TEXT_AA_AUTO: u32 = 0;
1661/// `KUI_TEXT_AA_GRAYSCALE`.
1662pub const KUI_TEXT_AA_GRAYSCALE: u32 = 1;
1663/// `KUI_TEXT_AA_SUBPIXEL`.
1664pub const KUI_TEXT_AA_SUBPIXEL: u32 = 2;
1665/// `KUI_DIAG_DEFAULT`: the build's — on in debug, off in release.
1666pub const KUI_DIAG_DEFAULT: u32 = 0;
1667/// `KUI_DIAG_ON`.
1668pub const KUI_DIAG_ON: u32 = 1;
1669/// `KUI_DIAG_OFF`.
1670pub const KUI_DIAG_OFF: u32 = 2;
1671
1672/// A `KuiRunConfig` read: what `kui_run_with` tells the launcher, in the
1673/// launcher's own terms. Separate from the launcher so the reading is a
1674/// test without a window.
1675#[cfg(any(feature = "runner", test))]
1676#[derive(Debug, PartialEq, Default)]
1677pub(crate) struct RunOptions {
1678 pub size: Option<(f64, f64)>,
1679 pub min_size: Option<(f64, f64)>,
1680 pub max_size: Option<(f64, f64)>,
1681 /// `KUI_CHROME_*`, checked.
1682 pub chrome: u32,
1683 /// `KUI_TEXT_AA_*`, checked.
1684 pub text_aa: u32,
1685 /// `None` is the build's default.
1686 pub diagnostics: Option<bool>,
1687 /// `None` is the launcher's default.
1688 pub frame_latency: Option<u32>,
1689 /// The backdrop asked for, checked.
1690 pub backdrop: kui_core::Backdrop,
1691}
1692
1693/// A max side left at zero is unbounded: a bound no display reaches, as
1694/// Node's `maxWidth` alone is.
1695#[cfg(any(feature = "runner", test))]
1696pub(crate) const UNBOUNDED_SIZE: f64 = 65_535.0;
1697
1698/// Reads a config the way `kui_window_declare` reads its own — literally,
1699/// NULL for the defaults — except that a word this build does not have is
1700/// refused with its reason rather than degraded: a window that opened
1701/// native when asked for the custom chrome would draw its titlebar under
1702/// the OS's.
1703#[cfg(any(feature = "runner", test))]
1704pub(crate) fn run_options_of(c: Option<&KuiRunConfig>) -> Result<RunOptions, String> {
1705 let Some(c) = c else {
1706 return Ok(RunOptions::default());
1707 };
1708 let side = |v: f32, what: &str| -> Result<f64, String> {
1709 if v.is_finite() && v >= 0.0 {
1710 Ok(f64::from(v))
1711 } else {
1712 Err(format!(
1713 "KuiRunConfig.{what} must be a finite, non-negative size, not {v}"
1714 ))
1715 }
1716 };
1717 let (w, h) = (side(c.width, "width")?, side(c.height, "height")?);
1718 let size =
1719 match (w > 0.0, h > 0.0) {
1720 (true, true) => Some((w, h)),
1721 (false, false) => None,
1722 _ => return Err(
1723 "KuiRunConfig: width and height go together (a min or max side may stand alone)"
1724 .into(),
1725 ),
1726 };
1727 let (min_w, min_h) = (side(c.min_w, "min_w")?, side(c.min_h, "min_h")?);
1728 let min_size = (min_w > 0.0 || min_h > 0.0).then_some((min_w, min_h));
1729 let (max_w, max_h) = (side(c.max_w, "max_w")?, side(c.max_h, "max_h")?);
1730 let unbounded = |v: f64| if v > 0.0 { v } else { UNBOUNDED_SIZE };
1731 let max_size = (max_w > 0.0 || max_h > 0.0).then_some((unbounded(max_w), unbounded(max_h)));
1732 if c.chrome > KUI_CHROME_BORDERLESS {
1733 return Err(format!(
1734 "KuiRunConfig.chrome must be KUI_CHROME_NATIVE, KUI_CHROME_CUSTOM or KUI_CHROME_BORDERLESS, not {}",
1735 c.chrome
1736 ));
1737 }
1738 if c.text_aa > KUI_TEXT_AA_SUBPIXEL {
1739 return Err(format!(
1740 "KuiRunConfig.text_aa must be KUI_TEXT_AA_AUTO, KUI_TEXT_AA_GRAYSCALE or KUI_TEXT_AA_SUBPIXEL, not {}",
1741 c.text_aa
1742 ));
1743 }
1744 let diagnostics = match c.diagnostics {
1745 KUI_DIAG_DEFAULT => None,
1746 KUI_DIAG_ON => Some(true),
1747 KUI_DIAG_OFF => Some(false),
1748 other => {
1749 return Err(format!(
1750 "KuiRunConfig.diagnostics must be KUI_DIAG_DEFAULT, KUI_DIAG_ON or KUI_DIAG_OFF, not {other}"
1751 ));
1752 }
1753 };
1754 let Some(backdrop) = kui_core::Backdrop::from_code(c.backdrop) else {
1755 return Err(format!(
1756 "KuiRunConfig.backdrop must be KUI_BACKDROP_OPAQUE, KUI_BACKDROP_TRANSPARENT, KUI_BACKDROP_BLUR or KUI_BACKDROP_TINTED, not {}",
1757 c.backdrop
1758 ));
1759 };
1760 Ok(RunOptions {
1761 size,
1762 min_size,
1763 max_size,
1764 chrome: c.chrome,
1765 text_aa: c.text_aa,
1766 diagnostics,
1767 frame_latency: (c.frame_latency > 0).then_some(c.frame_latency),
1768 backdrop,
1769 })
1770}
1771
1772fn window_config_to_c(c: WindowConfig) -> KuiWindowConfig {
1773 KuiWindowConfig {
1774 kind: match c.kind {
1775 WindowKind::Normal => KUI_WINDOW_KIND_NORMAL,
1776 WindowKind::Popup => KUI_WINDOW_KIND_POPUP,
1777 },
1778 width: c.size.w,
1779 height: c.size.h,
1780 activates: c.activates as u32,
1781 anchor_x: c.anchor.x,
1782 anchor_y: c.anchor.y,
1783 anchor_w: c.anchor.w,
1784 anchor_h: c.anchor.h,
1785 }
1786}
1787
1788/// `KUI_DISMISS_OUTSIDE`, `KUI_DISMISS_ESCAPE`: why a window was asked to
1789/// go away (`kui_window_dismissed`).
1790pub const KUI_DISMISS_OUTSIDE: u32 = 0;
1791pub const KUI_DISMISS_ESCAPE: u32 = 1;
1792
1793/// `KUI_OPTION_AS_ALT_NONE`, `_LEFT`, `_RIGHT`, `_BOTH`: which Option
1794/// keys act as Alt on macOS (`kui_set_option_as_alt`).
1795pub const KUI_OPTION_AS_ALT_NONE: u32 = 0;
1796pub const KUI_OPTION_AS_ALT_LEFT: u32 = 1;
1797pub const KUI_OPTION_AS_ALT_RIGHT: u32 = 2;
1798pub const KUI_OPTION_AS_ALT_BOTH: u32 = 3;
1799
1800/// `KUI_CMD_START_DRAG`, `KUI_CMD_CLOSE`, `KUI_CMD_MINIMIZE`,
1801/// `KUI_CMD_TOGGLE_MAXIMIZE`: the verbs chrome nodes issue.
1802pub const KUI_CMD_START_DRAG: u32 = 1;
1803pub const KUI_CMD_CLOSE: u32 = 2;
1804pub const KUI_CMD_MINIMIZE: u32 = 3;
1805pub const KUI_CMD_TOGGLE_MAXIMIZE: u32 = 4;
1806/// `KUI_CMD_OPEN`: the declared set gained a window; `config` says what.
1807pub const KUI_CMD_OPEN: u32 = 5;
1808/// `KUI_CMD_SET_SIZE`: the app asked for a size (`kui_set_window_size`);
1809/// `width`/`height` carry it. `KUI_CMD_FOCUS`: it asked for focus.
1810pub const KUI_CMD_SET_SIZE: u32 = 6;
1811pub const KUI_CMD_FOCUS: u32 = 7;
1812/// `KUI_CMD_REDRAW`: draw `window` again, because another window's input
1813/// changed what it shows. A host that redraws every window on every event
1814/// may ignore it.
1815pub const KUI_CMD_REDRAW: u32 = 8;
1816
1817/// One window command (`kui_take_window_command`): what a chrome node
1818/// asked for, or what the declared window set's diff decided. Plain data
1819/// (an `Open` carries no title; the window's first frame declares one
1820/// through `kui_window_title`), so nothing borrowed enters a host's drain
1821/// loop. An `[out]` struct: start from `KUI_WINDOW_COMMAND_INIT`.
1822#[repr(C)]
1823pub struct KuiWindowCommand {
1824 /// Set to `sizeof(KuiWindowCommand)` before the call
1825 /// (`KUI_WINDOW_COMMAND_INIT` does); comes back as the bytes filled.
1826 pub size: u32,
1827 /// `KUI_CMD_*`.
1828 pub kind: u32,
1829 /// Which window: the one the chrome node was drawn in, or for
1830 /// `KUI_CMD_OPEN` the id the core assigned the new window — what its
1831 /// events will carry in `KuiEvent.window`.
1832 pub window: u32,
1833 /// `KUI_CMD_OPEN` only: which frontend's declaration won (0 = the host,
1834 /// 1+ = an extension), so a host can refuse an extension's window.
1835 pub origin: u16,
1836 /// `KUI_CMD_OPEN` only: the config from the declaration that opened it.
1837 pub config: KuiWindowConfig,
1838 /// `KUI_CMD_SET_SIZE` only: the size asked for, logical px. Appended in
1839 /// ABI 6; only the host's own `kui_set_window_size` produces the verb
1840 /// that fills them.
1841 pub width: f32,
1842 pub height: f32,
1843 /// `KUI_CMD_OPEN` only: the window whose frame declared this one. For a
1844 /// `KUI_WINDOW_KIND_POPUP` it is the owner — the surface `config`'s
1845 /// `anchor_*` is measured against, the one to parent it to, and the one
1846 /// whose closing closes it. (The core closes it either way: an owner's
1847 /// declarations leave the declared set with it, so the same drain
1848 /// carries the popup's `KUI_CMD_CLOSE`.)
1849 pub owner: u32,
1850}
1851
1852impl Default for KuiWindowCommand {
1853 fn default() -> Self {
1854 Self {
1855 size: std::mem::size_of::<Self>() as u32,
1856 kind: 0,
1857 window: 0,
1858 origin: 0,
1859 config: KuiWindowConfig::default(),
1860 width: 0.0,
1861 height: 0.0,
1862 owner: 0,
1863 }
1864 }
1865}
1866
1867// SAFETY: `repr(C)` with `size: u32` first.
1868unsafe impl OutParam for KuiWindowCommand {
1869 /// Through `config`: the whole struct as it first shipped, in ABI 5.
1870 /// ABI 6's `width`/`height` and ABI 7's `owner` sit past it, so the
1871 /// floor never moved for those — but ABI 7 also grew `KuiWindowConfig`
1872 /// itself, by the four anchor floats a popup is placed against, and a
1873 /// field appended *inside* an embedded struct moves everything after
1874 /// it. So the floor is 16 bytes higher than the whole ABI-6 struct was,
1875 /// an ABI-6 host's reservation is refused rather than short-written
1876 /// (`out_accepts`), and `kui_abi_version()` is what catches that before
1877 /// it looks like an empty queue. The size handshake bounds the damage;
1878 /// only the version check prevents it.
1879 const ABI_V1_SIZE: u32 = abi_through!(KuiWindowCommand, config, KuiWindowConfig);
1880 fn size_mut(&mut self) -> &mut u32 {
1881 &mut self.size
1882 }
1883}
1884
1885pub(crate) fn window_command_to_c(cmd: WindowCommand) -> KuiWindowCommand {
1886 let mut size = Size::new(0.0, 0.0);
1887 let mut owner = 0;
1888 let (kind, origin, config) = match cmd {
1889 WindowCommand::StartDrag(_) => (KUI_CMD_START_DRAG, 0, KuiWindowConfig::default()),
1890 WindowCommand::Close(_) => (KUI_CMD_CLOSE, 0, KuiWindowConfig::default()),
1891 WindowCommand::Minimize(_) => (KUI_CMD_MINIMIZE, 0, KuiWindowConfig::default()),
1892 WindowCommand::ToggleMaximize(_) => {
1893 (KUI_CMD_TOGGLE_MAXIMIZE, 0, KuiWindowConfig::default())
1894 }
1895 WindowCommand::Open {
1896 owner: o,
1897 origin,
1898 config,
1899 ..
1900 } => {
1901 owner = o.0;
1902 (KUI_CMD_OPEN, origin.0, window_config_to_c(config))
1903 }
1904 WindowCommand::SetSize { size: s, .. } => {
1905 size = s;
1906 (KUI_CMD_SET_SIZE, 0, KuiWindowConfig::default())
1907 }
1908 WindowCommand::Focus(_) => (KUI_CMD_FOCUS, 0, KuiWindowConfig::default()),
1909 WindowCommand::Redraw(_) => (KUI_CMD_REDRAW, 0, KuiWindowConfig::default()),
1910 };
1911 KuiWindowCommand {
1912 kind,
1913 window: cmd.window().0,
1914 origin,
1915 config,
1916 width: size.w,
1917 height: size.h,
1918 owner,
1919 ..Default::default()
1920 }
1921}
1922
1923/// One quad of a frame's draw list, in physical pixels: a rounded
1924/// rectangle, border, shadow, glyph, image or segment, told apart by
1925/// `kind`. A renderer draws them in order, every one with the same
1926/// instanced pipeline; `KuiDrawData` hands out the array.
1927#[repr(C)]
1928#[derive(Clone, Copy)]
1929pub struct KuiQuad {
1930 pub x: f32,
1931 pub y: f32,
1932 pub w: f32,
1933 pub h: f32,
1934 pub color: [f32; 4],
1935 pub border_color: [f32; 4],
1936 /// Corner radii (physical px), clockwise from the top-left.
1937 pub radius: [f32; 4],
1938 pub border_w: f32,
1939 /// KUI_QUAD_SHADOW only: blur radius (physical px), which is also how
1940 /// far `x`/`y`/`w`/`h` is inflated past the shape being blurred.
1941 pub blur: f32,
1942 /// KUI_QUAD_*
1943 pub kind: u32,
1944 /// Which entry of `KuiDrawData::clips` clips this quad; entry zero
1945 /// clips nothing.
1946 pub clip: u32,
1947 /// Atlas texels: x, y, w, h. `KUI_QUAD_SEGMENT`: the endpoints as
1948 /// float bits (see `kui_core::Quad::segment_ends`).
1949 pub uv: [u32; 4],
1950}
1951
1952/// One clip a frame's quads name, in physical pixels. Mirrors
1953/// `kui_core::Clip`, so `KuiDrawData::clips` is a cast and not a copy.
1954#[repr(C)]
1955#[derive(Clone, Copy)]
1956pub struct KuiClip {
1957 /// Clip rect: x, y, w, h. Pixels outside are transparent.
1958 pub rect: [f32; 4],
1959 /// Corner radii (physical px), clockwise from the top-left: pixels
1960 /// outside the rounded clip are transparent too. All zero — every clip
1961 /// of a frame with no rounded clipper — is the plain rect clip.
1962 pub radius: [f32; 4],
1963 /// The turn every quad naming this entry is drawn through (ADR
1964 /// 0043): angle in radians (clockwise, y down), scale, tx, ty —
1965 /// `pixel = R(angle) · scale · p + (tx, ty)` for `p` a point of the
1966 /// quad's own rect. `{0, 1, 0, 0}`, the identity, on every entry of a
1967 /// frame that turns nothing. ABI 27.
1968 pub transform: [f32; 4],
1969 /// A second clip in the quad's own space, before the turn: x, y, w,
1970 /// h, from clipping nodes inside a turned subtree. The clip that clips
1971 /// nothing (a rect past any pixel) when nothing inside a turn clips.
1972 pub inner: [f32; 4],
1973 /// `inner`'s corner radii, as `radius` is `rect`'s.
1974 pub inner_radius: [f32; 4],
1975}
1976
1977/// One `KUI_QUAD_FRAGMENT`'s draw, addressed by that quad's `uv[0]`.
1978#[repr(C)]
1979#[derive(Clone, Copy)]
1980pub struct KuiFragmentDraw {
1981 /// The registered handle, for `kui_fragment_source` and for keying a
1982 /// renderer's pipeline cache.
1983 pub fragment: u64,
1984 /// What the node declared, zero-padded to sixteen.
1985 pub params: [f32; 16],
1986 /// Where the draw's `image` is: `KUI_FRAGMENT_IMAGE_NONE`,
1987 /// `_ATLAS` (bind the atlas, as for any fragment) or `_TEXTURE` (bind
1988 /// the texture `image_texture` names, as for a `KUI_QUAD_TEXTURE`
1989 /// quad). Added in ABI 15.
1990 pub image_source: u32,
1991 /// The `textures` index the draw reads, when `image_source` is
1992 /// `KUI_FRAGMENT_IMAGE_TEXTURE`; 0 otherwise.
1993 pub image_texture: u32,
1994 /// The texel rect the shader is given as `FragmentIn::image`, in the
1995 /// atlas or in that texture; zero with no image.
1996 pub image_uv: [u32; 4],
1997}
1998
1999/// `KuiFragmentDraw::image_source`: no image.
2000pub const KUI_FRAGMENT_IMAGE_NONE: u32 = 0;
2001/// `KuiFragmentDraw::image_source`: the image is in the atlas.
2002pub const KUI_FRAGMENT_IMAGE_ATLAS: u32 = 1;
2003/// `KuiFragmentDraw::image_source`: the image has a texture of its own.
2004pub const KUI_FRAGMENT_IMAGE_TEXTURE: u32 = 2;
2005
2006/// One `KUI_QUAD_TEXTURE`'s draw, addressed by that quad's `uv[0]`.
2007#[repr(C)]
2008#[derive(Clone, Copy)]
2009pub struct KuiTextureDraw {
2010 /// The image handle, for `kui_image_pixels` and for keying a
2011 /// renderer's texture cache.
2012 pub image: u64,
2013 /// Moves with every `kui_image_update`; a renderer that uploaded this
2014 /// revision has nothing to do.
2015 pub rev: u32,
2016 pub width: u32,
2017 pub height: u32,
2018 /// The texel rect to show, `[x, y, w, h]` in the image's own texels —
2019 /// the whole image, or the crop a `fit = cover` made.
2020 pub uv: [u32; 4],
2021}
2022
2023/// The finished frame's draw list, as `kui_draw_data` writes it: the
2024/// quads, the clips they index, the glyph atlas to mirror as a texture,
2025/// and the side lists for fragments and texture-backed images.
2026///
2027/// Everything is in physical pixels. The pointers are valid until the
2028/// next `kui_frame_begin` on the context. An `[out]` struct: start from
2029/// `KUI_DRAW_DATA_INIT`.
2030#[repr(C)]
2031pub struct KuiDrawData {
2032 /// `[out]` reservation; see `KUI_DRAW_DATA_INIT`.
2033 pub size: u32,
2034 pub quads: *const KuiQuad,
2035 pub quad_count: usize,
2036 pub viewport_w: f32,
2037 pub viewport_h: f32,
2038 pub scale: f32,
2039 /// RGBA, atlas_size * atlas_size * 4 bytes.
2040 pub atlas_pixels: *const u8,
2041 /// Can grow or shrink between frames: a page extended for one frame
2042 /// goes back to its size at the next. Size the texture to it, not to
2043 /// the largest seen.
2044 pub atlas_size: u32,
2045 /// Re-upload the atlas texture when either of these changes/sets.
2046 pub atlas_dirty: bool,
2047 pub atlas_epoch: u64,
2048 /// One per `KUI_QUAD_FRAGMENT` quad, indexed by its `uv[0]`; null and
2049 /// zero on a frame that draws none. Added in ABI 9.
2050 pub fragments: *const KuiFragmentDraw,
2051 pub fragment_count: usize,
2052 /// The frame clock in seconds, for a fragment's `time`.
2053 pub time: f32,
2054 /// The clips the quads index through `KuiQuad::clip`. Never empty on a
2055 /// frame that drew anything: entry zero clips nothing. Added in
2056 /// ABI 11.
2057 pub clips: *const KuiClip,
2058 pub clip_count: usize,
2059 /// One per `KUI_QUAD_TEXTURE` quad, indexed by its `uv[0]`; null and
2060 /// zero on a frame that draws none. Added in ABI 14.
2061 pub textures: *const KuiTextureDraw,
2062 pub texture_count: usize,
2063}
2064
2065impl Default for KuiDrawData {
2066 fn default() -> Self {
2067 Self {
2068 size: std::mem::size_of::<Self>() as u32,
2069 quads: std::ptr::null(),
2070 quad_count: 0,
2071 viewport_w: 0.0,
2072 viewport_h: 0.0,
2073 scale: 1.0,
2074 atlas_pixels: std::ptr::null(),
2075 atlas_size: 0,
2076 atlas_dirty: false,
2077 atlas_epoch: 0,
2078 fragments: std::ptr::null(),
2079 fragment_count: 0,
2080 time: 0.0,
2081 clips: std::ptr::null(),
2082 clip_count: 0,
2083 textures: std::ptr::null(),
2084 texture_count: 0,
2085 }
2086 }
2087}
2088
2089// SAFETY: `repr(C)` with `size: u32` first.
2090unsafe impl OutParam for KuiDrawData {
2091 const ABI_V1_SIZE: u32 = abi_through!(KuiDrawData, atlas_epoch, u64);
2092 fn size_mut(&mut self) -> &mut u32 {
2093 &mut self.size
2094 }
2095}
2096
2097/// What the last layout resolved for a scroll container (`kui_scroll_geometry`):
2098/// its own box, its content size and the clamped offset, all logical px in
2099/// viewport coordinates.
2100#[repr(C)]
2101#[derive(Clone, Copy)]
2102pub struct KuiScrollGeometry {
2103 /// `[out]` reservation; see `KUI_SCROLL_GEOMETRY_INIT`.
2104 pub size: u32,
2105 /// The container's box, as the last layout placed and sized it.
2106 pub x: f32,
2107 pub y: f32,
2108 pub w: f32,
2109 pub h: f32,
2110 /// Its laid-out content, padding included.
2111 pub content_w: f32,
2112 pub content_h: f32,
2113 /// Where it is scrolled to: the retained offset clamped to the travel
2114 /// below, so it is always a position within the content.
2115 pub offset_x: f32,
2116 pub offset_y: f32,
2117 /// How far the offset can travel; zero on an axis that does not scroll.
2118 pub max_offset_x: f32,
2119 pub max_offset_y: f32,
2120}
2121
2122impl Default for KuiScrollGeometry {
2123 fn default() -> Self {
2124 Self {
2125 size: std::mem::size_of::<Self>() as u32,
2126 x: 0.0,
2127 y: 0.0,
2128 w: 0.0,
2129 h: 0.0,
2130 content_w: 0.0,
2131 content_h: 0.0,
2132 offset_x: 0.0,
2133 offset_y: 0.0,
2134 max_offset_x: 0.0,
2135 max_offset_y: 0.0,
2136 }
2137 }
2138}
2139
2140/// One cell of a `kui_cells` grid: a Unicode scalar, colours as
2141/// `0xRRGGBBAA` (a `bg` of 0 is none), `KUI_CELL_*` attribute bits.
2142/// Travels as an array, so a change here is an ABI bump.
2143#[repr(C)]
2144#[derive(Clone, Copy, Default)]
2145pub struct KuiCell {
2146 pub ch: u32,
2147 pub fg: u32,
2148 pub bg: u32,
2149 pub flags: u32,
2150 /// The underline's own colour (SGR 58), 0 for `fg`. ABI 17.
2151 pub ul: u32,
2152}
2153
2154/// What choosing a context-menu row left for the host
2155/// (`kui_take_menu_action`): the clipboard, which is the host's in this
2156/// library. `KUI_MENU_ACTION_SET_CLIPBOARD` carries the text to put there;
2157/// `KUI_MENU_ACTION_PASTE` carries nothing and asks for what is there,
2158/// which the host delivers back with `kui_input_paste` (or
2159/// `kui_input_commit`); `KUI_MENU_ACTION_SET_CLIPBOARD_SECRET` carries a
2160/// secret to put there marked concealed and transient.
2161#[repr(C)]
2162#[derive(Clone, Copy)]
2163pub struct KuiMenuAction {
2164 /// `[out]` reservation; see `KUI_MENU_ACTION_INIT`.
2165 pub size: u32,
2166 /// A `KUI_MENU_ACTION_*` kind.
2167 pub kind: u32,
2168 /// Borrowed until the next `kui_take_menu_action` on this context.
2169 pub text: KuiStr,
2170 /// The same selection with the formatting the core knows about, for a
2171 /// host offering a second clipboard flavour.
2172 /// Empty when there is none to carry — and never a *replacement* for
2173 /// `text`: a clipboard whose only flavour is HTML pastes markup into
2174 /// every plain-text field on the machine.
2175 pub html: KuiStr,
2176 /// `KUI_MENU_ACTION_LOOK_UP` only: where to anchor the panel — the
2177 /// baseline origin of the selection's first line, logical viewport
2178 /// px. Zero for every other kind.
2179 pub x: f32,
2180 pub y: f32,
2181}
2182
2183impl Default for KuiMenuAction {
2184 fn default() -> Self {
2185 Self {
2186 size: std::mem::size_of::<Self>() as u32,
2187 kind: 0,
2188 text: KuiStr {
2189 ptr: std::ptr::null(),
2190 len: 0,
2191 },
2192 html: KuiStr {
2193 ptr: std::ptr::null(),
2194 len: 0,
2195 },
2196 x: 0.0,
2197 y: 0.0,
2198 }
2199 }
2200}
2201
2202// SAFETY: `repr(C)` with `size: u32` first.
2203unsafe impl OutParam for KuiMenuAction {
2204 const ABI_V1_SIZE: u32 = abi_through!(KuiMenuAction, y, f32);
2205 fn size_mut(&mut self) -> &mut u32 {
2206 &mut self.size
2207 }
2208}
2209
2210/// Where a point landed in the text a keyed node drew (`kui_text_hit`):
2211/// a byte offset into that text, across the node's text runs in order,
2212/// and the visual (wrapped) line it is on.
2213#[repr(C)]
2214#[derive(Clone, Copy)]
2215pub struct KuiTextHit {
2216 /// `[out]` reservation; see `KUI_TEXT_HIT_INIT`.
2217 pub size: u32,
2218 pub line: u32,
2219 pub byte: u64,
2220}
2221
2222impl Default for KuiTextHit {
2223 fn default() -> Self {
2224 Self {
2225 size: std::mem::size_of::<Self>() as u32,
2226 line: 0,
2227 byte: 0,
2228 }
2229 }
2230}
2231
2232// SAFETY: `repr(C)` with `size: u32` first.
2233unsafe impl OutParam for KuiTextHit {
2234 const ABI_V1_SIZE: u32 = abi_through!(KuiTextHit, byte, u64);
2235 fn size_mut(&mut self) -> &mut u32 {
2236 &mut self.size
2237 }
2238}
2239
2240/// The rect a node was laid out at (`kui_layout_of`): logical px in
2241/// viewport coordinates, the `layout` event's numbers without the event.
2242#[repr(C)]
2243#[derive(Clone, Copy)]
2244pub struct KuiLayoutRect {
2245 /// `[out]` reservation; see `KUI_LAYOUT_RECT_INIT`.
2246 pub size: u32,
2247 pub x: f32,
2248 pub y: f32,
2249 pub w: f32,
2250 pub h: f32,
2251}
2252
2253impl Default for KuiLayoutRect {
2254 fn default() -> Self {
2255 Self {
2256 size: std::mem::size_of::<Self>() as u32,
2257 x: 0.0,
2258 y: 0.0,
2259 w: 0.0,
2260 h: 0.0,
2261 }
2262 }
2263}
2264
2265// SAFETY: `repr(C)` with `size: u32` first.
2266unsafe impl OutParam for KuiLayoutRect {
2267 const ABI_V1_SIZE: u32 = abi_through!(KuiLayoutRect, h, f32);
2268 fn size_mut(&mut self) -> &mut u32 {
2269 &mut self.size
2270 }
2271}
2272
2273/// A caret rect (`kui_caret_rect`): logical px in viewport coordinates,
2274/// zero wide, one line tall.
2275#[repr(C)]
2276#[derive(Clone, Copy)]
2277pub struct KuiCaretRect {
2278 /// `[out]` reservation; see `KUI_CARET_RECT_INIT`.
2279 pub size: u32,
2280 pub x: f32,
2281 pub y: f32,
2282 pub w: f32,
2283 pub h: f32,
2284}
2285
2286impl Default for KuiCaretRect {
2287 fn default() -> Self {
2288 Self {
2289 size: std::mem::size_of::<Self>() as u32,
2290 x: 0.0,
2291 y: 0.0,
2292 w: 0.0,
2293 h: 0.0,
2294 }
2295 }
2296}
2297
2298// SAFETY: `repr(C)` with `size: u32` first.
2299unsafe impl OutParam for KuiCaretRect {
2300 const ABI_V1_SIZE: u32 = abi_through!(KuiCaretRect, h, f32);
2301 fn size_mut(&mut self) -> &mut u32 {
2302 &mut self.size
2303 }
2304}
2305
2306// SAFETY: `repr(C)` with `size: u32` first.
2307unsafe impl OutParam for KuiScrollGeometry {
2308 const ABI_V1_SIZE: u32 = abi_through!(KuiScrollGeometry, max_offset_y, f32);
2309 fn size_mut(&mut self) -> &mut u32 {
2310 &mut self.size
2311 }
2312}
2313
2314// ---------------------------------------------------------------------------
2315// The plain-constant enums the header spells and the entry points read.
2316//
2317// Each of these used to be a literal at the one site that read it (`kind =
2318// 3`, `flags & 8`), with the header the only place the number had a name.
2319// Named here so `mod abi_parity` can pin every one of them to the header
2320// by name, the way it pins `KUI_CMD_*`: a value renumbered on either side
2321// fails the C build instead of meaning something else at runtime.
2322
2323/// `KUI_SPAN_*`: the flags on a `KuiSpan`.
2324pub const KUI_SPAN_BOLD: u32 = 1 << 0;
2325pub const KUI_SPAN_ITALIC: u32 = 1 << 1;
2326pub const KUI_SPAN_UNDERLINE: u32 = 1 << 2;
2327pub const KUI_SPAN_STRIKETHROUGH: u32 = 1 << 3;
2328/// `KUI_SPAN_FAMILY`: `KuiSpan.family` names the span's face (ABI 26).
2329pub const KUI_SPAN_FAMILY: u32 = 1 << 4;
2330
2331/// `KUI_UNDERLINE_*`: an underline's shape, `KuiTextStyle.underline_style`
2332/// and `KuiSpan.underline_style`.
2333pub const KUI_UNDERLINE_SOLID: u32 = 0;
2334pub const KUI_UNDERLINE_WAVY: u32 = 1;
2335pub const KUI_UNDERLINE_DOTTED: u32 = 2;
2336
2337/// `KUI_KMOD_*`: the modifier bits `kui_input_key_down` and its siblings
2338/// take, and `kui_input_modifiers` reports — the core's own
2339/// `KeyMods::bits`, which is also what the conformance corpus's
2340/// `modifiers` step spells, so the header and the corpus cannot drift.
2341pub const KUI_KMOD_SHIFT: u32 = kui_core::KeyMods::SHIFT;
2342pub const KUI_KMOD_CTRL: u32 = kui_core::KeyMods::CTRL;
2343pub const KUI_KMOD_ALT: u32 = kui_core::KeyMods::ALT;
2344pub const KUI_KMOD_SUPER: u32 = kui_core::KeyMods::SUPER;
2345
2346/// `KUI_KLOCK_*` and `KUI_KLOC_*`: which lock keys were on and which of a
2347/// key's twins it was, in the same word as the `KUI_KMOD_*` bits
2348/// `kui_input_key_down` and its siblings take. Zero is no lock on and the
2349/// standard key.
2350pub const KUI_KLOCK_CAPS: u32 = kui_core::KeyLocks::CAPS;
2351pub const KUI_KLOCK_NUM: u32 = kui_core::KeyLocks::NUM;
2352pub const KUI_KLOC_LEFT: u32 = 1 << kui_core::KeyLocation::SHIFT;
2353pub const KUI_KLOC_RIGHT: u32 = 2 << kui_core::KeyLocation::SHIFT;
2354pub const KUI_KLOC_NUMPAD: u32 = 3 << kui_core::KeyLocation::SHIFT;
2355/// `KUI_KLAYOUT_NONLATIN`: the press was typed on a layout that writes no
2356/// Latin, so the US key stands in for its ASCII too. Zero judges each key
2357/// by itself.
2358pub const KUI_KLAYOUT_NONLATIN: u32 = kui_core::LayoutScript::NON_LATIN;
2359
2360/// `KUI_EDIT_*`: the flags `kui_text_edit` takes. `WRAP` is the `wrap`
2361/// row declared on a field (the mode is `KuiTextStyle.wrap`, whose zero
2362/// is `KUI_WRAP_WORD`, so the style alone cannot say): the field folds to
2363/// its width the way a document does and keeps a field's keyboard.
2364pub const KUI_EDIT_MULTILINE: u32 = 1 << 0;
2365pub const KUI_EDIT_AUTOFOCUS: u32 = 1 << 1;
2366pub const KUI_EDIT_WRAP: u32 = 1 << 2;
2367
2368/// `KUI_MOD_*`: the editing modifiers `kui_input_key` takes — extend the
2369/// selection, move by word, move by document.
2370pub const KUI_MOD_SHIFT: u32 = 1 << 0;
2371pub const KUI_MOD_WORD: u32 = 1 << 1;
2372pub const KUI_MOD_DOC: u32 = 1 << 2;
2373
2374/// `KUI_KEY_*`: the editing keys `kui_input_key` takes, in the header's
2375/// order — which is not `EditKey`'s declaration order, so the table is
2376/// the pin rather than a cast. `edit_key_of` reads it and `mod
2377/// abi_parity` emits it.
2378pub const KUI_EDIT_KEYS: [(&str, EditKey); 16] = [
2379 ("KUI_KEY_LEFT", EditKey::Left),
2380 ("KUI_KEY_RIGHT", EditKey::Right),
2381 ("KUI_KEY_UP", EditKey::Up),
2382 ("KUI_KEY_DOWN", EditKey::Down),
2383 ("KUI_KEY_HOME", EditKey::Home),
2384 ("KUI_KEY_END", EditKey::End),
2385 ("KUI_KEY_PAGE_UP", EditKey::PageUp),
2386 ("KUI_KEY_PAGE_DOWN", EditKey::PageDown),
2387 ("KUI_KEY_BACKSPACE", EditKey::Backspace),
2388 ("KUI_KEY_DELETE", EditKey::Delete),
2389 ("KUI_KEY_ENTER", EditKey::Enter),
2390 ("KUI_KEY_TAB", EditKey::Tab),
2391 ("KUI_KEY_SELECT_ALL", EditKey::SelectAll),
2392 ("KUI_KEY_ESCAPE", EditKey::Escape),
2393 ("KUI_KEY_UNDO", EditKey::Undo),
2394 ("KUI_KEY_REDO", EditKey::Redo),
2395];
2396
2397/// `KUI_MOUSE_*`: `kui_input_mouse_button`'s button, which is
2398/// `MouseButton::code` — the core owns the numbering, this is its name.
2399pub const KUI_MOUSE_PRIMARY: u32 = 0;
2400pub const KUI_MOUSE_SECONDARY: u32 = 1;
2401pub const KUI_MOUSE_MIDDLE: u32 = 2;
2402pub const KUI_MOUSE_OTHER: u32 = 3;
2403
2404/// `KUI_MENU_*`: a `KuiMenuItem.role`, the position in `MenuRole::ALL`.
2405pub const KUI_MENU_CUSTOM: u32 = 0;
2406pub const KUI_MENU_SEPARATOR: u32 = 1;
2407pub const KUI_MENU_CUT: u32 = 2;
2408pub const KUI_MENU_COPY: u32 = 3;
2409pub const KUI_MENU_PASTE: u32 = 4;
2410pub const KUI_MENU_SELECT_ALL: u32 = 5;
2411pub const KUI_MENU_LOOK_UP: u32 = 6;
2412
2413/// `KUI_MENU_ITEM_*`: the flags `kui_menu_bar_item` and `kui_menu_item`
2414/// report on a row.
2415pub const KUI_MENU_ITEM_ENABLED: u32 = 1 << 0;
2416pub const KUI_MENU_ITEM_CHECKED: u32 = 1 << 1;
2417/// `KUI_MENU_ITEM_SUBMENU`: the row opens rows of its own (backlog F128).
2418pub const KUI_MENU_ITEM_SUBMENU: u32 = 1 << 2;
2419
2420/// `KUI_MENU_ACTION_*`: a `KuiMenuAction.kind`.
2421pub const KUI_MENU_ACTION_SET_CLIPBOARD: u32 = 0;
2422pub const KUI_MENU_ACTION_PASTE: u32 = 1;
2423pub const KUI_MENU_ACTION_LOOK_UP: u32 = 2;
2424/// A secret for the clipboard, to write marked concealed and transient
2425/// (`kui_set_clipboard_secret`). A host that does not know the kind drops
2426/// the copy, which for a secret is the safe way to fail.
2427pub const KUI_MENU_ACTION_SET_CLIPBOARD_SECRET: u32 = 3;
2428
2429/// `KUI_PASTE_*`: the pasteboard's markers on a paste's answer
2430/// (`kui_input_paste`).
2431pub const KUI_PASTE_CONCEALED: u32 = 1 << 0;
2432pub const KUI_PASTE_TRANSIENT: u32 = 1 << 1;
2433
2434/// `KUI_BUTTONS_*`: the buttons `KuiSpec.on_button` claims
2435/// (`KuiSpec.buttons`); none set is all three.
2436pub const KUI_BUTTONS_SECONDARY: u32 = kui_core::Buttons::SECONDARY.bits();
2437pub const KUI_BUTTONS_MIDDLE: u32 = kui_core::Buttons::MIDDLE.bits();
2438pub const KUI_BUTTONS_OTHER: u32 = kui_core::Buttons::OTHER.bits();
2439
2440/// `KUI_OWED_*`: the bits of what `kui_owed` returns, `kui_animating` by
2441/// kind.
2442pub const KUI_OWED_TRANSITION: u32 = 1 << 0;
2443pub const KUI_OWED_CYCLE: u32 = 1 << 1;
2444pub const KUI_OWED_DEPART: u32 = 1 << 2;
2445pub const KUI_OWED_REQUESTED: u32 = 1 << 3;
2446pub const KUI_OWED_AUTOSCROLL: u32 = 1 << 4;
2447pub const KUI_OWED_SCROLL: u32 = 1 << 5;
2448
2449/// `KUI_FRAME_CAUSE_*`: the bits of what `kui_frame_cause` returns and
2450/// `kui_note_frame_cause` takes.
2451pub const KUI_FRAME_CAUSE_POINTER_MOVE: u32 = kui_core::FrameCause::POINTER_MOVE.bits();
2452pub const KUI_FRAME_CAUSE_POINTER_LEAVE: u32 = kui_core::FrameCause::POINTER_LEAVE.bits();
2453pub const KUI_FRAME_CAUSE_BUTTON: u32 = kui_core::FrameCause::BUTTON.bits();
2454pub const KUI_FRAME_CAUSE_WHEEL: u32 = kui_core::FrameCause::WHEEL.bits();
2455pub const KUI_FRAME_CAUSE_KEY: u32 = kui_core::FrameCause::KEY.bits();
2456pub const KUI_FRAME_CAUSE_MODIFIERS: u32 = kui_core::FrameCause::MODIFIERS.bits();
2457pub const KUI_FRAME_CAUSE_TEXT: u32 = kui_core::FrameCause::TEXT.bits();
2458pub const KUI_FRAME_CAUSE_PREEDIT: u32 = kui_core::FrameCause::PREEDIT.bits();
2459pub const KUI_FRAME_CAUSE_ACCESS: u32 = kui_core::FrameCause::ACCESS.bits();
2460pub const KUI_FRAME_CAUSE_FILE_DRAG: u32 = kui_core::FrameCause::FILE_DRAG.bits();
2461pub const KUI_FRAME_CAUSE_FILES: u32 = kui_core::FrameCause::FILES.bits();
2462pub const KUI_FRAME_CAUSE_FIRST: u32 = kui_core::FrameCause::FIRST.bits();
2463pub const KUI_FRAME_CAUSE_WAKE: u32 = kui_core::FrameCause::WAKE.bits();
2464pub const KUI_FRAME_CAUSE_HOST: u32 = kui_core::FrameCause::HOST.bits();
2465pub const KUI_FRAME_CAUSE_RESIZE: u32 = kui_core::FrameCause::RESIZE.bits();
2466pub const KUI_FRAME_CAUSE_SCALE: u32 = kui_core::FrameCause::SCALE.bits();
2467pub const KUI_FRAME_CAUSE_FOCUS: u32 = kui_core::FrameCause::FOCUS.bits();
2468pub const KUI_FRAME_CAUSE_OCCLUSION: u32 = kui_core::FrameCause::OCCLUSION.bits();
2469pub const KUI_FRAME_CAUSE_APPEARANCE: u32 = kui_core::FrameCause::APPEARANCE.bits();
2470pub const KUI_FRAME_CAUSE_CARET: u32 = kui_core::FrameCause::CARET.bits();
2471pub const KUI_FRAME_CAUSE_RETRY: u32 = kui_core::FrameCause::RETRY.bits();
2472pub const KUI_FRAME_CAUSE_OVERDUE: u32 = kui_core::FrameCause::OVERDUE.bits();
2473pub const KUI_FRAME_CAUSE_DEVICE: u32 = kui_core::FrameCause::DEVICE.bits();
2474pub const KUI_FRAME_CAUSE_AFTER_FRAME: u32 = kui_core::FrameCause::AFTER_FRAME.bits();
2475pub const KUI_FRAME_CAUSE_ELSEWHERE: u32 = kui_core::FrameCause::ELSEWHERE.bits();
2476pub const KUI_FRAME_CAUSE_MENU: u32 = kui_core::FrameCause::MENU.bits();
2477pub const KUI_FRAME_CAUSE_AUDIO: u32 = kui_core::FrameCause::AUDIO.bits();
2478pub const KUI_FRAME_CAUSE_SMOKE: u32 = kui_core::FrameCause::SMOKE.bits();
2479pub const KUI_FRAME_CAUSE_OWED: u32 = kui_core::FrameCause::OWED.bits();
2480
2481/// `KUI_COPY_*`: what `kui_request_copy` returns.
2482pub const KUI_COPY_READY: u32 = 0;
2483pub const KUI_COPY_ASKED: u32 = 1;
2484pub const KUI_COPY_NOTHING: u32 = 2;
2485
2486/// `KUI_AUDIO_*`: a `KuiAudioCommand.kind`.
2487pub const KUI_AUDIO_PLAY: u32 = 1;
2488pub const KUI_AUDIO_STOP: u32 = 2;
2489pub const KUI_AUDIO_SET_VOLUME: u32 = 3;
2490pub const KUI_AUDIO_PAUSE: u32 = 4;
2491pub const KUI_AUDIO_RESUME: u32 = 5;
2492pub const KUI_AUDIO_MASTER_VOLUME: u32 = 6;
2493pub const KUI_AUDIO_UNLOAD: u32 = 7;
2494
2495/// `KUI_WINDOW_NONE`: a `KuiSpec.window_role` that is no chrome role.
2496pub const KUI_WINDOW_NONE: u32 = 0;