]> uap-core.de Git - note.git/commitdiff
add UiDoc main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Apr 2026 06:08:33 +0000 (08:08 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Apr 2026 06:08:33 +0000 (08:08 +0200)
ui-rs/src/ui/button.rs
ui-rs/src/ui/list.rs
ui-rs/src/ui/text.rs
ui-rs/src/ui/toolkit.rs
ui-rs/src/ui/window.rs

index 26dcf4f39c1ed272440b2d4a856cf1830c4269e7..846aa4056b0cf1c11773725e095e68a5367029c6 100644 (file)
@@ -261,7 +261,7 @@ impl<'a, T> ButtonBuilder<'a, T> {
     pub fn onclick<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
         let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
-        let ptr = self.obj.reg_box(wrapper);
+        let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_button_args_set_onclick(self.args, Some(event::event_wrapper::<T>));
             ui_button_args_set_onclickdata(self.args, ptr as *mut c_void);
@@ -453,7 +453,7 @@ impl<'a, T> ToggleBuilder<'a, T> {
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
         let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
-        let ptr = self.obj.reg_box(wrapper);
+        let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_toggle_args_set_onchange(self.args, Some(event::event_wrapper::<T>));
             ui_toggle_args_set_onchangedata(self.args, ptr as *mut c_void);
index 7398b757bc89981658ae9024d2f5b3d9fdb7beab..94a343229d50c6e343c88d5220a024bb30b00e71 100644 (file)
@@ -242,7 +242,7 @@ impl<'a, T, E> ListViewBuilder<'a, T, E> {
     where F: Fn(&E, i32, i32) -> ListValue<'a> + 'static {
         unsafe {
             let wrapper = Box::new(GetValueWrapper { callback: Box::new(f), is_table: false });
-            let ptr = self.obj.reg_box(wrapper);
+            let ptr = self.obj.ctx.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);
         }
@@ -420,7 +420,7 @@ impl<'a, T, E> TableViewBuilder<'a, T, E> {
     where F: Fn(&E, i32, i32) -> ListValue<'a> + 'static {
         unsafe {
             let wrapper = Box::new(GetValueWrapper { callback: Box::new(f), is_table: true });
-            let ptr = self.obj.reg_box(wrapper);
+            let ptr = self.obj.ctx.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);
         }
index 9d9dbdaae7a2a3be12a8eaff9c49b4ea9224e712..fde423231e2c06f4514bc462b233fa68bf8610f8 100644 (file)
@@ -164,7 +164,7 @@ impl<'a, T> TextAreaBuilder<'a, T> {
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
         let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
-        let ptr = self.obj.reg_box(wrapper);
+        let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textarea_args_set_onchange(self.args, Some(event::event_wrapper::<T>));
             ui_textarea_args_set_onchangedata(self.args, ptr as *mut c_void);
@@ -382,7 +382,7 @@ impl<'a, T> TextFieldBuilder<'a, T> {
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
         let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
-        let ptr = self.obj.reg_box(wrapper);
+        let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textfield_args_set_onchange(self.args, Some(event::event_wrapper::<T>));
             ui_textfield_args_set_onchangedata(self.args, ptr as *mut c_void);
index 87e5d76d21e7550d8f0aa377eeb38b778fb2d8b5..f9bed168cc2b89d4199cd156390720314233e269 100644 (file)
@@ -1,25 +1,19 @@
 #![allow(dead_code)]
 
 use std::ffi::{c_char, c_int, c_void, CStr, CString};
-use crate::ui::ffi;
+use crate::ui::{ffi, ui_object_get_context, ui_reg_destructor};
 
 use std::marker::PhantomData;
+use std::mem;
 
 pub struct UiContext {
-    pub ptr: *mut ffi::UiContext,
-    doc: *mut c_void
+    pub ptr: *mut ffi::UiContext
 }
 
 impl Clone for UiContext {
     fn clone(&self) -> Self {
-        unsafe {
-            if !self.doc.is_null() {
-                ui_document_ref(self.doc);
-            }
-        }
         UiContext {
-            ptr: self.ptr,
-            doc: self.doc
+            ptr: self.ptr
         }
     }
 }
@@ -27,28 +21,35 @@ impl Clone for UiContext {
 impl Default for UiContext {
     fn default() -> Self {
         UiContext {
-            ptr: std::ptr::null_mut(),
-            doc: std::ptr::null_mut()
+            ptr: std::ptr::null_mut()
         }
     }
 }
 
-impl Drop for UiContext {
-    fn drop(&mut self) {
-        if !self.doc.is_null() {
-            unsafe {
-                ui_document_unref(self.doc);
-            }
+impl UiContext {
+    pub fn from_ptr(ctx: *mut ffi::UiContext) -> UiContext {
+        UiContext {
+            ptr: ctx
         }
     }
-}
 
+    pub fn reg_box<B>(&mut self, b: Box<B>) -> *mut B  {
+        let ptr = Box::into_raw(b);
+        unsafe {
+            ui_reg_destructor(self.ptr, ptr as *mut c_void, destroy_boxed::<B>);
+        }
+        ptr
+    }
 
-impl UiContext {
-    pub fn from_ptr(ctx: *mut ffi::UiContext) -> UiContext {
-        UiContext {
-            ptr: ctx,
-            doc: std::ptr::null_mut()
+    pub fn attach(&mut self, doc: &UiDoc) {
+        unsafe {
+            ui_attach_document(self.ptr, doc.ptr);
+        }
+    }
+
+    pub fn detach(&mut self, doc: &UiDoc) {
+        unsafe {
+            ui_attach_document(self.ptr, doc.ptr);
         }
     }
 
@@ -59,6 +60,56 @@ impl UiContext {
     }
 }
 
+extern "C" fn destroy_boxed<T>(data: *mut c_void) {
+    if data.is_null() {
+        return;
+    }
+    unsafe {
+        drop(Box::from_raw(data as *mut T));
+    }
+}
+
+pub struct UiDoc {
+    pub ctx: UiContext,
+    ptr: *mut c_void
+}
+
+impl Clone for UiDoc {
+    fn clone(&self) -> Self {
+        unsafe {
+            ui_document_ref(self.ptr);
+        }
+        UiDoc {
+            ctx: self.ctx.clone(),
+            ptr: self.ptr
+        }
+    }
+}
+
+impl Drop for UiDoc {
+    fn drop(&mut self) {
+        unsafe {
+            if !self.ptr.is_null() {
+                ui_document_unref(self.ptr);
+            }
+        }
+    }
+}
+
+impl UiDoc {
+    pub fn new<T: UiModel>(mut data: T) -> UiDoc {
+        unsafe {
+            let doc = ui_document_new(mem::size_of::<*mut T>());
+            let mut ctx = UiContext { ptr: ui_document_context(doc) };
+            data.init(&ctx);
+            let data_ptr = ctx.reg_box(Box::new(data)); // returns *mut T
+            let doc_storage: *mut *mut T = doc.cast();
+            *doc_storage = data_ptr;
+            UiDoc { ctx: ctx, ptr: doc }
+        }
+    }
+}
+
 pub trait UiModel {
     fn init(&mut self, ctx: &UiContext);
 }
@@ -260,7 +311,9 @@ impl<T> Drop for UiList<T> {
         unsafe {
             // This does not free the UiList pointer, because it could still be in use by
             // UI elements, but it will have no reference to any object managed by Rust
-            ui_list_class_set_data(self.ptr, std::ptr::null_mut());
+            if !self.ptr.is_null() {
+                ui_list_class_set_data(self.ptr, std::ptr::null_mut());
+            }
         }
     }
 }
@@ -353,6 +406,9 @@ extern "C" {
     fn ui_document_new(size: usize) -> *mut c_void;
     fn ui_document_ref(doc: *mut c_void);
     fn ui_document_unref(doc: *mut c_void);
+    fn ui_document_context(doc: *mut c_void) -> *mut ffi::UiContext;
+    fn ui_attach_document(ctx: *mut ffi::UiContext, doc: *mut c_void);
+    fn ui_detach_document(ctx: *mut ffi::UiContext, doc: *mut c_void);
 
     fn ui_int_new(ctx: *mut ffi::UiContext, name: *const c_char) -> *mut ffi::UiInteger;
     fn ui_double_new(ctx: *mut ffi::UiContext, name: *const c_char) -> *mut ffi::UiDouble;
index a046e290e57d27831df90d70091ec96d9971d367..35782134ad6bdfc3fd2425cac3e7e5c1eaa02620 100644 (file)
@@ -23,14 +23,6 @@ extern "C" {
     pub fn ui_reg_destructor(ctx: *mut UiContext, data: *mut c_void, destructor: UiDestructor);
 }
 
-extern "C" fn destroy_boxed<T>(data: *mut c_void) {
-    if data.is_null() {
-        return;
-    }
-    unsafe {
-        drop(Box::from_raw(data as *mut T));
-    }
-}
 
 impl<T> toolkit::UiObject<T> {
     pub fn show(&self) {
@@ -38,15 +30,6 @@ impl<T> toolkit::UiObject<T> {
             ui_show(self.ptr);
         }
     }
-
-    pub fn reg_box<B>(&mut self, b: Box<B>) -> *mut B  {
-        let ptr = Box::into_raw(b);
-        unsafe {
-            let ctx = ui_object_get_context(self.ptr);
-            ui_reg_destructor(ctx, ptr as *mut c_void, destroy_boxed::<B>);
-        }
-        ptr
-    }
 }
 
 enum WindowType {
@@ -88,7 +71,7 @@ where F: FnOnce(&mut toolkit::UiObject<T>, &mut T) {
 
     // store windowdata object in the UiObject
     let window_data = Box::new(data);
-    let wdata_ptr = obj.reg_box(window_data);
+    let wdata_ptr = obj.ctx.reg_box(window_data);
     unsafe {
         ui_object_set_windowdata(objptr, wdata_ptr as *mut c_void);
     }