From 7b90714b86ab60bed5453f86f7dae91bcbba0c47 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Tue, 21 Apr 2026 21:18:24 +0200 Subject: [PATCH] add sublist implementation --- ui-rs/src/ui/list.rs | 34 ++++++++++++++++++++++++++++++++++ ui-rs/src/ui/toolkit.rs | 9 +++++++++ ui/cocoa/EventData.h | 3 ++- ui/cocoa/EventData.m | 27 ++++++++++++++++++--------- ui/cocoa/Toolbar.m | 2 +- ui/cocoa/action.h | 4 ++++ ui/cocoa/action.m | 12 ++++++++++++ ui/cocoa/button.m | 21 +++++++++++++-------- ui/cocoa/menu.m | 2 +- ui/cocoa/window.m | 8 ++++---- ui/common/types.c | 7 +++---- 11 files changed, 101 insertions(+), 28 deletions(-) diff --git a/ui-rs/src/ui/list.rs b/ui-rs/src/ui/list.rs index eee2c4c..a667220 100644 --- a/ui-rs/src/ui/list.rs +++ b/ui-rs/src/ui/list.rs @@ -680,6 +680,35 @@ impl Drop for TableModel { } +// SubList implementation + +impl SubList { + pub fn new() -> Self { + unsafe { + SubList { + handle: ui_sublist_new(), + list: toolkit::UiList::new() + } + } + } + + pub fn set_header(&mut self, title: &str) { + let cstr = CString::new(title).unwrap(); + unsafe { + ui_sublist_set_header(self.handle, cstr.as_ptr()); + } + } +} + +impl Drop for SubList { + fn drop(&mut self) { + unsafe { + ui_sublist_free(self.handle); + } + } +} + + /* ------------------------------- getvalue func wrapper -------------------------------- */ type GetValueFunc = extern "C" fn(list: *const ffi::UiList, elm_ptr: *const c_void, row: i32, col: i32, wrapper: *const c_void, free: *mut bool) -> *mut c_void; @@ -822,4 +851,9 @@ extern "C" { fn ui_sourcelist_args_set_states(args: *mut UiSourceListArgs, states: *const c_int, numstates: c_int); fn ui_sourcelist_args_set_visibility_states(args: *mut UiSourceListArgs, states: *const c_int, numstates: c_int); fn ui_sourcelist_args_free(args: *mut UiSourceListArgs); + + fn ui_sublist_new() -> *mut ffi::UiSubList; + fn ui_sublist_set_value(list: *mut ffi::UiSubList, value: *mut ffi::UiList); + fn ui_sublist_set_header(list: *mut ffi::UiSubList, header: *const c_char); + fn ui_sublist_free(list: *mut ffi::UiSubList); } \ No newline at end of file diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index 982a351..4a5b8e8 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -302,6 +302,15 @@ impl UiInteger { impl UiList { + pub fn new() -> UiList { + let mut list: UiList = Self::default(); + let ctx = UiContext { + ptr: std::ptr::null_mut(), + }; + list.init(&ctx, None); + list + } + pub fn data(&mut self) -> &mut Vec { self.data.as_mut() } diff --git a/ui/cocoa/EventData.h b/ui/cocoa/EventData.h index 4ee89f3..603b87c 100644 --- a/ui/cocoa/EventData.h +++ b/ui/cocoa/EventData.h @@ -37,11 +37,12 @@ typedef void(*get_eventdata_func)(id sender, UiVar *var, void **eventdata, int * @property int vartype; @property ui_callback callback; @property void *userdata; +@property NSString *action; @property void *data; @property int value; @property get_eventdata_func get_eventdata; -- (EventData*)init:(ui_callback)cb userdata:(void*)userdata; +- (EventData*)init:(ui_callback)cb userdata:(void*)userdata action:(const char*)action; - (void)handleEvent:(id)sender; diff --git a/ui/cocoa/EventData.m b/ui/cocoa/EventData.m index 1df6d9b..c7e95ec 100644 --- a/ui/cocoa/EventData.m +++ b/ui/cocoa/EventData.m @@ -27,29 +27,38 @@ */ #import "EventData.h" +#import "action.h" #import @implementation EventData -- (EventData*)init:(ui_callback)cb userdata:(void*)userdata { +- (EventData*)init:(ui_callback)cb userdata:(void*)userdata action:(const char*)action { _callback = cb; _userdata = userdata; + if(action != nil) { + _action = [[NSString alloc]initWithUTF8String:action]; + } return self; } - (void)handleEvent:(id)sender { - if(_callback) { - UiEvent event; - event.obj = self.obj; - event.window = event.obj->window; - event.document = event.obj->ctx->document; - event.eventdata = self.data; - event.intval = self.value; - event.set = ui_get_setop(); + UiEvent event; + event.obj = self.obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.eventdata = self.data; + event.intval = self.value; + event.set = ui_get_setop(); + + if(_callback != nil) { self.callback(&event, self.userdata); } + + if(_action != nil) { + uic_action_callback(&event, self.action.UTF8String); + } } - (void)handleEventWithEventData:(id)sender { diff --git a/ui/cocoa/Toolbar.m b/ui/cocoa/Toolbar.m index 8ab2ad8..cf03ced 100644 --- a/ui/cocoa/Toolbar.m +++ b/ui/cocoa/Toolbar.m @@ -220,7 +220,7 @@ NSToolbarItem* ui_nstoolbaritem_create_item(UiObject *obj, UiToolbarItem *item, } if(item->args.onclick) { - EventData *event = [[EventData alloc] init:item->args.onclick userdata:item->args.onclickdata]; + EventData *event = [[EventData alloc] init:item->args.onclick userdata:item->args.onclickdata action:item->args.action]; event.obj = obj; button.target = event; button.action = @selector(handleEvent:); diff --git a/ui/cocoa/action.h b/ui/cocoa/action.h index e0398a0..4d9d19f 100644 --- a/ui/cocoa/action.h +++ b/ui/cocoa/action.h @@ -28,3 +28,7 @@ #include "../ui/toolkit.h" #include "../common/action.h" + +#import "widget.h" + +void ui_cocoa_view_bind_action(UiContext *ctx, NSView *view, const char *action); diff --git a/ui/cocoa/action.m b/ui/cocoa/action.m index 80f0a42..943341a 100644 --- a/ui/cocoa/action.m +++ b/ui/cocoa/action.m @@ -51,3 +51,15 @@ void ui_add_action_with_accelerator( // TODO: accelerator } + + +void ui_cocoa_view_bind_action(UiContext *ctx, NSView *view, const char *action) { + if(action) { + void *widget = (__bridge void*)view; + uic_bind_action(ctx, action, widget, (ui_enablefunc)ui_set_enabled); + UiAction *ui_action = uic_resolve_action(ctx, action); + if(!ui_action) { + ui_set_enabled(widget, FALSE); + } + } +} diff --git a/ui/cocoa/button.m b/ui/cocoa/button.m index 03c6367..70ee28c 100644 --- a/ui/cocoa/button.m +++ b/ui/cocoa/button.m @@ -30,6 +30,7 @@ #import "EventData.h" #import "container.h" #import "image.h" +#import "action.h" #import #import @@ -47,7 +48,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { } if(args->onclick) { - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:args->action]; event.obj = obj; button.target = event; button.action = @selector(handleEvent:); @@ -88,8 +89,8 @@ UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs *args, enum NSButtonTyp i->set = ui_togglebutton_set; } - if(args->onchange) { - EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata]; + if(args->onchange || args->action) { + EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata action:args->action]; event.get_eventdata = togglebutton_eventdata; event.obj = obj; event.var = var; @@ -97,6 +98,8 @@ UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs *args, enum NSButtonTyp button.target = event; button.action = @selector(handleEventWithEventData:); objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + + ui_cocoa_view_bind_action(obj->ctx, button, args->action); } UiLayout layout = UI_INIT_LAYOUT(args); @@ -149,8 +152,8 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) { i->set = ui_switch_set; } - if(args->onchange) { - EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata]; + if(args->onchange || args->action) { + EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata action:args->action]; event.get_eventdata = switch_eventdata; event.obj = obj; event.var = var; @@ -158,6 +161,7 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) { button.target = event; button.action = @selector(handleEventWithEventData:); objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + ui_cocoa_view_bind_action(obj->ctx, button, args->action); } UiLayout layout = UI_INIT_LAYOUT(args); @@ -238,18 +242,19 @@ UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) { objc_setAssociatedObject(button, "radiogroup", buttons, OBJC_ASSOCIATION_RETAIN); } - if(args->onchange || var) { - EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata]; + if(args->onchange || args->action || var) { + EventData *event = [[EventData alloc] init:args->onchange userdata:args->onchangedata action:args->action]; event.get_eventdata = radiobutton_eventdata; event.obj = obj; event.var = var; event.vartype = UI_VAR_INTEGER; button.target = event; - button.action = @selector(handleEventWithEventData:); objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + + ui_cocoa_view_bind_action(obj->ctx, button, args->action); } UiLayout layout = UI_INIT_LAYOUT(args); diff --git a/ui/cocoa/menu.m b/ui/cocoa/menu.m index eae8a50..100fb56 100644 --- a/ui/cocoa/menu.m +++ b/ui/cocoa/menu.m @@ -112,7 +112,7 @@ void add_menuitem_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuItemAction) keyEquivalent:@""]; if(it->callback) { - EventData *event = [[EventData alloc] init:it->callback userdata:it->userdata]; + EventData *event = [[EventData alloc] init:it->callback userdata:it->userdata action:it->action]; if(obj) { event.obj = obj; menuItem.target = event; diff --git a/ui/cocoa/window.m b/ui/cocoa/window.m index 7d89edd..0946387 100644 --- a/ui/cocoa/window.m +++ b/ui/cocoa/window.m @@ -343,7 +343,7 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { [lbutton1.leadingAnchor constraintEqualToAnchor:buttonArea.leadingAnchor constant:0] ]]; - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:nil]; event.obj = obj; event.value = 1; lbutton1.target = event; @@ -363,7 +363,7 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { [lbutton2.leadingAnchor constraintEqualToAnchor:anchor constant:off] ]]; - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:nil]; event.obj = obj; event.value = 2; lbutton2.target = event; @@ -382,7 +382,7 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { [rbutton4.trailingAnchor constraintEqualToAnchor:buttonArea.trailingAnchor constant:0] ]]; - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:nil]; event.obj = obj; event.value = 2; rbutton4.target = event; @@ -402,7 +402,7 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { [rbutton3.trailingAnchor constraintEqualToAnchor:anchor constant:off] ]]; - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:nil]; event.obj = obj; event.value = 2; rbutton3.target = event; diff --git a/ui/common/types.c b/ui/common/types.c index ea6a378..c4b51ce 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -110,7 +110,6 @@ void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) { void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused) { cxListFree(list->data); - ui_free(ctx, list); } UiList* ui_list_new(UiContext *ctx, const char *name) { @@ -118,11 +117,11 @@ UiList* ui_list_new(UiContext *ctx, const char *name) { } UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listinit, void *userdata) { - UiList *list = cxMalloc(ctx->mp->allocator, sizeof(UiList)); + UiList *list = ui_malloc(ctx, sizeof(UiList)); memset(list, 0, sizeof(UiList)); listinit(ctx, list, userdata); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_LIST, list); } @@ -137,7 +136,7 @@ void ui_list_free(UiContext *ctx, UiList *list) { } else { default_list_destroy(ctx, list, default_list_destroy_userdata); } - + ui_free(ctx, list); } void* ui_list_first(UiList *list) { -- 2.47.3