"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"
[workspace]
members = [
"ui-rs",
- "application"
+ "ui-rs-derive",
+ "application" ,
]
resolver = "2"
use ui_rs::ui;
-use ui_rs::ui::{ListValue, UiContext, UiList};
+use ui_rs::ui::{ListValue, UiList};
fn main() {
ui::app_init("note");
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);
data.list = Some(list);
});
-
-
window.show();
}
--- /dev/null
+[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
--- /dev/null
+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
edition = "2021"
[dependencies]
-
+ui-rs-derive = { path = "../ui-rs-derive" }
+#![allow(unused_imports)]
+
pub mod ui;
+pub use ui_rs_derive::*;
\ No newline at end of file
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>
}
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);
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;
}
};
+ 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);
}
#endif
+ ctx->ref = 1;
+
return 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) {
ui_callback close_callback;
void *close_data;
+
+ unsigned int ref;
};
struct UiVar {
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);
}
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);
}
}
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