From: Olaf Wintermann Date: Wed, 15 Apr 2026 10:40:42 +0000 (+0200) Subject: refactor UiContext trait into a struct X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=129349bd2d91e3fcbfd5174c83887e31c232598d;p=note.git refactor UiContext trait into a struct --- diff --git a/Cargo.lock b/Cargo.lock index 3697568..2888ccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index e4cdb20..5d208c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ "ui-rs", - "application" + "ui-rs-derive", + "application" , ] resolver = "2" diff --git a/application/src/main.rs b/application/src/main.rs index fabbe19..a62fe81 100644 --- a/application/src/main.rs +++ b/application/src/main.rs @@ -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::(); + let mut list = obj.ctx.list::(); 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 index 0000000..6306e72 --- /dev/null +++ b/ui-rs-derive/Cargo.toml @@ -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 index 0000000..e0ab62c --- /dev/null +++ b/ui-rs-derive/src/lib.rs @@ -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 diff --git a/ui-rs/Cargo.toml b/ui-rs/Cargo.toml index ab578f0..3d4c54f 100644 --- a/ui-rs/Cargo.toml +++ b/ui-rs/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] - +ui-rs-derive = { path = "../ui-rs-derive" } diff --git a/ui-rs/src/lib.rs b/ui-rs/src/lib.rs index 6bae95d..0490e85 100644 --- a/ui-rs/src/lib.rs +++ b/ui-rs/src/lib.rs @@ -1 +1,4 @@ +#![allow(unused_imports)] + pub mod ui; +pub use ui_rs_derive::*; \ No newline at end of file diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index 6a99bd8..d6b2fce 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -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(&self) -> UiList { - 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(&self) -> UiList { let v: Vec = 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::, data as *mut c_void), + ptr: ui_list_new2(self.ptr, std::ptr::null_mut(), list_init::, data as *mut c_void), data: Box::from_raw(data as *mut Vec) } } } } +pub trait WindowModel { + fn init(&mut self, ctx: *const ffi::UiContext); +} + pub struct UiObject { pub ptr: *mut ffi::UiObject, + pub ctx: UiContext, pub _data: PhantomData } @@ -60,6 +98,10 @@ impl UiList { 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); diff --git a/ui-rs/src/ui/window.rs b/ui-rs/src/ui/window.rs index 46e521c..a19569e 100644 --- a/ui-rs/src/ui/window.rs +++ b/ui-rs/src/ui/window.rs @@ -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 crate::ui::UiContext for crate::ui::UiObject { - fn get_context(&self) -> *mut UiContext { - unsafe { - ui_object_get_context(self.ptr) - } - } -} - - - - extern "C" fn destroy_boxed(data: *mut c_void) { if data.is_null() { return; @@ -80,8 +69,16 @@ where F: FnOnce(&mut toolkit::UiObject, &mut T) { } }; + let ctxptr = unsafe { + ui_object_get_context(objptr) + }; + // create local UiObject - let mut obj = toolkit::UiObject:: { ptr: objptr, _data: PhantomData }; + let mut obj = toolkit::UiObject:: { + ptr: objptr, + ctx: toolkit::UiContext::from_ptr(ctxptr), + _data: PhantomData + }; // call ui building closure create_ui(&mut obj, &mut data); diff --git a/ui/common/context.c b/ui/common/context.c index 3e7abfc..37249d7 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -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) { diff --git a/ui/common/context.h b/ui/common/context.h index de80481..50f5b44 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -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); diff --git a/ui/common/document.c b/ui/common/document.c index 3eb5874..6c6da19 100644 --- a/ui/common/document.c +++ b/ui/common/document.c @@ -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); } } diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index df8594b..76a4e56 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -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