From: Olaf Wintermann Date: Thu, 16 Jul 2026 20:26:29 +0000 (+0200) Subject: add support for creating a UiDoc for dyn objects X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=HEAD;p=note.git add support for creating a UiDoc for dyn objects --- diff --git a/ui-rs/src/ui/event.rs b/ui-rs/src/ui/event.rs index 3fb2104..93bf370 100644 --- a/ui-rs/src/ui/event.rs +++ b/ui-rs/src/ui/event.rs @@ -278,10 +278,15 @@ pub struct ActionEventWrapper { pub target: *mut T } +pub struct ActionEventWrapperBoxed { + pub callback: Box, + pub target: *mut Box +} + pub extern "C" fn action_event_wrapper(e: *const ffi::UiEvent, data: *mut c_void) { unsafe { let wrapper = &mut *(data as *mut ActionEventWrapper); - let target = &mut *(wrapper.target as *mut T); + let target = &mut *(wrapper.target); action_callback(e, |event| { (wrapper.callback)(target, event); @@ -289,6 +294,17 @@ pub extern "C" fn action_event_wrapper(e: *const ffi::UiEvent, data: *mut c_v } } +pub extern "C" fn action_event_wrapper_boxed(e: *const ffi::UiEvent, data: *mut c_void) { + unsafe { + let wrapper = &mut *(data as *mut ActionEventWrapperBoxed); + let target = &mut *(wrapper.target); + let target_ref = target.as_mut(); + action_callback(e, |event| { + (wrapper.callback)(target_ref, event); + }); + } +} + fn action_callback(e: *const ffi::UiEvent, f: F) where F: FnOnce(&mut ActionEvent) { unsafe { diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index 39c119d..63e1023 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -30,7 +30,7 @@ use std::any::Any; use std::ffi::{c_char, c_int, c_void, CStr, CString}; -use crate::ui::{action_event_wrapper, event, ffi, simple_event_wrapper, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ui_remove_destructor, untyped_event_wrapper, ActionEventWrapper, Event, EventWrapper, NoAppData, SimpleEventWrapper, SubList, UntypedEventWrapper, RUST_TYPED_OBJECT_BOX_ANY}; +use crate::ui::{action_event_wrapper, action_event_wrapper_boxed, event, ffi, simple_event_wrapper, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ui_remove_destructor, untyped_event_wrapper, ActionEventWrapper, ActionEventWrapperBoxed, Event, EventWrapper, NoAppData, SimpleEventWrapper, SubList, UntypedEventWrapper, RUST_TYPED_OBJECT_BOX_ANY}; use std::marker::PhantomData; use std::mem; @@ -75,15 +75,15 @@ impl UiContext { ptr } - pub fn attach(&mut self, doc: &UiDoc) { + pub fn attach(&mut self, doc: &UiDoc) { unsafe { - ui_attach_document(self.ptr, doc.ptr); + ui_attach_document(self.ptr, doc.ptr.cast()); } } - pub fn detach(&mut self, doc: &UiDoc) { + pub fn detach(&mut self, doc: &UiDoc) { unsafe { - ui_detach_document(self.ptr, doc.ptr); + ui_detach_document(self.ptr, doc.ptr.cast()); } } @@ -164,16 +164,17 @@ impl UiContext { unsafe { let doc_ptr = ui_context_document(self.ptr) as *mut T; let target_ptr = if !doc_ptr.is_null() { - let doc_storage: *mut *mut T = doc_ptr.cast(); - *doc_storage + let doc_storage: *mut *mut Box = doc_ptr.cast(); + let target_ptr = *doc_storage; + self.add_action_for_target_boxed(target_ptr, name, f); } else { let obj_ptr = ui_context_obj(self.ptr); assert!(!obj_ptr.is_null()); let obj_wdata_ptr = ui_object_get_windowdata(obj_ptr); assert!(!obj_wdata_ptr.is_null()); - obj_wdata_ptr as *mut T + let target_ptr = obj_wdata_ptr as *mut T; + self.add_action_for_target(target_ptr, name, f); }; - self.add_action_for_target(target_ptr, name, f); } } @@ -187,6 +188,16 @@ impl UiContext { } } + pub unsafe fn add_action_for_target_boxed(&self, target_ptr: *mut Box, name: &str, f: F) + where F: FnMut(&mut T, &mut event::ActionEvent) + 'static { + let wrapper = Box::new(ActionEventWrapperBoxed { callback: Box::new(f), target: target_ptr }); + let ptr = self.reg_box(wrapper); + let cstr = CString::new(name).unwrap(); + unsafe { + ui_add_action(self.ptr, cstr.as_ptr(), Some(action_event_wrapper_boxed::), ptr as *mut c_void); + } + } + pub fn add_action_untyped(&self, name: &str, f: F) where F: FnMut(&mut event::ActionEvent) + 'static { unsafe { @@ -247,16 +258,16 @@ pub extern "C" fn destroy_boxed(data: *mut c_void) { } } -pub struct UiDoc { +pub struct UiDoc { pub ctx: UiContext, - ptr: *mut c_void, + ptr: *mut *mut Box, _marker: PhantomData } -impl Clone for UiDoc { +impl Clone for UiDoc { fn clone(&self) -> Self { unsafe { - ui_document_ref(self.ptr); + ui_document_ref(self.ptr.cast()); } UiDoc:: { ctx: self.ctx.clone(), @@ -266,64 +277,118 @@ impl Clone for UiDoc { } } -impl Drop for UiDoc { +impl Drop for UiDoc { fn drop(&mut self) { unsafe { if !self.ptr.is_null() { - ui_document_unref(self.ptr); + ui_document_unref(self.ptr.cast()); } } } } - -impl UiDoc { +impl UiDoc { fn from_ptr(ptr: *mut c_void) -> UiDoc { unsafe { let ctx = UiContext { ptr: ui_document_context(ptr) }; ui_document_ref(ptr); - UiDoc:: { ctx: ctx, ptr: ptr, _marker: PhantomData } + UiDoc:: { ctx: ctx, ptr: ptr.cast(), _marker: PhantomData } } } - pub fn new(data: T) -> UiDoc { - UiDoc::new2(data, |_,_| {}) + pub fn new_from_box(data: Box) { + UiDoc::new_from_box2(data, |_,_| {}); } - - pub fn new2(data: T, init: F) -> UiDoc + + pub fn new_from_box2(data: Box, init: F) -> UiDoc where F: FnOnce(&mut T, &UiDoc) { unsafe { - let doc = ui_document_new(mem::size_of::<*mut T>()); + let doc = ui_document_new(mem::size_of::<*mut Box>()); let ctx = UiContext::from_ptr(ui_document_context(doc)); ui_app_ref(); ui_reg_destructor(ctx.ptr, std::ptr::null_mut(), doc_app_unref); - let data_ptr = ctx.reg_box(Box::new(data)); // returns *mut T - let doc_storage: *mut *mut T = doc.cast(); + let data_ptr = ctx.reg_box(Box::new(data)); // returns *mut Box + let doc_storage: *mut *mut Box = doc.cast(); *doc_storage = data_ptr; let doc_ref = &mut *data_ptr; doc_ref.init(&ctx); doc_ref.init_actions(&ctx); - let doc_handle = UiDoc:: { ctx: ctx, ptr: doc, _marker: PhantomData }; + let doc_handle = UiDoc:: { ctx: ctx, ptr: doc.cast(), _marker: PhantomData }; init(doc_ref, &doc_handle); doc_handle } } + pub fn cast( + self, + f: impl FnOnce(Box) -> Box, + ) -> UiDoc { + unsafe { + // replace the Box container for this document + // the destructor for the previous Box must be removed + ui_remove_destructor(self.ctx.ptr, self.ptr.cast()); + ui_document_ref(self.ptr.cast()); + + let outer: Box> = Box::from_raw(*self.ptr); + + // Prevent dropping the outer box while extracting the inner box + let outer = std::mem::ManuallyDrop::new(outer); + + let inner: Box = std::ptr::read(&**outer); + + let new_inner: Box = f(inner); + + let new_outer: Box> = Box::new(new_inner); + + *self.ptr.cast::<*mut Box>() = Box::into_raw(new_outer); + + UiDoc { + ctx: self.ctx.clone(), + ptr: self.ptr.cast(), + _marker: PhantomData, + } + } + } + pub fn doc_ref(&self) -> UiDocRef { - UiDocRef::from_ptr(self.ptr) + UiDocRef::from_ptr(self.ptr.cast()) } pub fn doc_proxy(&self) -> UiDocProxy { - UiDocProxy::from_ptr(self.ptr) + UiDocProxy::from_ptr(self.ptr.cast()) } - pub unsafe fn get_data_ptr(&self) -> *mut T { + pub unsafe fn get_data_ptr(&self) -> *mut Box { + unsafe { + let box_ptr: *mut *mut Box = self.ptr.cast(); + *box_ptr + } + } +} + +#[macro_export] +macro_rules! doc_cast { + ($doc:expr, dyn $trait:path) => { + $doc.cast(|b| Box::new(*b) as Box) + }; +} + +impl UiDoc { + + + pub fn new(data: T) -> UiDoc { + UiDoc::new2(data, |_,_| {}) + } + + pub fn new2(data: T, init: F) -> UiDoc + where F: FnOnce(&mut T, &UiDoc) { unsafe { - let ptr: *mut *mut T = self.ptr.cast(); - *ptr + let inner_box = Box::new(data); + UiDoc::new_from_box2(inner_box, init) } } + /* pub fn add_action(&mut self, name: &str, f: F) where F: FnMut(&mut T, &mut event::ActionEvent) + 'static { unsafe { @@ -333,6 +398,7 @@ impl UiDoc { ui_add_action(self.ctx.ptr, cstr.as_ptr(), Some(action_event_wrapper::), ptr as *mut c_void); } } + */ } extern "C" fn doc_app_unref(_: *mut c_void) { @@ -517,13 +583,13 @@ impl Drop for UiObjProxy { -pub struct UiDocRef { +pub struct UiDocRef { ptr: Box<*mut c_void>, orig_ptr: *mut c_void, _data: PhantomData } -impl UiDocRef { +impl UiDocRef { fn from_ptr(doc_ptr: *mut c_void) -> UiDocRef { let obj_ref = UiDocRef { ptr: Box::new(doc_ptr), orig_ptr: doc_ptr, _data: PhantomData }; if !doc_ptr.is_null() { @@ -545,7 +611,7 @@ impl UiDocRef { } } -impl Drop for UiDocRef { +impl Drop for UiDocRef { fn drop(&mut self) { unsafe { let doc_ptr = *self.ptr; @@ -582,14 +648,14 @@ impl Default for UiDocRef { } } -pub struct UiDocProxy { +pub struct UiDocProxy { ptr: *mut c_void, _data: PhantomData } -unsafe impl Send for UiDocProxy {} +unsafe impl Send for UiDocProxy {} -impl UiDocProxy { +impl UiDocProxy { fn from_ptr(ptr: *mut c_void) -> UiDocProxy { unsafe { ui_document_ref(ptr); @@ -610,7 +676,7 @@ impl UiDocProxy { } } -impl Drop for UiDocProxy { +impl Drop for UiDocProxy { fn drop(&mut self) { unsafe { ui_mainthread_document_unref(self.ptr);