#![allow(clippy::not_unsafe_ptr_arg_deref)]
mod ext;
pub use ext::CExtension;
#[macro_use]
mod abi;
mod access;
mod convert;
mod dialogs;
mod focus;
mod frame;
mod input;
mod menu;
mod resources;
#[cfg(feature = "runner")]
mod run;
mod scrolling;
mod select;
mod size;
mod slots;
mod types;
mod value;
mod widgets;
mod windows;
pub use abi::*;
pub use access::*;
pub use dialogs::*;
pub use focus::*;
pub use frame::*;
pub use input::*;
pub use menu::*;
pub use resources::*;
#[cfg(feature = "runner")]
pub use run::*;
pub use scrolling::*;
pub use select::*;
pub use size::*;
pub use slots::*;
pub use types::*;
pub use value::*;
pub use widgets::*;
pub use windows::*;
use convert::*;
use std::collections::VecDeque;
use std::ffi::c_void;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::rc::Rc;
use kui_core::{
Align, Appearance, Assistive, AudioDevice, AudioEnv, Color, Core, DismissReason, Edges,
EditKey, EditOptions, Enter, FloatConfig, InputEvent, Key, Keyframe, Locale, Mods, MotionPref,
MouseButton, NodeSpec, OptionAsAlt, Rect, Size, Sizing, Span, SystemEnv, TextStyle, UiEvent,
Value, Vec2, WindowButton, WindowCommand, WindowConfig, WindowId, WindowKind,
};
#[unsafe(no_mangle)]
pub extern "C" fn kui_ctx_new() -> *mut KuiCtx {
guard(std::ptr::null_mut(), || {
let mut owned = Box::new(Core::new());
owned.set_diagnostics(false);
let core: *mut Core = &mut *owned;
Box::into_raw(Box::new(KuiCtx {
core,
_owned: Some(owned),
events: Vec::new(),
last_payload: None,
last_edit_text: None,
fragment_source: String::new(),
fragment_draws: Vec::new(),
texture_draws: Vec::new(),
draws_current: false,
image_pixels: None,
last_warnings: Vec::new(),
pending_warnings: Vec::new(),
last_access: Default::default(),
last_runs: Vec::new(),
last_announcements: Vec::new(),
window_commands: VecDeque::new(),
menu_actions: VecDeque::new(),
menu_text: String::new(),
row_text: String::new(),
menu_accel: String::new(),
copy_text: String::new(),
menu_html: String::new(),
devtools_key: String::new(),
file_request: None,
file_filter_text: String::new(),
devtools_tab: String::new(),
selection_text: String::new(),
selection_html: String::new(),
font_families: Vec::new(),
system_fonts: Vec::new(),
nodes: None,
last_window_name: None,
slot_name: None,
slot_namespace: None,
slot_params: None,
extensions: Default::default(),
last_ext_error: String::new(),
host_ui: std::ptr::null_mut(),
}))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_ctx_free(ptr: *mut KuiCtx) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_env_set(ptr: *mut KuiCtx, refresh_hz: f32, focused: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().env.refresh_hz = (refresh_hz > 0.0).then_some(refresh_hz);
c.core().set_focused(focused);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_env_set_system(
ptr: *mut KuiCtx,
appearance: u32,
accent: u32,
motion: u32,
locale: KuiStr,
) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
let sys = SystemEnv {
appearance: Appearance::from_code(appearance).unwrap_or_default(),
motion: MotionPref::from_code(motion).unwrap_or_default(),
accent: (accent != 0).then(|| Color::hex(accent)),
locale: opt_str(locale).and_then(|tag| Locale::new(&tag)),
assistive: c.core().env.system.assistive,
};
c.core().set_system(sys);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_env_set_assistive(ptr: *mut KuiCtx, assistive: u32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().env.system.assistive = Assistive::from_code(assistive).unwrap_or_default();
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_env_set_audio(ptr: *mut KuiCtx, device: u32, live: u32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().env.audio = AudioEnv {
device: AudioDevice::from_code(device).unwrap_or_default(),
live,
};
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_theme(ptr: *mut KuiCtx, out: *mut KuiTheme) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let t = *c.core().theme();
write_out(
out,
KuiTheme {
appearance: t.appearance.code(),
disabled_opacity: t.disabled_opacity,
bg: t.bg.to_hex(),
surface: t.surface.to_hex(),
raised: t.raised.to_hex(),
sunken: t.sunken.to_hex(),
border: t.border.to_hex(),
border_strong: t.border_strong.to_hex(),
fg: t.fg.to_hex(),
muted: t.muted.to_hex(),
faint: t.faint.to_hex(),
accent: t.accent.to_hex(),
accent_hover: t.accent_hover.to_hex(),
accent_pressed: t.accent_pressed.to_hex(),
on_accent: t.on_accent.to_hex(),
accent_soft: t.accent_soft.to_hex(),
selection: t.selection.to_hex(),
focus_ring: t.focus_ring.to_hex(),
hover: t.hover.to_hex(),
pressed: t.pressed.to_hex(),
success: t.success.to_hex(),
warning: t.warning.to_hex(),
danger: t.danger.to_hex(),
scrollbar: t.scrollbar.to_hex(),
scrollbar_active: t.scrollbar_active.to_hex(),
..Default::default()
},
)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_theme_set_accent(ptr: *mut KuiCtx, accent: u32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
match accent {
0 => c.core().derive_theme(),
hex => c.core().set_accent(Color::hex(hex)),
}
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_theme_set(ptr: *mut KuiCtx, theme: *const KuiTheme) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
match unsafe { theme.as_ref() } {
None => c.core().derive_theme(),
Some(t) => c.core().set_theme(theme_of(t)),
}
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_tokens_set(
ptr: *mut KuiCtx,
colors: *const KuiColorToken,
color_count: usize,
lengths: *const KuiLengthToken,
length_count: usize,
) {
guard((), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return;
};
let mut t = kui_core::Tokens::new();
if !colors.is_null() {
for tok in unsafe { std::slice::from_raw_parts(colors, color_count) } {
t = t.color_themed(
kstr(tok.name).into_owned(),
Color::hex(tok.light),
Color::hex(tok.dark),
);
}
}
if !lengths.is_null() {
for tok in unsafe { std::slice::from_raw_parts(lengths, length_count) } {
t = t.length(kstr(tok.name).into_owned(), tok.value);
}
}
c.core().set_tokens(t);
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_tokens_derive(
ptr: *mut KuiCtx,
derived: *const KuiDerivedToken,
count: usize,
) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
if derived.is_null() || count == 0 {
return true;
}
let mut t = c.core().tokens().cloned().unwrap_or_default();
for d in unsafe { std::slice::from_raw_parts(derived, count) } {
let ops = if d.ops.is_null() {
&[][..]
} else {
unsafe { std::slice::from_raw_parts(d.ops, d.op_count) }
};
let mut chain = Vec::with_capacity(ops.len());
for op in ops {
let Some(verb) = kui_core::ColorOp::VERBS.get(op.op as usize) else {
return false;
};
let other = kstr(op.other);
let other = (!other.is_empty()).then_some(&*other);
let Some(step) = kui_core::ColorOp::parse(verb, other, op.t) else {
return false;
};
chain.push(step);
}
t = t.derive(kstr(d.name).into_owned(), &kstr(d.from), chain);
}
c.core().set_tokens(t);
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_token_color(ptr: *mut KuiCtx, name: KuiStr, out: *mut u32) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let Some(out) = (unsafe { out.as_mut() }) else {
return false;
};
let name = kstr(name);
match c.core().token_lookup().color(&name) {
Ok(col) => {
*out = col.to_hex();
true
}
Err(e) => {
c.core().warn_unknown_token(&e);
false
}
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_token_length(ptr: *mut KuiCtx, name: KuiStr, out: *mut f32) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let Some(out) = (unsafe { out.as_mut() }) else {
return false;
};
let name = kstr(name);
match c.core().token_lookup().length(&name) {
Ok(v) => {
*out = v;
true
}
Err(e) => {
c.core().warn_unknown_token(&e);
false
}
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_metrics(ptr: *mut KuiCtx, out: *mut KuiMetrics) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let m = KuiMetrics::of(c.core().metrics());
write_out(out, m)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_metrics_set(ptr: *mut KuiCtx, metrics: *const KuiMetrics) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
match unsafe { metrics.as_ref() } {
None => c.core().set_metrics(kui_core::Metrics::default()),
Some(m) => c.core().set_metrics(m.to_core()),
}
}
})
}
fn theme_of(t: &KuiTheme) -> kui_core::Theme {
kui_core::Theme {
appearance: Appearance::from_code(t.appearance).unwrap_or_default(),
disabled_opacity: t.disabled_opacity,
bg: Color::hex(t.bg),
surface: Color::hex(t.surface),
raised: Color::hex(t.raised),
sunken: Color::hex(t.sunken),
border: Color::hex(t.border),
border_strong: Color::hex(t.border_strong),
fg: Color::hex(t.fg),
muted: Color::hex(t.muted),
faint: Color::hex(t.faint),
accent: Color::hex(t.accent),
accent_hover: Color::hex(t.accent_hover),
accent_pressed: Color::hex(t.accent_pressed),
on_accent: Color::hex(t.on_accent),
accent_soft: Color::hex(t.accent_soft),
selection: Color::hex(t.selection),
focus_ring: Color::hex(t.focus_ring),
hover: Color::hex(t.hover),
pressed: Color::hex(t.pressed),
success: Color::hex(t.success),
warning: Color::hex(t.warning),
danger: Color::hex(t.danger),
scrollbar: Color::hex(t.scrollbar),
scrollbar_active: Color::hex(t.scrollbar_active),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_time(ptr: *mut KuiCtx, now_secs: f64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_time(now_secs);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_exit_with(ptr: *mut KuiCtx, key: u64, exit: *const KuiEnter) {
guard((), || {
if exit.is_null() {
return;
}
let e = crate::convert::enter_of(unsafe { &*exit });
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_exit(kui_core::Key(key), e);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_request_frame_at(ptr: *mut KuiCtx, at: f64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().request_frame_at(at);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_next_frame_at(ptr: *mut KuiCtx) -> f64 {
guard(f64::INFINITY, || {
unsafe { ctx(ptr) }
.and_then(|c| c.core().next_frame_at())
.unwrap_or(f64::INFINITY)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_now(ptr: *mut KuiCtx) -> f64 {
guard(0.0, || unsafe { ctx(ptr) }.map_or(0.0, |c| c.core().now()))
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_animating(ptr: *mut KuiCtx) -> bool {
guard(false, || {
unsafe { ctx(ptr) }.is_some_and(|c| c.core().animating())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_owed(ptr: *mut KuiCtx) -> u32 {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| {
let o = c.core().owed();
(o.transition as u32 * KUI_OWED_TRANSITION)
| (o.cycle as u32 * KUI_OWED_CYCLE)
| (o.depart as u32 * KUI_OWED_DEPART)
| (o.requested as u32 * KUI_OWED_REQUESTED)
| (o.autoscroll as u32 * KUI_OWED_AUTOSCROLL)
| (o.scroll as u32 * KUI_OWED_SCROLL)
})
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_frame_trace(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_frame_trace(on);
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_frame_cause(ptr: *mut KuiCtx) -> u32 {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| c.core().frame_cause().bits())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_note_frame_cause(ptr: *mut KuiCtx, cause: u32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core()
.note_frame_cause(kui_core::FrameCause::from_bits(cause));
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_frame_unchanged(ptr: *mut KuiCtx) -> i32 {
guard(-1, || {
unsafe { ctx(ptr) }.map_or(-1, |c| match c.core().frame_unchanged() {
Some(same) => same as i32,
None => -1,
})
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_subpixel_text(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_subpixel_text(on);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_text_cache_budget(ptr: *mut KuiCtx, bytes: usize) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_text_cache_budget(bytes);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_text_cache_bytes(ptr: *mut KuiCtx) -> usize {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| c.core().text_cache_bytes())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_take_warnings(ptr: *mut KuiCtx, out: *mut KuiWarning, cap: usize) -> usize {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
if out.is_null() || cap == 0 {
return 0;
}
let raised = c.core().take_warnings();
c.pending_warnings.extend(raised);
let n = c.pending_warnings.len().min(cap);
c.last_warnings = c.pending_warnings.drain(..n).collect();
for (i, w) in c.last_warnings.iter().enumerate() {
let s = |s: &str| KuiStr {
ptr: s.as_ptr(),
len: s.len(),
};
unsafe {
out.add(i).write(KuiWarning {
code: s(w.code),
key: w.key.0,
message: s(&w.message),
})
};
}
n
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_diagnostics(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_diagnostics(on);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_devtools(on);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_dock(ptr: *mut KuiCtx, dock: KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let Some(dock) = kui_core::DevtoolsDock::parse(&kstr(dock)) else {
return false;
};
c.core().set_devtools_dock(dock);
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools(ptr: *mut KuiCtx) -> bool {
guard(false, || {
unsafe { ctx(ptr) }.is_some_and(|c| c.core().devtools())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_dock(ptr: *mut KuiCtx, out: *mut KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let name = c.core().devtools_dock().name();
if let Some(out) = unsafe { out.as_mut() } {
*out = KuiStr {
ptr: name.as_ptr(),
len: name.len(),
};
}
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_host_rect(ptr: *mut KuiCtx, out: *mut KuiLayoutRect) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let r = c.core().host_rect();
write_out(
out,
KuiLayoutRect {
x: r.x,
y: r.y,
w: r.w,
h: r.h,
..Default::default()
},
)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_theme(ptr: *mut KuiCtx, base: KuiStr, accent: u32) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let base = match kstr(base).as_ref() {
"" => None,
"light" => Some(kui_core::Appearance::Light),
"dark" => Some(kui_core::Appearance::Dark),
_ => return false,
};
let accent = (accent != 0).then(|| color_of(accent));
c.core().set_devtools_theme(base, accent);
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_key(ptr: *mut KuiCtx, key: KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let Some(accel) = kui_core::Accel::parse(&kstr(key)) else {
return false;
};
c.core().set_devtools_key(accel);
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_key(ptr: *mut KuiCtx, out: *mut KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
c.devtools_key = c.core().devtools_key().spelling();
if let Some(out) = unsafe { out.as_mut() } {
*out = KuiStr {
ptr: c.devtools_key.as_ptr(),
len: c.devtools_key.len(),
};
}
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_tab(
ptr: *mut KuiCtx,
name: KuiStr,
label: KuiStr,
slot: KuiStr,
) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
c.core()
.devtools_tab_declare(&kstr(name), &kstr(label), Some(&kstr(slot)))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_tab_open(ptr: *mut KuiCtx, name: KuiStr, label: KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
let name = kstr(name);
let core = c.core();
if !core.devtools_tab_declare(&name, &kstr(label), None) || !core.devtools_tab_shown(&name)
{
return false;
}
core.devtools_tab_open(&name);
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_selected(ptr: *mut KuiCtx) -> u64 {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| c.core().devtools_selected().map_or(0, |k| k.0))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_hovered(ptr: *mut KuiCtx) -> u64 {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| c.core().devtools_hovered().map_or(0, |k| k.0))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_picked(ptr: *mut KuiCtx) -> u64 {
guard(0, || {
unsafe { ctx(ptr) }.map_or(0, |c| c.core().devtools_picked().map_or(0, |k| k.0))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_pick(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_devtools_pick(on);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_picking(ptr: *mut KuiCtx) -> bool {
guard(false, || {
unsafe { ctx(ptr) }.is_some_and(|c| c.core().devtools_picking())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_tab(ptr: *mut KuiCtx, name: KuiStr) -> bool {
guard(false, || {
unsafe { ctx(ptr) }.is_some_and(|c| c.core().set_devtools_tab(&kstr(name)))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_devtools_current_tab(ptr: *mut KuiCtx, out: *mut KuiStr) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
c.devtools_tab = c.core().devtools_current_tab();
if let Some(out) = unsafe { out.as_mut() } {
*out = KuiStr {
ptr: c.devtools_tab.as_ptr(),
len: c.devtools_tab.len(),
};
}
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_selected(ptr: *mut KuiCtx, key: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core()
.set_devtools_selected((key != 0).then_some(kui_core::Key(key)));
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_devtools_legend(
ptr: *mut KuiCtx,
keys: *const KuiStr,
what: *const KuiStr,
count: usize,
) {
guard((), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return;
};
let rows: Vec<(String, String)> = if keys.is_null() || what.is_null() {
Vec::new()
} else {
let keys = unsafe { std::slice::from_raw_parts(keys, count) };
let what = unsafe { std::slice::from_raw_parts(what, count) };
keys.iter()
.zip(what)
.map(|(k, w)| (kstr(*k).into_owned(), kstr(*w).into_owned()))
.collect()
};
let borrowed: Vec<(&str, &str)> =
rows.iter().map(|(k, w)| (k.as_str(), w.as_str())).collect();
c.core().set_devtools_legend(&borrowed);
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_inspect(ptr: *mut KuiCtx, on: bool) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_inspect(on);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_nodes(ptr: *mut KuiCtx) -> *const KuiValue {
guard(std::ptr::null(), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return std::ptr::null();
};
let list = c
.core()
.nodes()
.iter()
.map(|n| {
let mut v = n.to_value(kui_core::Handles::INT);
if let Value::Map(entries) = &mut v {
entries.push((
"events".into(),
Value::Map(
n.events
.iter()
.map(|(name, v)| ((*name).to_string(), v.clone()))
.collect(),
),
));
}
v
})
.collect();
c.nodes = Some(Box::new(KuiValue(Value::List(list))));
c.nodes
.as_deref()
.map_or(std::ptr::null(), |v| v as *const KuiValue)
})
}
#[cfg(test)]
mod schema_parity;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod abi_handshake;
#[cfg(test)]
mod abi_parity;