use super::*;
fn with_ui(ptr: *mut KuiCtx, f: impl FnOnce(&mut kui_core::Ui<'_>)) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
f(&mut kui_core::Ui::wrap(c.core()));
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_titlebar(ptr: *mut KuiCtx, title: KuiStr) {
with_ui(ptr, |ui| kui_core::widgets::titlebar(ui, &kstr(title)));
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_titlebar_with(ptr: *mut KuiCtx, body: ViewFn, user: *mut c_void) {
with_ui(ptr, |ui| {
kui_core::widgets::titlebar_with(ui, |_| body(user, ptr))
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_window_buttons(ptr: *mut KuiCtx) {
with_ui(ptr, kui_core::widgets::window_buttons);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_tooltip(ptr: *mut KuiCtx, text: KuiStr) {
with_ui(ptr, |ui| kui_core::widgets::tooltip(ui, &kstr(text)));
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_tooltip_with(ptr: *mut KuiCtx, body: ViewFn, user: *mut c_void) {
with_ui(ptr, |ui| {
kui_core::widgets::tooltip_with(ui, |_| body(user, ptr))
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_latency_graph(ptr: *mut KuiCtx) {
with_ui(ptr, kui_core::widgets::latency_graph);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_latency_hud(ptr: *mut KuiCtx, x: u32, y: u32) {
with_ui(ptr, |ui| {
kui_core::widgets::latency_hud_at(ui, align_of(x), align_of(y))
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_text_input(ptr: *mut KuiCtx, label: KuiStr, initial: KuiStr) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
kui_core::widgets::text_input(
&mut kui_core::Ui::wrap(c.core()),
&kstr(label),
&kstr(initial),
)
.0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_select(
ptr: *mut KuiCtx,
label: KuiStr,
items: *const KuiMenuItem,
count: usize,
current: i64,
) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let label = kstr(label);
if label.is_empty() || items.is_null() || count == 0 {
return 0;
}
let rows = unsafe { std::slice::from_raw_parts(items, count) };
let mut parsed = Vec::with_capacity(count);
for row in rows {
let Some(item) = row.to_core() else {
return 0;
};
parsed.push(item);
}
let current = usize::try_from(current).ok();
kui_core::widgets::select_items(&mut kui_core::Ui::wrap(c.core()), &label, &parsed, current)
.0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_button(ptr: *mut KuiCtx, label: KuiStr, payload: *mut KuiValue) {
kui_button_with(ptr, label, std::ptr::null(), payload);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_button_with(
ptr: *mut KuiCtx,
text: KuiStr,
spec: *const KuiSpec,
payload: *mut KuiValue,
) {
guard((), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
if !payload.is_null() {
drop(unsafe { Box::from_raw(payload) });
}
return;
};
let text = kstr(text);
let value = if payload.is_null() {
Value::Null
} else {
unsafe { Box::from_raw(payload) }.0
};
let (theme, metrics) = {
let core = c.core();
(*core.theme(), *core.metrics())
};
let mut node = kui_core::widgets::button_spec(&theme, &metrics).on_click(value);
let mut hint = None;
if let Some(s) = unsafe { spec.as_ref() } {
if let Some(h) = opt_str(s.tooltip) {
node = node.apply_tooltip(&h);
hint = Some(h);
}
if let Some(l) = opt_str(s.label) {
node = node.label(l.as_ref());
}
if let Some(d) = opt_str(s.description) {
node = node.description(d.as_ref());
}
node = node.disabled(s.disabled != 0);
if s.accent != 0 {
node = node.accent();
}
}
kui_core::widgets::button_with(
&mut kui_core::Ui::wrap(c.core()),
&text,
&text,
node,
hint.as_deref(),
);
});
}
fn toggle(
ptr: *mut KuiCtx,
kind: kui_core::widgets::Toggle,
text: KuiStr,
spec: *const KuiSpec,
payload: *mut KuiValue,
) -> u64 {
guard(0, || {
let value = if payload.is_null() {
Value::Null
} else {
unsafe { Box::from_raw(payload) }.0
};
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let text = kstr(text);
let metrics = *c.core().metrics();
let mut node = kui_core::widgets::toggle_spec(&metrics).on_click(value);
let mut hint = None;
if let Some(s) = unsafe { spec.as_ref() } {
if let Some(h) = opt_str(s.tooltip) {
node = node.apply_tooltip(&h);
hint = Some(h);
}
if let Some(l) = opt_str(s.label) {
node = node.label(l.as_ref());
}
if let Some(d) = opt_str(s.description) {
node = node.description(d.as_ref());
}
node = node
.disabled(s.disabled != 0)
.checked(s.checked != 0)
.mixed(s.mixed != 0);
}
kui_core::widgets::toggle_with(
&mut kui_core::Ui::wrap(c.core()),
kind,
&text,
&text,
node,
hint.as_deref(),
)
.0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_checkbox(
ptr: *mut KuiCtx,
text: KuiStr,
spec: *const KuiSpec,
payload: *mut KuiValue,
) -> u64 {
toggle(
ptr,
kui_core::widgets::Toggle::Checkbox,
text,
spec,
payload,
)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_radio(
ptr: *mut KuiCtx,
text: KuiStr,
spec: *const KuiSpec,
payload: *mut KuiValue,
) -> u64 {
toggle(ptr, kui_core::widgets::Toggle::Radio, text, spec, payload)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_switch(
ptr: *mut KuiCtx,
text: KuiStr,
spec: *const KuiSpec,
payload: *mut KuiValue,
) -> u64 {
toggle(ptr, kui_core::widgets::Toggle::Switch, text, spec, payload)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_radio_group_open(
ptr: *mut KuiCtx,
label: KuiStr,
spec: *const KuiSpec,
) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let label = kstr(label);
let base = unsafe { spec.as_ref() }
.map_or_else(NodeSpec::column, |s| spec_of(s, NONE, NONE, NONE, NONE));
let metrics = *c.core().metrics();
let node = kui_core::widgets::radio_group_open_spec(&metrics, &label, base);
c.core().open_keyed(&label, node).0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_slider(ptr: *mut KuiCtx, label: KuiStr, spec: *const KuiSpec) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let label = kstr(label);
let metrics = *c.core().metrics();
let mut node = kui_core::widgets::slider_spec(&metrics);
let mut hint = None;
if let Some(s) = unsafe { spec.as_ref() } {
if let Some(h) = opt_str(s.tooltip) {
node = node.apply_tooltip(&h);
hint = Some(h);
}
if let Some(l) = opt_str(s.label) {
node = node.label(l.as_ref());
}
if let Some(d) = opt_str(s.description) {
node = node.description(d.as_ref());
}
if s.width.tag != 0 {
node = node.width(sizing_of(s.width));
}
if s.min_w != 0.0 {
node = node.min_width(min_of(s.min_w));
}
if s.max_w > 0.0 {
node = node.max_width(s.max_w);
}
if s.value_set & KUI_VALUE_NOW != 0 {
node = node.value_now(s.value_now);
}
if s.value_set & KUI_VALUE_MIN != 0 {
node = node.value_min(s.value_min);
}
if s.value_set & KUI_VALUE_MAX != 0 {
node = node.value_max(s.value_max);
}
if s.value_set & KUI_VALUE_STEP != 0 {
node = node.value_step(s.value_step);
}
if let Some(t) = opt_str(s.value_text) {
node = node.value_text(t.into_owned());
}
if let Some(tag) = unsafe { s.on_change.as_ref() } {
node = node.on_change(tag.0.clone());
}
node = node.disabled(s.disabled != 0);
}
kui_core::widgets::slider_with(
&mut kui_core::Ui::wrap(c.core()),
&label,
node,
hint.as_deref(),
)
.0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_text_edit(
ptr: *mut KuiCtx,
label: KuiStr,
initial: KuiStr,
style: *const KuiTextStyle,
flags: u32,
spec: *const KuiSpec,
) -> u64 {
let none = KuiStr {
ptr: std::ptr::null(),
len: 0,
};
text_edit(ptr, label, initial, style, flags, none, spec)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_text_edit_placeholder(
ptr: *mut KuiCtx,
label: KuiStr,
initial: KuiStr,
style: *const KuiTextStyle,
flags: u32,
placeholder: KuiStr,
spec: *const KuiSpec,
) -> u64 {
text_edit(ptr, label, initial, style, flags, placeholder, spec)
}
fn text_edit(
ptr: *mut KuiCtx,
label: KuiStr,
initial: KuiStr,
style: *const KuiTextStyle,
flags: u32,
placeholder: KuiStr,
spec: *const KuiSpec,
) -> u64 {
guard(0, || {
let (Some(c), Some(sp)) = (unsafe { ctx(ptr) }, unsafe { spec.as_ref() }) else {
return 0;
};
let opts = EditOptions {
style: unsafe { style.as_ref() }
.map(text_style_of)
.unwrap_or_default(),
multiline: flags & KUI_EDIT_MULTILINE != 0,
autofocus: flags & KUI_EDIT_AUTOFOCUS != 0,
wrap: flags & KUI_EDIT_WRAP != 0,
keep_tab: flags & KUI_EDIT_KEEP_TAB != 0,
placeholder: opt_str(placeholder).map(|p| p.into_owned()),
..Default::default()
};
let spec = leaf_spec_of(sp, NONE, NONE, NONE, NONE);
c.core()
.text_edit(&kstr(label), &kstr(initial), &opts, spec)
.0
})
}