+use std::any::Any;
use std::rc::Rc;
use ui_rs::{action, ui_actions, UiModel};
use ui_rs::ui::*;
if let Some(mut nb) = self.doc_ref.get_doc() {
nb.ctx.attach(&doc);
self.selected_note = Some(doc);
+
+ let param: Box<dyn Any> = Box::new("hello world".to_string());
+ nb.ctx.call_action_with_parameter("navigation", param);
}
}
}
}
+ #[action(String)]
+ pub fn navigation(&mut self, _event: &ActionEvent, arg: &String) {
+ println!("navigation: {}", arg);
+ }
+
#[action]
pub fn message(&mut self, _event: &ActionEvent) {
while let Ok(msg) = self.broadcast_rx.try_recv() {
use proc_macro::TokenStream;
use quote::quote;
-use syn::{parse_macro_input, Attribute, Data, DeriveInput, Expr, ExprLit, ImplItem, ItemImpl, Lit, Meta};
+use syn::{parse_macro_input, Attribute, Data, DeriveInput, Expr, ExprLit, ImplItem, ItemImpl, Lit, Meta, Type};
#[proc_macro_derive(UiModel, attributes(bind))]
pub fn derive_ui_model(input: TokenStream) -> TokenStream {
let self_ty = &impl_block.self_ty;
let mut handlers = vec![];
+ let mut param_handlers = vec![];
for item in &impl_block.items {
if let ImplItem::Fn(method) = item {
- if has_handler_attr(&method.attrs) {
- handlers.push(method.sig.ident.clone());
+ if let Some(attr) = has_handler_attr(&method.attrs) {
+ match attr {
+ Some(param) => param_handlers.push((param, method.sig.ident.clone())),
+ None => handlers.push(method.sig.ident.clone()),
+ }
}
}
}
+ let typed_actions = param_handlers.into_iter().map(|(ty, name)| {
+ quote! {
+ ctx.add_action(
+ stringify!(#name),
+ |target: &mut Self, event| {
+ if let EventType::TypedObject(obj) = &event.event_type {
+ if let Some(arg) = obj.downcast_ref::<#ty>() {
+ target.#name(event, arg);
+ }
+ }
+ }
+ );
+ }
+ });
+
let expanded = quote! {
#impl_block
impl UiActions for #self_ty {
target.#handlers(event);
}
);
- )*
+ )*;
+ #(#typed_actions)*
}
}
}
TokenStream::from(expanded)
}
-fn has_handler_attr(attrs: &[Attribute]) -> bool {
- attrs.iter().any(|attr| attr.path().is_ident("action"))
+fn has_handler_attr(attrs: &[Attribute]) -> Option<Option<Type>> {
+ for attr in attrs {
+ if !attr.path().is_ident("action") {
+ continue;
+ }
+ match &attr.meta {
+ Meta::Path(_) => return Some(None),
+ Meta::List(list) => {
+ let ty: Type = syn::parse2(list.tokens.clone()).ok()?;
+ return Some(Some(ty));
+ },
+ _ => panic!("Unexpected Attribute")
+ }
+ }
+ None
}
#[proc_macro_attribute]
#![allow(dead_code)]
+use std::any::Any;
use std::ffi::{c_char, c_void, CStr, CString};
use std::slice;
use crate::ui::{event, ffi, UiDouble, UiInteger, UiString, UiText, UiRange, ListSelection, UiObject, NoAppData, UiSourceList};
-use crate::ui::ffi::{UiEvent, UiSubListEventData, UiTextChangeEventData};
+use crate::ui::ffi::{UiEvent, UiSubListEventData, UiTextChangeEventData, UiTypedObj};
use crate::ui::text::{TextInsert, TextDelete};
+pub const RUST_TYPED_OBJECT_BOX_ANY: u64 = 0x4416222c10162501;
+
pub struct Event<'a, T> {
pub obj: &'a mut UiObject<T>,
pub data: &'a mut T,
ListElm,
DND,
SubList,
- FileList
+ FileList,
+ TypedObject
}
pub enum EventType<'a> {
ListElement,
Dnd,
SubList(&'a mut SubListEvent),
- FileList
+ FileList,
+ TypedObject(&'a mut dyn Any)
}
enum EventTypeData {
ListElement,
Dnd,
SubList(SubListEvent),
- FileList
+ FileList,
+ TypedObject(*mut Box<dyn Any>)
}
fn get_event_data(e: *const ffi::UiEvent) -> EventTypeData {
UiEventType::FileList => {
// filelist
EventTypeData::Null
- }
+ },
+ UiEventType::TypedObject => {
+ unsafe {
+ if ui_typed_obj_get_type(ptr.cast()) == RUST_TYPED_OBJECT_BOX_ANY && !ptr.is_null() {
+ let box_ptr: *mut Box<dyn Any> = ui_typed_obj_get_ptr(ptr.cast()).cast();
+ EventTypeData::TypedObject(box_ptr)
+ } else {
+ EventTypeData::Null
+
+ }
+ }
+ },
_ => EventTypeData::Null
}
}
EventTypeData::Dnd => EventType::Dnd,
EventTypeData::SubList(s) => EventType::SubList( s ),
EventTypeData::FileList => EventType::FileList,
+ EventTypeData::TypedObject(ptr) => unsafe {
+ let boxed: &mut Box<dyn Any> = ptr.as_mut().unwrap();
+ let any: &mut dyn Any = boxed.as_mut();
+ EventType::TypedObject(any)
+ }
}
}
fn ui_event_get_int(event: *const UiEvent) -> i32;
fn ui_event_get_set(event: *const UiEvent) -> i32;
+ fn ui_typed_obj_get_ptr(obj: *const UiTypedObj) -> *mut c_void;
+ fn ui_typed_obj_get_type(obj: *const UiTypedObj) -> u64;
+
fn ui_text_change_event_get_type(data: *const UiTextChangeEventData) -> i32;
fn ui_text_change_event_get_begin(data: *const UiTextChangeEventData) -> i32;
fn ui_text_change_event_get_end(data: *const UiTextChangeEventData) -> i32;
_private: [u8; 0],
}
+#[repr(C)]
+pub struct UiTypedObj {
+ _private: [u8; 0],
+}
+
#[repr(C)]
pub struct UiTextChangeEventData {
_private: [u8; 0],
#![allow(dead_code)]
+use std::any::Any;
use std::ffi::{c_char, c_int, c_void, CStr, CString};
-use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ui_remove_destructor, ActionEventWrapper, Event, EventWrapper, SubList};
+use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ui_remove_destructor, ActionEventWrapper, Event, EventWrapper, SubList, RUST_TYPED_OBJECT_BOX_ANY};
use std::marker::PhantomData;
use std::mem;
ui_call_action(self.ptr, cstr.as_ptr());
}
}
+
+ pub fn call_action_with_parameter(&self, action: &str, mut param: Box<dyn Any>) {
+ let cstr = CString::new(action).unwrap();
+ unsafe {
+ let param_ptr = &mut param as *mut Box<dyn Any>;
+ ui_call_action3(self.ptr, cstr.as_ptr(), param_ptr.cast(), RUST_TYPED_OBJECT_BOX_ANY);
+ }
+ }
}
pub extern "C" fn destroy_boxed<T>(data: *mut c_void) {
fn ui_text_length(text: *const ffi::UiText) -> c_int;
fn ui_text_remove(text: *mut ffi::UiText, begin: c_int, end: c_int);
- fn ui_call_action(ctx: *mut ffi::UiContext, action: *const c_char);
+ fn ui_call_action(ctx: *mut ffi::UiContext, action: *const c_char) -> c_int;
+ fn ui_call_action3(ctx: *mut ffi::UiContext, action: *const c_char, data: *mut c_void, typeid: u64) -> c_int;
fn ui_mainthread_broadcast(action: *const c_char);
}
}
}
-void ui_call_action(UiContext *ctx, const char *action_name) {
- ui_call_action2(ctx, action_name, NULL, 0);
-}
-
-void ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval) {
+static int call_action(UiContext *ctx, const char *action_name, void *eventdata, UiEventType eventdatatype, int intval) {
UiAction *action = uic_resolve_action(ctx, action_name);
if(action && action->callback) {
UiEvent event;
event.document = ctx->self_doc ? ctx->self_doc : ctx->document;
if(eventdata) {
event.eventdata = eventdata;
- event.eventdatatype = UI_EVENT_DATA_POINTER;
+ event.eventdatatype = eventdatatype;
}
event.intval = intval;
action->callback(&event, action->userdata);
+ return 1;
+ } else {
+ return 0;
}
}
+int ui_call_action(UiContext *ctx, const char *action_name) {
+ return ui_call_action2(ctx, action_name, NULL, 0);
+}
+
+int ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval) {
+ return call_action(ctx, action_name, eventdata, UI_EVENT_DATA_POINTER, intval);
+}
+
+int ui_call_action3(UiContext *ctx, const char *action_name, void *ptr, uint64_t type_id) {
+ UiTypedObj *obj = malloc(sizeof(UiTypedObj));
+ obj->ptr = ptr;
+ obj->type = type_id;
+ int ret = call_action(ctx, action_name, obj, UI_EVENT_DATA_TYPED_OBJECT, 0);
+ free(obj);
+ return ret;
+}
+
void ui_broadcast_action(const char *action_name) {
ui_broadcast_action2(action_name, NULL, 0);
}
}
+/* ---------------------------- UiTypedObj ---------------------------- */
+
+void* ui_typed_obj_get_ptr(UiTypedObj *obj) {
+ return obj->ptr;
+}
+
+uint64_t ui_typed_obj_get_type(UiTypedObj *obj) {
+ return obj->type;
+}
+
+
/* ------------------------- SubListItem (public) ------------------------- */
void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon) {
UIEXPORT int ui_event_get_int(UiEvent *event);
UIEXPORT int ui_event_get_set(UiEvent *event);
+UIEXPORT void* ui_typed_obj_get_ptr(UiTypedObj *obj);
+UIEXPORT uint64_t ui_typed_obj_get_type(UiTypedObj *obj);
+
UIEXPORT int ui_list_selection_get_count(UiListSelection *sel);
UIEXPORT int* ui_list_selection_get_rows(UiListSelection *sel);
UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num);
typedef struct UiTextStyle UiTextStyle;
typedef struct UiColor UiColor;
+typedef enum UiEventType UiEventType;
+
/* begin opaque types */
typedef struct UiContext UiContext;
typedef struct UiContainer UiContainer;
unsigned int ref;
};
+enum UiEventType {
+ UI_EVENT_DATA_NULL = 0,
+ UI_EVENT_DATA_POINTER,
+ UI_EVENT_DATA_STRING,
+ UI_EVENT_DATA_INTEGER_VALUE,
+ UI_EVENT_DATA_STRING_VALUE,
+ UI_EVENT_DATA_TEXT_VALUE,
+ UI_EVENT_DATA_DOUBLE_VALUE,
+ UI_EVENT_DATA_RANGE_VALUE,
+ UI_EVENT_DATA_TEXT_CHANGED,
+ UI_EVENT_DATA_LIST_SELECTION,
+ UI_EVENT_DATA_LIST_ELM,
+ UI_EVENT_DATA_DND,
+ UI_EVENT_DATA_SUBLIST,
+ UI_EVENT_DATA_FILE_LIST,
+ UI_EVENT_DATA_TYPED_OBJECT
+};
+
struct UiEvent {
- UiObject *obj;
- void *document;
- void *window;
- void *eventdata;
- int eventdatatype;
- int intval;
- int set;
+ UiObject *obj;
+ void *document;
+ void *window;
+ void *eventdata;
+ UiEventType eventdatatype;
+ int intval;
+ int set;
};
struct UiMouseEvent {
int intdata;
} UiCondVar;
-enum UiEventType {
- UI_EVENT_DATA_NULL = 0,
- UI_EVENT_DATA_POINTER,
- UI_EVENT_DATA_STRING,
- UI_EVENT_DATA_INTEGER_VALUE,
- UI_EVENT_DATA_STRING_VALUE,
- UI_EVENT_DATA_TEXT_VALUE,
- UI_EVENT_DATA_DOUBLE_VALUE,
- UI_EVENT_DATA_RANGE_VALUE,
- UI_EVENT_DATA_TEXT_CHANGED,
- UI_EVENT_DATA_LIST_SELECTION,
- UI_EVENT_DATA_LIST_ELM,
- UI_EVENT_DATA_DND,
- UI_EVENT_DATA_SUBLIST,
- UI_EVENT_DATA_FILE_LIST
-};
+// eventdata in case eventdatatype is UI_EVENT_DATA_TYPED_OBJECT
+typedef struct UiTypedObj {
+ void *ptr;
+ uint64_t type;
+} UiTypedObj;
#define UI_COLOR(r, g, b) (UiColor){r, g, b}
struct UiColor {
const char *accelerator,
const char *accelerator_text);
UIEXPORT void ui_update_action_bindings(UiContext *ctx);
-UIEXPORT void ui_call_action(UiContext *ctx, const char *action_name);
-UIEXPORT void ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval);
+UIEXPORT int ui_call_action(UiContext *ctx, const char *action_name);
+UIEXPORT int ui_call_action2(UiContext *ctx, const char *action_name, void *eventdata, int intval);
+UIEXPORT int ui_call_action3(UiContext *ctx, const char *action_name, void *ptr, uint64_t type_id);
UIEXPORT void ui_broadcast_action(const char *action_name);
UIEXPORT void ui_broadcast_action2(const char *action_name, void *eventdata, int intval);
UIEXPORT void ui_mainthread_broadcast(const char *action_name);