From: Olaf Wintermann Date: Sun, 12 Apr 2026 16:31:37 +0000 (+0200) Subject: add button event handler X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=HEAD;p=note.git add button event handler --- diff --git a/application/src/main.rs b/application/src/main.rs index f2d9840..daf250e 100644 --- a/application/src/main.rs +++ b/application/src/main.rs @@ -15,11 +15,13 @@ struct TestData { impl ui::Application for App { fn on_startup(&self) { - let testdata = TestData { i: 123} ; + let testdata = TestData { i: 0 } ; - let window = ui::window("note", testdata, |obj, data| { - obj.button_builder().label("Hello").create(); - println!("test: {}", data.i); + 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/button.rs b/ui-rs/src/ui/button.rs index ab6dd11..1925275 100644 --- a/ui-rs/src/ui/button.rs +++ b/ui-rs/src/ui/button.rs @@ -3,19 +3,21 @@ use std::ffi::{c_char, c_int, c_void}; use std::ffi::CString; -use crate::ui::{toolkit}; +use std::marker::PhantomData; +use crate::ui::{event, toolkit, EventWrapper}; use crate::ui::ffi::*; use crate::ui::widget::widget_fn; -pub struct ButtonBuilder { +pub struct ButtonBuilder<'a, T> { args: *mut UiButtonArgs, - obj: *const UiObject + obj: &'a mut toolkit::UiObject, } -pub struct ToggleBuilder { +pub struct ToggleBuilder { args: *mut UiToggleArgs, obj: *const UiObject, - create: ToggleButtonCreate + create: ToggleButtonCreate, + _marker: PhantomData } pub enum LabelType { @@ -34,40 +36,40 @@ impl toolkit::UiObject { widget_fn!(switch, switch_builder, ToggleBuilder); widget_fn!(radiobutton, radiobutton_builder, ToggleBuilder); - pub fn button_builder(&self) -> ButtonBuilder { + pub fn button_builder<'a>(&'a mut self) -> ButtonBuilder<'a, T> { unsafe { let args = ui_button_args_new(); - ButtonBuilder { args: args, obj: self.ptr } + ButtonBuilder { args: args, obj: self } } } - pub fn togglebutton_builder(&self) -> ToggleBuilder { + pub fn togglebutton_builder(&self) -> ToggleBuilder { unsafe { let args = ui_toggle_args_new(); - ToggleBuilder { args: args, obj: self.ptr, create: togglebutton_create } + ToggleBuilder { args: args, obj: self.ptr, create: togglebutton_create, _marker: PhantomData } } } - pub fn checkbox_builder(&self) -> ToggleBuilder { + pub fn checkbox_builder(&self) -> ToggleBuilder { unsafe { let args = ui_toggle_args_new(); - ToggleBuilder { args: args, obj: self.ptr, create: checkbox_create } + ToggleBuilder { args: args, obj: self.ptr, create: checkbox_create, _marker: PhantomData } } } - pub fn switch_builder(&self) -> ToggleBuilder { + pub fn switch_builder(&self) -> ToggleBuilder { unsafe { let args = ui_toggle_args_new(); - ToggleBuilder { args: args, obj: self.ptr, create: switch_create } + ToggleBuilder { args: args, obj: self.ptr, create: switch_create, _marker: PhantomData } } } - pub fn radiobutton_builder(&self) -> ToggleBuilder { + pub fn radiobutton_builder(&self) -> ToggleBuilder { unsafe { let args = ui_toggle_args_new(); - ToggleBuilder { args: args, obj: self.ptr, create: radiobutton_create } + ToggleBuilder { args: args, obj: self.ptr, create: radiobutton_create, _marker: PhantomData } } } } @@ -96,7 +98,7 @@ fn radiobutton_create(obj: *const UiObject, args: *const UiToggleArgs) { } } -impl Drop for ButtonBuilder { +impl<'a, T> Drop for ButtonBuilder<'a, T> { fn drop(&mut self) { unsafe { ui_button_args_free(self.args); @@ -104,7 +106,7 @@ impl Drop for ButtonBuilder { } } -impl Drop for ToggleBuilder { +impl Drop for ToggleBuilder { fn drop(&mut self) { unsafe { ui_toggle_args_free(self.args); @@ -112,10 +114,10 @@ impl Drop for ToggleBuilder { } } -impl ButtonBuilder { +impl<'a, T> ButtonBuilder<'a, T> { pub fn create(&mut self) { unsafe { - ui_button_create(self.obj, self.args); + ui_button_create(self.obj.ptr, self.args); } } @@ -258,10 +260,19 @@ impl ButtonBuilder { self } - // TODO: callback, states + pub fn onclick(&mut self, f: F) -> &mut Self + where F: FnMut(&mut event::Event) + 'static { + let wrapper = Box::new(EventWrapper { callback: Box::new(f) }); + let ptr = self.obj.reg_box(wrapper); + unsafe { + ui_button_args_set_onclick(self.args, Some(event::event_wrapper::)); + ui_button_args_set_onclickdata(self.args, ptr as *mut c_void); + } + self + } } -impl ToggleBuilder { +impl ToggleBuilder { pub fn create(&mut self) { (self.create)(self.obj, self.args) } diff --git a/ui-rs/src/ui/event.rs b/ui-rs/src/ui/event.rs new file mode 100644 index 0000000..d8e0392 --- /dev/null +++ b/ui-rs/src/ui/event.rs @@ -0,0 +1,29 @@ +use std::ffi::c_void; +use crate::ui::ffi; +use crate::ui::ffi::UiEvent; + +pub struct Event<'a, T> { + pub data: &'a mut T +} + +pub struct EventWrapper { + pub callback: Box)> +} + +pub extern "C" fn event_wrapper(e: *const ffi::UiEvent, data: *mut c_void) { + unsafe { + let wrapper = &mut *(data as *mut EventWrapper); + + let wdata_ptr = ui_event_get_windowdata(e); + let wdata = &mut *(wdata_ptr as *mut T); + + let mut event = Event { data: wdata }; + + (wrapper.callback)(&mut event); + } +} + + +extern "C" { + fn ui_event_get_windowdata(event: *const UiEvent) -> *const c_void; +} \ No newline at end of file diff --git a/ui-rs/src/ui/mod.rs b/ui-rs/src/ui/mod.rs index 583875c..79da3bd 100644 --- a/ui-rs/src/ui/mod.rs +++ b/ui-rs/src/ui/mod.rs @@ -6,8 +6,11 @@ mod button; mod container; mod widget; mod text; +pub mod event; pub use toolkit::*; +pub use event::*; pub use application::*; pub use window::*; pub use button::*; +pub use text::*; diff --git a/ui-rs/src/ui/text.rs b/ui-rs/src/ui/text.rs index 54710a4..942c85e 100644 --- a/ui-rs/src/ui/text.rs +++ b/ui-rs/src/ui/text.rs @@ -3,6 +3,7 @@ use std::ffi::{c_char, c_int, c_void}; use std::ffi::CString; +use std::marker::PhantomData; use crate::ui::{toolkit}; use crate::ui::ffi::*; use crate::ui::widget::widget_fn; @@ -10,23 +11,24 @@ use crate::ui::widget::widget_fn; /* -------------------------------- TextArea -------------------------------- */ -pub struct TextAreaBuilder { +pub struct TextAreaBuilder { args: *mut UiTextAreaArgs, - obj: *const UiObject + obj: *const UiObject, + _marker: PhantomData } impl toolkit::UiObject { widget_fn!(textarea, textarea_builder, TextAreaBuilder); - pub fn textarea_builder(&self) -> TextAreaBuilder { + pub fn textarea_builder(&self) -> TextAreaBuilder { unsafe { let args = ui_textarea_args_new(); - TextAreaBuilder { args: args, obj: self.ptr } + TextAreaBuilder { args: args, obj: self.ptr, _marker: PhantomData } } } } -impl Drop for TextAreaBuilder { +impl Drop for TextAreaBuilder { fn drop(&mut self) { unsafe { ui_textarea_args_free(self.args); @@ -34,7 +36,7 @@ impl Drop for TextAreaBuilder { } } -impl TextAreaBuilder { +impl TextAreaBuilder { pub fn create(&mut self) { unsafe { ui_textarea_create(self.obj, self.args); @@ -170,10 +172,11 @@ impl TextAreaBuilder { pub type TextFieldCreate = fn(*const UiObject, *const UiTextFieldArgs); -pub struct TextFieldBuilder { +pub struct TextFieldBuilder { args: *mut UiTextFieldArgs, obj: *const UiObject, - create: TextFieldCreate + create: TextFieldCreate, + _marker: PhantomData } pub fn textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) { @@ -199,29 +202,29 @@ impl toolkit::UiObject { widget_fn!(passwordfield, passwordfield_builder, TextFieldBuilder); widget_fn!(frameless_textfield, frameless_textfield_builder, TextFieldBuilder); - pub fn textfield_builder(&self) -> TextFieldBuilder { + pub fn textfield_builder(&self) -> TextFieldBuilder { unsafe { let args = ui_textfield_args_new(); - TextFieldBuilder { args: args, obj: self.ptr, create: textfield_create } + TextFieldBuilder { args: args, obj: self.ptr, create: textfield_create, _marker: PhantomData } } } - pub fn passwordfield_builder(&self) -> TextFieldBuilder { + pub fn passwordfield_builder(&self) -> TextFieldBuilder { unsafe { let args = ui_textfield_args_new(); - TextFieldBuilder { args: args, obj: self.ptr, create: passwordfield_create } + TextFieldBuilder { args: args, obj: self.ptr, create: passwordfield_create, _marker: PhantomData } } } - pub fn frameless_textfield_builder(&self) -> TextFieldBuilder { + pub fn frameless_textfield_builder(&self) -> TextFieldBuilder { unsafe { let args = ui_textfield_args_new(); - TextFieldBuilder { args: args, obj: self.ptr, create: frameless_textfield_create } + TextFieldBuilder { args: args, obj: self.ptr, create: frameless_textfield_create, _marker: PhantomData } } } } -impl Drop for TextFieldBuilder { +impl Drop for TextFieldBuilder { fn drop(&mut self) { unsafe { ui_textfield_args_free(self.args); @@ -229,7 +232,7 @@ impl Drop for TextFieldBuilder { } } -impl TextFieldBuilder { +impl TextFieldBuilder { pub fn create(&mut self) { unsafe { ui_textfield_create(self.obj, self.args); diff --git a/ui-rs/src/ui/widget.rs b/ui-rs/src/ui/widget.rs index 671f4b9..a35bd3d 100644 --- a/ui-rs/src/ui/widget.rs +++ b/ui-rs/src/ui/widget.rs @@ -15,9 +15,9 @@ */ macro_rules! widget_fn { ($fn_name:ident, $builder_fn:ident, $builder_ty:ident) => { - pub fn $fn_name(&self, build: F) + pub fn $fn_name(&mut self, build: F) where - F: Fn(&mut $builder_ty), + F: Fn(&mut $builder_ty), { let mut builder = self.$builder_fn(); build(&mut builder); diff --git a/ui-rs/src/ui/window.rs b/ui-rs/src/ui/window.rs index 6be3ff1..e154e14 100644 --- a/ui-rs/src/ui/window.rs +++ b/ui-rs/src/ui/window.rs @@ -4,7 +4,7 @@ use std::ffi::{c_char, c_int, c_void}; use std::ffi::CString; use std::marker::PhantomData; -use crate::ui::toolkit; +use crate::ui::{toolkit}; use crate::ui::ffi::{UiContext, UiDestructor, UiObject}; extern "C" { @@ -24,6 +24,14 @@ extern "C" { } +extern "C" fn destroy_boxed(data: *mut c_void) { + if data.is_null() { + return; + } + unsafe { + drop(Box::from_raw(data as *mut T)); + } +} impl toolkit::UiObject { pub fn show(&self) { @@ -31,6 +39,15 @@ impl toolkit::UiObject { ui_show(self.ptr); } } + + 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::); + } + ptr + } } enum WindowType { @@ -61,24 +78,13 @@ where F: FnOnce(&mut toolkit::UiObject, &mut T) { // store windowdata object in the UiObject let window_data = Box::new(data); - let wdata_ptr = Box::into_raw(window_data); + let wdata_ptr = obj.reg_box(window_data); unsafe { ui_object_set_windowdata(objptr, wdata_ptr as *mut c_void); - let ctx = ui_object_get_context(objptr); - ui_reg_destructor(ctx, wdata_ptr as *mut c_void, destroy_boxed::); } obj } -extern "C" fn destroy_boxed(data: *mut c_void) { - if data.is_null() { - return; - } - unsafe { - drop(Box::from_raw(data as *mut T)); - } -} - pub fn window(title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) {