]> uap-core.de Git - note.git/commitdiff
refactor UiContext trait into a struct
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 15 Apr 2026 10:40:42 +0000 (12:40 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 15 Apr 2026 10:40:42 +0000 (12:40 +0200)
13 files changed:
Cargo.lock
Cargo.toml
application/src/main.rs
ui-rs-derive/Cargo.toml [new file with mode: 0644]
ui-rs-derive/src/lib.rs [new file with mode: 0644]
ui-rs/Cargo.toml
ui-rs/src/lib.rs
ui-rs/src/ui/toolkit.rs
ui-rs/src/ui/window.rs
ui/common/context.c
ui/common/context.h
ui/common/document.c
ui/ui/toolkit.h

index 369756834c5a73d9613784838cc26f3761ac5bc1..2888ccd9d50ae024f30c856cd23730d1d203dc26 100644 (file)
@@ -9,6 +9,53 @@ dependencies = [
  "ui-rs",
 ]
 
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "ui-rs"
 version = "0.1.0"
+dependencies = [
+ "ui-rs-derive",
+]
+
+[[package]]
+name = "ui-rs-derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
index e4cdb2043972d73dae82b89296fdb4586aa0b778..5d208c0cf8c51ab00de6ab1be3b137b6fe90d95a 100644 (file)
@@ -1,7 +1,8 @@
 [workspace]
 members = [
     "ui-rs",
-    "application"
+    "ui-rs-derive",
+    "application" ,
 ]
 
 resolver = "2"
index fabbe19e19f0e2850f08826145216afd057405bd..a62fe81200f77ea7eff96f7a4b80f79414821077 100644 (file)
@@ -1,5 +1,5 @@
 use ui_rs::ui;
-use ui_rs::ui::{ListValue, UiContext, UiList};
+use ui_rs::ui::{ListValue, UiList};
 
 fn main() {
     ui::app_init("note");
@@ -19,7 +19,7 @@ fn create_window() {
     let testdata = TestData { i: 0, list: None } ;
 
     let window = ui::window("note", testdata, |obj, data| {
-        let mut list = obj.list::<i32>();
+        let mut list = obj.ctx.list::<i32>();
         let v = list.data();
         v.push(10);
         v.push(11);
@@ -38,8 +38,6 @@ fn create_window() {
         data.list = Some(list);
     });
 
-
-
     window.show();
 }
 
diff --git a/ui-rs-derive/Cargo.toml b/ui-rs-derive/Cargo.toml
new file mode 100644 (file)
index 0000000..6306e72
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+name = "ui-rs-derive"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "2"
+quote = "1"
+proc-macro2 = "1"
\ No newline at end of file
diff --git a/ui-rs-derive/src/lib.rs b/ui-rs-derive/src/lib.rs
new file mode 100644 (file)
index 0000000..e0ab62c
--- /dev/null
@@ -0,0 +1,20 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{parse_macro_input, DeriveInput};
+
+#[proc_macro_derive(ViewModel)]
+pub fn derive_view_model(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+
+    let name = input.ident;
+
+    let expanded = quote! {
+        impl ViewModel for #name {
+            fn init(&mut self, _ctx: &ui_rs::ui::UiContext) {
+                // empty for now
+            }
+        }
+    };
+
+    TokenStream::from(expanded)
+}
\ No newline at end of file
index ab578f0739655c73a8acf0fd53fda385147470e0..3d4c54faa1091c91d6e356712e807dc8554c64e1 100644 (file)
@@ -4,4 +4,4 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-
+ui-rs-derive = { path = "../ui-rs-derive" }
index 6bae95df97a86ba99733b3ac0a40af71a8bdfa8b..0490e85c716a54f60623d76d9fc8a99edd878183 100644 (file)
@@ -1 +1,4 @@
+#![allow(unused_imports)]
+
 pub mod ui;
+pub use ui_rs_derive::*;
\ No newline at end of file
index 6a99bd83ebb2fbe301ec26bbddcc6d8ef68f9933..d6b2fcee182813c31ff95127488bf71cc9cf4565 100644 (file)
@@ -5,27 +5,65 @@ use crate::ui::ffi;
 
 use std::marker::PhantomData;
 
-pub trait UiContext {
-    fn get_context(&self) -> *mut ffi::UiContext;
+pub struct UiContext {
+    pub ptr: *mut ffi::UiContext,
+    doc: *mut c_void
+}
 
-    fn list<T>(&self) -> UiList<T> {
-        let ctx = self.get_context();
+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
+        }
+    }
+}
 
+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,
+            doc: std::ptr::null_mut()
+        }
+    }
+    
+    pub fn list<T>(&self) -> UiList<T> {
         let v: Vec<T> = Vec::new();
         let b = Box::new(v);
         let data = Box::into_raw(b);
 
         unsafe {
             UiList {
-                ptr: ui_list_new2(ctx, std::ptr::null_mut(), list_init::<T>, data as *mut c_void),
+                ptr: ui_list_new2(self.ptr, std::ptr::null_mut(), list_init::<T>, data as *mut c_void),
                 data: Box::from_raw(data as *mut Vec<T>)
             }
         }
     }
 }
 
+pub trait WindowModel {
+    fn init(&mut self, ctx: *const ffi::UiContext);
+}
+
 pub struct UiObject<T> {
     pub ptr: *mut ffi::UiObject,
+    pub ctx: UiContext,
     pub _data: PhantomData<T>
 }
 
