From: Olaf Wintermann Date: Sun, 19 Apr 2026 13:33:38 +0000 (+0200) Subject: implement actions X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=d12a17d15513c13d77769ef0189031fb6a90e562;p=note.git implement actions --- diff --git a/application/src/main.rs b/application/src/main.rs index f845c50..b68af8b 100644 --- a/application/src/main.rs +++ b/application/src/main.rs @@ -1,4 +1,4 @@ -use ui_rs::{ui, UiModel}; +use ui_rs::{action, ui, ui_actions, UiModel}; use ui_rs::ui::*; fn main() { @@ -14,9 +14,17 @@ struct App; struct TestData { i: i32, #[bind("list")] - list: UiList + list: UiList } +#[ui_actions] +impl TestData { + #[action] + pub fn my_action(&mut self, _event: &ActionEvent) { + println!("my action {}", self.i); + self.i += 1; + } +} fn create_window() { let testdata = TestData::default(); @@ -31,6 +39,7 @@ fn create_window() { println!("Button clicked: {}", e.data.i); e.data.i += 1; }).create(); + obj.button_builder().label("Action").action("my_action").create(); let mut model = TableModel::new(); model.add_column("Name", ColumnType::String, -1); obj.tableview_builder::().fill(true).varname("list").model(&model).getvalue(|elm, _row, _col| { diff --git a/ui-rs-derive/Cargo.toml b/ui-rs-derive/Cargo.toml index 6306e72..65ad522 100644 --- a/ui-rs-derive/Cargo.toml +++ b/ui-rs-derive/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" proc-macro = true [dependencies] -syn = "2" +syn = { version = "2", features = ["full"] } 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 index 9f427d2..51f043c 100644 --- a/ui-rs-derive/src/lib.rs +++ b/ui-rs-derive/src/lib.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Expr, ExprLit, Lit, Meta}; +use syn::{parse_macro_input, Attribute, Data, DeriveInput, Expr, ExprLit, ImplItem, ItemImpl, Lit, Meta}; #[proc_macro_derive(UiModel, attributes(bind))] pub fn derive_ui_model(input: TokenStream) -> TokenStream { @@ -66,4 +66,133 @@ pub fn derive_ui_model(input: TokenStream) -> TokenStream { //eprintln!("{}", expanded); TokenStream::from(expanded) +} + +/// Derives a no-op implementation of [`UiActions`]. +/// +/// This macro generates an empty implementation of the [`UiActions`] trait +/// for the annotated type. It is intended for use with UI models that do not +/// define any actions via [`ui_actions`], but still need to satisfy trait +/// bounds such as `T: UiModel + UiActions`. +/// +/// If you define actions using the [`ui_actions`] attribute macro, you should +/// **not** also derive `UiActions`, as both macros generate an implementation +/// of the same trait and will conflict. +/// +/// # Generated code +/// +/// This derive expands to: +/// +/// ```ignore +/// impl UiActions for YourType {} +/// ``` +/// +/// # When to use +/// +/// Use `#[derive(UiActions)]` when: +/// +/// - Your type implements [`UiModel`] +/// - You do **not** define any actions using `#[ui_actions]` +/// - You still need to satisfy a `UiActions` trait bound +/// +/// # See also +/// +/// - [`ui_actions`] — Defines UI actions for a type and generates a non-empty +/// implementation of [`UiActions`]. +#[proc_macro_derive(UiActions)] +pub fn derive_ui_actions(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + let expanded = quote! { + impl UiActions for #name { + + } + }; + + TokenStream::from(expanded) +} + +/// Generates an implementation of [`UiActions`] for an `impl` block containing +/// methods marked with the `#[action]` attribute. +/// +/// This macro scans the provided `impl` block, collects all methods annotated +/// with `#[action]`, and generates a corresponding implementation of +/// [`UiActions`] that registers these methods as UI actions in the provided +/// [`UiContext`]. +/// +/// The original `impl` block is preserved and emitted unchanged. +/// +/// # Requirements +/// +/// - Must be applied to an `impl` block +/// - Methods intended as actions must be annotated with `#[action]` +/// - The type must be compatible with [`UiActions`] +/// +/// # Example +/// +/// ``` +/// #[ui_actions] +/// impl TestData { +/// #[action] +/// pub fn my_action(&mut self, event: &ActionEvent) { +/// println!("action triggered"); +/// } +/// } +/// ``` +/// +/// # Notes +/// +/// - Only methods marked with `#[action]` are registered +/// - Methods without `#[action]` are ignored +/// - Action names are derived from method names via `stringify!` +/// +/// # See also +/// +/// - [`UiActions`] +/// - [`UiContext`] +/// - `#[action]` attribute macro +#[proc_macro_attribute] +pub fn ui_actions(_attr: TokenStream, item: TokenStream) -> TokenStream { + let impl_block = parse_macro_input!(item as ItemImpl); + let self_ty = &impl_block.self_ty; + + let mut 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()); + } + } + } + + let expanded = quote! { + #impl_block + impl UiActions for #self_ty { + fn init_actions(&mut self, ctx: &mut UiContext) { + unsafe { + #( + ctx.add_action( + stringify!(#handlers), + |target: &mut Self, event| { + target.#handlers(event); + } + ); + )* + } + } + } + }; + //eprintln!("{}", expanded); + TokenStream::from(expanded) +} + +fn has_handler_attr(attrs: &[Attribute]) -> bool { + attrs.iter().any(|attr| attr.path().is_ident("action")) +} + +#[proc_macro_attribute] +pub fn action(_attr: TokenStream, item: TokenStream) -> TokenStream { + item } \ No newline at end of file diff --git a/ui-rs/src/ui/event.rs b/ui-rs/src/ui/event.rs index bbf822c..0ad7c8f 100644 --- a/ui-rs/src/ui/event.rs +++ b/ui-rs/src/ui/event.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use std::ffi::c_void; -use crate::ui::{ffi, UiDouble, UiInteger, UiString, UiText}; +use crate::ui::{event, ffi, UiDouble, UiInteger, UiString, UiText}; use crate::ui::ffi::{UiEvent, UiRange}; pub struct Event<'a, T> { @@ -11,6 +11,12 @@ pub struct Event<'a, T> { pub set: bool } +pub struct ActionEvent<'a> { + pub event_type: EventType<'a>, + pub intval: i32, + pub set: bool +} + pub enum EventType<'a> { Null, Pointer, @@ -31,6 +37,13 @@ pub struct EventWrapper { pub callback: Box)> } +impl EventWrapper { + pub fn new(f: F) -> EventWrapper + where F: FnMut(&mut event::Event) + 'static { + EventWrapper { callback: Box::new(f) } + } +} + pub extern "C" fn event_wrapper(e: *const ffi::UiEvent, data: *mut c_void) { unsafe { let wrapper = &mut *(data as *mut EventWrapper); @@ -53,6 +66,28 @@ pub extern "C" fn event_wrapper(e: *const ffi::UiEvent, data: *mut c_void) { } } +pub struct ActionEventWrapper { + pub callback: Box, + pub target: *mut T +} + +pub extern "C" fn action_event_wrapper(e: *const ffi::UiEvent, data: *mut c_void) { + unsafe { + let wrapper = &mut *(data as *mut ActionEventWrapper); + let target = &mut *(wrapper.target as *mut T); + + let ev_int = ui_event_get_int(e); + let ev_set = ui_event_get_set(e) != 0; + + let event = ActionEvent { + event_type: EventType::Null, + intval: ev_int, + set: ev_set + }; + + (wrapper.callback)(target, &event); + } +} extern "C" { fn ui_event_get_windowdata(event: *const UiEvent) -> *const c_void; diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index f9bed16..fecf197 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -1,10 +1,11 @@ #![allow(dead_code)] use std::ffi::{c_char, c_int, c_void, CStr, CString}; -use crate::ui::{ffi, ui_object_get_context, ui_reg_destructor}; +use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ActionEventWrapper, EventWrapper}; use std::marker::PhantomData; use std::mem; +use crate::ui::ffi::UiCallback; pub struct UiContext { pub ptr: *mut ffi::UiContext @@ -41,13 +42,13 @@ impl UiContext { ptr } - pub fn attach(&mut self, doc: &UiDoc) { + pub fn attach(&mut self, doc: &UiDoc) { unsafe { ui_attach_document(self.ptr, doc.ptr); } } - pub fn detach(&mut self, doc: &UiDoc) { + pub fn detach(&mut self, doc: &UiDoc) { unsafe { ui_attach_document(self.ptr, doc.ptr); } @@ -58,6 +59,26 @@ impl UiContext { ls.init(self, None); ls } + + pub unsafe fn add_action(&mut self, name: &str, f: F) + where F: FnMut(&mut T, &event::ActionEvent) + 'static { + // if this is a document context, use the document pointer as target + // otherwise it is a UiObject context, in that case we use the window_data as target + let doc_ptr = ui_context_document(self.ptr) as *mut T; + let target_ptr = if !doc_ptr.is_null() { + doc_ptr + } else { + let obj_ptr = ui_context_obj(self.ptr); + assert!(!obj_ptr.is_null()); + let obj_wdata_ptr = ui_object_get_windowdata(obj_ptr); + assert!(!obj_wdata_ptr.is_null()); + obj_wdata_ptr as *mut T + }; + let wrapper = Box::new(ActionEventWrapper { callback: Box::new(f), target: target_ptr }); + let ptr = self.reg_box(wrapper); + let cstr = CString::new(name).unwrap(); + ui_add_action(self.ptr, cstr.as_ptr(), Some(action_event_wrapper::), ptr as *mut c_void); + } } extern "C" fn destroy_boxed(data: *mut c_void) { @@ -69,24 +90,26 @@ extern "C" fn destroy_boxed(data: *mut c_void) { } } -pub struct UiDoc { +pub struct UiDoc { pub ctx: UiContext, - ptr: *mut c_void + ptr: *mut c_void, + _marker: PhantomData } -impl Clone for UiDoc { +impl Clone for UiDoc { fn clone(&self) -> Self { unsafe { ui_document_ref(self.ptr); } - UiDoc { + UiDoc:: { ctx: self.ctx.clone(), - ptr: self.ptr + ptr: self.ptr, + _marker: PhantomData } } } -impl Drop for UiDoc { +impl Drop for UiDoc { fn drop(&mut self) { unsafe { if !self.ptr.is_null() { @@ -96,8 +119,8 @@ impl Drop for UiDoc { } } -impl UiDoc { - pub fn new(mut data: T) -> UiDoc { +impl UiDoc { + pub fn new(mut data: T) -> UiDoc { unsafe { let doc = ui_document_new(mem::size_of::<*mut T>()); let mut ctx = UiContext { ptr: ui_document_context(doc) }; @@ -105,7 +128,22 @@ impl UiDoc { let data_ptr = ctx.reg_box(Box::new(data)); // returns *mut T let doc_storage: *mut *mut T = doc.cast(); *doc_storage = data_ptr; - UiDoc { ctx: ctx, ptr: doc } + UiDoc:: { ctx: ctx, ptr: doc, _marker: PhantomData } + } + } + + pub unsafe fn get_data_ptr(&self) -> *mut T { + let ptr: *mut *mut T = self.ptr.cast(); + *ptr + } + + pub fn add_action(&mut self, name: &str, f: F) + where F: FnMut(&mut T, &event::ActionEvent) + 'static { + unsafe { + let wrapper = Box::new(ActionEventWrapper { callback: Box::new(f), target: self.get_data_ptr() }); + let ptr = self.ctx.reg_box(wrapper); + let cstr = CString::new(name).unwrap(); + ui_add_action(self.ctx.ptr, cstr.as_ptr(), Some(action_event_wrapper::), ptr as *mut c_void); } } } @@ -114,6 +152,11 @@ pub trait UiModel { fn init(&mut self, ctx: &UiContext); } +pub trait UiActions { + fn init_actions(&mut self, _ctx: &mut UiContext) {} +} + + pub struct UiObject { pub ptr: *mut ffi::UiObject, pub ctx: UiContext, @@ -409,6 +452,10 @@ extern "C" { fn ui_document_context(doc: *mut c_void) -> *mut ffi::UiContext; fn ui_attach_document(ctx: *mut ffi::UiContext, doc: *mut c_void); fn ui_detach_document(ctx: *mut ffi::UiContext, doc: *mut c_void); + fn ui_context_document(ctx: *mut ffi::UiContext) -> *mut c_void; + fn ui_context_obj(ctx: *mut ffi::UiContext) -> *mut ffi::UiObject; + + fn ui_add_action(ctx: *mut ffi::UiContext, name: *const c_char, callback: UiCallback, data: *mut c_void); fn ui_int_new(ctx: *mut ffi::UiContext, name: *const c_char) -> *mut ffi::UiInteger; fn ui_double_new(ctx: *mut ffi::UiContext, name: *const c_char) -> *mut ffi::UiDouble; diff --git a/ui-rs/src/ui/window.rs b/ui-rs/src/ui/window.rs index 3578213..d61df8a 100644 --- a/ui-rs/src/ui/window.rs +++ b/ui-rs/src/ui/window.rs @@ -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, UiModel}; +use crate::ui::{toolkit, UiActions, UiModel}; use crate::ui::ffi::{UiContext, UiDestructor, UiObject}; extern "C" { @@ -39,7 +39,7 @@ enum WindowType { Simple } -fn window_create(title: &str, kind: WindowType, mut data: T, create_ui: F) -> toolkit::UiObject +fn window_create(title: &str, kind: WindowType, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { // create the window let objptr = unsafe { @@ -63,40 +63,44 @@ where F: FnOnce(&mut toolkit::UiObject, &mut T) { _data: PhantomData }; - // init view model - data.init(&obj.ctx); - - // call ui building closure - create_ui(&mut obj, &mut data); - // store windowdata object in the UiObject let window_data = Box::new(data); let wdata_ptr = obj.ctx.reg_box(window_data); unsafe { ui_object_set_windowdata(objptr, wdata_ptr as *mut c_void); } + + let wdata = unsafe {&mut *(wdata_ptr) }; + + // init view model + wdata.init(&obj.ctx); + wdata.init_actions(&mut obj.ctx); + + // call ui building closure + create_ui(&mut obj, wdata); + obj } -pub fn window(title: &str, data: T, create_ui: F) -> toolkit::UiObject +pub fn window(title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { window_create(title, WindowType::Standard, data, create_ui) } -pub fn sidebar_window(title: &str, data: T, create_ui: F) -> toolkit::UiObject +pub fn sidebar_window(title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { window_create(title, WindowType::Sidebar, data, create_ui) } -pub fn splitview_window(title: &str, sidebar: bool, data: T, create_ui: F) -> toolkit::UiObject +pub fn splitview_window(title: &str, sidebar: bool, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { window_create(title, WindowType::SplitView(sidebar), data, create_ui) } -pub fn simple_window(title: &str, data: T, create_ui: F) -> toolkit::UiObject +pub fn simple_window(title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { window_create(title, WindowType::Simple, data, create_ui) diff --git a/ui/common/context.c b/ui/common/context.c index f729978..581469e 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -133,6 +133,7 @@ void uic_context_attach_document(UiContext *ctx, void *document) { UiContext *doc_ctx = ui_document_context(document); doc_ctx->parent = ctx; + doc_ctx->ref++; // if a document variable has the same name as a parent variable, // move the bindings to the document @@ -152,7 +153,7 @@ void uic_context_attach_document(UiContext *ctx, void *document) { var_ctx = var_ctx->parent; } - + ui_update_action_bindings(ctx); } @@ -196,6 +197,7 @@ void uic_context_detach_document(UiContext *ctx, void *document) { UiContext *docctx = ui_document_context(document); uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent docctx->parent = NULL; + ui_document_unref(document); ui_update_action_bindings(ctx); } diff --git a/ui/common/document.c b/ui/common/document.c index b05d484..b4c9402 100644 --- a/ui/common/document.c +++ b/ui/common/document.c @@ -78,3 +78,11 @@ UiContext* ui_document_context(void *doc) { return NULL; } } + +void* ui_context_document(UiContext *ctx) { + return ctx->self_doc; +} + +UiObject* ui_context_obj(UiContext *ctx) { + return ctx->obj; +} diff --git a/ui/common/toolbar.c b/ui/common/toolbar.c index f87e02a..9a389d0 100644 --- a/ui/common/toolbar.c +++ b/ui/common/toolbar.c @@ -57,6 +57,7 @@ static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups, newargs.tooltip = nl_strdup(args->tooltip); newargs.onclick = args->onclick; newargs.onclickdata = args->onclickdata; + newargs.action = nl_strdup(args->action); newargs.states = uic_copy_states(args->states, ngroups); newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates); return newargs; @@ -78,6 +79,7 @@ static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args newargs.varname = nl_strdup(args->varname); newargs.onchange = args->onchange; newargs.onchangedata = args->onchangedata; + newargs.action = nl_strdup(args->action); newargs.states = uic_copy_states(args->states, ngroups); newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates); return newargs; diff --git a/ui/gtk/button.c b/ui/gtk/button.c index 9ce23bf..00ad370 100644 --- a/ui/gtk/button.c +++ b/ui/gtk/button.c @@ -31,11 +31,13 @@ #include "button.h" #include "container.h" +#include "widget.h" #include #include #include #include "../common/context.h" #include "../common/object.h" +#include "../common/action.h" void ui_button_set_icon_name(GtkWidget *button, const char *icon) { if(!icon) { @@ -63,6 +65,7 @@ GtkWidget* ui_create_button( const char *tooltip, ui_callback onclick, void *userdata, + const char *action, int event_value, bool activate_event) { @@ -72,12 +75,13 @@ GtkWidget* ui_create_button( gtk_widget_set_tooltip_text(button, tooltip); } - if(onclick) { + if(onclick || action) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; event->userdata = userdata; event->callback = onclick; event->value = event_value; + event->action = action ? strdup(action) : NULL; event->customdata = NULL; event->customint = 0; @@ -89,7 +93,7 @@ GtkWidget* ui_create_button( g_signal_connect( button, "destroy", - G_CALLBACK(ui_destroy_userdata), + G_CALLBACK(ui_destroy_eventdata), event); if(activate_event) { g_signal_connect( @@ -98,13 +102,21 @@ GtkWidget* ui_create_button( G_CALLBACK(ui_button_clicked), event); } + + if(action) { + uic_bind_action(obj->ctx, action, button, (ui_enablefunc)ui_set_enabled); + UiAction *ui_action = uic_resolve_action(obj->ctx, action); + if(!ui_action) { + ui_set_enabled(button, FALSE); + } + } } return button; } UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) { - GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, 0, FALSE); + GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, args->action, 0, FALSE); ui_set_name_and_style(button, args->name, args->style_class); ui_set_widget_states(obj->ctx, button, args->states); UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; @@ -124,7 +136,13 @@ void ui_button_clicked(GtkWidget *widget, UiEventData *event) { e.eventdatatype = 0; e.intval = event->value; e.set = ui_get_setop(); - event->callback(&e, event->userdata); + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(event->action) { + uic_action_callback(&e, event->action); + } } void ui_button_set_label(UIWIDGET button, const char *label) { diff --git a/ui/gtk/button.h b/ui/gtk/button.h index ce94b90..9197b8f 100644 --- a/ui/gtk/button.h +++ b/ui/gtk/button.h @@ -58,6 +58,7 @@ GtkWidget* ui_create_button( const char *tooltip, ui_callback onclick, void *userdata, + const char *action, int event_value, bool activate_event); diff --git a/ui/gtk/headerbar.c b/ui/gtk/headerbar.c index ef1d9c7..97e57e6 100644 --- a/ui/gtk/headerbar.c +++ b/ui/gtk/headerbar.c @@ -163,7 +163,7 @@ void ui_add_headerbar_item( UiObject *obj, enum UiToolbarPos pos) { - GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, 0, FALSE); + GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, item->args.action, 0, FALSE); ui_set_widget_states(obj->ctx, button, item->args.states); ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states); WIDGET_ADD_CSS_CLASS(button, "flat"); diff --git a/ui/gtk/window.c b/ui/gtk/window.c index 58af741..0ef8093 100644 --- a/ui/gtk/window.c +++ b/ui/gtk/window.c @@ -987,7 +987,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } if(args->lbutton1) { - GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1); + GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 1, args->default_button == 1); gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button); if(args->default_button == 1) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -995,7 +995,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } } if(args->lbutton2) { - GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2); + GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 2, args->default_button == 2); gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button); if(args->default_button == 2) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1004,7 +1004,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } if(args->rbutton4) { - GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4); + GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 4, args->default_button == 4); gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button); if(args->default_button == 4) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1012,7 +1012,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } } if(args->rbutton3) { - GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3); + GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 3, args->default_button == 3); gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button); if(args->default_button == 3) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1033,7 +1033,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); if(args->lbutton1) { - GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1); + GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 1, args->default_button == 1); gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1); if(args->default_button == 1) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1041,7 +1041,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } } if(args->lbutton2) { - GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2); + GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 2, args->default_button == 2); gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1); if(args->default_button == 2) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1052,7 +1052,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { gtk_widget_set_hexpand(space, TRUE); gtk_grid_attach(GTK_GRID(grid), space, 2, 0, 1, 1); if(args->rbutton3) { - GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3); + GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 3, args->default_button == 3); gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1); if(args->default_button == 3) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); @@ -1060,7 +1060,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { } } if(args->rbutton4) { - GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4); + GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, NULL, 4, args->default_button == 4); gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1); if(args->default_button == 4) { WIDGET_ADD_CSS_CLASS(button, "suggested-action"); diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index cdb75b7..af1036e 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -579,6 +579,8 @@ UIEXPORT void ui_document_destroy(void *doc); UIEXPORT void* ui_get_subdocument(void *document); // deprecated UIEXPORT UiContext* ui_document_context(void *doc); +UIEXPORT void* ui_context_document(UiContext *ctx); +UIEXPORT UiObject* ui_context_obj(UiContext *ctx); UIEXPORT void* ui_context_get_document(UiContext *ctx); UIEXPORT void ui_context_single_attachment_mode(UiContext *ctx, UiBool enable);