From 7483396933a570f6707afa33282c2e1f19791d16 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Tue, 14 Apr 2026 18:07:03 +0200 Subject: [PATCH] implement UiList --- application/src/main.rs | 18 +++++- ui-rs/src/ui/list.rs | 2 + ui-rs/src/ui/mod.rs | 1 + ui-rs/src/ui/text.rs | 1 - ui-rs/src/ui/toolkit.rs | 135 +++++++++++++++++++++++++++++++++++++++- ui-rs/src/ui/window.rs | 14 ++++- 6 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 ui-rs/src/ui/list.rs diff --git a/application/src/main.rs b/application/src/main.rs index 3ed693d..9cca73e 100644 --- a/application/src/main.rs +++ b/application/src/main.rs @@ -1,4 +1,5 @@ use ui_rs::ui; +use ui_rs::ui::{UiContext, UiList}; fn main() { ui::app_init("note"); @@ -10,19 +11,30 @@ fn main() { struct App; struct TestData { - i: i32 + i: i32, + list: Option> } fn create_window() { - let testdata = TestData { i: 0 } ; + let testdata = TestData { i: 0, list: None } ; + + let window = ui::window("note", testdata, |obj, data| { + let mut list = obj.list::(); + let v = list.data(); + v.push(10); + v.push(11); + v.push(12); + + data.list = Some(list); - let window = ui::window("note", testdata, |obj, _data| { obj.button_builder().label("Hello").onclick(|e| { println!("Button clicked: {}", e.data.i); e.data.i += 1; }).create(); }); + + window.show(); } diff --git a/ui-rs/src/ui/list.rs b/ui-rs/src/ui/list.rs new file mode 100644 index 0000000..3b768e4 --- /dev/null +++ b/ui-rs/src/ui/list.rs @@ -0,0 +1,2 @@ +#![allow(dead_code)] + diff --git a/ui-rs/src/ui/mod.rs b/ui-rs/src/ui/mod.rs index 79da3bd..8e0ce22 100644 --- a/ui-rs/src/ui/mod.rs +++ b/ui-rs/src/ui/mod.rs @@ -7,6 +7,7 @@ mod container; mod widget; mod text; pub mod event; +mod list; pub use toolkit::*; pub use event::*; diff --git a/ui-rs/src/ui/text.rs b/ui-rs/src/ui/text.rs index 3f159b6..9d9dbda 100644 --- a/ui-rs/src/ui/text.rs +++ b/ui-rs/src/ui/text.rs @@ -1,5 +1,4 @@ #![allow(dead_code)] -#[allow(unused_imports)] use std::ffi::{c_char, c_int, c_void}; use std::ffi::CString; diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index 07d0938..c0d4882 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -1,15 +1,35 @@ #![allow(dead_code)] -use std::ffi::{c_char, c_int, CStr, CString}; +use std::ffi::{c_char, c_int, c_void, CStr, CString}; use crate::ui::ffi; use std::marker::PhantomData; +pub trait UiContext { + fn get_context(&self) -> *mut ffi::UiContext; + + fn list(&self) -> UiList { + let ctx = self.get_context(); + + let v: Vec = Vec::new(); + let mut b = Box::new(v); + let data = b.as_mut_ptr(); + + unsafe { + UiList { + ptr: ui_list_new2(ctx, std::ptr::null_mut(), list_init::, data as *mut c_void), + data: b + } + } + } +} + pub struct UiObject { pub ptr: *mut ffi::UiObject, pub _data: PhantomData } + pub struct UiText { pub ptr: *mut ffi::UiText } @@ -26,6 +46,18 @@ pub struct UiDouble { pub ptr: *mut ffi::UiDouble } +pub struct UiList { + pub ptr: *mut ffi::UiList, + data: Box> +} + +impl UiList { + pub fn data(&mut self) -> &mut Vec { + self.data.as_mut() + } +} + + extern "C" { fn ui_init(appname: *const c_char, argc: c_int, argv: *const *const c_char); @@ -100,3 +132,104 @@ impl UiInteger { } } } + + +/* -------------------------------- List -------------------------------- */ + +/* + * UiList init func, that is used by ui_list_new2 + */ +extern "C" fn list_init(_ctx: *mut ffi::UiContext, list: *mut ffi::UiList, data: *mut c_void) { + unsafe { + ui_list_class_set_data(list, data); + ui_list_class_set_first(list, list_first::); + ui_list_class_set_next(list, list_next::); + ui_list_class_set_get(list, list_get::); + ui_list_class_set_count(list, list_count::); + } +} + +extern "C" fn list_first(list: *mut ffi::UiList) -> *mut c_void { + unsafe { + let data = ui_list_get_data(list); + if !data.is_null() { + let ls = &*(data as *mut Vec); + if ls.len() > 0 { + let iter = 1; + ui_list_set_iter(list, iter as *mut c_void); + return ls.as_ptr() as *mut c_void + } + } + std::ptr::null_mut() + } +} + +extern "C" fn list_next(list: *mut ffi::UiList) -> *mut c_void { + unsafe { + let data = ui_list_get_data(list); + let iter = ui_list_get_iter(list); + + if !data.is_null() { + let ls = &*(data as *mut Vec); + let mut index = 0; + if !iter.is_null() { + index = iter as usize; + } + + if index < ls.len() { + let value = ls.as_ptr().add(index); + index += 1; + ui_list_set_iter(list, index as *mut c_void); + return value as *mut c_void; + } + } + } + std::ptr::null_mut() +} + +extern "C" fn list_get(list: *mut ffi::UiList, index: c_int) -> *mut c_void { + unsafe { + let data = ui_list_get_data(list); + if !data.is_null() { + let ls = &*(data as *mut Vec); + let i = index as usize; + if i < ls.len() { + let value = ls.as_ptr().add(i); + return value as *mut c_void; + } + } + } + std::ptr::null_mut() +} + +extern "C" fn list_count(list: *mut ffi::UiList) -> c_int { + unsafe { + let data = ui_list_get_data(list); + if !data.is_null() { + let ls = &*(data as *mut Vec); + return ls.len() as c_int; + } + 0 + } +} + +type UiListInitFunc = extern "C" fn(*mut ffi::UiContext, *mut ffi::UiList, *mut c_void); +type UiListDestroyFunc = extern "C" fn(*mut ffi::UiContext, *mut ffi::UiList, *mut c_void); +type UiListFirstFunc = extern "C" fn(*mut ffi::UiList) -> *mut c_void; +type UiListNextFunc = extern "C" fn(*mut ffi::UiList) -> *mut c_void; +type UiListGetFunc = extern "C" fn(*mut ffi::UiList, c_int) -> *mut c_void; +type UiListCountFunc = extern "C" fn(*mut ffi::UiList) -> c_int; + +extern "C" { + fn ui_list_new2(ctx: *mut ffi::UiContext, name: *const c_char, init: UiListInitFunc, userdata: *mut c_void) -> *mut ffi::UiList; + fn ui_list_class_set_first(list: *mut ffi::UiList, func: UiListFirstFunc); + fn ui_list_class_set_next(list: *mut ffi::UiList, func: UiListNextFunc); + fn ui_list_class_set_get(list: *mut ffi::UiList, func: UiListGetFunc); + fn ui_list_class_set_count(list: *mut ffi::UiList, func: UiListCountFunc); + fn ui_list_class_set_data(list: *mut ffi::UiList, data: *mut c_void); + fn ui_list_class_set_iter(list: *mut ffi::UiList, iter: *mut c_void); + + fn ui_list_get_data(list: *mut ffi::UiList) -> *mut c_void; + fn ui_list_get_iter(list: *mut ffi::UiList) -> *mut c_void; + fn ui_list_set_iter(list: *mut ffi::UiList, iter: *mut c_void); +} diff --git a/ui-rs/src/ui/window.rs b/ui-rs/src/ui/window.rs index e154e14..46e521c 100644 --- a/ui-rs/src/ui/window.rs +++ b/ui-rs/src/ui/window.rs @@ -23,6 +23,16 @@ extern "C" { fn ui_reg_destructor(ctx: *mut UiContext, data: *mut c_void, destructor: UiDestructor); } +impl crate::ui::UiContext for crate::ui::UiObject { + fn get_context(&self) -> *mut UiContext { + unsafe { + ui_object_get_context(self.ptr) + } + } +} + + + extern "C" fn destroy_boxed(data: *mut c_void) { if data.is_null() { @@ -43,8 +53,8 @@ impl toolkit::UiObject { pub fn reg_box(&mut self, b: Box) -> *mut B { let ptr = Box::into_raw(b); unsafe { - let ctx = crate::ui::window::ui_object_get_context(self.ptr); - crate::ui::window::ui_reg_destructor(ctx, ptr as *mut c_void, destroy_boxed::); + let ctx = ui_object_get_context(self.ptr); + ui_reg_destructor(ctx, ptr as *mut c_void, destroy_boxed::); } ptr } -- 2.47.3