@@ -60,6 +98,10 @@ impl<T> UiList<T> {
 
 extern "C" {
     fn ui_init(appname: *const c_char, argc: c_int, argv: *const *const c_char);
+    
+    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_text_get(value: *const ffi::UiText) -> *mut c_char;
     fn ui_text_set(value: *const ffi::UiText, str: *const c_char);
index 46e521c4b5df05acef8d03a2af79c8c544fdf606..a19569ee69d29db646e623c9297680a80f1daef6 100644 (file)
@@ -16,24 +16,13 @@ extern "C" {
 
     fn ui_show(ui: *const UiObject);
 
-    fn ui_object_get_windowdata(obj: *const UiObject) -> *mut c_void;
-    fn ui_object_set_windowdata(obj: *mut UiObject, data: *mut c_void);
-    fn ui_object_get_context(obj: *const UiObject) -> *mut UiContext;
+    pub fn ui_object_get_windowdata(obj: *const UiObject) -> *mut c_void;
+    pub fn ui_object_set_windowdata(obj: *mut UiObject, data: *mut c_void);
+    pub fn ui_object_get_context(obj: *const UiObject) -> *mut UiContext;
 
-    fn ui_reg_destructor(ctx: *mut UiContext, data: *mut c_void, destructor: UiDestructor);
+    pub fn ui_reg_destructor(ctx: *mut UiContext, data: *mut c_void, destructor: UiDestructor);
 }
 
-impl<T> crate::ui::UiContext for crate::ui::UiObject<T> {
-    fn get_context(&self) ->  *mut UiContext {
-        unsafe {
-            ui_object_get_context(self.ptr)
-        }
-    }
-}
-
-
-
-
 extern "C" fn destroy_boxed<T>(data: *mut c_void) {
     if data.is_null() {
         return;
@@ -80,8 +69,16 @@ where F: FnOnce(&mut toolkit::UiObject<T>, &mut T) {
         }
     };
 
+    let ctxptr = unsafe {
+        ui_object_get_context(objptr)
+    };
+
     // create local UiObject
-    let mut obj = toolkit::UiObject::<T> { ptr: objptr, _data: PhantomData };
+    let mut obj = toolkit::UiObject::<T> {
+        ptr: objptr,
+        ctx: toolkit::UiContext::from_ptr(ctxptr),
+        _data: PhantomData
+    };
 
     // call ui building closure
     create_ui(&mut obj, &mut data);
index 3e7abfc0cf47e10d78bd2b57065f5f42c3b1f508..37249d7f25b5d170cd87477edda5e9b84e23576d 100644 (file)
@@ -81,6 +81,8 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     }
 #endif
     
+    ctx->ref = 1;
+    
     return ctx;
 }
 
@@ -100,6 +102,25 @@ void uic_context_prepare_close(UiContext *ctx) {
     cxListClear(ctx->state_widgets);
 }
 
+void uic_context_destroy(UiContext *ctx, void *document) {
+    if(!ctx) {
+        return;
+    }
+    
+    UiEvent ev;
+    ev.window = NULL;
+    ev.document = document;
+    ev.obj = NULL;
+    ev.eventdata = NULL;
+    ev.eventdatatype = 0;
+    ev.intval = 0;
+
+    if(ctx->close_callback) {
+        ctx->close_callback(&ev, ctx->close_data);
+    }
+    cxMempoolFree(ctx->mp);
+}
+
 void uic_context_attach_document(UiContext *ctx, void *document) {
     if(ctx->single_document_mode) {
         if(ctx->document) {
index de804818de35418ee6118d0172d5bdceafe05cfa..50f5b445eec5b31f64447cb5dc29260c27cc2f03 100644 (file)
@@ -100,6 +100,8 @@ struct UiContext {
     
     ui_callback   close_callback;
     void          *close_data;
+    
+    unsigned int  ref;
 };
 
 struct UiVar {
@@ -131,6 +133,7 @@ UiContext* uic_root_context(UiContext *ctx);
 void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
 
 void uic_context_prepare_close(UiContext *ctx);
+void uic_context_destroy(UiContext *ctx, void *document);
 
 void uic_context_attach_document(UiContext *ctx, void *document);
 void uic_context_detach_document(UiContext *ctx, void *document);
index 3eb5874d870d9989fd28d3b6fbbb0f5ce45ac2c3..6c6da19681a9f0b30a770ddbbfa308ebabaedee8 100644 (file)
@@ -49,20 +49,22 @@ void* ui_document_new(size_t size) {
 }
 
 void ui_document_destroy(void *doc) {
+    uic_context_destroy(ui_document_context(doc), doc);
+}
+
+void ui_document_ref(void *doc) {
     UiContext *ctx = ui_document_context(doc);
     if(ctx) {
-        UiEvent ev;
-        ev.window = NULL;
-        ev.document = doc;
-        ev.obj = NULL;
-        ev.eventdata = NULL;
-        ev.eventdatatype = 0;
-        ev.intval = 0;
+        ctx->ref++;
+    }
+}
 
-        if(ctx->close_callback) {
-            ctx->close_callback(&ev, ctx->close_data);
+void ui_document_unref(void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(ctx) {
+        if(--ctx->ref == 0) {
+            uic_context_destroy(ctx, doc);
         }
-        cxMempoolFree(ctx->mp);
     }
 }
 
index df8594bba17aa6c02f066becd0b5ba211337678c..76a4e56ae78f57377dcb74e39603f3e46adb9a3a 100644 (file)
@@ -572,6 +572,8 @@ UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool);
 UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd);
 
 UIEXPORT void* ui_document_new(size_t size);
+UIEXPORT void  ui_document_ref(void *doc);
+UIEXPORT void  ui_document_unref(void *doc);
 UIEXPORT void  ui_document_destroy(void *doc);
 
 UIEXPORT void* ui_get_subdocument(void *document);               // deprecated