]> uap-core.de Git - note.git/commitdiff
add button event handler main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 12 Apr 2026 16:31:37 +0000 (18:31 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 12 Apr 2026 16:31:37 +0000 (18:31 +0200)
application/src/main.rs
ui-rs/src/ui/button.rs
ui-rs/src/ui/event.rs [new file with mode: 0644]
ui-rs/src/ui/mod.rs
ui-rs/src/ui/text.rs
ui-rs/src/ui/widget.rs
ui-rs/src/ui/window.rs

index f2d984042842a4f3f736662d5f9d1bf90c3451e6..daf250ee55252e4b42bea7dd2c6635ea85d538c9 100644 (file)
@@ -15,11 +15,13 @@ struct TestData {
 
 impl ui::Application for App {
     fn on_startup(&self) {
-        let testdata = TestData { i: 123} ;
+        let testdata = TestData { i: } ;
 
-        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();
index ab6dd11a47f35f072487d257c87aa51a12d2d3a2..19252750476b0f15dba7e8100cb8f325fe5affc6 100644 (file)
@@ -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<T>,
 }
 
-pub struct ToggleBuilder {
+pub struct ToggleBuilder<T> {
     args: *mut UiToggleArgs,
     obj: *const UiObject,
-    create: ToggleButtonCreate
+    create: ToggleButtonCreate,
+    _marker: PhantomData<T>
 }
 
 pub enum LabelType {
@@ -34,40 +36,40 @@ impl<T> toolkit::UiObject<T> {
     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<T> {
         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<T> {
         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<T> {
         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<T> {
         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<T> Drop for ToggleBuilder<T> {
     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<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);
+        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);
+        }
+        self
+    }
 }
 
-impl ToggleBuilder {
+impl<T> ToggleBuilder<T> {
     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 (file)
index 0000000..d8e0392
--- /dev/null
@@ -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<T> {
+    pub callback: Box<dyn FnMut(&mut Event<T>)>
+}
+
+pub extern "C" fn event_wrapper<T>(e: *const ffi::UiEvent, data: *mut c_void) {
+    unsafe {
+        let wrapper = &mut *(data as *mut EventWrapper<T>);
+
+        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
index 583875ce39e2a4b4253f0b0e8574c51cc1805863..79da3bd99f66bcee93472adfb3e8373444505270 100644 (file)
@@ -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::*;
index 54710a4f82479a9e0ccf9fa603d4ce4ab48f1401..942c85ec7d4756d456c53dd5a0fbaef7ac7b7a5d 100644 (file)
@@ -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<T> {
     args: *mut UiTextAreaArgs,
-    obj: *const UiObject
+    obj: *const UiObject,
+    _marker: PhantomData<T>
 }
 
 impl<T> toolkit::UiObject<T> {
     widget_fn!(textarea, textarea_builder, TextAreaBuilder);
 
-    pub fn textarea_builder(&self) -> TextAreaBuilder {
+    pub fn textarea_builder(&self) -> TextAreaBuilder<T> {
         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<T> Drop for TextAreaBuilder<T> {
     fn drop(&mut self) {
         unsafe {
             ui_textarea_args_free(self.args);
@@ -34,7 +36,7 @@ impl Drop for TextAreaBuilder {
     }
 }
 
-impl TextAreaBuilder {
+impl<T> TextAreaBuilder<T> {
     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<T> {
     args: *mut UiTextFieldArgs,
     obj: *const UiObject,
-    create: TextFieldCreate
+    create: TextFieldCreate,
+    _marker: PhantomData<T>
 }
 
 pub fn textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) {
@@ -199,29 +202,29 @@ impl<T> toolkit::UiObject<T> {
     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<T> {
         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<T> {
         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<T> {
         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<T> Drop for TextFieldBuilder<T> {
     fn drop(&mut self) {
         unsafe {
             ui_textfield_args_free(self.args);
@@ -229,7 +232,7 @@ impl Drop for TextFieldBuilder {
     }
 }
 
-impl TextFieldBuilder {
+impl<T> TextFieldBuilder<T> {
     pub fn create(&mut self) {
         unsafe {
             ui_textfield_create(self.obj, self.args);
index 671f4b9130fc05a4b95d06d55719a37ed22232b0..a35bd3d05c6b7b1eb93daab33f43f588f9b5d677 100644 (file)
@@ -15,9 +15,9 @@
  */
 macro_rules! widget_fn {
     ($fn_name:ident, $builder_fn:ident, $builder_ty:ident) => {
-        pub fn $fn_name<F>(&self, build: F)
+        pub fn $fn_name<F>(&mut self, build: F)
         where
-            F: Fn(&mut $builder_ty),
+            F: Fn(&mut $builder_ty<T>),
         {
             let mut builder = self.$builder_fn();
             build(&mut builder);
index 6be3ff1cc4745d9636434a4798e266e1e81d08a8..e154e146225f9b777b0134d1e9d38b1efa61df78 100644 (file)
@@ -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<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) {
@@ -31,6 +39,15 @@ 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 = crate::ui::window::ui_object_get_context(self.ptr);
+            crate::ui::window::ui_reg_destructor(ctx, ptr as *mut c_void, destroy_boxed::<B>);
+        }
+        ptr
+    }
 }
 
 enum WindowType {
@@ -61,24 +78,13 @@ where F: FnOnce(&mut toolkit::UiObject<T>, &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::<T>);
     }
     obj
 }
 
-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 fn window<T, F>(title: &str, data: T, create_ui: F) -> toolkit::UiObject<T>
 where F: FnOnce(&mut toolkit::UiObject<T>, &mut T)
 {