]> uap-core.de Git - note.git/commitdiff
add listview main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 14 Apr 2026 17:38:41 +0000 (19:38 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 14 Apr 2026 17:38:41 +0000 (19:38 +0200)
application/src/main.rs
ui-rs/src/ui/ffi.rs
ui-rs/src/ui/list.rs
ui-rs/src/ui/mod.rs
ui-rs/src/ui/widget.rs

index 9cca73e2135e3d8a4049fef03ed99ec953227f75..fabbe19e19f0e2850f08826145216afd057405bd 100644 (file)
@@ -1,5 +1,5 @@
 use ui_rs::ui;
-use ui_rs::ui::{UiContext, UiList};
+use ui_rs::ui::{ListValue, UiContext, UiList};
 
 fn main() {
     ui::app_init("note");
@@ -25,12 +25,17 @@ fn create_window() {
         v.push(11);
         v.push(12);
 
-        data.list = Some(list);
+
 
         obj.button_builder().label("Hello").onclick(|e| {
             println!("Button clicked: {}", e.data.i);
             e.data.i += 1;
         }).create();
+        obj.listview_builder::<i32>().fill(true).value(&list).getvalue(|elm, _row, _col| {
+            ListValue::String(elm.to_string())
+        }).create();
+
+        data.list = Some(list);
     });
 
 
index 8e2da0666e192f54edab81abcd9176179f58f64f..99eba46df7e942f8189485cf3dcf5519e63033b9 100644 (file)
@@ -111,3 +111,8 @@ pub struct UiTextFieldArgs {
     _private: [u8; 0],
 }
 
+#[repr(C)]
+pub struct UiListArgs {
+    _private: [u8; 0],
+}
+
index 3b768e4c1f7030baff15251b493d14b17aab641e..045fef952c0d5b4363f8e4184d2e13bdad09f5f4 100644 (file)
@@ -1,2 +1,277 @@
 #![allow(dead_code)]
 
+use crate::ui::ffi::{UiObject, UiListArgs, UiCallback, UiList};
+use crate::ui::{ffi, toolkit};
+use std::ffi::{c_char, c_int, c_void};
+use std::ffi::CString;
+use std::marker::PhantomData;
+use crate::ui::widget::{widget_typed_fn};
+
+pub enum ListValue<'a> {
+    None,
+    Str(&'a str),
+    String(String)
+}
+
+pub struct ListBuilder<'a, T, E> {
+    args: *mut UiListArgs,
+    obj: &'a mut toolkit::UiObject<T>,
+    create: ListBuilderCreate,
+    has_getvalue_func: bool,
+    _marker: PhantomData<E>
+}
+
+pub type ListBuilderCreate = fn(*const UiObject, *const UiListArgs);
+
+impl<T> toolkit::UiObject<T> {
+    widget_typed_fn!(listview, listview_builder, ListBuilder);
+    pub fn listview_builder<'a, E>(&'a mut self) -> ListBuilder<'a, T, E> {
+        unsafe {
+            let args = ui_list_args_new();
+            ListBuilder { args: args, obj: self, create: list_create, has_getvalue_func: false, _marker: PhantomData }
+        }
+    }
+}
+
+fn list_create(obj: *const UiObject, args: *const UiListArgs) {
+    unsafe {
+        ui_listview_create(obj, args);
+    }
+}
+
+impl<'a, T, E> Drop for ListBuilder<'a, T, E> {
+    fn drop(&mut self) {
+        unsafe {
+            ui_list_args_free(self.args);
+        }
+    }
+}
+
+
+impl<'a, T, E> ListBuilder<'a, T, E> {
+    pub fn create(&mut self) {
+        if !self.has_getvalue_func {
+            unsafe {
+                ui_list_args_set_getvalue_func2(self.args, null_getvalue_wrapper);
+            }
+        }
+        (self.create)(self.obj.ptr, self.args);
+    }
+
+    pub fn fill(&mut self, fill: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_fill(self.args, if fill { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn hexpand(&mut self, value: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_hexpand(self.args, if value { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn vexpand(&mut self, value: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_vexpand(self.args, if value { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn hfill(&mut self, value: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_hfill(self.args, if value { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn vfill(&mut self, value: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_vfill(self.args, if value { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn override_defaults(&mut self, value: bool) -> &mut Self {
+        unsafe {
+            ui_list_args_set_override_defaults(self.args, if value { 1 } else { 0 });
+        }
+        self
+    }
+
+    pub fn margin(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_margin(self.args, value);
+        }
+        self
+    }
+
+    pub fn margin_left(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_margin_left(self.args, value);
+        }
+        self
+    }
+
+    pub fn margin_right(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_margin_right(self.args, value);
+        }
+        self
+    }
+
+    pub fn margin_top(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_margin_top(self.args, value);
+        }
+        self
+    }
+
+    pub fn margin_bottom(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_margin_bottom(self.args, value);
+        }
+        self
+    }
+
+    pub fn colspan(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_colspan(self.args, value);
+        }
+        self
+    }
+
+    pub fn rowspan(&mut self, value: i32) -> &mut Self {
+        unsafe {
+            ui_list_args_set_rowspan(self.args, value);
+        }
+        self
+    }
+
+    pub fn name(&mut self, value: &str) -> &mut Self {
+        let cstr = CString::new(value).unwrap();
+        unsafe {
+            ui_list_args_set_name(self.args, cstr.as_ptr());
+        }
+        self
+    }
+
+    pub fn style_class(&mut self, value: &str) -> &mut Self {
+        let cstr = CString::new(value).unwrap();
+        unsafe {
+            ui_list_args_set_style_class(self.args, cstr.as_ptr());
+        }
+        self
+    }
+
+    pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self {
+        unsafe {
+            ui_list_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int);
+        }
+        self
+    }
+
+    pub fn value<C>(&mut self, value: &toolkit::UiList<C>) -> &mut Self {
+        unsafe {
+            ui_list_args_set_value(self.args, value.ptr);
+        }
+        self
+    }
+
+    pub fn getvalue<F>(&mut self, f: F) -> &mut Self
+    where F: Fn(&E, i32, i32) -> ListValue<'a> + 'static {
+        unsafe {
+            let wrapper = Box::new(GetValueWrapper { callback: Box::new(f) });
+            let ptr = self.obj.reg_box(wrapper);
+            ui_list_args_set_getvalue_func2(self.args, getvalue_wrapper::<T>);
+            ui_list_args_set_getvalue_data(self.args, ptr as *mut c_void);
+        }
+        self.has_getvalue_func = true;
+        self
+    }
+
+    pub fn states(&mut self, states: &[i32]) -> &mut Self {
+        unsafe {
+            ui_list_args_set_states(self.args, states.as_ptr(), states.len() as c_int);
+        }
+        self
+    }
+}
+
+type GetValueFunc = extern "C" fn(list: *const ffi::UiList, elm_ptr: *const c_void, row: i32, col: i32, wrapper: *const c_void, free: *mut bool) -> *mut c_void;
+
+pub struct GetValueWrapper<'a, T> {
+    pub callback: Box<dyn Fn(&T, i32, i32) -> ListValue<'a>>,
+}
+
+
+fn str_dup(str: &str) -> *mut c_void {
+    let cstr = CString::new(str).unwrap();
+    let bytes = cstr.as_bytes_with_nul();
+
+    unsafe {
+        let ptr = malloc(bytes.len()) as *mut c_char;
+        if ptr.is_null() {
+            return std::ptr::null_mut();
+        }
+
+        std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
+        ptr as *mut c_void
+    }
+}
+
+pub extern "C" fn getvalue_wrapper<T>(_list: *const ffi::UiList, elm_ptr: *const c_void, row: i32, col: i32, wrapper_ptr: *const c_void, free: *mut bool) -> *mut c_void {
+    let wrapper = unsafe { &*(wrapper_ptr as *const GetValueWrapper<T> ) };
+    let elm = unsafe { &*(elm_ptr as *const T) };
+
+    unsafe {
+        *free = true;
+    }
+
+    let result = (wrapper.callback)(elm, col, row);
+    match result {
+        ListValue::None => std::ptr::null_mut(),
+        ListValue::Str(s) => str_dup(s),
+        ListValue::String(s) => str_dup(s.as_str())
+    }
+}
+
+pub extern "C" fn null_getvalue_wrapper(_list: *const ffi::UiList, _elm_ptr: *const c_void, _row: i32, _col: i32, _wrapper: *const c_void, _free: *mut bool) -> *mut c_void {
+    std::ptr::null_mut()
+}
+
+
+extern "C" {
+    fn malloc(size: usize) -> *mut c_void;
+
+    fn ui_listview_create(obj: *const UiObject, args: *const UiListArgs);
+
+    fn ui_list_args_new() -> *mut UiListArgs;
+    fn ui_list_args_set_fill(args: *mut UiListArgs, fill: c_int);
+    fn ui_list_args_set_hexpand(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_vexpand(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_hfill(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_vfill(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_override_defaults(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_margin(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_margin_left(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_margin_right(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_margin_top(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_margin_bottom(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_colspan(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_rowspan(args: *mut UiListArgs, value: c_int);
+    fn ui_list_args_set_name(args: *mut UiListArgs, name: *const c_char);
+    fn ui_list_args_set_style_class(args: *mut UiListArgs, classname: *const c_char);
+    fn ui_list_args_set_onchange(args: *mut UiListArgs, callback: UiCallback);
+    fn ui_list_args_set_onchangedata(args: *mut UiListArgs, data: *mut c_void);
+    fn ui_list_args_set_varname(args: *mut UiListArgs, varname: *const c_char);
+    fn ui_list_args_set_value(args: *mut UiListArgs, ivalue: *mut UiList);
+    fn ui_list_args_set_getvalue_func2(args: *mut UiListArgs, func: GetValueFunc);
+    fn ui_list_args_set_getvalue_data(args: *mut UiListArgs, data: *mut c_void);
+    fn ui_list_args_set_enablestate(args: *mut UiListArgs, state: c_int);
+    fn ui_list_args_set_states(args: *mut UiListArgs, states: *const c_int, numstates: c_int);
+    fn ui_list_args_set_visibility_states(args: *mut UiListArgs, states: *const c_int, numstates: c_int);
+    fn ui_list_args_free(args: *mut UiListArgs);
+
+}
\ No newline at end of file
index 8e0ce222bb0836a53c11efcf3804a6e8666d93c2..5451bac9a8322c9d264fa7109dc48123fab8c96e 100644 (file)
@@ -7,7 +7,7 @@ mod container;
 mod widget;
 mod text;
 pub mod event;
-mod list;
+pub mod list;
 
 pub use toolkit::*;
 pub use event::*;
@@ -15,3 +15,4 @@ pub use application::*;
 pub use window::*;
 pub use button::*;
 pub use text::*;
+pub use list::*;
index a35bd3d05c6b7b1eb93daab33f43f588f9b5d677..4ae67dca6989ec433932ea69dc320c86a0305cf9 100644 (file)
@@ -26,4 +26,18 @@ macro_rules! widget_fn {
     };
 }
 
-pub(super) use widget_fn;
\ No newline at end of file
+macro_rules! widget_typed_fn {
+    ($fn_name:ident, $builder_fn:ident, $builder_ty:ident) => {
+        pub fn $fn_name<F, E>(&mut self, build: F)
+        where
+            F: Fn(&mut $builder_ty<T, E>),
+        {
+            let mut builder = self.$builder_fn();
+            build(&mut builder);
+            builder.create();
+        }
+    };
+}
+
+pub(super) use widget_fn;
+pub(super) use widget_typed_fn;
\ No newline at end of file