From: Olaf Wintermann Date: Sat, 11 Jul 2026 18:17:58 +0000 (+0200) Subject: update toolkit X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;p=uwplayer.git update toolkit --- diff --git a/ui/Makefile b/ui/Makefile index ad5aad0..b03b6d3 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -41,8 +41,5 @@ OBJ = $(TOOLKITOBJS) $(COMMONOBJS) all: $(UI_LIB) $(UI_SHLIB) +include common/Makefile include $(TOOLKIT)/Makefile - -$(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c - $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $< - diff --git a/ui/cocoa/AppDelegate.h b/ui/cocoa/AppDelegate.h new file mode 100644 index 0000000..7c2ce1e --- /dev/null +++ b/ui/cocoa/AppDelegate.h @@ -0,0 +1,37 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "../ui/toolkit.h" +#include "../common/context.h" +#include "../common/object.h" + +@interface AppDelegate : NSObject + + +@end diff --git a/ui/cocoa/AppDelegate.m b/ui/cocoa/AppDelegate.m new file mode 100644 index 0000000..b28df42 --- /dev/null +++ b/ui/cocoa/AppDelegate.m @@ -0,0 +1,62 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "AppDelegate.h" +#import "WindowManager.h" + +#import "toolkit.h" +#import "menu.h" + +#import "../common/app.h" + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + NSLog(@"toolkit applicationDidFinishLaunching"); + uic_application_startup(NULL); + // The menu init func can be called multiple times and is also called + // when a new window is created + // The only usecase for calling init here is, that an application might not + // open a window on startup, but wants a working menubar + ui_menu_init(); +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + NSLog(@"toolkit applicationWillTerminate"); + uic_application_exit(NULL); + [[WindowManager sharedWindowManager] shutdown]; + ui_app_save_settings(); +} + + +- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app { + return YES; +} + + +@end diff --git a/ui/cocoa/BoxContainer.h b/ui/cocoa/BoxContainer.h index a80ae7d..065c78f 100644 --- a/ui/cocoa/BoxContainer.h +++ b/ui/cocoa/BoxContainer.h @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import "Container.h" +#import "container.h" #import "GridLayout.h" @interface BoxContainer : GridLayout diff --git a/ui/cocoa/EventData.h b/ui/cocoa/EventData.h index 4ee89f3..f0c8eac 100644 --- a/ui/cocoa/EventData.h +++ b/ui/cocoa/EventData.h @@ -29,7 +29,7 @@ #import "../ui/toolkit.h" #import "../common/context.h" -typedef void(*get_eventdata_func)(id sender, UiVar *var, void **eventdata, int *value); +typedef void(*get_eventdata_func)(id sender, UiVar *var, void **eventdata, UiEventType *eventdatatype, int *value); @interface EventData : NSObject @property UiObject *obj; @@ -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..aa8c74b 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 { @@ -61,7 +70,7 @@ event.intval = 0; event.set = ui_get_setop(); if(_get_eventdata) { - _get_eventdata(sender, _var, &event.eventdata, &event.intval); + _get_eventdata(sender, _var, &event.eventdata, &event.eventdatatype, &event.intval); } if(self.callback) { self.callback(&event, self.userdata); diff --git a/ui/cocoa/GridLayout.h b/ui/cocoa/GridLayout.h index 362c9b2..ccb6528 100644 --- a/ui/cocoa/GridLayout.h +++ b/ui/cocoa/GridLayout.h @@ -28,7 +28,7 @@ #import "toolkit.h" -#import "Container.h" +#import "container.h" #import @@ -56,7 +56,7 @@ typedef struct GridDef { @interface GridLayout : NSView -@property UiContainerX *container; +@property UiContainer *container; @property int columnspacing; @property int rowspacing; diff --git a/ui/cocoa/ListDelegate.h b/ui/cocoa/ListDelegate.h index 27762f7..6603b82 100644 --- a/ui/cocoa/ListDelegate.h +++ b/ui/cocoa/ListDelegate.h @@ -34,8 +34,10 @@ @property UiObject *obj; @property ui_callback onselection; @property void *onselectiondata; +@property NSString *onselection_action; @property ui_callback onactivate; @property void *onactivatedata; +@property NSString *onactivate_action; - (id)init:(NSTableView*) tableview obj:(UiObject*)obj; diff --git a/ui/cocoa/ListDelegate.m b/ui/cocoa/ListDelegate.m index 7e15f3d..d464231 100644 --- a/ui/cocoa/ListDelegate.m +++ b/ui/cocoa/ListDelegate.m @@ -38,31 +38,36 @@ - (void)activateEvent:(id)sender { NSTableView *table = sender; + + int row = (int)table.clickedRow; + + UiListSelection sel; + sel.count = 1; + sel.rows = &row; + + UiEvent event; + event.obj = _obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.eventdata = &sel; + event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION; + event.intval = row; + event.set = ui_get_setop(); + if(_onactivate) { - int row = (int)table.clickedRow; - - UiListSelection sel; - sel.count = 1; - sel.rows = &row; - - UiEvent event; - event.obj = _obj; - event.window = event.obj->window; - event.document = event.obj->ctx->document; - event.eventdata = &sel; - event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION; - event.intval = row; - event.set = ui_get_setop(); - _onactivate(&event, _onactivatedata); } + + if(_onselection_action) { + uic_action_callback(&event, _onselection_action.UTF8String); + } } - (void) tableViewSelectionDidChange:(NSNotification *) notification { - if(_onselection) { + if(ui_selection_events_is_enabled()) { UiListSelection sel = ui_tableview_selection(_tableview); - UiEvent event; + UiEvent event; event.obj = _obj; event.window = event.obj->window; event.document = event.obj->ctx->document; @@ -71,7 +76,13 @@ event.intval = 0; event.set = ui_get_setop(); - _onselection(&event, _onselectiondata); + if(_onselection) { + _onselection(&event, _onselectiondata); + } + + if(_onselection_action) { + uic_action_callback(&event, _onselection_action.UTF8String); + } } } diff --git a/ui/cocoa/MainWindow.h b/ui/cocoa/MainWindow.h index 7c8cbf6..52ad47f 100644 --- a/ui/cocoa/MainWindow.h +++ b/ui/cocoa/MainWindow.h @@ -29,7 +29,7 @@ #import "toolkit.h" #import "../ui/window.h" -@interface MainWindow : NSWindow +@interface MainWindow : NSWindow @property UiObject *obj; @property (strong) NSSplitView *splitview; @@ -38,7 +38,8 @@ @property (strong) NSView *rightPanel; @property int topOffset; -- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview; +- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview width:(int)width height:(int)height; +- (void) saveWindowSize; @end diff --git a/ui/cocoa/MainWindow.m b/ui/cocoa/MainWindow.m index c62079f..944c9aa 100644 --- a/ui/cocoa/MainWindow.m +++ b/ui/cocoa/MainWindow.m @@ -27,7 +27,8 @@ */ #import "MainWindow.h" -#import "Container.h" +#import "WindowManager.h" +#import "container.h" #import "GridLayout.h" #import "BoxContainer.h" #import "../common/object.h" @@ -38,10 +39,12 @@ #import "menu.h" #import "Toolbar.h" + + @implementation MainWindow -- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview{ - NSRect frame = NSMakeRect(300, 200, 600, 500); +- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview width:(int)width height:(int)height { + NSRect frame = NSMakeRect(300, 200, width, height); self = [self initWithContentRect:frame styleMask:NSWindowStyleMaskTitled | @@ -51,7 +54,7 @@ backing:NSBackingStoreBuffered defer:false]; _obj = obj; - + self.delegate = self; int top = 4; NSView *content = self.contentView; @@ -126,7 +129,7 @@ [vbox.trailingAnchor constraintEqualToAnchor:content.trailingAnchor], [vbox.bottomAnchor constraintEqualToAnchor:content.bottomAnchor], ]]; - UiContainerX *container = ui_create_container(obj, vbox); + UiContainer *container = ui_create_container(obj, vbox); vbox.container = container; uic_object_push_container(obj, container); } @@ -137,10 +140,21 @@ [self setToolbar:toolbar]; } - return self; } +- (void) saveWindowSize { + CGSize size = self.frame.size; + if(size.width > 0 && size.height > 0) { + char width_str[32]; + char height_str[32]; + snprintf(width_str, 32, "%d", (int)size.width); + snprintf(height_str, 32, "%d", (int)size.height); + ui_set_property("ui.window.width", width_str); + ui_set_property("ui.window.height", height_str); + } +} + - (BOOL) getIsVisible { return [self isVisible]; } @@ -153,7 +167,37 @@ } } +- (void) windowWillClose:(NSNotification *) notification { + UiObject *obj = _obj; + + if(obj->onclose) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.obj = obj; + event.window = obj->window; + event.document = obj->ctx->document; + obj->onclose(&event, obj->onclosedata); + } + + if(obj->ref > 0) { + obj->ref--; + } else { + // warn about invalid reference counting + NSLog(@"Error: UiObject %p ref == 0\n", obj); + } + + if(obj->ref == 0) { + [self saveWindowSize]; + // this cleans up any widget references from the context + uic_context_prepare_close(obj->ctx); + [[WindowManager sharedWindowManager] closeWindow:self]; + } +} +- (void) dealloc { + uic_object_destroy(_obj); + NSLog(@"MainWindow dealloc"); +} @end diff --git a/ui/cocoa/TabView.h b/ui/cocoa/TabView.h index d6e4b0d..506c1e6 100644 --- a/ui/cocoa/TabView.h +++ b/ui/cocoa/TabView.h @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import "Container.h" +#import "container.h" @protocol TabView diff --git a/ui/cocoa/TabView.m b/ui/cocoa/TabView.m index 5b50048..5cfc1bf 100644 --- a/ui/cocoa/TabView.m +++ b/ui/cocoa/TabView.m @@ -113,7 +113,7 @@ UiObject *newobj = uic_object_new_toplevel(); newobj->widget = (__bridge void*)sub; - UiContainerX *container = ui_create_container(newobj, sub); + UiContainer *container = ui_create_container(newobj, sub); uic_object_push_container(newobj, container); return newobj; diff --git a/ui/cocoa/Toolbar.h b/ui/cocoa/Toolbar.h index 7ec7bbd..042fa24 100644 --- a/ui/cocoa/Toolbar.h +++ b/ui/cocoa/Toolbar.h @@ -50,7 +50,7 @@ NSMutableArray *defaultItems; } -@property MainWindow *window; +@property (weak) MainWindow *window; @property UiObject *obj; - (UiToolbar*) initWithWindow:(MainWindow*)window; diff --git a/ui/cocoa/Toolbar.m b/ui/cocoa/Toolbar.m index 8ab2ad8..e9a0967 100644 --- a/ui/cocoa/Toolbar.m +++ b/ui/cocoa/Toolbar.m @@ -39,7 +39,21 @@ void ui_toolbar_init(void) { } +static void toolitem_set_enabled(void *item, int enabled) { + NSToolbarItem *i = (__bridge NSToolbarItem*)item; + i.enabled = enabled; +} +static void toolitem_bind_action(UiContext *ctx, NSToolbarItem *item, const char *action) { + if(action) { + void *widget = (__bridge void*)item; + uic_bind_action(ctx, action, widget, (ui_enablefunc)toolitem_set_enabled); + UiAction *ui_action = uic_resolve_action(ctx, action); + if(!ui_action) { + toolitem_set_enabled(widget, FALSE); + } + } +} /* --------------------- UiToolbar --------------------- */ @@ -219,12 +233,14 @@ NSToolbarItem* ui_nstoolbaritem_create_item(UiObject *obj, UiToolbarItem *item, button.image = ui_cocoa_named_icon(item->args.icon); } - if(item->args.onclick) { - EventData *event = [[EventData alloc] init:item->args.onclick userdata:item->args.onclickdata]; + if(item->args.onclick || item->args.action) { + 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:); objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + + toolitem_bind_action(obj->ctx, button, item->args.action); } return button; } @@ -243,14 +259,23 @@ NSToolbarItem* ui_nstoolbaritem_create_toggle(UiObject *obj, UiToolbarToggleItem } objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); - NSSegmentedControl *seg; + NSSegmentedControl *seg = nil; if(!item->args.icon) { - NSArray *labels = @[[[NSString alloc] initWithUTF8String:item->args.label]]; - seg = [NSSegmentedControl segmentedControlWithLabels:labels trackingMode:NSSegmentSwitchTrackingSelectAny target:event action:@selector(handleEvent:)]; - button.view = seg; + if(item->args.label) { + NSArray *labels = @[[[NSString alloc] initWithUTF8String:item->args.label]]; + seg = [NSSegmentedControl segmentedControlWithLabels:labels trackingMode:NSSegmentSwitchTrackingSelectAny target:event action:@selector(handleEvent:)]; + button.view = seg; + } else { + NSLog(@"UI Error: toggle button has no icon or label"); + } } else { - NSArray *images = @[ui_cocoa_named_icon(item->args.icon)]; - seg = [NSSegmentedControl segmentedControlWithImages:images trackingMode:NSSegmentSwitchTrackingSelectAny target:event action:@selector(handleEvent:)]; + NSImage *image = ui_cocoa_named_icon(item->args.icon); + if(image != nil) { + NSArray *images = @[image]; + seg = [NSSegmentedControl segmentedControlWithImages:images trackingMode:NSSegmentSwitchTrackingSelectAny target:event action:@selector(handleEvent:)]; + } else { + NSLog(@"UI Error: icon %s not found", item->args.icon); + } } button.view = seg; @@ -265,7 +290,6 @@ NSToolbarItem* ui_nstoolbaritem_create_toggle(UiObject *obj, UiToolbarToggleItem } i->obj = (__bridge void*)seg; - printf("seg: %p\n", seg); i->get = ui_toolbar_seg_toggleitem_get; i->set = ui_toolbar_seg_toggleitem_set; } diff --git a/ui/cocoa/WindowManager.h b/ui/cocoa/WindowManager.h index 7f1b225..76e3c65 100644 --- a/ui/cocoa/WindowManager.h +++ b/ui/cocoa/WindowManager.h @@ -28,14 +28,18 @@ #import "toolkit.h" -@interface WindowManager : NSObject +@interface WindowManager : NSObject -@property NSMutableArray *windows; +@property NSMutableArray *windows; + (WindowManager*) sharedWindowManager; - (WindowManager*)init; -- (void)addWindow:(NSWindow*)win; +- (void)addWindow:(NSWindowController*)win; + +- (void)closeWindow:(NSWindow*)win; + +- (void)shutdown; @end diff --git a/ui/cocoa/WindowManager.m b/ui/cocoa/WindowManager.m index ca03182..9b5d04a 100644 --- a/ui/cocoa/WindowManager.m +++ b/ui/cocoa/WindowManager.m @@ -27,6 +27,7 @@ */ #import "WindowManager.h" +#import "MainWindow.h" @implementation WindowManager @@ -44,14 +45,21 @@ static WindowManager *instance = nil; return self; } -- (void)addWindow:(NSWindow*)win { +- (void)addWindow:(NSWindowController*)win { [_windows addObject:win]; - [win setDelegate:self]; } -- (void) windowWillClose:(NSNotification *) notification { - NSWindow *window = notification.object; - [_windows removeObject:window]; +- (void)closeWindow:(NSWindow*)win { + [_windows removeObject:win.windowController]; +} + +- (void)shutdown { + if(_windows.count > 0) { + NSWindowController *controller = _windows.firstObject; + MainWindow *win = (MainWindow*)controller.window; + [win saveWindowSize]; + } + [_windows removeAllObjects]; } @end diff --git a/ui/cocoa/action.h b/ui/cocoa/action.h new file mode 100644 index 0000000..4d9d19f --- /dev/null +++ b/ui/cocoa/action.h @@ -0,0 +1,34 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#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 new file mode 100644 index 0000000..943341a --- /dev/null +++ b/ui/cocoa/action.m @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "action.h" + +#include +#include + + + +/* ------------------------------ public API ------------------------------ */ + +void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata) { + uic_add_action(ctx, name, callback, userdata, NULL, NULL); +} + +void ui_add_action_with_accelerator( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text) +{ + uic_add_action(ctx, name, callback, userdata, accelerator, accelerator_text); + + // 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 54295da..dd1c559 100644 --- a/ui/cocoa/button.m +++ b/ui/cocoa/button.m @@ -28,8 +28,9 @@ #import "button.h" #import "EventData.h" -#import "Container.h" +#import "container.h" #import "image.h" +#import "action.h" #import #import @@ -46,12 +47,14 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { button.image = ui_cocoa_named_icon(args->icon);; } - if(args->onclick) { - EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata]; + if(args->onclick || args->action) { + EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:args->action]; event.obj = obj; button.target = event; button.action = @selector(handleEvent:); objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + + ui_cocoa_view_bind_action(obj->ctx, button, args->action); } UiLayout layout = UI_INIT_LAYOUT(args); @@ -61,7 +64,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { } -static void togglebutton_eventdata(id button, UiVar *var, void **eventdata, int *value) { +static void togglebutton_eventdata(id button, UiVar *var, void **eventdata, UiEventType *eventdatatype, int *value) { NSButton *btn = (NSButton*)button; NSControlStateValue state = btn.state; *value = (int)state; @@ -88,8 +91,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 +100,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); @@ -132,7 +137,7 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) { return togglebutton_create(obj, args, NSButtonTypeSwitch); } -static void switch_eventdata(id button, UiVar *var, void **eventdata, int *value) { +static void switch_eventdata(id button, UiVar *var, void **eventdata, UiEventType *eventdatatype, int *value) { NSSwitch *btn = (NSSwitch*)button; NSControlStateValue state = btn.state; *value = (int)state; @@ -149,8 +154,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 +163,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); @@ -201,10 +207,10 @@ void ui_switch_set(UiInteger *i, int64_t value) { @end -static void radiobutton_eventdata(id button, UiVar *var, void **eventdata, int *value) { +static void radiobutton_eventdata(id button, UiVar *var, void **eventdata, UiEventType *eventdatatype, int *value) { if(var) { - UiInteger *value = var->value; - NSMutableArray *buttons = (__bridge NSMutableArray*)value->obj; + UiInteger *i = var->value; + NSMutableArray *buttons = (__bridge NSMutableArray*)i->obj; for(UiRadioButton *b in buttons) { if(b != button) { b.direct_state = YES; @@ -238,18 +244,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); @@ -370,7 +377,7 @@ static char* create_linkbutton_jsonvalue(const char *label, const char *uri, UiB CxJsonWriter writer = cxJsonWriterCompact(); CxBuffer buf; - cxBufferInit(&buf, NULL, 128, NULL, CX_BUFFER_AUTO_EXTEND); + cxBufferInit(&buf, NULL, NULL, 128, CX_BUFFER_AUTO_EXTEND); cxJsonWrite(&buf, obj, (cx_write_func)cxBufferWrite, &writer); cxJsonValueFree(obj); cxBufferTerminate(&buf); diff --git a/ui/cocoa/container.h b/ui/cocoa/container.h index ed2dc67..89512ac 100644 --- a/ui/cocoa/container.h +++ b/ui/cocoa/container.h @@ -51,7 +51,7 @@ typedef struct UiLayout UiLayout; @protocol Container -@property UiContainerX *container; +@property UiContainer *container; - (void) addView:(NSView*)view layout:(UiLayout*)layout; @@ -73,6 +73,6 @@ typedef struct UiLayout UiLayout; @end -UiContainerX* ui_create_container(UiObject *obj, id container); +UiContainer* ui_create_container(UiObject *obj, id container); void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout); diff --git a/ui/cocoa/container.m b/ui/cocoa/container.m index d9b2e2d..2bd54a2 100644 --- a/ui/cocoa/container.m +++ b/ui/cocoa/container.m @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import "Container.h" +#import "container.h" #import "GridLayout.h" #import "BoxContainer.h" #import "TabView.h" @@ -36,7 +36,7 @@ static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterfaceLayoutOrientation orientation) { BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args->spacing]; box.translatesAutoresizingMaskIntoConstraints = false; - UiContainerX *container = ui_create_container(obj, box); + UiContainer *container = ui_create_container(obj, box); // add box to the parent UiLayout layout = UI_INIT_LAYOUT(args); @@ -61,7 +61,7 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { grid.translatesAutoresizingMaskIntoConstraints = false; grid.columnspacing = args->columnspacing; grid.rowspacing = args->rowspacing; - UiContainerX *container = ui_create_container(obj, grid); + UiContainer *container = ui_create_container(obj, grid); grid.container = container; // add box to the parent @@ -81,7 +81,7 @@ UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { ui_container_add(obj, frame, &layout); // add container to the chain - UiContainerX *container; + UiContainer *container; UiLayout subLayout = {0}; switch(args->subcontainer) { default: { @@ -137,12 +137,22 @@ UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs *args) { UiLayout layout = UI_ARGS2LAYOUT(args); ui_container_add(obj, scrollview, &layout); - UiContainerX *container = ui_create_container(obj, scrollview); + UiContainer *container = ui_create_container(obj, scrollview); uic_object_push_container(obj, container); return (__bridge void*)scrollview; } +static int64_t tabview_get(UiInteger *i) { + NSView *tabview = (__bridge id)i->obj; + return 0; +} + +static void tabview_set(UiInteger *i, int64_t value) { + NSView *tabview = (__bridge id)i->obj; + +} + UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) { NSView *tabview; switch(args->tabview) { @@ -152,19 +162,19 @@ UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) { UiLayout layout = UI_ARGS2LAYOUT(args); ui_container_add(obj, tabview, &layout); - UiContainerX *container = ui_create_container(obj, tabview); + UiContainer *container = ui_create_container(obj, tabview); uic_object_push_container(obj, container); return (__bridge void*)tabview; } void ui_tab_create(UiObject *obj, const char* title) { - UiContainerX *ctn = obj->container_end; + UiContainer *ctn = obj->container_end; id tabview = (__bridge id)ctn->container; NSString *s = title ? [[NSString alloc]initWithUTF8String:title] : @""; NSView *sub = [tabview createTab:-1 title:s]; - UiContainerX *container = ui_create_container(obj, sub); + UiContainer *container = ui_create_container(obj, sub); uic_object_push_container(obj, container); } @@ -204,12 +214,12 @@ UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) { void ui_container_begin_close(UiObject *obj) { - UiContainerX *ct = obj->container_end; + UiContainer *ct = obj->container_end; ct->close = 1; } int ui_container_finish(UiObject *obj) { - UiContainerX *ct = obj->container_end; + UiContainer *ct = obj->container_end; if(ct->close) { ui_end_new(obj); return 0; @@ -307,8 +317,8 @@ int ui_container_finish(UiObject *obj) { /* ------------------------- private functions ------------------------- */ -UiContainerX* ui_create_container(UiObject *obj, id container) { - UiContainerX *ctn = ui_malloc(obj->ctx, sizeof(UiContainerX)); +UiContainer* ui_create_container(UiObject *obj, id container) { + UiContainer *ctn = ui_malloc(obj->ctx, sizeof(UiContainer)); ctn->container = (__bridge void*)container; ctn->close = 0; ctn->prev = NULL; @@ -318,7 +328,7 @@ UiContainerX* ui_create_container(UiObject *obj, id container) { } void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) { - UiContainerX *ctn = obj->container_end; + UiContainer *ctn = obj->container_end; id container = (__bridge id)ctn->container; UiLayout adjustedLayout = *layout; if(adjustedLayout.margin > 0) { diff --git a/ui/cocoa/entry.h b/ui/cocoa/entry.h index b0cb2fd..227d984 100644 --- a/ui/cocoa/entry.h +++ b/ui/cocoa/entry.h @@ -27,7 +27,7 @@ */ #import "toolkit.h" -#import "Container.h" +#import "container.h" #import "../ui/entry.h" diff --git a/ui/cocoa/image.h b/ui/cocoa/image.h index 8b80a70..70f1d8d 100644 --- a/ui/cocoa/image.h +++ b/ui/cocoa/image.h @@ -28,7 +28,7 @@ #include "../ui/image.h" -#include "Container.h" +#include "container.h" typedef struct UiImage { void *nsimage; diff --git a/ui/cocoa/image.m b/ui/cocoa/image.m index a6794c0..80ae7d2 100644 --- a/ui/cocoa/image.m +++ b/ui/cocoa/image.m @@ -100,11 +100,12 @@ void ui_icon_init(void) { NSImage* ui_cocoa_named_icon(const char *name) { NSString *imageName = [[NSString alloc] initWithUTF8String:name]; - NSString *imgName = [standardIconNames objectForKey:imageName]; - if(imgName) { - imageName = imgName; - } - return [NSImage imageNamed:imageName]; + //NSString *imgName = [standardIconNames objectForKey:imageName]; + //if(imgName) { + // imageName = imgName; + //} + //return [NSImage imageNamed:imageName]; + return [NSImage imageWithSystemSymbolName:imageName accessibilityDescription:nil]; } static UIIMAGE create_image(NSImage *image) { diff --git a/ui/cocoa/label.m b/ui/cocoa/label.m index 4e75e01..44e9045 100644 --- a/ui/cocoa/label.m +++ b/ui/cocoa/label.m @@ -27,7 +27,7 @@ */ #import "label.h" -#import "Container.h" +#import "container.h" #import diff --git a/ui/cocoa/list.h b/ui/cocoa/list.h index 6a3b174..173afc6 100644 --- a/ui/cocoa/list.h +++ b/ui/cocoa/list.h @@ -27,7 +27,7 @@ */ #import "toolkit.h" -#import "Container.h" +#import "container.h" #import "../ui/list.h" #import "ListDataSource.h" diff --git a/ui/cocoa/list.m b/ui/cocoa/list.m index 5e72e92..132d84a 100644 --- a/ui/cocoa/list.m +++ b/ui/cocoa/list.m @@ -54,8 +54,14 @@ static void add_listdelegate(UiObject *obj, NSTableView *tableview, UiListArgs * ListDelegate *delegate = [[ListDelegate alloc] init:tableview obj:obj]; delegate.onactivate = args->onactivate; delegate.onactivatedata = args->onactivatedata; + if(args->onactivate_action) { + delegate.onactivate_action = [[NSString alloc]initWithUTF8String:args->onactivate_action]; + } delegate.onselection = args->onselection; delegate.onselectiondata = args->onselectiondata; + if(args->onselection_action) { + delegate.onselection_action = [[NSString alloc]initWithUTF8String:args->onselection_action]; + } tableview.delegate = delegate; objc_setAssociatedObject(tableview, "ui_listdelegate", delegate, OBJC_ASSOCIATION_RETAIN); tableview.doubleAction = @selector(activateEvent:); @@ -209,6 +215,7 @@ UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args) { void ui_tableview_update(UiList *list, int i) { NSTableView *tableview = (__bridge NSTableView*)list->obj; if(i < 0) { + [tableview deselectAll: tableview]; [tableview reloadData]; } else { [tableview reloadData]; // TODO: optimize @@ -263,7 +270,7 @@ void ui_tableview_setselection(UiList *list, UiListSelection selection) { event.eventdatatype = UI_EVENT_DATA_LIST_ELM; event.intval = index; - if(_onselection) { + if(_onselection && ui_selection_events_is_enabled()) { _onselection(&event, _onselectiondata); } @@ -468,7 +475,7 @@ UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) { data.onactivate = args->onactivate; data.onactivatedata = args->onactivatedata; data.onbuttonclick = args->onbuttonclick; - data.onactivatedata = args->onbuttonclickdata; + data.onbuttonclickdata = args->onbuttonclickdata; [data update:-1]; outline.dataSource = data; @@ -508,18 +515,37 @@ void ui_sourcelist_update(UiList *list, int row) { [_sections removeAllObjects]; - CxIterator i = cxListIterator(_sublists); - int index = 0; - int rownum = 0; - cx_foreach(UiSubList *, sl, i) { - UiSourceListItem *section = [[UiSourceListItem alloc] init:self sublist:sl]; - section.sublistIndex = index; - section.rownum = rownum; - section.sublistStartRow = rownum; - [section update:-1]; - [_sections addObject:section]; - index++; - rownum += 1 + section.items.count; + if(_sublists) { + CxIterator i = cxListIterator(_sublists); + int index = 0; + int rownum = 0; + cx_foreach(UiSubList *, sl, i) { + UiSourceListItem *section = [[UiSourceListItem alloc] init:self sublist:sl]; + section.sublistIndex = index; + section.rownum = rownum; + section.sublistStartRow = rownum; + [section update:-1]; + [_sections addObject:section]; + index++; + rownum += 1 + section.items.count; + } + } else if (_dynamic_sublists) { + UiList *sublists = _dynamic_sublists->value; + UiSubList *sl = sublists->first(sublists); + int index = 0; + int rownum = 0; + while(sl) { + UiSourceListItem *section = [[UiSourceListItem alloc] init:self sublist:sl]; + section.sublistIndex = index; + section.rownum = rownum; + section.sublistStartRow = rownum; + [section update:-1]; + [_sections addObject:section]; + index++; + rownum += 1 + section.items.count; + + sl = sublists->next(sublists); + } } [_outlineView reloadData]; diff --git a/ui/cocoa/menu.m b/ui/cocoa/menu.m index eae8a50..9e7a39d 100644 --- a/ui/cocoa/menu.m +++ b/ui/cocoa/menu.m @@ -109,10 +109,10 @@ void add_menuitem_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item UiMenuItem *it = (UiMenuItem*)item; NSString *str = [[NSString alloc] initWithUTF8String:it->label]; - NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuItemAction) keyEquivalent:@""]; + 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; @@ -186,11 +186,19 @@ void add_menuitem_list_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI } +static BOOL menu_is_initialized = NO; + void ui_menu_init(void) { - bindingItems = [[NSMutableArray alloc] init]; - UiMenu *menus_begin = uic_get_menu_list(); UiMenu *ls = menus_begin; + + if(menu_is_initialized || !ls) { + return; + } + menu_is_initialized = YES; + + bindingItems = [[NSMutableArray alloc] init]; + int index = 1; while(ls) { if(ls->item.type == UI_MENU) { diff --git a/ui/cocoa/objs.mk b/ui/cocoa/objs.mk index d4d0e61..a37ec4f 100644 --- a/ui/cocoa/objs.mk +++ b/ui/cocoa/objs.mk @@ -38,7 +38,7 @@ COCOAOBJ += UiThread.o COCOAOBJ += MainWindow.o COCOAOBJ += WindowManager.o COCOAOBJ += window.o -COCOAOBJ += Container.o +COCOAOBJ += container.o COCOAOBJ += button.o COCOAOBJ += text.o COCOAOBJ += menu.o @@ -51,6 +51,7 @@ COCOAOBJ += widget.o COCOAOBJ += image.o COCOAOBJ += entry.o COCOAOBJ += TabView.o +COCOAOBJ += action.o TOOLKITOBJS += $(COCOAOBJ:%=$(COCOA_OBJPRE)%) TOOLKITSOURCE += $(COCOAOBJ:%.o=cocoa/%.m) diff --git a/ui/cocoa/text.h b/ui/cocoa/text.h index 23bc438..eec2fe4 100644 --- a/ui/cocoa/text.h +++ b/ui/cocoa/text.h @@ -37,7 +37,7 @@ void ui_textarea_restore(UiText *text); void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_get(UiText *text); char* ui_textarea_getsubstr(UiText *text, int begin, int end); -void ui_textarea_insert(UiText *text, int pos, char *str); +void ui_textarea_insert(UiText *text, int pos, const char *str); void ui_textarea_setposition(UiText *text, int pos); int ui_textarea_position(UiText *text); void ui_textarea_setselection(UiText *text, int begin, int end); @@ -47,3 +47,31 @@ void ui_textarea_remove(UiText *text, int begin, int end); char* ui_textfield_get(UiString *s); void ui_textfield_set(UiString *s, const char *value); + + +@interface TextAreaDelegate: NSObject + +@property UiObject *obj; +@property UiVar *var; +@property ui_callback onchange; +@property void *onchangedata; +@property NSString *onchange_action; +@property ui_callback ontextchanged; +@property void *ontextchangeddata; +@property NSString *ontextchanged_action; + +- (id)init:(UiObject*)obj var:(UiVar*)var args:(UiTextAreaArgs*)args; + +@end + +@interface TextFieldDelegate : NSObject + +@property UiObject *obj; +@property UiVar *var; +@property ui_callback onchange; +@property void *onchangedata; +@property NSString *onchange_action; + +- (id)init:(UiObject*)obj var:(UiVar*)var; + +@end diff --git a/ui/cocoa/text.m b/ui/cocoa/text.m index 324d6e7..acbffed 100644 --- a/ui/cocoa/text.m +++ b/ui/cocoa/text.m @@ -28,7 +28,8 @@ #import "text.h" #import "EventData.h" -#import "Container.h" +#import "container.h" +#import "action.h" #import UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { @@ -41,6 +42,11 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { scrollview.hasVerticalScroller = YES; scrollview.documentView = textview; + // store link to the textview + // associate it with the textview and the scrollview to support both widgets in ui_textarea_gettextwidget + objc_setAssociatedObject(textview, "ui_textarea", textview, OBJC_ASSOCIATION_ASSIGN); + objc_setAssociatedObject(scrollview, "ui_textarea", textview, OBJC_ASSOCIATION_ASSIGN); + UiLayout layout = UI_INIT_LAYOUT(args); ui_container_add(obj, scrollview, &layout); @@ -66,11 +72,106 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { text->remove = ui_textarea_remove; } + if(args->onchange || args->ontextchanged || args->onchange_action || args->ontextchanged_action) { + TextAreaDelegate * tad = [[TextAreaDelegate alloc] init:obj var:var args:args]; + textview.delegate = tad; + objc_setAssociatedObject(textview, "delegate", tad, OBJC_ASSOCIATION_RETAIN); + } + return (__bridge void*)scrollview; } +UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { + id view = (__bridge id)textarea; + id textview = objc_getAssociatedObject(view, "ui_textarea"); + return (__bridge void*)textview; +} +void ui_textarea_focus(UIWIDGET textarea) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_focus: widget is not a textarea\n"); + return; + } + NSTextView *view = (__bridge NSTextView*)textarea; + [view.window makeFirstResponder:view]; +} + +void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_set_selection: widget is not a textarea\n"); + return; + } + NSTextView *view = (__bridge NSTextView*)textarea; + NSRange range = NSMakeRange(begin, end-begin); + [view setSelectedRange:range]; +} + +void ui_textarea_select_all(UIWIDGET textarea) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_select_all: widget is not a textarea\n"); + return; + } +} + +void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_set_editable: widget is not a textarea\n"); + return; + } + NSTextView *view = (__bridge NSTextView*)textarea; + view.editable = editable; +} + +UiBool ui_textarea_is_editable(UIWIDGET textarea) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_is_editable: widget is not a textarea\n"); + return 0; + } + NSTextView *view = (__bridge NSTextView*)textarea; + return view.isEditable; +} + +void ui_textarea_set_position(UIWIDGET textarea, int pos) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_set_position: widget is not a textarea\n"); + return; + } + NSTextView *view = (__bridge NSTextView*)textarea; + NSRange range = NSMakeRange(pos, 0); + [view setSelectedRange:range]; +} + +int ui_textarea_get_position(UIWIDGET textarea) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_get_position: widget is not a textarea\n"); + return 0; + } + NSTextView *view = (__bridge NSTextView*)textarea; + NSRange range = view.selectedRange; + return (int)range.location; +} + +void ui_textarea_scroll_to(UIWIDGET textarea, int pos) { + textarea = ui_textarea_gettextwidget(textarea); + if(!textarea) { + fprintf(stderr, "Error: ui_textarea_scroll_to: widget is not a textarea\n"); + return; + } + NSTextView *view = (__bridge NSTextView*)textarea; + NSRange range = NSMakeRange(pos, 0); + [view scrollRangeToVisible:range]; +} + + +// UiText textarea functions void ui_textarea_save(UiText *text) { @@ -120,7 +221,7 @@ char* ui_textarea_getsubstr(UiText *text, int begin, int end) { return strdup(sub.UTF8String); } -void ui_textarea_insert(UiText *text, int pos, char *str) { +void ui_textarea_insert(UiText *text, int pos, const char *str) { NSTextView *textview = (__bridge NSTextView*)text->obj; NSString *s = [[NSString alloc] initWithUTF8String:str]; NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithString:s]; @@ -174,8 +275,116 @@ void ui_textarea_remove(UiText *text, int begin, int end) { +@implementation TextAreaDelegate + +- (id)init:(UiObject*)obj var:(UiVar*)var args:(UiTextAreaArgs*)args { + self.onchange = args->onchange; + self.onchangedata = args->onchangedata; + if(args->onchange_action) { + self.onchange_action = [[NSString alloc]initWithUTF8String:args->onchange_action]; + } + self.ontextchanged = args->ontextchanged; + self.ontextchangeddata = args->ontextchangeddata; + if(args->ontextchanged_action) { + self.ontextchanged_action = [[NSString alloc]initWithUTF8String:args->ontextchanged_action]; + } + self.obj = obj; + self.var = var; + return self; +} + +- (BOOL) textView:(NSTextView *) textView + shouldChangeTextInRange:(NSRange) affectedCharRange + replacementString:(NSString *) replacementString { + + if(_onchange == nil && _onchange_action == nil) { + return YES; + } + + UiEvent event; + event.obj = _obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.intval = 0; + event.set = ui_get_setop(); + // event data not set yet + + if(affectedCharRange.length > 0) { + UiTextChangeEventData eventdata; + eventdata.type = UI_TEXT_DELETE; + eventdata.begin = (int)affectedCharRange.location; + eventdata.end = (int)(affectedCharRange.location + affectedCharRange.length); + eventdata.text = NULL; + eventdata.length = 0; + + event.eventdata = &eventdata; + event.eventdatatype = UI_EVENT_DATA_TEXT_CHANGED; + + if(_onchange) { + _onchange(&event, _onchangedata); + } + + if(_onchange_action) { + uic_action_callback(&event, _onchange_action.UTF8String); + } + } + + if(replacementString.length > 0) { + UiTextChangeEventData eventdata; + eventdata.type = UI_TEXT_INSERT; + eventdata.begin = (int)affectedCharRange.location; + eventdata.end = 0; + eventdata.text = replacementString.UTF8String; + eventdata.length = (int)replacementString.length; + + event.eventdata = &eventdata; + event.eventdatatype = UI_EVENT_DATA_TEXT_CHANGED; + + if(_onchange) { + _onchange(&event, _onchangedata); + } + + if(_onchange_action) { + uic_action_callback(&event, _onchange_action.UTF8String); + } + } + + return YES; +} + +- (void) textDidChange:(NSNotification *) notification { + UiEvent event; + event.obj = _obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + if(_var) { + event.eventdata = _var->value; + event.eventdatatype = UI_EVENT_DATA_TEXT_VALUE; + } else { + event.eventdata = NULL; + event.eventdatatype = 0; + } + event.intval = 0; + event.set = ui_get_setop(); + + if(_ontextchanged) { + _ontextchanged(&event, _ontextchangeddata); + } + + if(_ontextchanged_action) { + uic_action_callback(&event, _ontextchanged_action.UTF8String); + } +} + +@end + + /* -------------------------- TextField -------------------------- */ +static void textfield_geteventdata(id sender, UiVar *var, void **eventdata, UiEventType *eventdatatype, int *value) { + +} + static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs *args, BOOL password, BOOL frameless) { NSTextField *textfield; if(password) { @@ -212,6 +421,27 @@ static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs *args, BOOL pass s->set = ui_textfield_set; } + if(args->onactivate || args->onactivate_action) { + EventData *event = [[EventData alloc] init:args->onactivate userdata:args->onactivatedata action:args->onactivate_action]; + event.get_eventdata = textfield_geteventdata; + event.obj = obj; + textfield.target = event; + textfield.action = @selector(handleEventWithEventData:); + objc_setAssociatedObject(textfield, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + ui_cocoa_view_bind_action(obj->ctx, textfield, args->onactivate_action); + } + + if(args->onchange || args->onchange_action) { + TextFieldDelegate *tfd = [[TextFieldDelegate alloc]init:obj var:var]; + tfd.onchange = args->onchange; + tfd.onchangedata = args->onchangedata; + if(args->onchange_action) { + tfd.onchange_action = [[NSString alloc]initWithUTF8String:args->onchange_action]; + } + objc_setAssociatedObject(textfield, "delegate", tfd, OBJC_ASSOCIATION_RETAIN); + textfield.delegate = tfd; + } + return (__bridge void*)textfield; } @@ -248,3 +478,89 @@ void ui_textfield_set(UiString *s, const char *value) { NSTextField *textfield = (__bridge NSTextField*)s->obj; textfield.stringValue = [[NSString alloc] initWithUTF8String:value]; } + +/* -------------------------- public Textfield functions -------------------------- */ + +void ui_textfield_focus(UIWIDGET textfield) { + NSTextField *tf = (__bridge NSTextField*)textfield; + [tf.window makeFirstResponder:tf]; + [tf selectText:nil]; +} + +void ui_textfield_focus_without_selecting(UIWIDGET textfield) { + NSTextField *tf = (__bridge NSTextField*)textfield; + [tf.window makeFirstResponder:tf]; +} + +void ui_textfield_set_selection(UIWIDGET textfield, int begin, int end) { + NSTextField *tf = (__bridge NSTextField*)textfield; + [tf.window makeFirstResponder:tf]; + NSTextView *fieldEditor = (NSTextView *)[tf.window fieldEditor:YES forObject:tf]; + [fieldEditor setSelectedRange:NSMakeRange(begin, end-begin)]; +} + +void ui_textfield_select_all(UIWIDGET textfield) { + NSTextField *tf = (__bridge NSTextField*)textfield; + [tf selectText:nil]; +} + +void ui_textfield_set_editable(UIWIDGET textfield, UiBool editable) { + NSTextField *tf = (__bridge NSTextField*)textfield; + tf.editable = editable; +} + +UiBool ui_textfield_is_editable(UIWIDGET textfield) { + NSTextField *tf = (__bridge NSTextField*)textfield; + return tf.isEditable; +} + +void ui_textfield_set_position(UIWIDGET textfield, int pos) { + NSTextField *tf = (__bridge NSTextField*)textfield; + NSTextView *editor = (NSTextView *)[tf currentEditor]; + [editor setSelectedRange:NSMakeRange(pos, 0)]; +} + +int ui_textfield_get_position(UIWIDGET textfield) { + NSTextField *tf = (__bridge NSTextField*)textfield; + NSTextView *editor = (NSTextView *)[tf currentEditor]; + NSRange selectedRange = [editor selectedRange]; + return (int)selectedRange.location; +} + + +/* -------------------- textfield delegate -------------------- */ + +@implementation TextFieldDelegate + +- (id)init:(UiObject*)obj var:(UiVar*)var { + self.obj = obj; + self.var = var; + return self; +} + +- (void)controlTextDidChange:(NSNotification *)obj { + UiString *value = _var ? _var->value : NULL; + + UiEvent e; + e.obj = _obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = value; + e.eventdatatype = value ? UI_EVENT_DATA_STRING_VALUE : 0; + e.intval = 0; + e.set = ui_get_setop(); + + if(_onchange) { + _onchange(&e, _onchangedata); + } + + if(_var) { + ui_notify_evt(value->observers, &e); + } + + if(_onchange_action) { + uic_action_callback(&e, _onchange_action.UTF8String); + } +} + +@end diff --git a/ui/cocoa/toolkit.h b/ui/cocoa/toolkit.h index 9a377b3..ab4c6da 100644 --- a/ui/cocoa/toolkit.h +++ b/ui/cocoa/toolkit.h @@ -51,7 +51,4 @@ @end -void ui_cocoa_onstartup(void); -void ui_cocoa_onopen(const char *file); -void ui_cocoa_onexit(void); diff --git a/ui/cocoa/toolkit.m b/ui/cocoa/toolkit.m index c0e9edf..9a8e309 100644 --- a/ui/cocoa/toolkit.m +++ b/ui/cocoa/toolkit.m @@ -28,6 +28,9 @@ #import "toolkit.h" +#include +#include + #include "../common/document.h" #include "../common/properties.h" #include "../common/menu.h" @@ -47,35 +50,63 @@ static const char *application_name; static int app_argc; static const char **app_argv; -static UiBool exit_on_shutdown; +static UiBool exit_on_shutdown; + +static char *main_thread_error_msg; + +// This function is only used by language bindings, to improve error messages +// for example, when using java bindings, this can provide infos how to fix +// this (-XstartOnFirstThread) +void ui_set_main_thread_error_msg(const char *msg) { + main_thread_error_msg = msg ? strdup(msg) : NULL; +} /* ------------------- App Init / Event Loop functions ------------------- */ +static AppDelegate *app_delegate; + +static void main_thr_check(const char *func) { + if(![NSThread isMainThread]) { + fprintf(stderr, "Error: %s must run on the main thread.\n", func); + if(main_thread_error_msg) { + fprintf(stderr, "%s\n", main_thread_error_msg); + } + exit(1); + } +} void ui_init(const char *appname, int argc, char **argv) { - application_name = appname; + main_thr_check("ui_init"); + + application_name = appname ? strdup(appname) : NULL; app_argc = argc; app_argv = (const char**)argv; uic_init_global_context(); - + uic_menu_init(); uic_toolbar_init(); - + uic_load_app_properties(); - + NSApplication *app = [NSApplication sharedApplication]; - //[app setActivationPolicy:NSApplicationActivationPolicyRegular]; + [app setActivationPolicy:NSApplicationActivationPolicyRegular]; //[NSBundle loadNibNamed:@"MainMenu" owner:NSApp ]; //[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:&topLevelObjects]; + app_delegate = [[AppDelegate alloc] init]; + + fflush(stdout); + app.delegate = app_delegate; + + ui_icon_init(); ui_toolbar_init(); } -const char* ui_appname() { +const char* ui_appname(void) { return application_name; } @@ -83,41 +114,34 @@ void ui_app_exit_on_shutdown(UiBool exitapp) { exit_on_shutdown = exitapp; } -void ui_cocoa_onstartup(void) { - UiEvent e; - e.obj = NULL; - e.window = NULL; - e.document = NULL; - e.eventdata = NULL; - e.intval = 0; - uic_application_startup(&e); +void ui_main(void) { + main_thr_check("ui_main"); + + NSApplicationMain(app_argc,app_argv); + //[NSApp finishLaunching]; + //[NSApp activateIgnoringOtherApps:YES]; + //[NSApp run]; + if(exit_on_shutdown) { + exit(0); + } } -void ui_cocoa_onopen(const char *file) { - UiEvent e; - e.obj = NULL; - e.window = NULL; - e.document = NULL; - e.eventdata = NULL; - e.intval = 0; - uic_application_open(&e); +void ui_app_ref(void) { + // TODO } -void ui_cocoa_onexit(void) { - UiEvent e; - e.obj = NULL; - e.window = NULL; - e.document = NULL; - e.eventdata = NULL; - e.intval = 0; - uic_application_exit(&e); +void ui_app_unref(void) { + // TODO } -void ui_main(void) { - NSApplicationMain(app_argc, app_argv); - if(exit_on_shutdown) { - exit(0); - } +void ui_app_quit(void) { + [[NSApplication sharedApplication] terminate:nil]; +} + +void ui_open_uri(const char *uri) { + NSString *urlString = [NSString stringWithUTF8String:uri]; + NSURL *url = [NSURL URLWithString:urlString]; + [[NSWorkspace sharedWorkspace] openURL:url]; } /* ------------------- Window Visibility functions ------------------- */ @@ -174,6 +198,11 @@ void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) @end void ui_call_mainthread(ui_threadfunc tf, void* td) { + if(uic_mainthread_calls_is_buffered()) { + uic_add_buffered_mainthread_call(tf, td); + return; + } + UiAppCallback *cb = [[UiAppCallback alloc]initWithCallback:tf userdata:td]; [cb callMainThread]; } diff --git a/ui/cocoa/webview.m b/ui/cocoa/webview.m index 088ad5f..a4b4dae 100644 --- a/ui/cocoa/webview.m +++ b/ui/cocoa/webview.m @@ -52,7 +52,7 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) { data->webview = (__bridge void*)webview; data->javascript = TRUE; data->zoom = 1; - value->value = value; + value->value = data; } } diff --git a/ui/cocoa/widget.h b/ui/cocoa/widget.h index 772bf88..5857c86 100644 --- a/ui/cocoa/widget.h +++ b/ui/cocoa/widget.h @@ -27,5 +27,5 @@ */ #import "toolkit.h" -#import "Container.h" +#import "container.h" #import "../ui/widget.h" diff --git a/ui/cocoa/widget.m b/ui/cocoa/widget.m index edc78c1..ff32bfe 100644 --- a/ui/cocoa/widget.m +++ b/ui/cocoa/widget.m @@ -44,6 +44,14 @@ void ui_set_visible(UIWIDGET widget, int visible) { view.hidden = !visible; } +void ui_widget_set_size(UIWIDGET w, int width, int height) { + NSView *view = (__bridge NSView*)w; + NSRect frame = view.frame; + frame.size.width = width; + frame.size.height = height; + view.frame = frame; +} + UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) { // TODO diff --git a/ui/cocoa/window.m b/ui/cocoa/window.m index a3fe089..c027867 100644 --- a/ui/cocoa/window.m +++ b/ui/cocoa/window.m @@ -32,6 +32,7 @@ #import "WindowManager.h" #import "BoxContainer.h" #import "EventData.h" +#import "menu.h" #import @@ -41,6 +42,7 @@ #include "../common/menu.h" #include "../common/toolbar.h" #include "../common/object.h" +#include "../common/utils.h" #include @@ -50,19 +52,31 @@ static int window_default_height = 550; static int splitview_window_default_pos = -1; static UiBool splitview_window_use_prop = TRUE; +static void main_window_destroy(UiObject *obj) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + [window saveWindowSize]; + [[WindowManager sharedWindowManager] closeWindow:window]; +} + static UiObject* create_window(const char *title, BOOL simple, BOOL sidebar, BOOL splitview) { + ui_menu_init(); UiObject *obj = uic_object_new_toplevel(); - MainWindow *window = [[MainWindow alloc] init:obj withSidebar:sidebar withSplitview:splitview]; - [[WindowManager sharedWindowManager] addWindow:window]; - window.releasedWhenClosed = false; // TODO: we still need a cleanup strategy + int width = window_default_width; + int height = window_default_height; + if(!simple) { + ui_get_window_default_width(&width, &height); + } + + MainWindow *window = [[MainWindow alloc] init:obj withSidebar:sidebar withSplitview:splitview width:width height:height]; obj->wobj = (__bridge void*)window; + obj->destroy = main_window_destroy; MainWindowController *controller = [[MainWindowController alloc] initWithWindow:obj window:window]; window.windowController = controller; [window setNextResponder:(NSResponder*)controller]; - objc_setAssociatedObject(window, "windowcontroller", controller, OBJC_ASSOCIATION_RETAIN); + [[WindowManager sharedWindowManager] addWindow:controller]; return obj; } @@ -96,6 +110,35 @@ void ui_window_default_size(int width, int height) { window_default_height = height; } +/* ------------------------------- SplitView Window-------------------------------- */ + +void ui_splitview_window_set_pos(UiObject *obj, int pos) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + int divider = window.sidebar != nil ? 1 : 0; + [window.splitview setPosition:pos ofDividerAtIndex:divider]; +} + +int ui_splitview_window_get_pos(UiObject *obj) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + int divider = window.sidebar != nil ? 1 : 0; + return window.splitview.subviews[divider].frame.size.width; +} + +void ui_splitview_window_set_default_pos(int pos) { + splitview_window_default_pos = pos; +} + +void ui_splitview_window_use_property(UiBool enable) { + splitview_window_use_prop = enable; +} + +void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool visible) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + if(pane >= 0 && pane < 2) { + window.splitview.subviews[pane].hidden = visible; + } +} + /* --------------------------------- File Dialogs --------------------------------- */ void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) { @@ -281,13 +324,15 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { NSWindowStyleMaskUtilityWindow) backing:NSBackingStoreBuffered defer:NO]; + NSWindowController *controller = [[NSWindowController alloc] initWithWindow:panel]; + panel.windowController = controller; panel.parent = (__bridge NSWindow*)parent->wobj; panel.obj = obj; panel.modal = args->modal; panel.onclick = args->onclick; panel.onclickdata = args->onclickdata; [panel center]; - [[WindowManager sharedWindowManager] addWindow:panel]; + [[WindowManager sharedWindowManager] addWindow:controller]; obj->wobj = (__bridge void*)panel; NSView *content = panel.contentView; @@ -314,7 +359,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; @@ -334,7 +379,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; @@ -353,7 +398,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; @@ -373,7 +418,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; @@ -423,7 +468,7 @@ UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { [vbox.bottomAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0] ]]; - UiContainerX *container = ui_create_container(obj, vbox); + UiContainer *container = ui_create_container(obj, vbox); vbox.container = container; uic_object_push_container(obj, container); diff --git a/ui/common/Makefile b/ui/common/Makefile new file mode 100644 index 0000000..703da14 --- /dev/null +++ b/ui/common/Makefile @@ -0,0 +1,111 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2012 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +FORCE: + +$(COMMON_OBJPRE)uic_action$(OBJ_EXT): common/action.c common/action.h \ + common/../ui/toolkit.h common/context.h common/object.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_app$(OBJ_EXT): common/app.c common/app.h \ + common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_args$(OBJ_EXT): common/args.c common/args.h \ + common/../ui/window.h common/../ui/toolkit.h common/../ui/container.h \ + common/../ui/display.h common/../ui/button.h common/../ui/entry.h \ + common/../ui/menu.h common/../ui/toolbar.h common/../ui/list.h \ + common/../ui/text.h common/../ui/webview.h common/../ui/widget.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_condvar$(OBJ_EXT): common/condvar.c common/condvar.h \ + common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_container$(OBJ_EXT): common/container.c \ + common/container.h common/../ui/container.h common/../ui/toolkit.h \ + common/object.h common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_context$(OBJ_EXT): common/context.c common/context.h \ + common/../ui/toolkit.h common/action.h common/../ui/window.h \ + common/../ui/toolkit.h common/../ui/widget.h common/document.h \ + common/types.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_document$(OBJ_EXT): common/document.c \ + common/document.h common/../ui/toolkit.h common/context.h \ + common/action.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_icons$(OBJ_EXT): common/icons.c common/icons.h \ + common/../ui/icons.h common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_menu$(OBJ_EXT): common/menu.c common/menu.h \ + common/../ui/menu.h common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_message$(OBJ_EXT): common/message.c common/message.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_object$(OBJ_EXT): common/object.c common/object.h \ + common/../ui/toolkit.h common/context.h common/action.h \ + common/../ui/container.h common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_properties$(OBJ_EXT): common/properties.c \ + common/../ui/toolkit.h common/properties.h common/../ui/properties.h \ + common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_threadpool$(OBJ_EXT): common/threadpool.c \ + common/threadpool.h common/../ui/toolkit.h common/context.h \ + common/action.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_toolbar$(OBJ_EXT): common/toolbar.c common/toolbar.h \ + common/../ui/toolbar.h common/../ui/toolkit.h common/menu.h \ + common/../ui/menu.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_types$(OBJ_EXT): common/types.c common/../ui/list.h \ + common/../ui/toolkit.h common/types.h common/../ui/toolkit.h \ + common/context.h common/action.h common/../ui/image.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_utils$(OBJ_EXT): common/utils.c common/utils.h \ + common/../ui/toolkit.h common/../ui/text.h common/../ui/toolkit.h \ + common/properties.h common/../ui/properties.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(COMMON_OBJPRE)uic_wrapper$(OBJ_EXT): common/wrapper.c common/wrapper.h \ + common/../ui/toolkit.h common/../ui/list.h common/../ui/toolkit.h \ + common/../ui/text.h common/types.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + diff --git a/ui/common/action.c b/ui/common/action.c new file mode 100644 index 0000000..683ed37 --- /dev/null +++ b/ui/common/action.c @@ -0,0 +1,288 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "action.h" +#include "context.h" +#include "object.h" + +#include + +void uic_add_action( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text) +{ + if(!name) { + return; + } + + UiAction action; + action.name = ui_strdup(ctx, name); + action.callback = callback; + action.userdata = userdata; + action.accelerator = accelerator ? ui_strdup(ctx, accelerator) : NULL; + action.accelerator_text = accelerator_text ? ui_strdup(ctx, accelerator_text) : NULL; + action.ctx = ctx; + cxMapPut(ctx->actions, name, &action); + cxMapRehash(ctx->actions); +} + +void uic_bind_action( + UiContext *ctx, + const char *action, + void *bind_obj, + ui_enablefunc set_enabled) +{ + if(!action) { + return; + } + + UiActionBinding binding; + binding.action = ui_strdup(ctx, action); + binding.userdata = bind_obj; + binding.set_enabled = set_enabled; + cxListAdd(ctx->action_bindings, &binding); +} + +UiAction* uic_resolve_action(UiContext *ctx, const char *action) { + UiAction *a = NULL; + if(ctx->actions) { + a = cxMapGet(ctx->actions, action); + } + // check if any sub-document defines this action + // sub-document actions have precedence, the most specific action will + // be returned + CxIterator i = cxListIterator(ctx->documents); + cx_foreach(void *, doc, i) { + UiContext *doc_ctx = ui_document_context(doc); + UiAction *sub_action = uic_resolve_action(doc_ctx, action); + if(sub_action) { + a = sub_action; + // if one sub-tree has an action, we don't care about other + // subtrees + break; + } + } + + if(!a && ctx->parent) { + // check parents + a = uic_resolve_action_from_parents(ctx, action); + } + + return a; +} + +UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action) { + UiContext *parent = ctx->parent; + if(parent == NULL) { + return NULL; + } + if(parent->actions) { + UiAction *a = cxMapGet(parent->actions, action); + if(a) { + return a; + } + } + return uic_resolve_action_from_parents(parent, action); +} + + + +void ui_update_action_bindings(UiContext *ctx) { + CxIterator i = cxListIterator(ctx->action_bindings); + cx_foreach(UiActionBinding*, binding, i) { + UiAction *action = uic_resolve_action(ctx, binding->action); + if(binding->set_enabled) { + binding->set_enabled(binding->userdata, action != NULL); + } + } +} + +void uic_action_callback(UiEvent *event, const char *action_name) { + UiContext *ctx = ui_global_context(); + if(event->obj) { + ctx = event->obj->ctx; + } + + UiAction *action = uic_resolve_action(ctx, action_name); + if(action) { + // override event document: for actions we know that the event is + // for a specific document + event->document = action->ctx->self_doc; + if(action->callback) { + action->callback(event, action->userdata); + } + } +} + +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; + memset(&event, 0, sizeof(UiEvent)); + event.obj = ctx->obj; + event.window = event.obj ? event.obj->window : NULL; + event.document = ctx->self_doc ? ctx->self_doc : ctx->document; + if(eventdata) { + event.eventdata = eventdata; + 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; +} + +static void call_action_recursive(const char *action_name, UiContext *ctx, void *eventdata, UiEventType eventdatatype, int intval, UiBool call_children) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.obj = ctx->obj; + event.window = event.obj ? event.obj->window : NULL; + event.document = ctx->self_doc ? ctx->self_doc : ctx->document; + if(eventdata) { + event.eventdata = eventdata; + event.eventdatatype = eventdatatype; + } + event.intval = intval; + + UiAction *a = NULL; + if(ctx->actions) { + a = cxMapGet(ctx->actions, action_name); + } + if(a && a->callback) { + a->callback(&event, a->userdata); + } + + if(call_children) { + CxIterator i = cxListIterator(ctx->documents); + cx_foreach(void *, doc, i) { + UiContext *doc_ctx = ui_document_context(doc); + call_action_recursive(action_name, doc_ctx, eventdata, eventdatatype, intval, TRUE); + } + } +} + +static void broadcast_action(const char *action_name, void *eventdata, UiEventType eventdatatype, int intval) { + CxList *objects = uic_object_list(); + CxIterator i = cxListIterator(objects); + cx_foreach(UiObject*, obj, i) { + call_action_recursive(action_name, obj->ctx, eventdata, eventdatatype, intval, TRUE); + } + + call_action_recursive(action_name, ui_global_context(), eventdata, eventdatatype, intval, FALSE); +} + +void ui_broadcast_action(const char *action_name) { + broadcast_action(action_name, NULL, UI_EVENT_DATA_NULL, 0); +} + +void ui_broadcast_action2(const char *action_name, void *eventdata, int intval) { + broadcast_action(action_name, eventdata, UI_EVENT_DATA_POINTER, intval); +} + +void ui_call_action_on(UiContext *ctx, const char *action) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.obj = ctx->obj; + event.window = event.obj ? event.obj->window : NULL; + event.document = ctx->self_doc ? ctx->self_doc : ctx->document; + + UiAction *a = NULL; + if(ctx->actions) { + a = cxMapGet(ctx->actions, action); + } + if(a && a->callback) { + a->callback(&event, a->userdata); + } +} + +typedef struct UiActionBroadcast { + char *action; + void *eventdata; + UiEventType eventdatataype; + int intval; +} UiActionBroadcast; + +void ui_mainthread_broadcast(const char *action_name) { + ui_mainthread_broadcast2(action_name, NULL, 0); +} + +static int mainthread_action_broadcast(void *data) { + UiActionBroadcast *broadcast = data; + broadcast_action(broadcast->action, broadcast->eventdata, broadcast->eventdatataype, broadcast->intval); + if(broadcast->eventdatataype == UI_EVENT_DATA_TYPED_OBJECT) { + free(broadcast->eventdata); + } + free(broadcast->action); + free(broadcast); + return 0; +} + +void ui_mainthread_broadcast2(const char *action_name, void *eventdata, int intval) { + UiActionBroadcast *broadcast = malloc(sizeof(UiActionBroadcast)); + broadcast->action = strdup(action_name); + broadcast->eventdata = eventdata; + broadcast->eventdatataype = UI_EVENT_DATA_POINTER; + broadcast->intval = intval; + ui_call_mainthread(mainthread_action_broadcast, broadcast); +} + +void ui_mainthread_broadcast3(const char *action_name, void *ptr, uint64_t type_id) { + UiTypedObj *obj = malloc(sizeof(UiTypedObj)); + obj->ptr = ptr; + obj->type = type_id; + + UiActionBroadcast *broadcast = malloc(sizeof(UiActionBroadcast)); + broadcast->action = strdup(action_name); + broadcast->eventdata = obj; + broadcast->eventdatataype = UI_EVENT_DATA_TYPED_OBJECT; + broadcast->intval = 0; + ui_call_mainthread(mainthread_action_broadcast, broadcast); +} diff --git a/ui/common/action.h b/ui/common/action.h new file mode 100644 index 0000000..1364635 --- /dev/null +++ b/ui/common/action.h @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UIC_ACTION_H +#define UIC_ACTION_H + +#include "../ui/toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UiAction UiAction; +typedef struct UiActionBinding UiActionBinding; + +struct UiAction { + char *name; + char *accelerator; + char *accelerator_text; + ui_callback callback; + void *userdata; + UiContext *ctx; +}; + +struct UiActionBinding { + const char *action; + ui_enablefunc set_enabled; + void *userdata; +}; + +void uic_add_action( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text); + +void uic_bind_action( + UiContext *ctx, + const char *action, + void *bind_obj, + ui_enablefunc set_enabled); + +UiAction* uic_resolve_action(UiContext *ctx, const char *action); +UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action); + +// action event wrapper +void uic_action_callback(UiEvent *event, const char *action_name); + +#ifdef __cplusplus +} +#endif + +#endif /* UIC_ACTION_H */ + diff --git a/ui/common/app.c b/ui/common/app.c index 9674599..c7f80de 100644 --- a/ui/common/app.c +++ b/ui/common/app.c @@ -30,6 +30,8 @@ static ui_callback startup_func; static void *startup_data; +static ui_callback newwindow_func; +static void *newwindow_data; static ui_callback open_func; void *open_data; static ui_callback exit_func; @@ -41,6 +43,11 @@ void ui_onstartup(ui_callback f, void *userdata) { startup_data = userdata; } +void ui_onnewwindow(ui_callback f, void *userdata) { + newwindow_func = f; + newwindow_data = userdata; +} + void ui_onopen(ui_callback f, void *userdata) { open_func = f; open_data = userdata; @@ -51,13 +58,18 @@ void ui_onexit(ui_callback f, void *userdata) { exit_data = userdata; } - void uic_application_startup(UiEvent *event) { if(startup_func) { startup_func(event, startup_data); } } +void uic_application_newwindow(UiEvent *event) { + if(newwindow_func) { + newwindow_func(event, newwindow_data); + } +} + void uic_application_open(UiEvent *event) { if(open_func) { open_func(event, open_data); @@ -69,3 +81,7 @@ void uic_application_exit(UiEvent *event) { exit_func(event, exit_data); } } + +void ui_newwindow(void) { + uic_application_newwindow(NULL); +} diff --git a/ui/common/app.h b/ui/common/app.h index 02356a9..9176e85 100644 --- a/ui/common/app.h +++ b/ui/common/app.h @@ -36,6 +36,7 @@ extern "C" { #endif void uic_application_startup(UiEvent *event); +void uic_application_newwindow(UiEvent *event); void uic_application_open(UiEvent *event); void uic_application_exit(UiEvent *event); diff --git a/ui/common/args.c b/ui/common/args.c index 0ec8a4e..8c1e2b4 100644 --- a/ui/common/args.c +++ b/ui/common/args.c @@ -215,9 +215,14 @@ void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) { args->onclickdata = onclickdata; } +void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_menuitem_args_free(UiMenuItemArgs *args) { free((void*)args->label); free((void*)args->icon); + free((void*)args->action); free(args); } @@ -250,10 +255,15 @@ void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *o args->onchangedata = onclickdata; } +void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) { free((void*)args->label); free((void*)args->icon); free((void*)args->varname); + free((void*)args->action); free(args); } @@ -273,6 +283,14 @@ void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc args->getvalue = func; } +void ui_menuitemlist_args_set_getvalue2(UiMenuItemListArgs *args, ui_getvaluefunc2 func) { + args->getvalue2 = func; +} + +void ui_menuitemlist_args_set_getvaluedata(UiMenuItemListArgs *args, void *data) { + args->getvaluedata = data; +} + void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback) { args->onselect = callback; } @@ -310,6 +328,10 @@ void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *toolt args->tooltip = strdup(tooltip); } +void ui_toolbar_item_args_set_action(UiToolbarItemArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback) { args->onclick = callback; } @@ -327,6 +349,7 @@ void ui_toolbar_item_args_free(UiToolbarItemArgs *args) { free((void*)args->label); free((void*)args->icon); free((void*)args->tooltip); + free((void*)args->action); free((void*)args->states); free(args); } @@ -355,6 +378,10 @@ void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const args->varname = strdup(varname); } +void ui_toolbar_toggleitem_args_set_action(UiToolbarToggleItemArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback) { args->onchange = callback; } @@ -374,6 +401,82 @@ void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) { free((void*)args->icon); free((void*)args->tooltip); free((void*)args->varname); + free((void*)args->action); + free((void*)args->states); + free(args); +} + +/* ---------------------------- UiToolbarContentToggleItemArgs ---------------------------- */ + +UiToolbarContentToggleItemArgs* ui_toolbar_content_toggleitem_args_new(void) { + UiToolbarContentToggleItemArgs *args = malloc(sizeof(UiToolbarContentToggleItemArgs)); + memset(args, 0, sizeof(UiToolbarContentToggleItemArgs)); + return args; +} + +void ui_toolbar_content_toggleitem_args_set_label0(UiToolbarContentToggleItemArgs *args, const char *label) { + args->label0 = strdup(label); +} + +void ui_toolbar_content_toggleitem_args_set_icon0(UiToolbarContentToggleItemArgs *args, const char *icon) { + args->icon0 = strdup(icon); +} + +void ui_toolbar_content_toggleitem_args_set_tooltip0(UiToolbarContentToggleItemArgs *args, const char *tooltip) { + args->tooltip0 = strdup(tooltip); +} + +void ui_toolbar_content_toggleitem_args_set_label1(UiToolbarContentToggleItemArgs *args, const char *label) { + args->label1 = strdup(label); +} + +void ui_toolbar_content_toggleitem_args_set_icon1(UiToolbarContentToggleItemArgs *args, const char *icon) { + args->icon1 = strdup(icon); +} + +void ui_toolbar_content_toggleitem_args_set_tooltip1(UiToolbarContentToggleItemArgs *args, const char *tooltip) { + args->tooltip1 = strdup(tooltip); +} + +void ui_toolbar_content_toggleitem_args_set_varname(UiToolbarContentToggleItemArgs *args, const char *varname) { + args->varname = strdup(varname); +} + +void ui_toolbar_content_toggleitem_args_set_action(UiToolbarContentToggleItemArgs *args, const char *action) { + args->action = strdup(action); +} + +void ui_toolbar_content_toggleitem_args_set_onchange(UiToolbarContentToggleItemArgs *args, ui_callback callback) { + args->onchange = callback; +} + +void ui_toolbar_content_toggleitem_args_set_onchangedata(UiToolbarContentToggleItemArgs *args, void *onchangedata) { + args->onchangedata = onchangedata; +} + +void ui_toolbar_content_toggleitem_args_set_istogglebutton(UiToolbarContentToggleItemArgs *args, UiBool value) { + args->istogglebutton = value; +} + +void ui_toolbar_content_toggleitem_args_set_toggled_by_state(UiToolbarContentToggleItemArgs *args, int state) { + args->toggled_by_state = state; +} + +void ui_toolbar_content_toggleitem_args_set_states(UiToolbarContentToggleItemArgs *args,int *states, int numstates) { + args->states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->states, states, numstates * sizeof(int)); + ((int*)args->states)[numstates] = -1; +} + +void ui_toolbar_content_toggleitem_args_free(UiToolbarContentToggleItemArgs *args) { + free((void*)args->label0); + free((void*)args->icon0); + free((void*)args->tooltip0); + free((void*)args->label1); + free((void*)args->icon1); + free((void*)args->tooltip1); + free((void*)args->varname); + free((void*)args->action); free((void*)args->states); free(args); } @@ -519,10 +622,17 @@ void ui_container_args_set_rowspacing(UiContainerArgs *args, int value) { args->rowspacing = value; } +void ui_container_args_set_visibility_states(UiContainerArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_container_args_free(UiContainerArgs *args) { free((void*)args->name); free((void*)args->style_class); + free((void*)args->visibility_states); free(args); } @@ -637,10 +747,17 @@ void ui_frame_args_set_label(UiFrameArgs *args, const char *label) { args->label = strdup(label); } +void ui_frame_args_set_visibility_states(UiFrameArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_frame_args_free(UiFrameArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->label); + free((void*)args->visibility_states); free(args); } @@ -797,11 +914,18 @@ void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max) { args->max_panes = max; } +void ui_splitpane_args_set_visibility_states(UiSplitPaneArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_splitpane_args_free(UiSplitPaneArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); free((void*)args->position_property); + free((void*)args->visibility_states); free(args); } @@ -915,10 +1039,17 @@ void ui_tabview_args_set_subcontainer(UiTabViewArgs *args, UiSubContainerType su args->subcontainer = subcontainer; } +void ui_tabview_args_set_visibility_states(UiTabViewArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_tabview_args_free(UiTabViewArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->visibility_states); free(args); } @@ -1097,11 +1228,18 @@ void ui_label_args_set_value(UiLabelArgs *args, UiString *value) { args->value = value; } +void ui_label_args_set_visibility_states(UiLabelArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_label_args_free(UiLabelArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->label); free((void*)args->varname); + free((void*)args->visibility_states); free(args); } @@ -1200,10 +1338,17 @@ void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value) { args->value = value; } +void ui_progressbar_args_set_visibility_states(UiProgressbarArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_progressbar_args_free(UiProgressbarArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->visibility_states); free(args); } @@ -1284,10 +1429,17 @@ void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiIntege args->value = value; } +void ui_progress_spinner_args_set_visibility_states(UiProgressbarSpinnerArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->visibility_states); free(args); } @@ -1391,19 +1543,31 @@ void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){ args->onclickdata = onclickdata; } +void ui_button_args_set_action(UiButtonArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates) { args->states = calloc(numstates+1, sizeof(int)); memcpy((void*)args->states, states, numstates * sizeof(int)); ((int*)args->states)[numstates] = -1; } +void ui_button_args_set_visibility_states(UiButtonArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_button_args_free(UiButtonArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->label); free((void*)args->icon); free((void*)args->tooltip); + free((void*)args->action); free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -1502,6 +1666,10 @@ void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){ args->onchangedata = onchangedata; } +void ui_toggle_args_set_action(UiToggleArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) { args->varname = strdup(varname); } @@ -1520,6 +1688,12 @@ void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int numstates) { ((int*)args->states)[numstates] = -1; } +void ui_toggle_args_set_visibility_states(UiToggleArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_toggle_args_free(UiToggleArgs *args) { free((void*)args->name); free((void*)args->style_class); @@ -1527,7 +1701,167 @@ void ui_toggle_args_free(UiToggleArgs *args) { free((void*)args->icon); free((void*)args->tooltip); free((void*)args->varname); + free((void*)args->action); free((void*)args->states); + free((void*)args->visibility_states); + free(args); +} + +/* ------------------------- UiContentToggleArgs ----------------------------*/ + + +UiContentToggleArgs* ui_content_toggle_args_new(void) { + UiContentToggleArgs *args = malloc(sizeof(UiContentToggleArgs)); + memset(args, 0, sizeof(UiContentToggleArgs)); + return args; +} + +void ui_content_toggle_args_set_fill(UiContentToggleArgs *args, UiBool fill) { + args->fill = fill; +} + +void ui_content_toggle_args_set_hexpand(UiContentToggleArgs *args, UiBool value) { + args->hexpand = value; +} + +void ui_content_toggle_args_set_vexpand(UiContentToggleArgs *args, UiBool value) { + args->vexpand = value; +} + +void ui_content_toggle_args_set_hfill(UiContentToggleArgs *args, UiBool value) { + args->hfill = value; +} + +void ui_content_toggle_args_set_vfill(UiContentToggleArgs *args, UiBool value) { + args->vfill = value; +} + +void ui_content_toggle_args_set_override_defaults(UiContentToggleArgs *args, UiBool value) { + args->override_defaults = value; +} + +void ui_content_toggle_args_set_margin(UiContentToggleArgs *args, int value) { + args->margin = value; +} + +void ui_content_toggle_args_set_margin_left(UiContentToggleArgs *args, int value) { + args->margin_left = value; +} + +void ui_content_toggle_args_set_margin_right(UiContentToggleArgs *args, int value) { + args->margin_right = value; +} + +void ui_content_toggle_args_set_margin_top(UiContentToggleArgs *args, int value) { + args->margin_top = value; +} + +void ui_content_toggle_args_set_margin_bottom(UiContentToggleArgs *args, int value) { + args->margin_bottom = value; +} + +void ui_content_toggle_args_set_colspan(UiContentToggleArgs *args, int colspan) { + args->colspan = colspan; +} + +void ui_content_toggle_args_set_rowspan(UiContentToggleArgs *args, int rowspan) { + args->rowspan = rowspan; +} + + +void ui_content_toggle_args_set_name(UiContentToggleArgs *args, const char *name) { + args->name = strdup(name); +} + +void ui_content_toggle_args_set_style_class(UiContentToggleArgs *args, const char *classname) { + args->style_class = strdup(classname); +} + +void ui_content_toggle_args_set_label0(UiContentToggleArgs *args, const char *label){ + args->label0 = strdup(label); +} + +void ui_content_toggle_args_set_icon0(UiContentToggleArgs *args, const char *icon){ + args->icon0 = strdup(icon); +} + +void ui_content_toggle_args_set_tooltip0(UiContentToggleArgs *args, const char *tooltip) { + args->tooltip0 = strdup(tooltip); +} + +void ui_content_toggle_args_set_label1(UiContentToggleArgs *args, const char *label){ + args->label1 = strdup(label); +} + +void ui_content_toggle_args_set_icon1(UiContentToggleArgs *args, const char *icon){ + args->icon1 = strdup(icon); +} + +void ui_content_toggle_args_set_tooltip1(UiContentToggleArgs *args, const char *tooltip) { + args->tooltip1 = strdup(tooltip); +} + +void ui_content_toggle_args_set_labeltype(UiContentToggleArgs *args, int labeltype){ + args->labeltype = labeltype; +} + +void ui_content_toggle_args_set_onchange(UiContentToggleArgs *args, ui_callback callback){ + args->onchange = callback; +} + +void ui_content_toggle_args_set_onchangedata(UiContentToggleArgs *args, void *onchangedata){ + args->onchangedata = onchangedata; +} + +void ui_content_toggle_args_set_action(UiContentToggleArgs *args, const char *action) { + args->action = strdup(action); +} + +void ui_content_toggle_args_set_varname(UiContentToggleArgs *args, const char *varname) { + args->varname = strdup(varname); +} + +void ui_content_toggle_args_set_value(UiContentToggleArgs *args, UiInteger *value) { + args->value = value; +} + +void ui_content_toggle_args_set_toggled_by_state(UiContentToggleArgs *args, int state) { + args->toggled_by_state = state; +} + +void ui_content_toggle_args_set_istogglebutton(UiContentToggleArgs *args, UiBool value) { + args->istogglebutton = value; +} + +void ui_content_toggle_args_set_enablestate(UiContentToggleArgs *args, int state) { + args->enable_state = state; +} + +void ui_content_toggle_args_set_states(UiContentToggleArgs *args, int *states, int numstates) { + args->states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->states, states, numstates * sizeof(int)); + ((int*)args->states)[numstates] = -1; +} + +void ui_content_toggle_args_set_visibility_states(UiContentToggleArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + +void ui_content_toggle_args_free(UiContentToggleArgs *args) { + free((void*)args->name); + free((void*)args->style_class); + free((void*)args->label0); + free((void*)args->icon0); + free((void*)args->tooltip0); + free((void*)args->label1); + free((void*)args->icon1); + free((void*)args->tooltip1); + free((void*)args->varname); + free((void*)args->action); + free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -1625,6 +1959,10 @@ void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata) args->onclickdata = userdata; } +void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action) { + args->action = strdup(action); +} + void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value) { args->nofollow = value; } @@ -1647,11 +1985,18 @@ void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int nums ((int*)args->states)[numstates] = -1; } +void ui_linkbutton_args_set_visibility_states(UiLinkButtonArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_linkbutton_args_free(UiLinkButtonArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->label); free((void*)args->uri); + free((void*)args->action); free((void*)args->varname); free((void*)args->states); free(args); @@ -1775,6 +2120,10 @@ void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata) { args->onactivatedata = userdata; } +void ui_list_args_set_onactivate_action(UiListArgs *args, const char *action) { + args->onactivate_action = strdup(action); +} + void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback) { args->onselection = callback; } @@ -1783,6 +2132,10 @@ void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata) { args->onselectiondata = userdata; } +void ui_list_args_set_onselection_action(UiListArgs *args, const char *action) { + args->onselection_action = strdup(action); +} + void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback) { args->ondragstart = callback; } @@ -1791,6 +2144,10 @@ void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata) { args->ondragstartdata = userdata; } +void ui_list_args_set_ondragstart_action(UiListArgs *args, const char *action) { + args->ondragstart_action = strdup(action); +} + void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback) { args->ondragcomplete = callback; } @@ -1799,6 +2156,10 @@ void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata) { args->ondragcompletedata = userdata; } +void ui_list_args_set_ondragcomplete_action(UiListArgs *args, const char *action) { + args->ondragcomplete_action = strdup(action); +} + void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback) { args->ondrop = callback; } @@ -1807,6 +2168,10 @@ void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata) { args->ondropdata = userdata; } +void ui_list_args_set_ondrop_action(UiListArgs *args, const char *action) { + args->ondrop_action = strdup(action); +} + void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave) { args->onsave = onsave; } @@ -1829,10 +2194,21 @@ void ui_list_args_set_states(UiListArgs *args, int *states, int numstates) { ((int*)args->states)[numstates] = -1; } +void ui_list_args_set_visibility_states(UiListArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_list_args_free(UiListArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->onactivate_action); + free((void*)args->onselection_action); + free((void*)args->ondragstart_action); + free((void*)args->ondragcomplete_action); + free((void*)args->ondrop_action); if(args->static_elements) { for(int i=0;istatic_nelm;i++) { free(args->static_elements[i]); @@ -1840,6 +2216,7 @@ void ui_list_args_free(UiListArgs *args) { free(args->static_elements); } free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -1961,7 +2338,6 @@ void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback ca } - void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata) { args->onbuttonclickdata = userdata; } @@ -1974,12 +2350,25 @@ void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value) args->header_is_item = value; } +UIEXPORT void ui_sourcelist_args_set_states(UiSourceListArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->states, states, numstates * sizeof(int)); + ((int*)args->states)[numstates] = -1; +} + +void ui_sourcelist_args_set_visibility_states(UiSourceListArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_sourcelist_args_free(UiSourceListArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); free((void*)args->sublists); free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -2071,6 +2460,22 @@ void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata) args->onchangedata = onchangedata; } +void ui_textarea_args_set_onchange_action(UiTextAreaArgs *args, const char *action) { + args->onchange_action = strdup(action); +} + +void ui_textarea_args_set_ontextchanged(UiTextAreaArgs *args, ui_callback callback) { + args->ontextchanged = callback; +} + +void ui_textarea_args_set_ontextchangeddata(UiTextAreaArgs *args, void *onchangedata) { + args->ontextchangeddata = onchangedata; +} + +void ui_textarea_args_set_ontextchanged_action(UiTextAreaArgs *args, const char *action) { + args->ontextchanged_action = strdup(action); +} + void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname) { args->varname = strdup(varname); } @@ -2085,11 +2490,20 @@ void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstate ((int*)args->states)[numstates] = -1; } +void ui_textarea_args_set_visibility_states(UiTextAreaArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_textarea_args_free(UiTextAreaArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->onchange_action); + free((void*)args->ontextchanged_action); free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -2191,6 +2605,14 @@ void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivat args->onactivatedata = onactivatedata; } +void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action) { + args->onactivate_action = strdup(action); +} + +void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action) { + args->onchange_action = action; +} + void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname) { args->varname = strdup(varname); } @@ -2205,11 +2627,20 @@ void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numsta ((int*)args->states)[numstates] = -1; } +void ui_textfield_args_set_visibility_states(UiTextFieldArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_textfield_args_free(UiTextFieldArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); + free((void*)args->onactivate_action); + free((void*)args->onchange_action); free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -2328,11 +2759,18 @@ void ui_spinbox_args_set_states(UiSpinBoxArgs *args, int *states, int numstates) ((int*)args->states)[numstates] = -1; } +void ui_spinbox_args_set_visibility_states(UiSpinBoxArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_spinbox_args_free(UiSpinBoxArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); free((void*)args->states); + free((void*)args->visibility_states); free(args); } @@ -2428,11 +2866,18 @@ void ui_webview_args_set_states(UiWebviewArgs *args, int *states, int numstates) ((int*)args->states)[numstates] = -1; } +void ui_webview_args_set_visibility_states(UiWebviewArgs *args, int *states, int numstates) { + args->visibility_states = calloc(numstates+1, sizeof(int)); + memcpy((void*)args->visibility_states, states, numstates * sizeof(int)); + ((int*)args->visibility_states)[numstates] = -1; +} + void ui_webview_args_free(UiWebviewArgs *args) { free((void*)args->name); free((void*)args->style_class); free((void*)args->varname); free((void*)args->states); + free((void*)args->visibility_states); free(args); } diff --git a/ui/common/args.h b/ui/common/args.h index 12c0160..7a8dbd7 100644 --- a/ui/common/args.h +++ b/ui/common/args.h @@ -83,6 +83,7 @@ UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon); UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback); UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata); +UIEXPORT void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action); UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args); UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void); @@ -91,11 +92,14 @@ UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname); UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback); UIEXPORT void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onchangedata); +UIEXPORT void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action); UIEXPORT void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args); UIEXPORT UiMenuItemListArgs* ui_menuitemlist_args_new(void); UIEXPORT void ui_menuitemlist_args_set_varname(UiMenuItemListArgs *args, const char *varname); UIEXPORT void ui_menuitemlist_args_set_getvalue(UiMenuItemListArgs *args, ui_getvaluefunc func); +UIEXPORT void ui_menuitemlist_args_set_getvalue2(UiMenuItemListArgs *args, ui_getvaluefunc2 func); +UIEXPORT void ui_menuitemlist_args_set_getvaluedata(UiMenuItemListArgs *args, void *data); UIEXPORT void ui_menuitemlist_args_set_onselect(UiMenuItemListArgs *args, ui_callback callback); UIEXPORT void ui_menuitemlist_args_set_onselectdata(UiMenuItemListArgs *args, void *data); UIEXPORT void ui_menuitemlist_args_set_addseparator(UiMenuItemListArgs *args, UiBool value); @@ -105,6 +109,7 @@ UIEXPORT UiToolbarItemArgs* ui_toolbar_item_args_new(void); UIEXPORT void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label); UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon); UIEXPORT void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip); +UIEXPORT void ui_toolbar_item_args_set_action(UiToolbarItemArgs *args, const char *action); UIEXPORT void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback); UIEXPORT void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata); UIEXPORT void ui_toolbar_item_args_set_states(UiToolbarItemArgs *args, int *states, int numstates); @@ -115,11 +120,28 @@ UIEXPORT void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args UIEXPORT void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon); UIEXPORT void ui_toolbar_toggleitem_args_set_tooltip(UiToolbarToggleItemArgs *args, const char *tooltip); UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname); +UIEXPORT void ui_toolbar_toggleitem_args_set_action(UiToolbarToggleItemArgs *args, const char *action); UIEXPORT void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback); UIEXPORT void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata); UIEXPORT void ui_toolbar_toggleitem_args_set_states(UiToolbarToggleItemArgs *args, int *states, int numstates); UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args); +UIEXPORT UiToolbarContentToggleItemArgs* ui_toolbar_content_toggleitem_args_new(void); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_label0(UiToolbarContentToggleItemArgs *args, const char *label); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_icon0(UiToolbarContentToggleItemArgs *args, const char *icon); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_tooltip0(UiToolbarContentToggleItemArgs *args, const char *tooltip); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_label1(UiToolbarContentToggleItemArgs *args, const char *label); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_icon1(UiToolbarContentToggleItemArgs *args, const char *icon); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_tooltip1(UiToolbarContentToggleItemArgs *args, const char *tooltip); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_varname(UiToolbarContentToggleItemArgs *args, const char *varname); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_action(UiToolbarContentToggleItemArgs *args, const char *action); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_onchange(UiToolbarContentToggleItemArgs *args, ui_callback callback); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_onchangedata(UiToolbarContentToggleItemArgs *args, void *onchangedata); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_states(UiToolbarContentToggleItemArgs *args, int *states, int numstates); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_istogglebutton(UiToolbarContentToggleItemArgs *args, UiBool value); +UIEXPORT void ui_toolbar_content_toggleitem_args_set_toggled_by_state(UiToolbarContentToggleItemArgs *args, int state); +UIEXPORT void ui_toolbar_content_toggleitem_args_free(UiToolbarContentToggleItemArgs *args); + UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void); UIEXPORT void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label); UIEXPORT void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon); @@ -149,6 +171,7 @@ UIEXPORT void ui_container_args_set_style_class(UiContainerArgs *args, const cha UIEXPORT void ui_container_args_set_spacing(UiContainerArgs *args, int value); UIEXPORT void ui_container_args_set_columnspacing(UiContainerArgs *args, int value); UIEXPORT void ui_container_args_set_rowspacing(UiContainerArgs *args, int value); +UIEXPORT void ui_container_args_set_visibility_states(UiContainerArgs *args, int *states, int numstates); UIEXPORT void ui_container_args_free(UiContainerArgs *args); UIEXPORT UiFrameArgs* ui_frame_args_new(void); @@ -174,6 +197,7 @@ UIEXPORT void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value); UIEXPORT void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value); UIEXPORT void ui_frame_args_set_expanded(UiFrameArgs *args, UiBool value); UIEXPORT void ui_frame_args_set_label(UiFrameArgs *args, const char *label); +UIEXPORT void ui_frame_args_set_visibility_states(UiFrameArgs *args, int *states, int numstates); UIEXPORT void ui_frame_args_free(UiFrameArgs *args); UIEXPORT UiSidebarArgs* ui_sidebar_args_new(void); @@ -211,6 +235,7 @@ UIEXPORT void ui_splitpane_args_set_position_property(UiSplitPaneArgs *args, con UIEXPORT void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname); UIEXPORT void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value); UIEXPORT void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max); +UIEXPORT void ui_splitpane_args_set_visibility_states(UiSplitPaneArgs *args, int *states, int numstates); UIEXPORT void ui_splitpane_args_free(UiSplitPaneArgs *args); UIEXPORT UiTabViewArgs* ui_tabview_args_new(void); @@ -239,6 +264,7 @@ UIEXPORT void ui_tabview_args_set_onchangedata(UiTabViewArgs *args, void *userda UIEXPORT void ui_tabview_args_set_varname(UiTabViewArgs *args, const char *varname); UIEXPORT void ui_tabview_args_set_value(UiTabViewArgs *args, UiInteger *value); UIEXPORT void ui_tabview_args_set_subcontainer(UiTabViewArgs *args, UiSubContainerType subcontainer); +UIEXPORT void ui_tabview_args_set_visibility_states(UiTabViewArgs *args, int *states, int numstates); UIEXPORT void ui_tabview_args_free(UiTabViewArgs *args); UIEXPORT UiWidgetArgs* ui_widget_args_new(void); @@ -280,6 +306,7 @@ UIEXPORT void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align); UIEXPORT void ui_label_args_set_style(UiLabelArgs *args, UiLabelStyle style); UIEXPORT void ui_label_args_set_value(UiLabelArgs *args, UiString *value); UIEXPORT void ui_label_args_set_varname(UiLabelArgs *args, const char *varname); +UIEXPORT void ui_label_args_set_visibility_states(UiLabelArgs *args, int *states, int numstates); UIEXPORT void ui_label_args_free(UiLabelArgs *args); UIEXPORT UiProgressbarArgs* ui_progressbar_args_new(void); @@ -302,6 +329,7 @@ UIEXPORT void ui_progressbar_args_set_min(UiProgressbarArgs *args, double min); UIEXPORT void ui_progressbar_args_set_max(UiProgressbarArgs *args, double max); UIEXPORT void ui_progressbar_args_set_value(UiProgressbarArgs *args, UiDouble *value); UIEXPORT void ui_progressbar_args_set_varname(UiProgressbarArgs *args, const char *varname); +UIEXPORT void ui_progressbar_args_set_visibility_states(UiProgressbarArgs *args, int *states, int numstates); UIEXPORT void ui_progressbar_args_free(UiProgressbarArgs *args); UIEXPORT UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void); @@ -322,6 +350,7 @@ UIEXPORT void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, UIEXPORT void ui_progress_spinner_args_set_style_class(UiProgressbarSpinnerArgs *args, const char *classname); UIEXPORT void ui_progress_spinner_args_set_value(UiProgressbarSpinnerArgs *args, UiInteger *value); UIEXPORT void ui_progress_spinner_args_set_varname(UiProgressbarSpinnerArgs *args, const char *varname); +UIEXPORT void ui_progress_spinner_args_set_visibility_states(UiProgressbarSpinnerArgs *args, int *states, int numstates); UIEXPORT void ui_progress_spinner_args_free(UiProgressbarSpinnerArgs *args); UIEXPORT UiButtonArgs* ui_button_args_new(void); @@ -346,7 +375,9 @@ UIEXPORT void ui_button_args_set_tooltip(UiButtonArgs *args, const char *tooltip UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype); UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback); UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata); +UIEXPORT void ui_button_args_set_action(UiButtonArgs *args, const char *action); UIEXPORT void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates); +UIEXPORT void ui_button_args_set_visibility_states(UiButtonArgs *args, int *states, int numstates); UIEXPORT void ui_button_args_free(UiButtonArgs *args); UIEXPORT UiToggleArgs* ui_toggle_args_new(void); @@ -371,12 +402,49 @@ UIEXPORT void ui_toggle_args_set_tooltip(UiToggleArgs *args, const char *tooltip UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype); UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback); UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata); +UIEXPORT void ui_toggle_args_set_action(UiToggleArgs *args, const char *action); UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname); UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value); UIEXPORT void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state); UIEXPORT void ui_toggle_args_set_states(UiToggleArgs *args, int *states, int numstates); +UIEXPORT void ui_toggle_args_set_visibility_states(UiToggleArgs *args, int *states, int numstates); UIEXPORT void ui_toggle_args_free(UiToggleArgs *args); +UIEXPORT UiContentToggleArgs* ui_content_toggle_args_new(void); +UIEXPORT void ui_content_toggle_args_set_fill(UiContentToggleArgs *args, UiBool fill); +UIEXPORT void ui_content_toggle_args_set_hexpand(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_vexpand(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_hfill(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_vfill(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_override_defaults(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_margin(UiContentToggleArgs *args, int value); +UIEXPORT void ui_content_toggle_args_set_margin_left(UiContentToggleArgs *args, int value); +UIEXPORT void ui_content_toggle_args_set_margin_right(UiContentToggleArgs *args, int value); +UIEXPORT void ui_content_toggle_args_set_margin_top(UiContentToggleArgs *args, int value); +UIEXPORT void ui_content_toggle_args_set_margin_bottom(UiContentToggleArgs *args, int value); +UIEXPORT void ui_content_toggle_args_set_colspan(UiContentToggleArgs *args, int colspan); +UIEXPORT void ui_content_toggle_args_set_rowspan(UiContentToggleArgs *args, int rowspan); +UIEXPORT void ui_content_toggle_args_set_name(UiContentToggleArgs *args, const char *name); +UIEXPORT void ui_content_toggle_args_set_style_class(UiContentToggleArgs *args, const char *classname); +UIEXPORT void ui_content_toggle_args_set_label0(UiContentToggleArgs *args, const char *label); +UIEXPORT void ui_content_toggle_args_set_icon0(UiContentToggleArgs *args, const char *icon); +UIEXPORT void ui_content_toggle_args_set_tooltip0(UiContentToggleArgs *args, const char *tooltip); +UIEXPORT void ui_content_toggle_args_set_label1(UiContentToggleArgs *args, const char *label); +UIEXPORT void ui_content_toggle_args_set_icon1(UiContentToggleArgs *args, const char *icon); +UIEXPORT void ui_content_toggle_args_set_tooltip1(UiContentToggleArgs *args, const char *tooltip); +UIEXPORT void ui_content_toggle_args_set_labeltype(UiContentToggleArgs *args, int labeltype); +UIEXPORT void ui_content_toggle_args_set_onchange(UiContentToggleArgs *args, ui_callback callback); +UIEXPORT void ui_content_toggle_args_set_onchangedata(UiContentToggleArgs *args, void *onchangedata); +UIEXPORT void ui_content_toggle_args_set_action(UiContentToggleArgs *args, const char *action); +UIEXPORT void ui_content_toggle_args_set_varname(UiContentToggleArgs *args, const char *varname); +UIEXPORT void ui_content_toggle_args_set_value(UiContentToggleArgs *args, UiInteger *value); +UIEXPORT void ui_content_toggle_args_set_toggled_by_state(UiContentToggleArgs *args, int state); +UIEXPORT void ui_content_toggle_args_set_istogglebutton(UiContentToggleArgs *args, UiBool value); +UIEXPORT void ui_content_toggle_args_set_enablestate(UiContentToggleArgs *args, int state); +UIEXPORT void ui_content_toggle_args_set_states(UiContentToggleArgs *args, int *states, int numstates); +UIEXPORT void ui_content_toggle_args_set_visibility_states(UiContentToggleArgs *args, int *states, int numstates); +UIEXPORT void ui_content_toggle_args_free(UiContentToggleArgs *args); + UIEXPORT UiLinkButtonArgs* ui_linkbutton_args_new(void); UIEXPORT void ui_linkbutton_args_set_fill(UiLinkButtonArgs *args, UiBool fill); UIEXPORT void ui_linkbutton_args_set_hexpand(UiLinkButtonArgs *args, UiBool value); @@ -399,9 +467,11 @@ UIEXPORT void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *l UIEXPORT void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri); UIEXPORT void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback); UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata); +UIEXPORT void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action); UIEXPORT void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value); UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type); UIEXPORT void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates); +UIEXPORT void ui_linkbutton_args_set_visibility_states(UiLinkButtonArgs *args, int *states, int numstates); UIEXPORT void ui_linkbutton_args_free(UiLinkButtonArgs *args); UIEXPORT UiListArgs* ui_list_args_new(void); @@ -431,19 +501,25 @@ UIEXPORT void ui_list_args_set_getstyle_func(UiListArgs *args, ui_getstylefunc g UIEXPORT void ui_list_args_set_getstyle_data(UiListArgs *args, void *userdata); UIEXPORT void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback); UIEXPORT void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata); +UIEXPORT void ui_list_args_set_onactivate_action(UiListArgs *args, const char *action); UIEXPORT void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback); UIEXPORT void ui_list_args_set_onselectiondata(UiListArgs *args, void *userdata); +UIEXPORT void ui_list_args_set_onselection_action(UiListArgs *args, const char *action); UIEXPORT void ui_list_args_set_ondragstart(UiListArgs *args, ui_callback callback); UIEXPORT void ui_list_args_set_ondragstartdata(UiListArgs *args, void *userdata); +UIEXPORT void ui_list_args_set_ondragstart_action(UiListArgs *args, const char *action); UIEXPORT void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback callback); UIEXPORT void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata); +UIEXPORT void ui_list_args_set_ondragcomplete_action(UiListArgs *args, const char *action); UIEXPORT void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback); UIEXPORT void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata); +UIEXPORT void ui_list_args_set_ondrop_action(UiListArgs *args, const char *action); UIEXPORT void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave); UIEXPORT void ui_list_args_set_onsavedata(UiListArgs *args, void *userdata); UIEXPORT void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection); UIEXPORT void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder); UIEXPORT void ui_list_args_set_states(UiListArgs *args, int *states, int numstates); +UIEXPORT void ui_list_args_set_visibility_states(UiListArgs *args, int *states, int numstates); UIEXPORT void ui_list_args_free(UiListArgs *args); UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void); @@ -473,6 +549,8 @@ UIEXPORT void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_ca UIEXPORT void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata); UIEXPORT void ui_sourcelist_args_set_contextmenu(UiSourceListArgs *args, UiMenuBuilder *menubuilder); UIEXPORT void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value); +UIEXPORT void ui_sourcelist_args_set_states(UiSourceListArgs *args, int *states, int numstates); +UIEXPORT void ui_sourcelist_args_set_visibility_states(UiSourceListArgs *args, int *states, int numstates); UIEXPORT void ui_sourcelist_args_free(UiSourceListArgs *args); UIEXPORT UiTextAreaArgs* ui_textarea_args_new(void); @@ -493,9 +571,14 @@ UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name); UIEXPORT void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname); UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback); UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata); +UIEXPORT void ui_textarea_args_set_onchange_action(UiTextAreaArgs *args, const char *action); +UIEXPORT void ui_textarea_args_set_ontextchanged(UiTextAreaArgs *args, ui_callback callback); +UIEXPORT void ui_textarea_args_set_ontextchangeddata(UiTextAreaArgs *args, void *onchangedata); +UIEXPORT void ui_textarea_args_set_ontextchanged_action(UiTextAreaArgs *args, const char *action); UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname); UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value); UIEXPORT void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates); +UIEXPORT void ui_textarea_args_set_visibility_states(UiTextAreaArgs *args, int *states, int numstates); UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args); UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void); @@ -518,9 +601,12 @@ UIEXPORT void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback UIEXPORT void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata); UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback); UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata); +UIEXPORT void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action); +UIEXPORT void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action); UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname); UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value); UIEXPORT void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates); +UIEXPORT void ui_textfield_args_set_visibility_states(UiTextFieldArgs *args, int *states, int numstates); UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args); UIEXPORT UiSpinBoxArgs* ui_spinbox_args_new(void); @@ -550,6 +636,7 @@ UIEXPORT void ui_spinbox_args_set_intvalue(UiSpinBoxArgs *args, UiInteger *value UIEXPORT void ui_spinbox_args_set_doublevalue(UiSpinBoxArgs *args, UiDouble *value); UIEXPORT void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value); UIEXPORT void ui_spinbox_args_set_states(UiSpinBoxArgs *args, int *states, int numstates); +UIEXPORT void ui_spinbox_args_set_visibility_states(UiSpinBoxArgs *args, int *states, int numstates); UIEXPORT void ui_spinbox_args_free(UiSpinBoxArgs *args); UIEXPORT UiWebviewArgs* ui_webview_args_new(void); @@ -571,6 +658,7 @@ UIEXPORT void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *c UIEXPORT void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname); UIEXPORT void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value); UIEXPORT void ui_webview_args_set_states(UiWebviewArgs *args, int *states, int numstates); +UIEXPORT void ui_webview_args_set_visibility_states(UiWebviewArgs *args, int *states, int numstates); UIEXPORT void ui_webview_args_free(UiWebviewArgs *args); #ifdef __cplusplus diff --git a/ui/common/container.c b/ui/common/container.c index 6f0dde9..12c6267 100644 --- a/ui/common/container.c +++ b/ui/common/container.c @@ -33,13 +33,13 @@ void ui_end_new(UiObject *obj) { if(!obj->container_end) { return; } - UiContainerX *rm = obj->container_end; + UiContainer *rm = obj->container_end; uic_object_pop_container(obj); ui_free(obj->ctx, rm); } void ui_newline(UiObject *obj) { - UiContainerX *container = obj->container_end; + UiContainer *container = obj->container_end; if(container) { container->newline = TRUE; } diff --git a/ui/common/context.c b/ui/common/context.c index 9ddfdb7..757056f 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -67,9 +67,11 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { ctx->state_widgets = cxLinkedListCreate(mp->allocator, sizeof(UiStateWidget)); ctx->states = cxArrayListCreate(mp->allocator, sizeof(int), 32); cxSetCompareFunc(ctx->states, cx_cmp_int); + ctx->suppressed_states = cxArrayListCreate(mp->allocator, sizeof(int), 16); + cxSetCompareFunc(ctx->suppressed_states, cx_cmp_int); - ctx->attach_document = uic_context_attach_document; - ctx->detach_document2 = uic_context_detach_document; + ctx->actions = cxHashMapCreate(ctx->allocator, sizeof(UiAction), 8); + ctx->action_bindings = cxArrayListCreate(ctx->allocator, sizeof(UiActionBinding), 0); #if UI_GTK2 || UI_GTK3 if(toplevel && toplevel->widget) { @@ -78,6 +80,8 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { } #endif + ctx->ref = 1; + return ctx; } @@ -92,33 +96,64 @@ void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *d cxListAdd(ctx->destroy_handler, &handler); } +void uic_context_remove_destructor(UiContext *ctx, void *data) { + CxIterator i = cxListIterator(ctx->destroy_handler); + cx_foreach(UiDestroyHandler *, handler, i) { + if(handler->data == data) { + cxIteratorFlagRemoval(i); + } + } +} + void uic_context_prepare_close(UiContext *ctx) { cxListClear(ctx->states); cxListClear(ctx->state_widgets); + cxListClear(ctx->action_bindings); + uic_context_detach_all(ctx); } -void uic_context_attach_document(UiContext *ctx, void *document) { - if(ctx->single_document_mode) { - if(ctx->document) { - uic_context_detach_document(ctx, ctx->document); - } +void uic_context_destroy(UiContext *ctx, void *document) { + if(!ctx) { + return; } - cxListAdd(ctx->documents, document); - ctx->document = document; + UiEvent ev; + ev.obj = ctx->obj; + ev.window = ev.obj ? ev.obj->window : NULL; + ev.document = document; + ev.eventdata = NULL; + ev.eventdatatype = 0; + ev.intval = 0; + ev.set = 0; + + if(ctx->onclose) { + ctx->onclose(&ev, ctx->onclosedata); + } - UiContext *doc_ctx = ui_document_context(document); - doc_ctx->parent = ctx; + CxIterator i = cxListIterator(ctx->destroy_handler); + cx_foreach(UiDestroyHandler *, h, i) { + h->destructor(h->data); + } + uic_context_detach_all(ctx); + + cxMempoolFree(ctx->mp); +} + +void uic_context_update_bindings(UiContext *ctx) { + int onchange_enabled = ui_onchange_events_is_enabled(); + int onselection_enabled = ui_selection_events_is_enabled(); + ui_onchange_events_enable(FALSE); + ui_selection_events_enable(FALSE); // if a document variable has the same name as a parent variable, // move the bindings to the document - UiContext *var_ctx = ctx; + UiContext *var_ctx = ctx->parent; while(var_ctx) { CxMapIterator i = cxMapIterator(var_ctx->vars); cx_foreach(CxMapEntry*, entry, i) { - printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data); + // printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data); UiVar *var = entry->value; - UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key); + UiVar *docvar = cxMapGet(ctx->vars, *entry->key); if(docvar) { // bind var to document var uic_copy_var_binding(var, docvar, TRUE); @@ -128,13 +163,59 @@ void uic_context_attach_document(UiContext *ctx, void *document) { var_ctx = var_ctx->parent; } + + ui_update_action_bindings(ctx); + + if(ctx->documents) { + CxIterator i = cxListIterator(ctx->documents); + cx_foreach(void *, doc, i) { + UiContext *subctx = ui_document_context(doc); + uic_context_update_bindings(subctx); + } + } + ui_onchange_events_enable(onchange_enabled); + ui_selection_events_enable(onselection_enabled); +} + +void uic_context_attach_document(UiContext *ctx, void *document) { + if(ctx->single_document_mode) { + if(ctx->document) { + uic_context_detach_document(ctx, ctx->document); + } + } + + cxListAdd(ctx->documents, document); + ctx->document = document; + + UiContext *doc_ctx = ui_document_context(document); + doc_ctx->parent = ctx; + doc_ctx->ref++; + + uic_context_update_bindings(doc_ctx); + if(doc_ctx->onattach) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.document = document; + doc_ctx->onattach(&event, doc_ctx->onattachdata); + } + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); + UiObject *obj = ui_context_get_parent_obj(ctx); + uic_send_status_change(doc_ctx, obj); + + UiContext *obj_ctx = uic_obj_context(ctx); + if(obj_ctx) { + ui_update_action_bindings(obj_ctx); + } } static void uic_context_unbind_vars(UiContext *ctx) { + int onchange_enabled = ui_onchange_events_is_enabled(); + int onselection_enabled = ui_selection_events_is_enabled(); ui_onchange_events_enable(FALSE); + ui_selection_events_enable(FALSE); CxMapIterator mi = cxMapIterator(ctx->vars); cx_foreach(CxMapEntry*, entry, mi) { - printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data); + //printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data); UiVar *var = entry->value; // var->from && var->from_ctx && var->from_ctx != ctx uic_save_var(var); @@ -154,7 +235,8 @@ static void uic_context_unbind_vars(UiContext *ctx) { } } - ui_onchange_events_enable(TRUE); + ui_onchange_events_enable(onchange_enabled); + ui_selection_events_enable(onselection_enabled); } void uic_context_detach_document(UiContext *ctx, void *document) { @@ -167,9 +249,24 @@ void uic_context_detach_document(UiContext *ctx, void *document) { cxListRemove(ctx->documents, docIndex); ctx->document = cxListAt(ctx->documents, 0); - UiContext *docctx = ui_document_context(document); - uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent - docctx->parent = NULL; + UiContext *doc_ctx = ui_document_context(document); + uic_context_unbind_vars(doc_ctx); // unbind all doc/subdoc vars from the parent + doc_ctx->parent = NULL; + + UiContext *obj_ctx = uic_obj_context(ctx); + if(obj_ctx) { + ui_update_action_bindings(obj_ctx); + } + if(doc_ctx->ondetach) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.document = document; + doc_ctx->ondetach(&event, doc_ctx->ondetachdata); + } + + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); + uic_send_status_change(doc_ctx, NULL); + ui_document_unref(document); } void uic_context_detach_all(UiContext *ctx) { @@ -183,12 +280,40 @@ void uic_context_detach_all(UiContext *ctx) { // detach documents i = cxListIterator(ls); cx_foreach(void *, doc, i) { - ctx->detach_document2(ctx, doc); + uic_context_detach_document(ctx, doc); } cxListFree(ls); + ui_update_action_bindings(ctx); } +static void send_status_change(UiContext *ctx, UiEvent *event, UiObject *obj) { + CxIterator i = cxListIterator(ctx->documents); + cx_foreach(void *, doc, i) { + UiContext *doc_ctx = ui_document_context(doc); + if(doc_ctx->onattachmentstatuschange) { + event->obj = doc_ctx->obj ? doc_ctx->obj : obj; + event->window = event->obj ? event->obj->window : NULL; + event->document = doc_ctx->self_doc ? doc_ctx->self_doc : doc_ctx->document; + doc_ctx->onattachmentstatuschange(event, doc_ctx->onattachmentstatuschangedata); + } + } + + if(ctx->onattachmentstatuschange) { + event->obj = ctx->obj ? ctx->obj : obj; + event->window = event->obj ? event->obj->window : NULL; + event->document = ctx->self_doc ? ctx->self_doc : ctx->document; + ctx->onattachmentstatuschange(event, ctx->onattachmentstatuschangedata); + } +} + +void uic_send_status_change(UiContext *ctx, UiObject *obj) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + send_status_change(ctx, &event, obj); +} + + static UiVar* ctx_getvar(UiContext *ctx, CxHashKey key) { UiVar *var = cxMapGet(ctx->vars, key); if(!var && ctx->documents) { @@ -404,8 +529,21 @@ void uic_copy_value_binding(UiVarType type, void *from, void *to) { case UI_VAR_LIST: { UiList *f = from; UiList *t = to; + // save selection + ui_list_selection_free(f->saved_selection); + if(f->getselection && f->save_selection) { + f->saved_selection = ui_list_get_selection_allocated(f); + } else { + f->saved_selection = NULL; + } + uic_list_copy(f, t); ui_list_update(t); + if(t->setselection && t->saved_selection) { + t->setselection(t, *t->saved_selection); + } + ui_list_selection_free(t->saved_selection); + t->saved_selection = NULL; break; } case UI_VAR_RANGE: { @@ -517,22 +655,23 @@ void ui_detach_document(UiContext *ctx, void *document) { } void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) { - ctx->close_callback = fnc; - ctx->close_data = udata; -} - -void ui_context_destroy(UiContext *ctx) { - CxIterator i = cxListIterator(ctx->destroy_handler); - cx_foreach(UiDestroyHandler *, h, i) { - h->destructor(h->data); - } - cxMempoolFree(ctx->mp); + ctx->onclose = fnc; + ctx->onclosedata = udata; } UiContext* ui_context_parent(UiContext *ctx) { return ctx->parent; } +UiContext* ui_context_toplevel_parent(UiContext *ctx) { + if(ctx->obj) { + return ctx; + } else if (ctx->parent) { + return ui_context_toplevel_parent(ctx->parent); + } + return NULL; +} + void ui_set_state(UiContext *ctx, int state) { if(!cxListIndexValid(ctx->states, cxListFind(ctx->states, &state))) { @@ -540,7 +679,7 @@ void ui_set_state(UiContext *ctx, int state) { } // enable/disable group widgets - uic_check_state_widgets(ctx); + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); } void ui_unset_state(UiContext *ctx, int state) { @@ -550,25 +689,94 @@ void ui_unset_state(UiContext *ctx, int state) { } // enable/disable group widgets - uic_check_state_widgets(ctx); + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); +} + +void ui_suppress_state(UiContext *ctx, int state) { + if(!cxListIndexValid(ctx->suppressed_states, cxListFind(ctx->suppressed_states, &state))) { + cxListAdd(ctx->suppressed_states, &state); + } + + // enable/disable group widgets + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); +} + +void ui_unsuppress_state(UiContext *ctx, int state) { + int i = cxListFind(ctx->suppressed_states, &state); + if(i != -1) { + cxListRemove(ctx->suppressed_states, i); + } + + // enable/disable group widgets + uic_check_state_widgets(ui_context_toplevel_parent(ctx)); +} + +typedef struct StatesList { + CX_ARRAY(int, states); + CX_ARRAY(int, suppressed); +} StatesList; + +static void add_ctx_states(UiContext *ctx, StatesList *states) { + size_t nstates = cxListSize(ctx->states); + int *ctx_states = cxListAt(ctx->states, 0); + + size_t nsuppressed = cxListSize(ctx->suppressed_states); + int *ctx_suppressed_states = cxListAt(ctx->suppressed_states, 0); + + cx_array_add_array(states->states, ctx_states, nstates); + cx_array_add_array(states->suppressed, ctx_suppressed_states, nsuppressed); + + CxIterator i = cxListIterator(ctx->documents); + cx_foreach(void *, doc, i) { + UiContext *doc_ctx = ui_document_context(doc); + add_ctx_states(doc_ctx, states); + } } int* ui_active_states(UiContext *ctx, int *nstates) { - *nstates = cxListSize(ctx->states); - return cxListAt(ctx->states, 0); + StatesList states; + cx_array_init(states.states, 32); + cx_array_init(states.suppressed, 8); + add_ctx_states(ctx, &states); + + // remove suppressed states + for(size_t i=0;istate_widgets); cx_foreach(UiStateWidget *, gw, i) { char *check = calloc(1, gw->numstates); - for(int i=0;inumstates;k++) { - if(groups[i] == gw->states[k]) { + if(states[i] == gw->states[k]) { check[k] = 1; } } @@ -584,6 +792,8 @@ void uic_check_state_widgets(UiContext *ctx) { free(check); gw->enable(gw->widget, enable); } + + free(states); } void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) { @@ -621,6 +831,13 @@ void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int ui_widget_set_states2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates); } +void uic_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states) { + if(states) { + size_t nstates = uic_state_array_size(states); + ui_widget_set_visibility_states(ctx, widget, states, (int)nstates); + } +} + size_t uic_state_array_size(const int *states) { int i; for(i=0;states[i] >= 0;i++) { } @@ -661,26 +878,30 @@ void* ui_cx_mempool(UiContext *ctx) { } void* ui_malloc(UiContext *ctx, size_t size) { - return ctx ? cxMalloc(ctx->allocator, size) : NULL; + return ctx ? cxMalloc(ctx->allocator, size) : malloc(size); } void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize) { - return ctx ? cxCalloc(ctx->allocator, nelem, elsize) : NULL; + return ctx ? cxCalloc(ctx->allocator, nelem, elsize) : calloc(nelem, elsize); } void ui_free(UiContext *ctx, void *ptr) { - if(ctx && ptr) { - cxFree(ctx->allocator, ptr); + if(ptr) { + if(ctx) { + cxFree(ctx->allocator, ptr); + } else { + free(ptr); + } } } void* ui_realloc(UiContext *ctx, void *ptr, size_t size) { - return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL; + return ctx ? cxRealloc(ctx->allocator, ptr, size) : realloc(ptr, size); } char* ui_strdup(UiContext *ctx, const char *str) { if(!ctx) { - return NULL; + return strdup(str ? str : ""); } cxstring s = cx_str(str); cxmutstr d = cx_strdup_a(ctx->allocator, s); @@ -688,7 +909,12 @@ char* ui_strdup(UiContext *ctx, const char *str) { } void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) { - cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr); + //cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr); + uic_context_add_destructor(ctx, destr, data); +} + +void ui_remove_destructor(UiContext *ctx, void *data) { + uic_context_remove_destructor(ctx, data); } void ui_set_destructor(void *mem, ui_destructor_func destr) { @@ -840,3 +1066,66 @@ UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name) { UiVar *var = uic_get_var_t(ctx, name, UI_VAR_GENERIC); return var ? var->value : NULL; } + + + +void ui_context_onattach(UiContext *ctx, ui_callback cb, void *data) { + ctx->onattach = cb; + ctx->onattachdata = data; +} + +void ui_context_ondetach(UiContext *ctx, ui_callback cb, void *data) { + ctx->ondetach = cb; + ctx->ondetachdata = data; +} + +void ui_context_onattachmentstatuschange(UiContext *ctx, ui_callback cb, void *data) { + ctx->onattachmentstatuschange = cb; + ctx->onattachmentstatuschangedata = data; +} + +static void attachment_action_callback(UiEvent *event, void *action) { + if(event->document) { + UiContext *ctx = ui_document_context(event->document); + ui_call_action_on(ctx, action); + } +} + +void ui_context_onattach_action(UiContext *ctx, const char *action) { + ctx->onattach = attachment_action_callback; + ctx->onattachdata = ui_strdup(ctx, action); +} + +void ui_context_ondetach_action(UiContext *ctx, const char *action) { + ctx->ondetach = attachment_action_callback; + ctx->ondetachdata = ui_strdup(ctx, action); +} + +void ui_context_onattachmentstatuschange_action(UiContext *ctx, const char *action) { + ctx->onattachmentstatuschange = attachment_action_callback; + ctx->onattachmentstatuschangedata = ui_strdup(ctx, action); +} + + +int ui_context_is_attached(UiContext *ctx) { + return ctx->parent != NULL; +} + +int ui_context_is_attached_to_obj(UiContext *ctx) { + return uic_obj_context(ctx) != NULL; +} + +UIEXPORT UiObject* ui_context_get_parent_obj(UiContext *ctx) { + UiContext *obj_ctx = uic_obj_context(ctx); + return obj_ctx ? obj_ctx->obj : NULL; +} + +UiContext* uic_obj_context(UiContext *ctx) { + if(ctx->obj) { + return ctx; + } + if(ctx->parent == NULL) { + return NULL; + } + return uic_obj_context(ctx->parent); +} diff --git a/ui/common/context.h b/ui/common/context.h index 407c051..0718007 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -36,6 +36,8 @@ #include #include +#include "action.h" + #ifdef __cplusplus extern "C" { #endif @@ -60,20 +62,24 @@ typedef enum UiVarType { struct UiContext { UiContext *parent; UiObject *obj; - CxMempool *mp; + CxMempool *mp; const CxAllocator *allocator; CxList *destroy_handler; + // document pointer, if this is a document context + void *self_doc; + void *document; CxList *documents; CxMap *vars; CxList *states; // int list + CxList *suppressed_states; // int list CxList *state_widgets; // UiGroupWidget list - void (*attach_document)(UiContext *ctx, void *document); - void (*detach_document2)(UiContext *ctx, void *document); + CxMap *actions; // key: action name (string), value: UiAction + CxList *action_bindings; // UiActionBinding list char *title; @@ -93,8 +99,19 @@ struct UiContext { // attaching a document will automatically detach the current document UiBool single_document_mode; - ui_callback close_callback; - void *close_data; + ui_callback onattach; + void *onattachdata; + + ui_callback ondetach; + void *ondetachdata; + + ui_callback onattachmentstatuschange; + void *onattachmentstatuschangedata; + + ui_callback onclose; + void *onclosedata; + + unsigned int ref; }; struct UiVar { @@ -124,15 +141,20 @@ void uic_init_global_context(void); UiContext* uic_context(UiObject *toplevel, CxMempool *mp); UiContext* uic_root_context(UiContext *ctx); void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data); +void uic_context_remove_destructor(UiContext *ctx, void *data); void uic_context_prepare_close(UiContext *ctx); +void uic_context_destroy(UiContext *ctx, void *document); +void uic_context_update_bindings(UiContext *ctx); void uic_context_attach_document(UiContext *ctx, void *document); void uic_context_detach_document(UiContext *ctx, void *document); void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx); // TODO void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx); // TODO void uic_context_detach_all(UiContext *ctx); +void uic_send_status_change(UiContext *ctx, UiObject *obj); + UiVar* uic_get_var(UiContext *ctx, const char *name); UiVar* uic_get_var_t(UiContext *ctx, const char *name, UiVarType type); UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type); @@ -150,12 +172,26 @@ const char *uic_type2str(UiVarType type); void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value); +void uic_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states); size_t uic_state_array_size(const int *states); void uic_check_state_widgets(UiContext *ctx); void uic_add_state_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *states); void uic_add_state_widget_i(UiContext *ctx, void *widget, ui_enablefunc enable, const int *states, size_t numstates); void uic_remove_state_widget(UiContext *ctx, void *widget); +UiContext* uic_obj_context(UiContext *ctx); + +UIEXPORT void ui_context_onattach(UiContext *ctx, ui_callback cb, void *data); +UIEXPORT void ui_context_ondetach(UiContext *ctx, ui_callback cb, void *data); +UIEXPORT void ui_context_onattachmentstatuschange(UiContext *ctx, ui_callback cb, void *data); +UIEXPORT void ui_context_onattach_action(UiContext *ctx, const char *action); +UIEXPORT void ui_context_ondetach_action(UiContext *ctx, const char *action); +UIEXPORT void ui_context_onattachmentstatuschange_action(UiContext *ctx, const char *action); + +UIEXPORT int ui_context_is_attached(UiContext *ctx); +UIEXPORT int ui_context_is_attached_to_obj(UiContext *ctx); +UIEXPORT UiObject* ui_context_get_parent_obj(UiContext *ctx); + #ifdef __cplusplus } #endif diff --git a/ui/common/document.c b/ui/common/document.c index 3eb5874..287b5b5 100644 --- a/ui/common/document.c +++ b/ui/common/document.c @@ -45,24 +45,27 @@ void* ui_document_new(size_t size) { UiDoc *document = cxCalloc(a, sizeof(UiDoc) + size, 1); document->ctx = ctx; - return &document->doc; + ctx->self_doc = &document->doc; + return ctx->self_doc; } 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; - - if(ctx->close_callback) { - ctx->close_callback(&ev, ctx->close_data); + ctx->ref++; + } +} + +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); } } @@ -75,3 +78,52 @@ 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; +} + +void ui_document_onattach(void *doc, ui_callback cb, void *data) { + UiContext *ctx = ui_document_context(doc); + ui_context_onattach(ctx, cb, data); +} + +void ui_document_ondetach(void *doc, ui_callback cb, void *data) { + UiContext *ctx = ui_document_context(doc); + ui_context_ondetach(ctx, cb, data); +} + +void ui_document_onattachmentstatuschange(void *doc, ui_callback cb, void *data) { + UiContext *ctx = ui_document_context(doc); + ui_context_onattachmentstatuschange(ctx, cb, data); +} + +void ui_document_onattach_action(void *doc, const char *action) { + UiContext *ctx = ui_document_context(doc); + ui_context_onattach_action(ctx, action); +} + +void ui_document_ondetach_action(void *doc, const char *action) { + UiContext *ctx = ui_document_context(doc); + ui_context_ondetach_action(ctx, action); +} + +void ui_document_onattachmentstatuschange_action(void *doc, const char *action) { + UiContext *ctx = ui_document_context(doc); + ui_context_onattachmentstatuschange_action(ctx, action); +} + + +int ui_document_is_attached(void *doc) { + UiContext *ctx = ui_document_context(doc); + return ui_context_is_attached(ctx); +} + +int ui_document_is_attached_to_obj(void *doc) { + UiContext *ctx = ui_document_context(doc); + return ui_context_is_attached_to_obj(ctx); +} diff --git a/ui/common/icons.c b/ui/common/icons.c new file mode 100644 index 0000000..377b1a7 --- /dev/null +++ b/ui/common/icons.c @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "icons.h" + +const char* ui_icon_name(enum UiIconId icon_id) { + switch(icon_id) { + case UI_ICON_ID_HOME : return UI_ICON_HOME; + case UI_ICON_ID_NEW_WINDOW : return UI_ICON_NEW_WINDOW; + case UI_ICON_ID_NEW_TAB : return UI_ICON_NEW_TAB; + case UI_ICON_ID_NEW_FOLDER : return UI_ICON_NEW_FOLDER; + case UI_ICON_ID_NEW_DOCUMENT : return UI_ICON_NEW_DOCUMENT; + case UI_ICON_ID_NEW_APPOINTMENT : return UI_ICON_NEW_APPOINTMENT; + case UI_ICON_ID_NEW_CHAT_MESSAGE : return UI_ICON_NEW_CHAT_MESSAGE; + case UI_ICON_ID_NEW_CONTACT : return UI_ICON_NEW_CONTACT; + case UI_ICON_ID_NEW_MAIL : return UI_ICON_NEW_MAIL; + case UI_ICON_ID_ADD_BOOKMARK : return UI_ICON_ADD_BOOKMARK; + case UI_ICON_ID_ADD_IMAGE : return UI_ICON_ADD_IMAGE; + case UI_ICON_ID_ADD_LINK : return UI_ICON_ADD_LINK; + case UI_ICON_ID_ADD_TEXT : return UI_ICON_ADD_TEXT; + case UI_ICON_ID_ADD : return UI_ICON_ADD; + case UI_ICON_ID_REMOVE : return UI_ICON_REMOVE; + case UI_ICON_ID_REFRESH : return UI_ICON_REFRESH; + case UI_ICON_ID_UPLOAD : return UI_ICON_UPLOAD; + case UI_ICON_ID_SAVE_LOCAL : return UI_ICON_SAVE_LOCAL; + case UI_ICON_ID_EDIT_COPY : return UI_ICON_EDIT_COPY; + case UI_ICON_ID_EDIT_CUT : return UI_ICON_EDIT_CUT; + case UI_ICON_ID_EDIT_DELETE : return UI_ICON_EDIT_DELETE; + case UI_ICON_ID_EDIT_PASTE : return UI_ICON_EDIT_PASTE ; + case UI_ICON_ID_UNDO : return UI_ICON_UNDO; + case UI_ICON_ID_REDO : return UI_ICON_REDO; + case UI_ICON_ID_SIDEBAR_LEFT : return UI_ICON_SIDEBAR_LEFT; + case UI_ICON_ID_SIDEBAR_RIGHT : return UI_ICON_SIDEBAR_RIGHT; + case UI_ICON_ID_GO_BACK : return UI_ICON_GO_BACK; + case UI_ICON_ID_GO_FORWARD : return UI_ICON_GO_FORWARD ; + case UI_ICON_ID_GO_UP : return UI_ICON_GO_UP; + case UI_ICON_ID_GO_DOWN : return UI_ICON_GO_DOWN; + case UI_ICON_ID_VIEW_LIST : return UI_ICON_VIEW_LIST; + case UI_ICON_ID_VIEW_GRID : return UI_ICON_VIEW_GRID; + case UI_ICON_ID_VIEW_DUAL : return UI_ICON_VIEW_DUAL; + case UI_ICON_ID_VIEW_FULLSCREEN : return UI_ICON_VIEW_FULLSCREEN; + case UI_ICON_ID_VIEW_RESTORE : return UI_ICON_VIEW_RESTORE; + case UI_ICON_ID_TEXT_BOLD : return UI_ICON_TEXT_BOLD; + case UI_ICON_ID_TEXT_ITALIC : return UI_ICON_TEXT_ITALIC; + case UI_ICON_ID_TEXT_UNDERLINE : return UI_ICON_TEXT_UNDERLINE; + case UI_ICON_ID_LIST_BULLET : return UI_ICON_LIST_BULLET ; + case UI_ICON_ID_LIST_ORDERED : return UI_ICON_LIST_ORDERED; + case UI_ICON_ID_LIST_CHECK : return UI_ICON_LIST_CHECK; + case UI_ICON_ID_CHECKBOX : return UI_ICON_CHECKBOX; + case UI_ICON_ID_STAR : return UI_ICON_STAR; + case UI_ICON_ID_VIEW_REVEAL : return UI_ICON_VIEW_REVEAL; + case UI_ICON_ID_VIEW_CONCEAL : return UI_ICON_VIEW_CONCEAL; + case UI_ICON_ID_SETTINGS : return UI_ICON_SETTINGS; + case UI_ICON_ID_MEDIA_PLAY : return UI_ICON_MEDIA_PLAY; + case UI_ICON_ID_MEDIA_STOP : return UI_ICON_MEDIA_STOP; + case UI_ICON_ID_MEDIA_PAUSE : return UI_ICON_MEDIA_PAUSE; + case UI_ICON_ID_MEDIA_SEEK_BACKWARD : return UI_ICON_MEDIA_SEEK_BACKWARD; + case UI_ICON_ID_MEDIA_SEEK_FORWARD : return UI_ICON_MEDIA_SEEK_FORWARD; + case UI_ICON_ID_MEDIA_SKIP_BACKWARD : return UI_ICON_MEDIA_SKIP_BACKWARD; + case UI_ICON_ID_MEDIA_SKIP_FORWARD : return UI_ICON_MEDIA_SKIP_FORWARD; + case UI_ICON_ID_CALL_START : return UI_ICON_CALL_START; + case UI_ICON_ID_CALL_STOP : return UI_ICON_CALL_STOP; + case UI_ICON_ID_CALL_INCOMING : return UI_ICON_CALL_INCOMING; + case UI_ICON_ID_CALL_OUTGOING : return UI_ICON_CALL_OUTGOING; + case UI_ICON_ID_MICROPHONE_ON : return UI_ICON_MICROPHONE_ON; + case UI_ICON_ID_MICROPHONE_OFF : return UI_ICON_MICROPHONE_OFF; + case UI_ICON_ID_LOCKED : return UI_ICON_LOCKED; + case UI_ICON_ID_UNLOCKED : return UI_ICON_UNLOCKED; + case UI_ICON_ID_SECURE : return UI_ICON_SECURE; + case UI_ICON_ID_INSECURE : return UI_ICON_INSECURE; + } + return NULL; +} diff --git a/ui/common/icons.h b/ui/common/icons.h new file mode 100644 index 0000000..d7062a6 --- /dev/null +++ b/ui/common/icons.h @@ -0,0 +1,44 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UIC_ICONS_H +#define UIC_ICONS_H + +#include "../ui/icons.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* UIC_ICONS_H */ + diff --git a/ui/common/menu.c b/ui/common/menu.c index b0a5d2e..83eb258 100644 --- a/ui/common/menu.c +++ b/ui/common/menu.c @@ -44,6 +44,17 @@ static int menu_item_counter = 0; static void *tmp_eventdata; static int tmp_eventdata_type; + +static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { + ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata; + return getvalue(elm, col); +} + +static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { + return elm; +} + + void uic_set_tmp_eventdata(void *eventdata, int type) { tmp_eventdata = eventdata; tmp_eventdata_type = type; @@ -148,6 +159,7 @@ void ui_menuitem_create(UiMenuItemArgs *args) { item->item.next = NULL; item->item.type = UI_MENU_ITEM; + item->action = nl_strdup(args->action); item->label = nl_strdup(args->label); item->icon = nl_strdup(args->icon); item->userdata = args->onclickdata; @@ -207,7 +219,15 @@ void ui_menu_itemlist_create(UiMenuItemListArgs *args) { item->item.prev = NULL; item->item.next = NULL; item->item.type = UI_MENU_ITEM_LIST; - item->getvalue = args->getvalue; + if(args->getvalue2) { + item->getvalue = args->getvalue2; + item->getvaluedata = args->getvaluedata; + } else if(args->getvalue) { + item->getvalue = getvalue_wrapper; + item->getvaluedata = (void*)args->getvalue; + } else { + item->getvalue = str_getvalue; + } item->callback = args->onselect; item->userdata = args->onselectdata; item->varname = nl_strdup(args->varname); @@ -222,6 +242,15 @@ void ui_menu_checkitemlist_create(UiMenuItemListArgs *args) { item->item.prev = NULL; item->item.next = NULL; item->item.type = UI_MENU_CHECKITEM_LIST; + if(args->getvalue2) { + item->getvalue = args->getvalue2; + item->getvaluedata = args->getvaluedata; + } else if(args->getvalue) { + item->getvalue = getvalue_wrapper; + item->getvaluedata = (void*)args->getvalue; + } else { + item->getvalue = str_getvalue; + } item->callback = args->onselect; item->userdata = args->onselectdata; item->varname = nl_strdup(args->varname); @@ -235,6 +264,15 @@ void ui_menu_radioitemlist_create(UiMenuItemListArgs *args) { item->item.prev = NULL; item->item.next = NULL; item->item.type = UI_MENU_RADIOITEM_LIST; + if(args->getvalue2) { + item->getvalue = args->getvalue2; + item->getvaluedata = args->getvaluedata; + } else if(args->getvalue) { + item->getvalue = getvalue_wrapper; + item->getvaluedata = (void*)args->getvalue; + } else { + item->getvalue = str_getvalue; + } item->callback = args->onselect; item->userdata = args->onselectdata; item->varname = nl_strdup(args->varname); diff --git a/ui/common/menu.h b/ui/common/menu.h index 9aea578..510e504 100644 --- a/ui/common/menu.h +++ b/ui/common/menu.h @@ -76,6 +76,7 @@ struct UiMenu { struct UiMenuItem { UiMenuItemI item; ui_callback callback; + char *action; char *label; char *icon; void *userdata; @@ -106,12 +107,13 @@ struct UiMenuRadioItem { }; struct UiMenuItemList { - UiMenuItemI item; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; - char *varname; - UiBool addseparator; + UiMenuItemI item; + ui_getvaluefunc2 getvalue; + void *getvaluedata; + ui_callback callback; + void *userdata; + char *varname; + UiBool addseparator; }; diff --git a/ui/common/object.c b/ui/common/object.c index f158230..8ea5b37 100644 --- a/ui/common/object.c +++ b/ui/common/object.c @@ -39,6 +39,8 @@ static CxList *creation_callbacks; static CxList *destruction_callbacks; +static CxList *objects; + typedef struct objcallback { ui_object_callback func; void *userdata; @@ -60,7 +62,18 @@ void ui_register_object_destruction_callback(ui_object_callback func, void *user cxListAdd(destruction_callbacks, &cb); } +UiObject* ui_dummy_object(void) { + UiObject *obj = uic_object_new_toplevel(); + obj->ref = 1; + return obj; +} + void uic_object_created(UiObject *obj) { + if(!objects) { + objects = cxLinkedListCreate(NULL, CX_STORE_POINTERS); + } + cxListAdd(objects, obj); + CxIterator i = cxListIterator(creation_callbacks); cx_foreach(objcallback *, cb, i) { cb->func(obj, cb->userdata); @@ -68,12 +81,20 @@ void uic_object_created(UiObject *obj) { } void uic_object_destroyed(UiObject *obj) { + if(objects) { + cxListFindRemove(objects, obj); + } + CxIterator i = cxListIterator(destruction_callbacks); cx_foreach(objcallback *, cb, i) { cb->func(obj, cb->userdata); } } +CxList* uic_object_list(void) { + return objects ? objects : cxEmptyList; +} + void ui_object_ref(UiObject *obj) { obj->ref++; } @@ -82,28 +103,20 @@ int ui_object_unref(UiObject *obj) { // it is possible to have 0 references, in case // a window was created but ui_show was never called if(obj->ref == 0 || --obj->ref == 0) { + uic_context_prepare_close(obj->ctx); if(obj->destroy) { obj->destroy(obj); + } else { + uic_object_destroy(obj); } - uic_object_destroy(obj); return 0; } return 1; } void uic_object_destroy(UiObject *obj) { - if(obj->ctx->close_callback) { - UiEvent ev; - ev.window = obj->window; - ev.document = obj->ctx->document; - ev.obj = obj; - ev.eventdata = NULL; - ev.eventdatatype = 0; - ev.intval = 0; - obj->ctx->close_callback(&ev, obj->ctx->close_data); - } uic_object_destroyed(obj); - cxMempoolFree(obj->ctx->mp); + uic_context_destroy(obj->ctx, obj->ctx->document); } UiObject* uic_object_new_toplevel(void) { @@ -123,7 +136,7 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) { return newobj; } -void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer) { +void uic_object_push_container(UiObject *toplevel, UiContainer *newcontainer) { newcontainer->prev = toplevel->container_end; if(toplevel->container_end) { toplevel->container_end->next = newcontainer; @@ -152,8 +165,8 @@ void uic_object_pop_container(UiObject *toplevel) { */ void uic_object_remove_second_last_container(UiObject *toplevel) { if(toplevel->container_end && toplevel->container_end->prev) { - UiContainerX *end = toplevel->container_end; - UiContainerX *rm = toplevel->container_end->prev; + UiContainer *end = toplevel->container_end; + UiContainer *rm = toplevel->container_end->prev; end->prev = rm->prev; if(rm->prev) { diff --git a/ui/common/object.h b/ui/common/object.h index 4327875..7ef1e12 100644 --- a/ui/common/object.h +++ b/ui/common/object.h @@ -50,12 +50,14 @@ void uic_object_created(UiObject *obj); void uic_object_destroyed(UiObject *obj); void uic_object_destroy(UiObject *obj); + +CxList* uic_object_list(void); UiObject* uic_object_new_toplevel(void); UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget); UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget); -void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer); +void uic_object_push_container(UiObject *toplevel, UiContainer *newcontainer); void uic_object_pop_container(UiObject *toplevel); void uic_object_remove_second_last_container(UiObject *toplevel); diff --git a/ui/common/objs.mk b/ui/common/objs.mk index e69125c..35fb9d6 100644 --- a/ui/common/objs.mk +++ b/ui/common/objs.mk @@ -32,6 +32,7 @@ COMMON_OBJPRE = $(OBJ_DIR)$(COMMON_SRC_DIR) COMMON_OBJ = context$(OBJ_EXT) COMMON_OBJ += document$(OBJ_EXT) COMMON_OBJ += object$(OBJ_EXT) +COMMON_OBJ += action$(OBJ_EXT) COMMON_OBJ += container$(OBJ_EXT) COMMON_OBJ += types$(OBJ_EXT) COMMON_OBJ += app$(OBJ_EXT) @@ -44,6 +45,7 @@ COMMON_OBJ += args$(OBJ_EXT) COMMON_OBJ += wrapper$(OBJ_EXT) COMMON_OBJ += utils$(OBJ_EXT) COMMON_OBJ += message$(OBJ_EXT) +COMMON_OBJ += icons$(OBJ_EXT) TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%) TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c) diff --git a/ui/common/properties.c b/ui/common/properties.c index 642603d..29c8ce6 100644 --- a/ui/common/properties.c +++ b/ui/common/properties.c @@ -62,6 +62,8 @@ static UiBool load_on_startup = TRUE; static void *properties_data = NULL; static size_t properties_data_length = 0; +static char *config_root = NULL; + void ui_load_properties_file_on_startup(UiBool enable) { load_on_startup = enable; } @@ -77,13 +79,26 @@ void ui_set_properties_data(const char *str, size_t len) { } char* ui_getappdir(void) { - if(ui_appname() == NULL) { + if(ui_appname() == NULL && config_root == NULL) { return NULL; } return ui_configfile(NULL); } +void ui_setappdir(const char *path) { + free(config_root); + if(path) { + cxmutstr cfgpath = cx_strdup(path); + config_root = cfgpath.ptr; + if(cfgpath.length > 0 && cfgpath.ptr[cfgpath.length-1] == '/') { + config_root[cfgpath.length-1] = 0; + } + } else { + config_root = NULL; + } +} + #ifndef _WIN32 #define UI_PATH_SEPARATOR '/' #define UI_ENV_HOME "HOME" @@ -95,6 +110,16 @@ char* ui_getappdir(void) { #define UI_XDG_CONFIG_HOME_VAR "XDG_CONFIG_HOME" char* ui_configfile(const char *name) { + if(config_root) { + if(!name) { + return strdup(config_root); + } else if(name[0] == '/') { + return cx_strdup(cx_strcat(CX_NULLSTR, 2, cx_str(config_root), cx_str(name))).ptr; + } else { + return cx_strdup(cx_strcat(CX_NULLSTR, 3, cx_str(config_root), cx_str("/"), cx_str(name))).ptr; + } + } + const char *appname = ui_appname(); if(!appname) { return NULL; @@ -209,11 +234,6 @@ void uic_load_app_properties() { return; } - if(!ui_appname()) { - // applications without name cannot load app properties - return; - } - char *dir = ui_configfile(NULL); if(!dir) { return; diff --git a/ui/common/threadpool.c b/ui/common/threadpool.c index 3b4c096..0710dcd 100644 --- a/ui/common/threadpool.c +++ b/ui/common/threadpool.c @@ -30,6 +30,7 @@ #include "threadpool.h" #include "context.h" +#include #include #include @@ -38,6 +39,83 @@ static threadpool_job kill_job; + + +static pthread_mutex_t mc_buffer_mutex; +static pthread_cond_t mc_buffer_available; +static CxList *mainthread_call_buffer; +static volatile int mainthread_call_buffered = 0; + +typedef struct UiMainCall { + ui_threadfunc func; + void *data; +} UiMainCall; + +void uic_init_threads(void) { + pthread_mutex_init(&mc_buffer_mutex, NULL); + pthread_cond_init(&mc_buffer_available, NULL); + mainthread_call_buffer = cxLinkedListCreate(NULL, sizeof(UiMainCall)); +} + +int uic_mainthread_calls_is_buffered(void) { + return mainthread_call_buffered; +} + +void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data) { + pthread_mutex_lock(&mc_buffer_mutex); + UiMainCall call; + call.func = func; + call.data = data; + cxListAdd(mainthread_call_buffer, &call); + pthread_cond_signal(&mc_buffer_available); + pthread_mutex_unlock(&mc_buffer_mutex); +} + + +void ui_buffer_mainthread_calls(UiBool enable_buffering) { + mainthread_call_buffered = enable_buffering; + if(!enable_buffering) { + ui_exec_buffered_mainthread_calls(); + } +} + +static void exec_buffered_calls(void) { + CxIterator i = cxListIterator(mainthread_call_buffer); + cx_foreach(UiMainCall *, call, i) { + if(call->func) { + call->func(call->data); + } + } + cxListClear(mainthread_call_buffer); +} + +void ui_exec_buffered_mainthread_calls(void) { + pthread_mutex_lock(&mc_buffer_mutex); + exec_buffered_calls(); + pthread_mutex_unlock(&mc_buffer_mutex); +} + +UIEXPORT void ui_exec_buffered_mainthread_calls_wait(int timeout) { + struct timespec ts; + if(timeout > 0) { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += timeout; + } + + pthread_mutex_lock(&mc_buffer_mutex); + while(cxListSize(mainthread_call_buffer) == 0) { + if(timeout > 0) { + if(pthread_cond_timedwait(&mc_buffer_available, &mc_buffer_mutex, &ts)) { + break; + } + } else { + pthread_cond_wait(&mc_buffer_available, &mc_buffer_mutex); + } + } + exec_buffered_calls(); + pthread_mutex_unlock(&mc_buffer_mutex); +} + UiThreadpool* threadpool_new(int min, int max) { UiThreadpool *pool = malloc(sizeof(UiThreadpool)); pool->queue = ui_queue_create(); diff --git a/ui/common/threadpool.h b/ui/common/threadpool.h index 4a997f6..8413b24 100644 --- a/ui/common/threadpool.h +++ b/ui/common/threadpool.h @@ -39,6 +39,10 @@ extern "C" { #endif +void uic_init_threads(void); +int uic_mainthread_calls_is_buffered(void); +void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data); + typedef struct UiQueueElm UiQueueElm; typedef struct UiQueue UiQueue; diff --git a/ui/common/toolbar.c b/ui/common/toolbar.c index f87e02a..552b8e1 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,26 @@ 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; +} + +static UiToolbarContentToggleItemArgs contenttoggleitemargs_copy(UiToolbarContentToggleItemArgs *args, size_t *ngroups, size_t *nvstates) { + UiToolbarContentToggleItemArgs newargs; + newargs.label0 = nl_strdup(args->label0); + newargs.icon0 = nl_strdup(args->icon0); + newargs.tooltip0 = nl_strdup(args->tooltip0); + newargs.label1 = nl_strdup(args->label1); + newargs.icon1 = nl_strdup(args->icon1); + newargs.tooltip1 = nl_strdup(args->tooltip1); + newargs.varname = nl_strdup(args->varname); + newargs.onchange = args->onchange; + newargs.onchangedata = args->onchangedata; + newargs.action = nl_strdup(args->action); + newargs.toggled_by_state = args->toggled_by_state; + newargs.istogglebutton = args->istogglebutton; newargs.states = uic_copy_states(args->states, ngroups); newargs.visibility_states = uic_copy_states(args->visibility_states, nvstates); return newargs; @@ -90,6 +111,13 @@ void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *arg cxMapPut(toolbar_items, name, item); } +void ui_toolbar_content_toggleitem_create(const char* name, UiToolbarContentToggleItemArgs *args) { + UiToolbarContentToggleItem* item = malloc(sizeof(UiToolbarContentToggleItem)); + item->item.type = UI_TOOLBAR_CONTENT_TOGGLEITEM; + item->args = contenttoggleitemargs_copy(args, &item->nstates, &item->nvstates); + cxMapPut(toolbar_items, name, item); +} + static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args, size_t *nvstates) { UiToolbarMenuArgs newargs; newargs.label = nl_strdup(args->label); diff --git a/ui/common/toolbar.h b/ui/common/toolbar.h index 9ae60f0..dd79264 100644 --- a/ui/common/toolbar.h +++ b/ui/common/toolbar.h @@ -40,16 +40,18 @@ extern "C" { #endif -typedef struct UiToolbarItemI UiToolbarItemI; +typedef struct UiToolbarItemI UiToolbarItemI; -typedef struct UiToolbarItem UiToolbarItem; -typedef struct UiToolbarToggleItem UiToolbarToggleItem; +typedef struct UiToolbarItem UiToolbarItem; +typedef struct UiToolbarToggleItem UiToolbarToggleItem; +typedef struct UiToolbarContentToggleItem UiToolbarContentToggleItem; -typedef struct UiToolbarMenuItem UiToolbarMenuItem; +typedef struct UiToolbarMenuItem UiToolbarMenuItem; enum UiToolbarItemType { UI_TOOLBAR_ITEM = 0, UI_TOOLBAR_TOGGLEITEM, + UI_TOOLBAR_CONTENT_TOGGLEITEM, UI_TOOLBAR_MENU }; @@ -73,6 +75,13 @@ struct UiToolbarToggleItem { size_t nvstates; }; +struct UiToolbarContentToggleItem { + UiToolbarItemI item; + UiToolbarContentToggleItemArgs args; + size_t nstates; + size_t nvstates; +}; + struct UiToolbarMenuItem { UiToolbarItemI item; UiMenu menu; diff --git a/ui/common/types.c b/ui/common/types.c index 2f65c16..fd1712b 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -100,7 +100,9 @@ void ui_notify_evt(UiObserver *observer, UiEvent *event) { /* --------------------------- UiList --------------------------- */ void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) { - list->data = cxArrayListCreate(ctx->mp->allocator, CX_STORE_POINTERS, 32); + const CxAllocator *a = ctx ? ctx->allocator : cxDefaultAllocator; + list->destroy = uic_ucx_list_destroy; + list->data = cxArrayListCreate(a, CX_STORE_POINTERS, 32); list->first = ui_list_first; list->next = ui_list_next; list->get = ui_list_get; @@ -109,7 +111,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) { @@ -117,11 +118,12 @@ 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); + list->save_selection = TRUE; - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_LIST, list); } @@ -129,12 +131,15 @@ UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listini } void ui_list_free(UiContext *ctx, UiList *list) { - if(!default_list_destroy) { + if(list->destroy) { + list->destroy(ctx, list, NULL); + } else if(!default_list_destroy) { uic_ucx_list_destroy(ctx, list, NULL); } else { default_list_destroy(ctx, list, default_list_destroy_userdata); } - + ui_list_selection_free(list->saved_selection); + ui_free(ctx, list); } void* ui_list_first(UiList *list) { @@ -153,7 +158,7 @@ void* ui_list_next(UiList *list) { } void* ui_list_get(UiList *list, int i) { - return cxListAt(list->data, i); + return i >= 0 ? cxListAt(list->data, i) : NULL; } int ui_list_count(UiList *list) { @@ -168,8 +173,14 @@ void ui_list_prepend(UiList *list, void *data) { cxListInsert(list->data, 0, data); } +void ui_list_insert(UiList *list, int index, void *data) { + cxListInsert(list->data, (size_t)index, data); +} + void ui_list_remove(UiList *list, int i) { - cxListRemove(list->data, i); + if(i >= 0) { + cxListRemove(list->data, i); + } } void ui_list_clear(UiList *list) { @@ -196,6 +207,12 @@ UiListSelection ui_list_get_selection(UiList *list) { } } +UIEXPORT void ui_list_set_selection(UiList *list, UiListSelection sel) { + if(list->setselection) { + list->setselection(list, sel); + } +} + void ui_list_addobsv(UiList *list, ui_callback f, void *data) { list->observers = ui_add_observer(list->observers, f, data); } @@ -204,6 +221,11 @@ void ui_list_notify(UiList *list) { ui_notify(list->observers, list); } +void ui_list_clear_saved_selection(UiList *list) { + ui_list_selection_free(list->saved_selection); + list->saved_selection = NULL; +} + typedef struct { int type; @@ -213,6 +235,7 @@ typedef struct { UiModel* ui_model(UiContext *ctx, ...) { UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); info->ctx = ctx; + info->ref = 1; va_list ap; va_start(ap, ctx); @@ -264,6 +287,7 @@ static void model_notify_observer(UiModel *model, int insert, int delete) { UiModel* ui_model_new(UiContext *ctx) { UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel)); info->ctx = ctx; + info->ref = 1; info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE; info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType)); info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*)); @@ -360,7 +384,7 @@ void ui_model_remove_observer(UiModel *model, void *data) { void ui_model_free(UiModel *mi) { UiContext *ctx = mi->ctx; - const CxAllocator* a = ctx->allocator; + const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator; for(int i=0;icolumns;i++) { ui_free(ctx, mi->titles[i]); } @@ -382,7 +406,7 @@ void ui_model_free(UiModel *mi) { UiInteger* ui_int_new(UiContext *ctx, const char *name) { UiInteger *i = ui_malloc(ctx, sizeof(UiInteger)); memset(i, 0, sizeof(UiInteger)); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_INTEGER, i); } return i; @@ -391,7 +415,7 @@ UiInteger* ui_int_new(UiContext *ctx, const char *name) { UiDouble* ui_double_new(UiContext *ctx, const char *name) { UiDouble *d = ui_malloc(ctx, sizeof(UiDouble)); memset(d, 0, sizeof(UiDouble)); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_DOUBLE, d); } return d; @@ -407,13 +431,16 @@ UiString* ui_string_new(UiContext *ctx, const char *name) { UiString *s = ui_malloc(ctx, sizeof(UiString)); memset(s, 0, sizeof(UiString)); ui_set_destructor(s, (ui_destructor_func)string_destroy); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_STRING, s); } return s; } static void text_destroy(UiText *t) { + if(t->value.free) { + t->value.free(t->value.ptr); + } if(t->destroy) { t->destroy(t); } @@ -423,7 +450,7 @@ UiText* ui_text_new(UiContext *ctx, const char *name) { UiText *t = ui_malloc(ctx, sizeof(UiText)); memset(t, 0, sizeof(UiText)); ui_set_destructor(t, (ui_destructor_func)text_destroy); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_TEXT, t); } return t; @@ -432,7 +459,7 @@ UiText* ui_text_new(UiContext *ctx, const char *name) { UiRange* ui_range_new(UiContext *ctx, const char *name) { UiRange *r = ui_malloc(ctx, sizeof(UiRange)); memset(r, 0, sizeof(UiRange)); - if(name) { + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_RANGE, r); } return r; @@ -447,8 +474,10 @@ static void generic_destroy(UiGeneric *g) { UiGeneric* ui_generic_new(UiContext *ctx, const char *name) { UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric)); memset(g, 0, sizeof(UiGeneric)); - ui_set_destructor(g, (ui_destructor_func)generic_destroy); - if(name) { + if(ctx) { + ui_set_destructor(g, (ui_destructor_func)generic_destroy); + } + if(name && ctx) { uic_reg_var(ctx, name, UI_VAR_GENERIC, g); } return g; @@ -500,7 +529,7 @@ void ui_string_set(UiString* s, const char* value) { if (s) { if (s->set) { ui_setop_enable(TRUE); - s->set(s, value); + s->set(s, value ? value : ""); ui_setop_enable(FALSE); } else { if(s->value.free) { @@ -530,7 +559,7 @@ void ui_text_set(UiText* s, const char* value) { if (s) { if (s->set) { ui_setop_enable(TRUE); - s->set(s, value); + s->set(s, value ? value : ""); ui_setop_enable(FALSE); } else { if(s->value.free) { @@ -668,11 +697,15 @@ void uic_text_copy(UiText *from, UiText *to) { to->set = from->set; to->getsubstr = from->getsubstr; to->insert = from->insert; + to->replace = from->replace; to->setposition = from->setposition; to->position = from->position; + to->showposition = from->showposition; + to->setselection = from->setselection; to->selection = from->selection; to->length = from->length; to->remove = from->remove; + to->setreadonly = from->setreadonly; to->restore = from->restore; to->save = from->save; to->destroy = from->destroy; @@ -731,6 +764,9 @@ void uic_range_save(UiRange *r) { void uic_generic_save(UiGeneric *g) { if(!g->obj) return; + // TODO: this leaks memory + // we can't just use get on Generic and ignore the result + // probably a separate save method is required g->get(g); } @@ -754,16 +790,27 @@ void uic_string_unbind(UiString *s) { } void uic_text_unbind(UiText *t) { + t->obj = NULL; + if(t->data1 && t->datatype == UI_TEXT_TYPE_BUFFER) { + // the binding functions all work with t->data1, not t->obj + // and we don't want to NULL them, because they will be still + // functional even without a widget binding + return; + } + t->set = NULL; t->get = NULL; t->getsubstr = NULL; t->insert = NULL; + t->replace = NULL; t->setposition = NULL; t->position = NULL; + t->showposition = NULL; t->selection = NULL; + t->setselection = NULL; t->length = NULL; t->remove = NULL; - t->obj = NULL; + t->setreadonly = NULL; } void uic_range_unbind(UiRange *r) { @@ -789,21 +836,52 @@ void uic_generic_unbind(UiGeneric *g) { } -UIEXPORT UiListSelection ui_list_getselection(UiList *list) { + +UiListSelection* ui_list_get_selection_allocated(UiList *list) { + UiListSelection *sel = malloc(sizeof(UiListSelection)); + *sel = ui_list_get_selection(list); + return sel; + +} + +void ui_list_selection_free(UiListSelection *sel) { + if(!sel) { + return; + } + ui_listselection_free(*sel); + free(sel); +} + + +UIEXPORT int ui_list_getselection(UiList *list) { + int selection = -1; if (list->getselection) { - return list->getselection(list); + UiListSelection sel = list->getselection(list); + if(sel.count > 0) { + selection = sel.rows[0]; + } + ui_listselection_free(sel); } - return (UiListSelection){ 0, NULL }; + return selection; } UIEXPORT void ui_list_setselection(UiList *list, int index) { + ui_list_setselection2(list, index, TRUE); +} + +UIEXPORT void ui_list_setselection2(UiList *list, int index, UiBool selection_event) { if (list->setselection) { UiListSelection sel = { 0, NULL }; if(index >= 0) { sel.count = 1; sel.rows = &index; } + UiBool events = ui_selection_events_is_enabled(); + if(!selection_event) { + ui_selection_events_enable(FALSE); + } list->setselection(list, sel); + ui_selection_events_enable(events); } } @@ -870,6 +948,7 @@ void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObser static int ui_set_op = 0; static int ui_onchange_events_enabled = TRUE; +static int ui_selection_events_enabled = TRUE; void ui_setop_enable(int set) { ui_set_op = set; @@ -887,6 +966,14 @@ UiBool ui_onchange_events_is_enabled(void) { return ui_onchange_events_enabled; } +void ui_selection_events_enable(UiBool enable) { + ui_selection_events_enabled = enable; +} + +UiBool ui_selection_events_is_enabled(void) { + return ui_selection_events_enabled; +} + /* ---------------- List initializers and wrapper functions ---------------- */ void ui_global_list_initializer(ui_list_init_func func, void *userdata) { @@ -899,6 +986,10 @@ void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) { default_list_destroy_userdata = userdata; } +UIEXPORT void ui_list_class_set_destructor(UiList *list, ui_list_destroy_func destroy) { + list->destroy = destroy; +} + void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) { list->first = first; } @@ -922,3 +1013,85 @@ void ui_list_class_set_data(UiList *list, void *data) { void ui_list_class_set_iter(UiList *list, void *iter) { list->iter = iter; } + +/* ---------------- Text functions ---------------- */ + +char* ui_text_getsubstr(UiText *text, int begin, int end) { + if(text->getsubstr) { + return text->getsubstr(text, begin, end); + } else { + return NULL; + } +} + +void ui_text_insert(UiText *text, int pos, const char *str) { + if(text->insert) { + text->insert(text, pos, str); + } +} + +void ui_text_replace(UiText *text, int begin, int end, const char *str) { + if(text->replace) { + text->replace(text, begin, end, str); + } +} + +void ui_text_setposition(UiText *text, int pos) { + if(text->setposition) { + text->setposition(text, pos); + } +} + +int ui_text_position(UiText *text) { + if(text->position) { + return text->position(text); + } else { + return 0; + } +} + +void ui_text_showposition(UiText *text, int pos) { + if(text->showposition) { + text->showposition(text, pos); + } +} + +void ui_text_setselection(UiText *text, int begin, int end) { + if(text->setselection) { + text->setselection(text, begin, end); + } +} + +void ui_text_selection(UiText *text, int *begin, int *end) { + if(text->selection) { + text->selection(text, begin, end); + } else { + if(begin) { + *begin = 0; + } + if(end) { + *end = 0; + } + } +} + +int ui_text_length(UiText *text) { + if(text->length) { + return text->length(text); + } else { + return 0; + } +} +void ui_text_remove(UiText *text, int begin, int end) { + if(text->remove) { + text->remove(text, begin, end); + } +} + +void ui_text_setreadonly(UiText *text, int readonly) { + if(text->setreadonly) { + text->setreadonly(text, readonly); + } else { + text->readonly = readonly; + } +} diff --git a/ui/common/types.h b/ui/common/types.h index 2f4a524..8723ce0 100644 --- a/ui/common/types.h +++ b/ui/common/types.h @@ -61,6 +61,9 @@ void uic_range_unbind(UiRange *r); void uic_list_unbind(UiList *l); void uic_generic_unbind(UiGeneric *g); +UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list); +UIEXPORT void ui_list_selection_free(UiListSelection *sel); + void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObserver *observer); #ifdef __cplusplus diff --git a/ui/common/wrapper.c b/ui/common/wrapper.c index 575dd29..29af77e 100644 --- a/ui/common/wrapper.c +++ b/ui/common/wrapper.c @@ -45,6 +45,40 @@ void ui_object_set_windowdata(UiObject *obj, void *windowdata) { obj->window = windowdata; } +void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata) { + obj->onclose = callback; + obj->onclosedata = userdata; +} + +static int obj_unref(void *ptr) { + ui_object_unref(ptr); + return 0; +} + +void ui_mainthread_object_unref(UiObject *obj) { + // TODO: detect if this is already the main thread and call + // ui_object_unref directly in that case + ui_call_mainthread(obj_unref, obj); +} + +static int doc_unref(void *ptr) { + ui_document_unref(ptr); + return 0; +} + +void ui_mainthread_document_unref(void *doc) { + // TODO: see ui_mainthread_object_unref + ui_call_mainthread(doc_unref, doc); +} + +static int app_unref(void *unused) { + ui_app_unref(); + return 0; +} + +void ui_mainthread_app_unref() { + ui_call_mainthread(app_unref, NULL); +} /* ---------------------------- UiList ---------------------------- */ @@ -64,6 +98,13 @@ void ui_list_set_iter(UiList *list, void *iter) { list->iter = iter; } +void ui_list_set_save_selection(UiList *list, UiBool value) { + list->save_selection = value; +} + +UiBool ui_list_get_save_selection(UiList *list) { + return list->save_selection; +} /* ------------------------------ UiSublist ------------------------------ */ @@ -209,6 +250,17 @@ int ui_event_get_set(UiEvent *event) { } +/* ---------------------------- 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) { @@ -241,13 +293,6 @@ void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) { /* ---------------------------- UiListSelection ---------------------------- */ -UiListSelection* ui_list_get_selection_allocated(UiList *list) { - UiListSelection *sel = malloc(sizeof(UiListSelection)); - *sel = ui_list_get_selection(list); - return sel; - -} - int ui_list_selection_get_count(UiListSelection *sel) { return sel->count; } @@ -265,9 +310,27 @@ UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num) } } -void ui_list_selection_free(UiListSelection *sel) { - ui_listselection_free(*sel); - free(sel); + +/* -------------------------- UiTextChangedEvent -------------------------- */ + +int ui_text_change_event_get_type(UiTextChangeEventData *event) { + return event->type; +} + +int ui_text_change_event_get_begin(UiTextChangeEventData *event) { + return event->begin; +} + +int ui_text_change_event_get_end(UiTextChangeEventData *event) { + return event->end; +} + +const char* ui_text_change_event_get_text(UiTextChangeEventData *event) { + return event->text; +} + +int ui_text_change_event_get_length(UiTextChangeEventData *event) { + return event->length; } /* ---------------------------- UiFileList ---------------------------- */ diff --git a/ui/common/wrapper.h b/ui/common/wrapper.h index 37f2f38..2883e56 100644 --- a/ui/common/wrapper.h +++ b/ui/common/wrapper.h @@ -31,6 +31,7 @@ #include "../ui/toolkit.h" #include "../ui/list.h" +#include "../ui/text.h" #ifdef __cplusplus extern "C" { @@ -39,10 +40,17 @@ extern "C" { UIEXPORT UiContext* ui_object_get_context(UiObject *obj); UIEXPORT void* ui_object_get_windowdata(UiObject *obj); UIEXPORT void ui_object_set_windowdata(UiObject *obj, void *windowdata); +UIEXPORT void ui_object_set_onclose(UiObject *obj, ui_callback callback, void *userdata); + +UIEXPORT void ui_mainthread_object_unref(UiObject *obj); +UIEXPORT void ui_mainthread_document_unref(void *doc); +UIEXPORT void ui_mainthread_app_unref(); UIEXPORT void* ui_list_get_data(UiList *list); UIEXPORT void* ui_list_get_iter(UiList *list); UIEXPORT void ui_list_set_iter(UiList *list, void *iter); +UIEXPORT void ui_list_set_save_selection(UiList *list, UiBool value); +UIEXPORT UiBool ui_list_get_save_selection(UiList *list); UIEXPORT UiSubList* ui_sublist_new(void); UIEXPORT void ui_sublist_set_value(UiSubList *sublist, UiList *value); @@ -76,11 +84,18 @@ UIEXPORT int ui_event_get_eventdatatype(UiEvent *event); UIEXPORT int ui_event_get_int(UiEvent *event); UIEXPORT int ui_event_get_set(UiEvent *event); -UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list); +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); -UIEXPORT void ui_list_selection_free(UiListSelection *sel); + +UIEXPORT int ui_text_change_event_get_type(UiTextChangeEventData *event); +UIEXPORT int ui_text_change_event_get_begin(UiTextChangeEventData *event); +UIEXPORT int ui_text_change_event_get_end(UiTextChangeEventData *event); +UIEXPORT const char* ui_text_change_event_get_text(UiTextChangeEventData *event); +UIEXPORT int ui_text_change_event_get_length(UiTextChangeEventData *event); UIEXPORT int ui_filelist_count(UiFileList *flist); UIEXPORT char* ui_filelist_get(UiFileList *flist, int index); diff --git a/ui/gtk/Makefile b/ui/gtk/Makefile index d1979fb..8f43a1b 100644 --- a/ui/gtk/Makefile +++ b/ui/gtk/Makefile @@ -26,11 +26,184 @@ # POSSIBILITY OF SUCH DAMAGE. # -$(GTK_OBJPRE)%.o: gtk/%.c - $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $< - $(UI_LIB): $(OBJ) $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ) $(UI_SHLIB): $(OBJ) $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx + +FORCE: + +$(GTK_OBJPRE)action.o: gtk/action.c gtk/action.h gtk/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)button.o: gtk/button.c gtk/button.h gtk/../ui/toolkit.h \ + gtk/../ui/button.h gtk/../ui/toolkit.h gtk/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/container.h \ + gtk/../ui/container.h gtk/widget.h gtk/../ui/widget.h \ + gtk/../common/action.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)container.o: gtk/container.c gtk/container.h \ + gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \ + gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/headerbar.h \ + gtk/../ui/toolbar.h gtk/../common/toolbar.h \ + gtk/../common/../ui/toolbar.h gtk/../common/menu.h \ + gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h \ + gtk/../common/container.h gtk/../common/../ui/container.h \ + gtk/../ui/properties.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)display.o: gtk/display.c gtk/display.h gtk/../ui/toolkit.h \ + gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/container.h \ + gtk/../ui/container.h gtk/../ui/toolkit.h gtk/../ui/display.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)dnd.o: gtk/dnd.c gtk/dnd.h gtk/../ui/dnd.h \ + gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)draw_cairo.o: gtk/draw_cairo.c gtk/container.h \ + gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \ + gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/draw_cairo.h \ + gtk/graphics.h gtk/../ui/graphics.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)draw_gdk.o: gtk/draw_gdk.c gtk/container.h \ + gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \ + gtk/toolkit.h gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/draw_gdk.h \ + gtk/graphics.h gtk/../ui/graphics.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)entry.o: gtk/entry.c gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/container.h gtk/../ui/toolkit.h \ + gtk/../ui/container.h gtk/../ui/toolkit.h gtk/toolkit.h gtk/entry.h \ + gtk/../ui/entry.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)graphics.o: gtk/graphics.c gtk/graphics.h \ + gtk/../ui/graphics.h gtk/../ui/toolkit.h gtk/toolkit.h \ + gtk/../ui/toolkit.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/container.h gtk/../ui/container.h \ + gtk/draw_cairo.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)headerbar.o: gtk/headerbar.c gtk/headerbar.h gtk/toolkit.h \ + gtk/../ui/toolkit.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/../ui/toolbar.h gtk/../ui/toolkit.h \ + gtk/../common/toolbar.h gtk/../common/../ui/toolbar.h \ + gtk/../common/menu.h gtk/../common/../ui/menu.h \ + gtk/../common/../ui/toolkit.h gtk/button.h gtk/../ui/button.h gtk/menu.h \ + gtk/../ui/menu.h gtk/../common/menu.h gtk/../ui/properties.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)icon.o: gtk/icon.c gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/icon.h \ + gtk/../ui/icons.h gtk/../ui/toolkit.h gtk/../common/properties.h \ + gtk/../common/../ui/properties.h gtk/../common/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)image.o: gtk/image.c gtk/image.h gtk/../ui/image.h \ + gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/container.h \ + gtk/../ui/container.h gtk/menu.h gtk/../ui/menu.h gtk/../common/menu.h \ + gtk/../common/../ui/menu.h gtk/widget.h gtk/../ui/widget.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)list.o: gtk/list.c gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/../common/action.h gtk/container.h \ + gtk/../ui/toolkit.h gtk/../ui/container.h gtk/../ui/toolkit.h \ + gtk/toolkit.h gtk/list.h gtk/../ui/list.h gtk/button.h \ + gtk/../ui/button.h gtk/icon.h gtk/../ui/icons.h gtk/menu.h \ + gtk/../ui/menu.h gtk/../common/menu.h gtk/../common/../ui/menu.h \ + gtk/dnd.h gtk/../ui/dnd.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)menu.o: gtk/menu.c gtk/menu.h gtk/../ui/menu.h \ + gtk/../ui/toolkit.h gtk/../common/menu.h gtk/../common/../ui/menu.h \ + gtk/toolkit.h gtk/../ui/toolkit.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/widget.h gtk/../ui/widget.h \ + gtk/../common/types.h gtk/../common/action.h gtk/../ui/properties.h \ + gtk/../ui/window.h gtk/container.h gtk/../ui/container.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)range.o: gtk/range.c gtk/range.h gtk/toolkit.h \ + gtk/../ui/toolkit.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h gtk/../ui/range.h gtk/../ui/toolkit.h \ + gtk/container.h gtk/../ui/container.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)text.o: gtk/text.c gtk/text.h gtk/../ui/text.h \ + gtk/../ui/toolkit.h gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/container.h \ + gtk/../ui/container.h gtk/widget.h gtk/../ui/widget.h \ + gtk/../common/types.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)toolbar.o: gtk/toolbar.c gtk/toolbar.h gtk/../ui/toolbar.h \ + gtk/../ui/toolkit.h gtk/../common/toolbar.h \ + gtk/../common/../ui/toolbar.h gtk/../common/menu.h \ + gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h gtk/list.h \ + gtk/../ui/list.h gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/menu.h \ + gtk/../ui/menu.h gtk/../common/menu.h gtk/button.h gtk/../ui/button.h \ + gtk/icon.h gtk/../ui/icons.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)toolkit.o: gtk/toolkit.c gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/toolbar.h \ + gtk/../ui/toolbar.h gtk/../ui/toolkit.h gtk/../common/toolbar.h \ + gtk/../common/../ui/toolbar.h gtk/../common/menu.h \ + gtk/../common/../ui/menu.h gtk/../common/../ui/toolkit.h gtk/list.h \ + gtk/../ui/list.h gtk/window.h gtk/icon.h gtk/../ui/icons.h \ + gtk/../common/document.h gtk/../common/context.h \ + gtk/../common/properties.h gtk/../common/../ui/properties.h \ + gtk/../common/menu.h gtk/../common/threadpool.h gtk/../common/app.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)webview.o: gtk/webview.c gtk/toolkit.h gtk/../ui/toolkit.h \ + gtk/../common/context.h gtk/../common/../ui/toolkit.h \ + gtk/../common/action.h gtk/../common/object.h gtk/container.h \ + gtk/../ui/container.h gtk/../ui/toolkit.h gtk/webview.h \ + gtk/../ui/webview.h gtk/widget.h gtk/../ui/widget.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)widget.o: gtk/widget.c gtk/widget.h gtk/../ui/widget.h \ + gtk/../ui/toolkit.h gtk/container.h gtk/../ui/toolkit.h \ + gtk/../ui/container.h gtk/toolkit.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/object.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(GTK_OBJPRE)window.o: gtk/window.c gtk/../ui/window.h \ + gtk/../ui/toolkit.h gtk/../ui/properties.h gtk/../common/context.h \ + gtk/../common/../ui/toolkit.h gtk/../common/action.h \ + gtk/../common/menu.h gtk/../common/../ui/menu.h \ + gtk/../common/../ui/toolkit.h gtk/../common/toolbar.h \ + gtk/../common/../ui/toolbar.h gtk/../common/menu.h gtk/../common/utils.h \ + gtk/../common/../ui/text.h gtk/menu.h gtk/../ui/menu.h gtk/toolkit.h \ + gtk/../ui/toolkit.h gtk/../common/object.h gtk/toolbar.h \ + gtk/../ui/toolbar.h gtk/list.h gtk/../ui/list.h gtk/container.h \ + gtk/../ui/container.h gtk/headerbar.h gtk/button.h gtk/../ui/button.h \ + gtk/window.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + diff --git a/ui/gtk/action.c b/ui/gtk/action.c new file mode 100644 index 0000000..80f0a42 --- /dev/null +++ b/ui/gtk/action.c @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "action.h" + +#include +#include + + + +/* ------------------------------ public API ------------------------------ */ + +void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata) { + uic_add_action(ctx, name, callback, userdata, NULL, NULL); +} + +void ui_add_action_with_accelerator( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text) +{ + uic_add_action(ctx, name, callback, userdata, accelerator, accelerator_text); + + // TODO: accelerator +} diff --git a/ui/gtk/action.h b/ui/gtk/action.h new file mode 100644 index 0000000..d13d3de --- /dev/null +++ b/ui/gtk/action.h @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ACTION_H +#define ACTION_H + +#include "../ui/toolkit.h" +#include "../common/action.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* ACTION_H */ + diff --git a/ui/gtk/button.c b/ui/gtk/button.c index d9acdbf..aa641bf 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,18 +102,27 @@ 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; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, button, &layout); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); return button; } @@ -123,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) { @@ -134,6 +153,47 @@ void ui_button_set_icon(UIWIDGET button, const char *icon) { ui_button_set_icon_name(button, icon); } +void ui_button_set_tooltip(UIWIDGET button, const char *tooltip) { + gtk_widget_set_tooltip_text(GTK_WIDGET(button), tooltip); +} + +void ui_togglebutton_set_label(UIWIDGET button, const char *label) { + ui_button_set_label(button, label); +} + +void ui_togglebutton_set_icon(UIWIDGET button, const char *icon) { + ui_button_set_icon(button, icon); +} + +void ui_togglebutton_set_tooltip(UIWIDGET button, const char *tooltip) { + ui_button_set_tooltip(button, tooltip); +} + +void ui_checkbox_set_label(UIWIDGET button, const char *label) { + ui_button_set_label(button, label); +} + +void ui_checkbox_set_icon(UIWIDGET button, const char *icon) { + ui_button_set_icon(button, icon); +} + +void ui_checkbox_set_tooltip(UIWIDGET button, const char *tooltip) { + ui_button_set_tooltip(button, tooltip); +} + +void ui_radiobutton_set_label(UIWIDGET button, const char *label) { + ui_button_set_label(button, label); +} + +void ui_radiobutton_set_icon(UIWIDGET button, const char *icon) { + ui_button_set_icon(button, icon); +} + +void ui_radiobutton_set_tooltip(UIWIDGET button, const char *tooltip) { + ui_button_set_tooltip(button, tooltip); +} + + int64_t ui_toggle_button_get(UiInteger *integer) { GtkToggleButton *button = integer->obj; integer->value = (int)gtk_toggle_button_get_active(button); @@ -169,7 +229,14 @@ static void ui_toggled_callback(GtkToggleButton *widget, UiEventData *event) { e.eventdatatype = 0; e.intval = gtk_toggle_button_get_active(widget); 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); + } } static void ui_togglebutton_enable_state_callback(GtkToggleButton *widget, UiEventData *event) { @@ -190,6 +257,7 @@ void ui_setup_togglebutton( UiInteger *value, ui_callback onchange, void *onchangedata, + const char *action, int enable_state) { if(label) { @@ -200,6 +268,14 @@ void ui_setup_togglebutton( gtk_widget_set_tooltip_text(togglebutton, tooltip); } + if(action) { + uic_bind_action(obj->ctx, action, togglebutton, (ui_enablefunc)ui_set_enabled); + UiAction *ui_action = uic_resolve_action(obj->ctx, action); + if(!ui_action) { + ui_set_enabled(togglebutton, FALSE); + } + } + ui_bind_togglebutton( obj, togglebutton, @@ -210,6 +286,7 @@ void ui_setup_togglebutton( (ui_toggled_func)ui_toggled_callback, onchange, onchangedata, + action, (ui_toggled_func)ui_togglebutton_enable_state_callback, enable_state ); @@ -225,6 +302,7 @@ void ui_bind_togglebutton( void (*toggled_callback)(void*, void*), ui_callback onchange, void *onchangedata, + const char *action, void (*enable_state_func)(void*, void*), int enable_state) { @@ -256,11 +334,12 @@ void ui_bind_togglebutton( event); } - if(onchange) { + if(onchange || action) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; event->userdata = onchangedata; event->callback = onchange; + event->action = action ? strdup(action) : NULL, event->value = 0; event->customdata = NULL; event->customint = 0; @@ -273,10 +352,10 @@ void ui_bind_togglebutton( g_signal_connect( widget, "destroy", - G_CALLBACK(ui_destroy_userdata), + G_CALLBACK(ui_destroy_eventdata), event); } - + if(enable_state > 0) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; @@ -310,6 +389,7 @@ static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleAr args->value, args->onchange, args->onchangedata, + args->action, args->enable_state); ui_set_name_and_style(widget, args->name, args->style_class); ui_set_widget_states(obj->ctx, widget, args->states); @@ -317,6 +397,7 @@ static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleAr UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, widget, &layout); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); return widget; } @@ -371,6 +452,7 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) { (ui_toggled_func)ui_checkbox_callback, args->onchange, args->onchangedata, + args->action, (ui_toggled_func)ui_checkbox_enable_state, args->enable_state); @@ -380,6 +462,7 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, widget, &layout); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); return widget; } @@ -469,6 +552,7 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, widget, &layout); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); return widget; } @@ -493,6 +577,171 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) { #endif +static void content_toggle_button_changed(UiContentToggleButton *button) { + if(button->toggled) { + gtk_button_set_label(GTK_BUTTON(button->widget), button->label1); + ui_button_set_icon_name(button->widget, button->icon1); + gtk_widget_set_tooltip_text(button->widget, button->tooltip1); + } else { + gtk_button_set_label(GTK_BUTTON(button->widget), button->label0); + ui_button_set_icon_name(button->widget, button->icon0); + gtk_widget_set_tooltip_text(button->widget, button->tooltip0); + } + + UiEvent e; + e.obj = button->obj; + e.window = button->obj->window; + e.document = button->obj->ctx->document; + e.eventdata = NULL; + e.eventdatatype = 0; + e.intval = button->toggled; + e.set = ui_get_setop(); + + if(button->onchange) { + button->onchange(&e, button->onchangedata); + } + + if(button->onchange_action) { + uic_action_callback(&e, button->onchange_action); + } +} + +static void ui_content_toggle_button_toggled(GtkWidget *widget, UiContentToggleButton *button) { + button->toggled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + if(ui_get_setop() == 0) { + content_toggle_button_changed(button); + } +} + +static void ui_content_toggle_button_clicked(GtkWidget *widget, UiContentToggleButton *button) { + button->toggled = !button->toggled; + content_toggle_button_changed(button); +} + +static void ui_destroy_content_togglebutton(GtkWidget *widget, UiContentToggleButton *button) { + free(button->label0); + free(button->icon0); + free(button->tooltip0); + free(button->label1); + free(button->icon1); + free(button->tooltip1); + free(button->onchange_action); + free(button); +} + +static void ui_content_togglebutton_enabled_by_state(void *data, int enabled) { + UiContentToggleButton *button = data; + if(button->toggled != enabled) { + button->toggled = enabled; + content_toggle_button_changed(button); + } +} + +UIWIDGET ui_create_content_togglebutton(UiObject *obj, UiContentToggleArgs *args) { + UiContentToggleButton *button = malloc(sizeof(UiContentToggleButton)); + memset(button, 0, sizeof(UiContentToggleButton)); + button->obj = obj; + button->label0 = args->label0 ? strdup(args->label0) : NULL; + button->icon0 = args->icon0 ? strdup(args->icon0) : NULL; + button->tooltip0 = args->tooltip0 ? strdup(args->tooltip0) : NULL; + button->label1 = args->label1 ? strdup(args->label1) : NULL; + button->icon1 = args->icon1 ? strdup(args->icon1) : NULL; + button->tooltip1 = args->tooltip1 ? strdup(args->tooltip1) : NULL; + button->enable_state = args->enable_state; + button->var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER); + button->onchange = args->onchange; + button->onchangedata = args->onchangedata; + button->onchange_action = args->action ? strdup(args->action) : NULL; + + const char *label = args->label0; + const char *icon = args->icon0; + const char *tooltip = args->tooltip0; + if(button->var) { + UiInteger *i = button->var->value; + i->obj = button; + i->get = ui_ctntogglebutton_get; + i->set = ui_ctntogglebutton_set; + + if(i->value) { + label = args->label1; + icon = args->label1; + tooltip = args->tooltip1; + button->toggled = 1; + } + } + + GtkWidget *widget; + if(args->istogglebutton) { + widget = gtk_toggle_button_new_with_label(label); + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(ui_content_toggle_button_toggled), + button); + } else { + widget = gtk_button_new_with_label(label); + + g_signal_connect( + widget, + "clicked", + G_CALLBACK(ui_content_toggle_button_clicked), + button); + } + ui_button_set_icon_name(widget, icon); + gtk_widget_set_tooltip_text(widget, tooltip); + button->widget = widget; + + if(args->action) { + uic_bind_action(obj->ctx, args->action, widget, (ui_enablefunc)ui_set_enabled); + UiAction *ui_action = uic_resolve_action(obj->ctx, args->action); + if(!ui_action) { + ui_set_enabled(widget, FALSE); + } + } + + if(args->toggled_by_state != 0) { + CxList *ls = cxArrayListCreate(NULL, sizeof(int), 1); + cxListAdd(ls, &args->toggled_by_state); + uic_add_state_widget(obj->ctx, button, ui_content_togglebutton_enabled_by_state, ls); + cxListFree(ls); + } + + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_content_togglebutton), + button); + + g_object_set_data(G_OBJECT(widget), "ui_content_togglebutton", button); + return widget; +} + +UIWIDGET ui_content_togglebutton_create(UiObject *obj, UiContentToggleArgs *args) { + GtkWidget *widget = ui_create_content_togglebutton(obj, args); + + ui_set_name_and_style(widget, args->name, args->style_class); + ui_set_widget_states(obj->ctx, widget, args->states); + UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; + UiLayout layout = UI_ARGS2LAYOUT(args); + ct->add(ct, widget, &layout); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); + return widget; +} + +int64_t ui_ctntogglebutton_get(UiInteger *value) { + UiContentToggleButton *button = value->obj; + value->value = button->toggled; + return value->value; +} + +void ui_ctntogglebutton_set(UiInteger *value, int64_t i) { + UiContentToggleButton *button = value->obj; + button->toggled = i != 0; + value->value = button->toggled; + content_toggle_button_changed(button); +} + #if GTK_MAJOR_VERSION >= 4 #define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label) #define RADIOBUTTON_SET_GROUP(button, group) @@ -621,6 +870,7 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, rbutton, &layout); + uic_widget_set_visibility_states(obj->ctx, rbutton, args->visibility_states); return rbutton; } @@ -836,16 +1086,7 @@ static void linkbutton_callback(GtkWidget *widget, UiLinkButton *data) { static void linkbutton_clicked(GtkWidget *widget, UiLinkButton *data) { linkbutton_callback(widget, data); if(data->link) { -#if GTK_CHECK_VERSION(4, 0, 0) - GtkUriLauncher *launcher = gtk_uri_launcher_new (data->link); - gtk_uri_launcher_launch (launcher, NULL, NULL, NULL, NULL); - g_object_unref (launcher); -#elif GTK_CHECK_VERSION(3, 22, 0) - GError *error = NULL; - gtk_show_uri_on_window(NULL, data->link, GDK_CURRENT_TIME, &error); -#elif - // TODO: call xdg-open -#endif + ui_open_uri(data->link); } } @@ -913,6 +1154,7 @@ UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, button, &layout); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); return button; } @@ -932,6 +1174,7 @@ void ui_linkbutton_set(UiString *s, const char *str) { if(s->value.free) { s->value.free(s->value.ptr); } + s->value.ptr = NULL; #if GTK_MAJOR_VERSION == 3 UiLinkButton *data = s->obj; GtkWidget *child = gtk_bin_get_child(GTK_BIN(data->widget)); diff --git a/ui/gtk/button.h b/ui/gtk/button.h index ce94b90..4972f35 100644 --- a/ui/gtk/button.h +++ b/ui/gtk/button.h @@ -37,6 +37,23 @@ extern "C" { #endif +typedef struct UiContentToggleButton { + UiObject *obj; + UiVar *var; + GtkWidget *widget; + char *label0; + char *icon0; + char *tooltip0; + char *label1; + char *icon1; + char *tooltip1; + ui_callback onchange; + void *onchangedata; + char *onchange_action; + int toggled; + int enable_state; +} UiContentToggleButton; + typedef struct UiLinkButton { UiObject *obj; GtkWidget *widget; @@ -58,6 +75,7 @@ GtkWidget* ui_create_button( const char *tooltip, ui_callback onclick, void *userdata, + const char *action, int event_value, bool activate_event); @@ -71,6 +89,7 @@ void ui_setup_togglebutton( UiInteger *value, ui_callback onchange, void *onchangedata, + const char *action, int enable_state); void ui_bind_togglebutton( @@ -83,6 +102,7 @@ void ui_bind_togglebutton( void (*toggled_callback)(void*, void*), ui_callback onchange, void *onchangedata, + const char *action, void (*enable_state_func)(void*, void*), int enable_state); @@ -98,9 +118,14 @@ UIWIDGET ui_radiobutton_var(UiObject *obj, char *label, UiVar *var); void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event); +UIWIDGET ui_create_content_togglebutton(UiObject *obj, UiContentToggleArgs *args); + int64_t ui_switch_get(UiInteger *value); void ui_switch_set(UiInteger *value, int64_t i); +int64_t ui_ctntogglebutton_get(UiInteger *value); +void ui_ctntogglebutton_set(UiInteger *value, int64_t i); + int64_t ui_radiobutton_get(UiInteger *value); void ui_radiobutton_set(UiInteger *value, int64_t i); diff --git a/ui/gtk/container.c b/ui/gtk/container.c index 7da333d..30960ff 100644 --- a/ui/gtk/container.c +++ b/ui/gtk/container.c @@ -43,12 +43,12 @@ void ui_container_begin_close(UiObject *obj) { - UiContainerX *ct = obj->container_end; + UiContainer *ct = obj->container_end; ct->close = 1; } int ui_container_finish(UiObject *obj) { - UiContainerX *ct = obj->container_end; + UiContainer *ct = obj->container_end; if(ct->close) { ui_end_new(obj); return 0; @@ -82,7 +82,7 @@ GtkWidget* ui_subcontainer_create( { GtkWidget *sub = NULL; GtkWidget *add = NULL; - UiContainerX *container = NULL; + UiContainer *container = NULL; switch(type) { default: { sub = ui_gtk_vbox_new(spacing); @@ -125,11 +125,11 @@ void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_fun container->container.widget = widget; container->add = add_child; container->userdata = userdata; - uic_object_push_container(obj, (UiContainerX*)container); + uic_object_push_container(obj, (UiContainer*)container); } /* -------------------- Box Container -------------------- */ -UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) { +UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) { UiBoxContainer *ct = cxCalloc( obj->ctx->allocator, 1, @@ -137,7 +137,7 @@ UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType ct->container.widget = box; ct->container.add = ui_box_container_add; ct->type = type; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -172,7 +172,7 @@ void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *l #endif } -UiContainerX* ui_grid_container( +UiContainer* ui_grid_container( UiObject *obj, GtkWidget *grid, UiBool def_hexpand, @@ -192,7 +192,7 @@ UiContainerX* ui_grid_container( ct->container.add = ui_grid_container_add; UI_GTK_V2(ct->width = 0); UI_GTK_V2(ct->height = 1); - return (UiContainerX*)ct; + return (UiContainer*)ct; } @@ -271,14 +271,14 @@ void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget) { } #endif -UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame) { +UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) { UiContainerPrivate *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiContainerPrivate)); ct->widget = frame; ct->add = ui_frame_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -286,14 +286,14 @@ void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout FRAME_SET_CHILD(ct->widget, widget); } -UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander) { +UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) { UiContainerPrivate *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiContainerPrivate)); ct->widget = expander; ct->add = ui_expander_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -307,24 +307,24 @@ void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, SCROLLEDWINDOW_SET_CHILD(ct->widget, widget); } -UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) { +UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) { UiContainerPrivate *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiContainerPrivate)); ct->widget = scrolledwindow; ct->add = ui_scrolledwindow_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } -UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview) { +UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) { UiTabViewContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiTabViewContainer)); ct->container.widget = tabview; ct->container.add = ui_tabview_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -390,9 +390,11 @@ UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType ui_set_name_and_style(box, args->name, args->style_class); ct->add(ct, box, &layout); - UiContainerX *container = ui_box_container(obj, box, type); + UiContainer *container = ui_box_container(obj, box, type); uic_object_push_container(obj, container); + uic_widget_set_visibility_states(obj->ctx, box, args->visibility_states); + return box; } @@ -426,9 +428,11 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { ui_set_name_and_style(grid, args->name, args->style_class); ct->add(ct, grid, &layout); - UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill); + UiContainer *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill); uic_object_push_container(obj, container); + uic_widget_set_visibility_states(obj->ctx, grid, args->visibility_states); + return grid; } @@ -472,10 +476,12 @@ UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { if(sub) { FRAME_SET_CHILD(frame, sub); } else { - UiContainerX *container = ui_frame_container(obj, frame); + UiContainer *container = ui_frame_container(obj, frame); uic_object_push_container(obj, container); } + uic_widget_set_visibility_states(obj->ctx, frame, args->visibility_states); + return frame; } @@ -496,10 +502,12 @@ UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) { if(sub) { EXPANDER_SET_CHILD(expander, sub); } else { - UiContainerX *container = ui_expander_container(obj, expander); + UiContainer *container = ui_expander_container(obj, expander); uic_object_push_container(obj, container); } + uic_widget_set_visibility_states(obj->ctx, expander, args->visibility_states); + return expander; } @@ -521,10 +529,12 @@ UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) { if(sub) { SCROLLEDWINDOW_SET_CHILD(sw, sub); } else { - UiContainerX *container = ui_scrolledwindow_container(obj, sw); + UiContainer *container = ui_scrolledwindow_container(obj, sw); uic_object_push_container(obj, container); } + uic_widget_set_visibility_states(obj->ctx, sw, args->visibility_states); + return sw; } @@ -733,10 +743,13 @@ typedef void (*ui_tabview_set_func)(UiInteger*, int64_t); UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) { UiGtkTabView *data = malloc(sizeof(UiGtkTabView)); memset(data, 0, sizeof(UiGtkTabView)); + data->obj = obj; data->padding = args->padding; data->spacing = args->spacing; data->columnspacing = args->columnspacing; data->rowspacing = args->rowspacing; + data->onchange = args->onchange; + data->onchangedata = args->onchangedata; ui_tabview_get_func getfunc = NULL; ui_tabview_set_func setfunc = NULL; @@ -808,14 +821,16 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) { UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, widget, &layout); - UiContainerX *container = ui_tabview_container(obj, widget); + UiContainer *container = ui_tabview_container(obj, widget); uic_object_push_container(obj, container); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); + return widget; } static GtkWidget* create_tab(UiObject *obj, UiGtkTabView *tabview, const char *title, int tab) { - UiContainerX *container; + UiContainer *container; GtkWidget *sub; switch(tabview->subcontainer) { default: { @@ -901,7 +916,7 @@ static void hb_set_part(UiObject *obj, int part) { sizeof(UiHeaderbarContainer)); memcpy(hb, ct, sizeof(UiHeaderbarContainer)); hb->part = part; - uic_object_push_container(obj, (UiContainerX*)hb); + uic_object_push_container(obj, (UiContainer*)hb); } void ui_headerbar_start_create(UiObject *obj) { @@ -924,7 +939,7 @@ UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) { ui_set_name_and_style(box, args->name, args->style_class); ct->add(ct, box, &layout); - UiContainerX *container = ui_headerbar_fallback_container(obj, box); + UiContainer *container = ui_headerbar_fallback_container(obj, box); uic_object_push_container(obj, container); return box; @@ -934,21 +949,21 @@ static void hb_fallback_set_part(UiObject *obj, int part) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; GtkWidget *headerbar = ct->widget; - UiContainerX *container = ui_headerbar_container(obj, headerbar); + UiContainer *container = ui_headerbar_container(obj, headerbar); uic_object_push_container(obj, container); UiHeaderbarContainer *hb = (UiHeaderbarContainer*)container; hb->part = part; } -UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) { +UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) { UiHeaderbarContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiHeaderbarContainer)); ct->container.widget = headerbar; ct->container.add = ui_headerbar_fallback_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -964,20 +979,20 @@ UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) { return ui_headerbar_fallback_create(obj, args); } - UiContainerX *container = ui_headerbar_container(obj, headerbar); + UiContainer *container = ui_headerbar_container(obj, headerbar); uic_object_push_container(obj, container); return headerbar; } -UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) { +UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) { UiHeaderbarContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiHeaderbarContainer)); ct->container.widget = headerbar; ct->container.add = ui_headerbar_container_add; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { @@ -1020,7 +1035,7 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) { ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box); - UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); + UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); uic_object_push_container(obj, container); return box; @@ -1033,7 +1048,7 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) { ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); BOX_ADD_EXPAND(sidebar_vbox, box); - UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); + UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); uic_object_push_container(obj, container); return box; @@ -1053,7 +1068,7 @@ static UIWIDGET splitwindow_panel(UiObject *obj, GtkWidget *pbox, UiSidebarArgs ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); BOX_ADD_EXPAND(pbox, box); - UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); + UiContainer *container = ui_box_container(obj, box, UI_CONTAINER_VBOX); uic_object_push_container(obj, container); return box; @@ -1120,7 +1135,7 @@ static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSpl } UiSplitPane *splitpane = ui_create_splitpane_data(pane0, orientation, max, args->initial_position); - UiContainerX *container = ui_splitpane_container(obj, pane0, splitpane); + UiContainer *container = ui_splitpane_container(obj, pane0, splitpane); uic_object_push_container(obj, container); g_object_set_data(G_OBJECT(pane0), "ui_splitpane", splitpane); @@ -1157,12 +1172,12 @@ UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation return ct; } -UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) { +UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) { UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer)); ct->container.widget = pane; ct->container.add = ui_splitpane_container_add; ct->splitpane = data; - return (UiContainerX*)ct; + return (UiContainer*)ct; } void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { diff --git a/ui/gtk/container.h b/ui/gtk/container.h index a5e46b2..352b50e 100644 --- a/ui/gtk/container.h +++ b/ui/gtk/container.h @@ -50,7 +50,7 @@ typedef struct UiDocumentView UiDocumentView; typedef struct UiContainerPrivate UiContainerPrivate; struct UiContainerPrivate { - UiContainerX container; + UiContainer container; GtkWidget *widget; UIMENU menu; @@ -160,11 +160,11 @@ GtkWidget* ui_subcontainer_create( GtkWidget* ui_gtk_set_margin(GtkWidget *widget, int margin, int margin_left, int margin_right, int margin_top, int margin_bottom); UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type); -UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type); +UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type); void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing); -UiContainerX* ui_grid_container( +UiContainer* ui_grid_container( UiObject *obj, GtkWidget *grid, UiBool def_hexpand, @@ -173,20 +173,20 @@ UiContainerX* ui_grid_container( UiBool def_vfill); void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); -UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame); +UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame); void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); -UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander); +UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander); void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); -UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow); +UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow); void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); -UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview); +UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview); void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init); -UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data); +UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data); void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); int64_t ui_splitpane_get(UiInteger *i); @@ -197,11 +197,11 @@ UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview); void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab); #if GTK_CHECK_VERSION(3, 10, 0) -UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar); +UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar); void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); #endif -UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar); +UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar); void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout); #ifdef __cplusplus diff --git a/ui/gtk/display.c b/ui/gtk/display.c index 1f8c39e..1a4073c 100644 --- a/ui/gtk/display.c +++ b/ui/gtk/display.c @@ -115,6 +115,8 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) { UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, widget, &layout); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); + return widget; } @@ -205,6 +207,8 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) { UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, progressbar, &layout); + uic_widget_set_visibility_states(obj->ctx, progressbar, args->visibility_states); + return progressbar; } @@ -246,6 +250,8 @@ UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, spinner, &layout); + uic_widget_set_visibility_states(obj->ctx, spinner, args->visibility_states); + return spinner; } diff --git a/ui/gtk/headerbar.c b/ui/gtk/headerbar.c index ef1d9c7..a8ba535 100644 --- a/ui/gtk/headerbar.c +++ b/ui/gtk/headerbar.c @@ -30,6 +30,9 @@ #include "button.h" #include "menu.h" +#include "../ui/widget.h" + +#include #include "../ui/properties.h" @@ -66,53 +69,66 @@ void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *m } // main toolbar - ui_headerbar_add_items(obj, main_headerbar, left_defaults, UI_TOOLBAR_LEFT); - ui_headerbar_add_items(obj, main_headerbar, center_defaults, UI_TOOLBAR_CENTER); + ui_headerbar_add_items(obj, main_headerbar, left_defaults, UI_TOOLBAR_LEFT, NULL); + ui_headerbar_add_items(obj, main_headerbar, center_defaults, UI_TOOLBAR_CENTER, NULL); if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHT) { ui_add_headerbar_menu(main_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT); } - ui_headerbar_add_items(obj, main_headerbar, right_defaults, UI_TOOLBAR_RIGHT); + ui_headerbar_add_items(obj, main_headerbar, right_defaults, UI_TOOLBAR_RIGHT, NULL); // sidebar if(sidebar_headerbar) { // ui_headerbar_add_items pos parameter uses only UI_TOOLBAR_LEFT, UI_TOOLBAR_CENTER, UI_TOOLBAR_RIGHT - ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_left_defaults, UI_TOOLBAR_LEFT); + ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_left_defaults, UI_TOOLBAR_LEFT, NULL); if(appmenu && appmenu_pos == UI_TOOLBAR_SIDEBAR_RIGHT) { ui_add_headerbar_menu(sidebar_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT); } - ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_right_defaults, UI_TOOLBAR_RIGHT); + ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_right_defaults, UI_TOOLBAR_RIGHT, NULL); } // right panel if(right_headerbar) { - ui_headerbar_add_items(obj, right_headerbar, rightpanel_left_defaults, UI_TOOLBAR_LEFT); - ui_headerbar_add_items(obj, right_headerbar, rightpanel_center_defaults, UI_TOOLBAR_CENTER); + // also add central toolbar items, in case the central pane is hidden + CxList *backup_toolbar_widgets = cxArrayListCreate(obj->ctx->allocator, CX_STORE_POINTERS, 16); + ui_headerbar_add_items(obj, right_headerbar, left_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets); + ui_headerbar_add_items(obj, right_headerbar, center_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets); + ui_headerbar_add_items(obj, right_headerbar, right_defaults, UI_TOOLBAR_LEFT, backup_toolbar_widgets); + CxIterator i = cxListIterator(backup_toolbar_widgets); + cx_foreach(GtkWidget *, w, i) { + ui_set_visible(w, FALSE); + } + g_object_set_data(G_OBJECT(obj->widget), "ui_toolbar_center_backup", backup_toolbar_widgets); + + // main items for the right panel + ui_headerbar_add_items(obj, right_headerbar, rightpanel_left_defaults, UI_TOOLBAR_LEFT, NULL); + ui_headerbar_add_items(obj, right_headerbar, rightpanel_center_defaults, UI_TOOLBAR_CENTER, NULL); if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHTPANEL_RIGHT) { ui_add_headerbar_menu(right_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT); } - ui_headerbar_add_items(obj, right_headerbar, rightpanel_right_defaults, UI_TOOLBAR_RIGHT); + ui_headerbar_add_items(obj, right_headerbar, rightpanel_right_defaults, UI_TOOLBAR_RIGHT, NULL); } } -static void create_item(UiObject *obj, GtkWidget *headerbar, GtkWidget *box, UiToolbarItemI *i, enum UiToolbarPos pos) { +static GtkWidget* create_item(UiObject *obj, GtkWidget *headerbar, GtkWidget *box, UiToolbarItemI *i, enum UiToolbarPos pos) { switch(i->type) { case UI_TOOLBAR_ITEM: { - ui_add_headerbar_item(headerbar, box, (UiToolbarItem*)i, obj, pos); - break; + return ui_add_headerbar_item(headerbar, box, (UiToolbarItem*)i, obj, pos); } case UI_TOOLBAR_TOGGLEITEM: { - ui_add_headerbar_toggleitem(headerbar, box, (UiToolbarToggleItem*)i, obj, pos); - break; + return ui_add_headerbar_toggleitem(headerbar, box, (UiToolbarToggleItem*)i, obj, pos); + } + case UI_TOOLBAR_CONTENT_TOGGLEITEM: { + return ui_add_headerbar_content_toggleitem(headerbar, box, (UiToolbarContentToggleItem*)i, obj, pos); } case UI_TOOLBAR_MENU: { - ui_add_headerbar_menu(headerbar, box, (UiToolbarMenuItem*)i, obj, pos); - break; + return ui_add_headerbar_menu(headerbar, box, (UiToolbarMenuItem*)i, obj, pos); } default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); } + return NULL; } static void headerbar_add(GtkWidget *headerbar, GtkWidget *box, GtkWidget *item, enum UiToolbarPos pos) { @@ -137,12 +153,15 @@ static void headerbar_add(GtkWidget *headerbar, GtkWidget *box, GtkWidget *item, } } -void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos) { +void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos, CxList *out_items) { GtkWidget *box = NULL; if(pos == UI_TOOLBAR_CENTER && cxListSize(items) > 0) { box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); UI_HEADERBAR_SET_TITLE_WIDGET(headerbar, box); + if(out_items) { + cxListAdd(out_items, box); + } } CxIterator i = pos == UI_TOOLBAR_RIGHT ? cxListBackwardsIterator(items) : cxListIterator(items); @@ -152,25 +171,29 @@ void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, fprintf(stderr, "unknown toolbar item: %s\n", def); continue; } - create_item(obj, headerbar, box, item, pos); + GtkWidget *item_widget = create_item(obj, headerbar, box, item, pos); + if(out_items && !box) { + cxListAdd(out_items, item_widget); + } } } -void ui_add_headerbar_item( +GtkWidget* ui_add_headerbar_item( GtkWidget *headerbar, GtkWidget *box, UiToolbarItem *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"); headerbar_add(headerbar, box, button, pos); + return button; } -void ui_add_headerbar_toggleitem( +GtkWidget* ui_add_headerbar_toggleitem( GtkWidget *headerbar, GtkWidget *box, UiToolbarToggleItem *item, @@ -181,11 +204,39 @@ void ui_add_headerbar_toggleitem( 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"); - ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, 0); + ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, item->args.action, 0); headerbar_add(headerbar, box, button, pos); + return button; } -void ui_add_headerbar_menu( +GtkWidget* ui_add_headerbar_content_toggleitem( + GtkWidget *headerbar, + GtkWidget *box, + UiToolbarContentToggleItem *item, + UiObject *obj, + enum UiToolbarPos pos) +{ + UiContentToggleArgs args = { 0 }; + args.label0 = item->args.label0; + args.icon0 = item->args.icon0; + args.tooltip0 = item->args.tooltip0; + args.label1 = item->args.label1; + args.icon1 = item->args.icon1; + args.tooltip1 = item->args.tooltip1; + args.varname = item->args.varname; + args.onchange = item->args.onchange; + args.onchangedata = item->args.onchangedata; + args.action = item->args.action; + args.istogglebutton = item->args.istogglebutton; + args.toggled_by_state = item->args.toggled_by_state; + + GtkWidget *button = ui_create_content_togglebutton(obj, &args); + WIDGET_ADD_CSS_CLASS(button, "flat"); + headerbar_add(headerbar, box, button, pos); + return button; +} + +GtkWidget* ui_add_headerbar_menu( GtkWidget *headerbar, GtkWidget *box, UiToolbarMenuItem *item, @@ -222,6 +273,8 @@ void ui_add_headerbar_menu( #endif headerbar_add(headerbar, box, menubutton, pos); + + return menubutton; } #endif // GTK_CHECK_VERSION(3, 10, 0) diff --git a/ui/gtk/headerbar.h b/ui/gtk/headerbar.h index d3786c8..50e877b 100644 --- a/ui/gtk/headerbar.h +++ b/ui/gtk/headerbar.h @@ -65,23 +65,30 @@ extern "C" { void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *main_headerbar, GtkWidget *right_headerbar); -void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos); +void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos, CxList *out_items); -void ui_add_headerbar_item( +GtkWidget* ui_add_headerbar_item( GtkWidget *headerbar, GtkWidget *box, UiToolbarItem *item, UiObject *obj, enum UiToolbarPos pos); -void ui_add_headerbar_toggleitem( +GtkWidget* ui_add_headerbar_toggleitem( GtkWidget *headerbar, GtkWidget *box, UiToolbarToggleItem *item, UiObject *obj, enum UiToolbarPos pos); -void ui_add_headerbar_menu( +GtkWidget* ui_add_headerbar_content_toggleitem( + GtkWidget *headerbar, + GtkWidget *box, + UiToolbarContentToggleItem *item, + UiObject *obj, + enum UiToolbarPos pos); + +GtkWidget* ui_add_headerbar_menu( GtkWidget *headerbar, GtkWidget *box, UiToolbarMenuItem *item, diff --git a/ui/gtk/icon.c b/ui/gtk/icon.c index 16568ee..1dfd52f 100644 --- a/ui/gtk/icon.c +++ b/ui/gtk/icon.c @@ -123,6 +123,8 @@ UiIcon* ui_fileicon(size_t size) { char *path = g_file_get_path(file); if(!path) { icon = ui_icon("application-x-generic", size); + } else { + g_free(path); } #else if(!icon) { @@ -143,6 +145,7 @@ GdkPixbuf* ui_icon_pixbuf(UiIcon *icon) { GError *error = NULL; char *path = g_file_get_path(file); icon->pixbuf = gdk_pixbuf_new_from_file(path, &error); + g_free(path); } return icon->pixbuf; } diff --git a/ui/gtk/list.c b/ui/gtk/list.c index e8b649c..14f8aec 100644 --- a/ui/gtk/list.c +++ b/ui/gtk/list.c @@ -33,6 +33,7 @@ #include "../common/context.h" #include "../common/object.h" +#include "../common/action.h" #include "container.h" #include @@ -83,14 +84,19 @@ static UiListView* create_listview(UiObject *obj, UiListArgs *args) { tableview->multiselection = args->multiselection; tableview->onactivate = args->onactivate; tableview->onactivatedata = args->onactivatedata; + tableview->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; tableview->onselection = args->onselection; tableview->onselectiondata = args->onselectiondata; + tableview->onselection_action = args->onselection_action ? strdup(args->onselection_action) : NULL; tableview->ondragstart = args->ondragstart; tableview->ondragstartdata = args->ondragstartdata; + tableview->ondragstart_action = args->ondragstart_action ? strdup(args->ondragstart_action) : NULL; tableview->ondragcomplete = args->ondragcomplete; tableview->ondragcompletedata = args->ondragcompletedata; + tableview->ondragcomplete_action = args->ondragcomplete_action ? strdup(args->ondragcomplete_action) : NULL; tableview->ondrop = args->ondrop; tableview->ondropdata = args->ondropdata; + tableview->ondrop_action = args->ondrop_action ? strdup(args->ondrop_action) : NULL; tableview->selection.count = 0; tableview->selection.rows = NULL; tableview->current_row = -1; @@ -254,7 +260,7 @@ static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, } else if(type == UI_BOOL_EDITABLE) { GtkWidget *checkbox = gtk_check_button_new(); gtk_list_item_set_child(item, checkbox); - }else { + } else { GtkWidget *label = gtk_label_new(NULL); gtk_label_set_xalign(GTK_LABEL(label), 0); gtk_list_item_set_child(item, label); @@ -345,6 +351,7 @@ static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, g } case UI_STRING: { gtk_label_set_label(GTK_LABEL(child), data); + gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_END); if(freevalue) { free(data); } @@ -508,7 +515,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { } // event handling - if(args->onactivate) { + if(args->onactivate || args->onactivate_action) { // columnview and listview can use the same callback function, because // the first parameter (which is technically a different pointer type) // is ignored @@ -661,6 +668,9 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection); GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model)); + if(args->hide_header) { + gtk_widget_set_visible(gtk_widget_get_first_child(view), FALSE); + } UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); @@ -715,7 +725,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { } // event handling - if(args->onactivate) { + if(args->onactivate || args->onactivate_action) { g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview); } if(args->contextmenu) { @@ -803,7 +813,7 @@ static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) { return sel; } -static void listview_event(ui_callback cb, void *cbdata, UiListView *view) { +static void listview_event(ui_callback cb, void *cbdata, const char *action, UiListView *view) { UiEvent event; event.obj = view->obj; event.document = event.obj->ctx->document; @@ -815,6 +825,10 @@ static void listview_event(ui_callback cb, void *cbdata, UiListView *view) { if(cb) { cb(&event, cbdata); } + + if(action) { + uic_action_callback(&event, action); + } } static void listview_update_selection(UiListView *view) { @@ -865,13 +879,15 @@ void ui_columnview_activate(void *ignore, guint position, gpointer userdata) { if(view->selection.count == 0) { listview_update_selection(view); } - listview_event(view->onactivate, view->onactivatedata, view); + listview_event(view->onactivate, view->onactivatedata, view->onactivate_action, view); } void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) { UiListView *view = userdata; listview_update_selection(view); - listview_event(view->onselection, view->onselectiondata, view); + if(ui_selection_events_is_enabled()) { + listview_event(view->onselection, view->onselectiondata, view->onselection_action, view); + } } void ui_dropdown_activate(GtkDropDown* self, gpointer userdata) { @@ -922,6 +938,9 @@ void ui_listview_update2(UiList *list, int i) { if(i < 0) { cxMapClear(view->bound_rows); ui_update_liststore(view->liststore, list); + free(view->selection.rows); + view->selection.rows = NULL; + view->selection.count = 0; } else { void *value = list->get(list, i); if(value) { @@ -1240,6 +1259,11 @@ static GtkListStore* create_list_store(UiListView *listview, UiList *list) { return store; } +static void ui_destroy_tree_eventdata(GtkWidget *object, UiTreeEventData *data) { + free(data->activate_action); + free(data->selection_action); + free(data); +} UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { // create treeview @@ -1297,22 +1321,23 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { event->obj = obj; event->activate = args->onactivate; event->activatedata = args->onactivatedata; + event->activate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; event->selection = args->onselection; event->selectiondata = args->onselectiondata; + event->selection_action = args->onselection_action ? strdup(args->onselection_action) : NULL; g_signal_connect( view, "destroy", - G_CALLBACK(ui_destroy_userdata), + G_CALLBACK(ui_destroy_tree_eventdata), event); - - if(args->onactivate) { + if(args->onactivate || args->onactivate_action) { g_signal_connect( view, "row-activated", G_CALLBACK(ui_listview_activate_event), event); } - if(args->onselection) { + if(args->onselection || args->onselection_action) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(view)); g_signal_connect( @@ -1385,6 +1410,9 @@ static void table_cell_edited( UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { // create treeview GtkWidget *view = gtk_tree_view_new(); + if(args->hide_header) { + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + } UiModel *model = args->model; int columns = model ? model->columns : 0; @@ -1521,20 +1549,27 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { list->obj = tableview; // add callback - UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); + UiTreeEventData *event = malloc(sizeof(UiTreeEventData)); event->obj = obj; event->activate = args->onactivate; - event->selection = args->onselection; event->activatedata = args->onactivatedata; + event->activate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; + event->selection = args->onselection; event->selectiondata = args->onselectiondata; - if(args->onactivate) { + event->selection_action = args->onselection_action ? strdup(args->onselection_action) : NULL; + g_signal_connect( + view, + "destroy", + G_CALLBACK(ui_destroy_tree_eventdata), + event); + if(args->onactivate || args->onactivate_action) { g_signal_connect( view, "row-activated", G_CALLBACK(ui_listview_activate_event), event); } - if(args->onselection) { + if(args->onselection || args->onselection_action) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(view)); g_signal_connect( @@ -1543,8 +1578,6 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { G_CALLBACK(ui_listview_selection_event), event); } - // TODO: destroy callback - if(args->ondragstart) { ui_listview_add_dnd(tableview, args); @@ -1776,19 +1809,28 @@ void ui_listview_activate_event( e.window = event->obj->window; e.document = event->obj->ctx->document; e.eventdata = &selection; + e.eventdatatype = UI_EVENT_DATA_LIST_SELECTION; e.intval = selection.count > 0 ? selection.rows[0] : -1; e.set = ui_get_setop(); - event->activate(&e, event->activatedata); - if(selection.count > 0) { - free(selection.rows); + if(event->activate) { + event->activate(&e, event->activatedata); + } + if(event->activate_action) { + uic_action_callback(&e, event->activate_action); } + + free(selection.rows); } void ui_listview_selection_event( GtkTreeSelection *treeselection, UiTreeEventData *event) { + if(!ui_selection_events_is_enabled()) { + return; + } + UiListSelection selection = ui_listview_get_selection(treeselection, event); UiEvent e; @@ -1796,13 +1838,17 @@ void ui_listview_selection_event( e.window = event->obj->window; e.document = event->obj->ctx->document; e.eventdata = &selection; + e.eventdatatype = UI_EVENT_DATA_LIST_SELECTION; e.intval = selection.count > 0 ? selection.rows[0] : -1; e.set = ui_get_setop(); - event->selection(&e, event->selectiondata); - - if(selection.count > 0) { - free(selection.rows); + if(event->selection) { + event->selection(&e, event->selectiondata); } + if(event->selection_action) { + uic_action_callback(&e, event->selection_action); + } + + free(selection.rows); } UiListSelection ui_listview_get_selection( @@ -2159,6 +2205,11 @@ void ui_table_dragdest_a(UIWIDGET tablewidget, int actions, char **targets, int */ void ui_listview_destroy(GtkWidget *w, UiListView *v) { + free(v->onactivate_action); + free(v->onselection_action); + free(v->ondragstart_action); + free(v->ondragcomplete_action); + free(v->ondrop_action); //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); if(v->var) { ui_destroy_boundvar(v->obj->ctx, v->var); diff --git a/ui/gtk/list.h b/ui/gtk/list.h index e7beb0e..69f30e4 100644 --- a/ui/gtk/list.h +++ b/ui/gtk/list.h @@ -81,14 +81,19 @@ struct UiListView { #endif ui_callback onactivate; void *onactivatedata; + char *onactivate_action; ui_callback onselection; void *onselectiondata; + char *onselection_action; ui_callback ondragstart; void *ondragstartdata; + char *ondragstart_action; ui_callback ondragcomplete; void *ondragcompletedata; + char *ondragcomplete_action; ui_callback ondrop; void *ondropdata; + char *ondrop_action; ui_list_savefunc onsave; void *onsavedata; UiListSelection selection; @@ -101,6 +106,8 @@ typedef struct UiTreeEventData { ui_callback selection; void *activatedata; void *selectiondata; + char *activate_action; + char *selection_action; } UiTreeEventData; typedef struct UiListBox UiListBox; diff --git a/ui/gtk/menu.c b/ui/gtk/menu.c index 8bfbbbf..5ce909d 100644 --- a/ui/gtk/menu.c +++ b/ui/gtk/menu.c @@ -37,6 +37,7 @@ #include "../common/context.h" #include "../common/menu.h" #include "../common/types.h" +#include "../common/action.h" #include "../ui/properties.h" #include "../ui/window.h" #include "container.h" @@ -276,6 +277,7 @@ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObje ls->index = index; ls->oldcount = 0; ls->getvalue = il->getvalue; + ls->getvaluedata = il->getvaluedata; UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); //UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST); @@ -339,10 +341,13 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) { gtk_widget_show(widget); } - ui_getvaluefunc getvalue = list->getvalue; + ui_getvaluefunc2 getvalue = list->getvalue; + void *getvaluedata = list->getvaluedata; int i = 1; + int row = 0; while(elm) { - char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + UiBool freeResult = FALSE; + char *label = (char*) (getvalue ? getvalue(ls, elm, row, 0, getvaluedata, &freeResult) : elm); GtkWidget *widget = gtk_menu_item_new_with_label(label); gtk_menu_shell_insert(list->menu, widget, list->index + i); @@ -371,6 +376,11 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) { elm = ui_list_next(ls); i++; + row++; + + if(freeResult) { + free(label); + } } list->oldcount = i; @@ -590,7 +600,15 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject cxListFree(groups); } - if(i->callback != NULL) { + if(i->action) { + uic_bind_action(obj->ctx, i->action, action, (ui_enablefunc)action_enable); + UiAction *ui_action = uic_resolve_action(obj->ctx, i->action); + if(!ui_action) { + action_enable(action, FALSE); + } + } + + if(i->callback != NULL || i->action) { UiEventData *event = malloc(sizeof(UiEventData)); event->obj = obj; event->userdata = i->userdata; @@ -598,6 +616,7 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject event->value = 0; event->customdata = NULL; event->customint = 0; + event->action = i->action ? strdup(i->action) : NULL; g_signal_connect( action, @@ -607,13 +626,13 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject g_signal_connect( obj->widget, "destroy", - G_CALLBACK(ui_destroy_userdata), + G_CALLBACK(ui_destroy_eventdata), event); } char action_name[32]; snprintf(action_name, 32, "win.%s", item->id); - + g_menu_append(parent, i->label, action_name); } @@ -658,7 +677,7 @@ static void stateful_action_notify_group(UiMenuRadioGroup *group, UiInteger *i) CxIterator iter = cxListIterator(group->callbacks); cx_foreach(UiCallbackData *, cb, iter) { - event.intval = intval == iter.index; + event.intval = intval-1 == iter.index; if(cb->callback) { cb->callback(&event, cb->userdata); } @@ -782,7 +801,7 @@ void ui_gmenu_add_radioitem(GMenu *parent, int index, UiMenuItemI *item, UiObjec cxListAdd(group->callbacks, &cb); - cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index); + cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index+1); g_menu_append(parent, i->label, action_name.ptr); free(action_name.ptr); } @@ -815,6 +834,7 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject ls->index = index; ls->oldcount = 0; ls->getvalue = il->getvalue; + ls->getvaluedata = il->getvalue; GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i")); g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); @@ -888,7 +908,12 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent evt.eventdatatype = uic_get_tmp_eventdata_type(); } evt.intval = intval; - event->callback(&evt, event->userdata); + if(event->callback) { + event->callback(&evt, event->userdata); + } + if(event->action) { + uic_action_callback(&evt, event->action); + } uic_set_tmp_eventdata(NULL, 0); } @@ -928,11 +953,13 @@ void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) { UiList *ls = list->var->value; // add list items - ui_getvaluefunc getvalue = list->getvalue; + ui_getvaluefunc2 getvalue = list->getvalue; + void *getvaluedata = list->getvaluedata; int i = 0; void* elm = ui_list_first(ls); while(elm) { - char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + UiBool freeResult = FALSE; + char *label = (char*) (getvalue ? getvalue(ls, elm, i, 0, getvaluedata, &freeResult) : elm); GMenuItem *item = g_menu_item_new(label, NULL); GVariant *v = g_variant_new("i", i); @@ -942,6 +969,10 @@ void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) { elm = ui_list_next(ls); i++; + + if(freeResult) { + free(label); + } } list->oldcount = i; diff --git a/ui/gtk/menu.h b/ui/gtk/menu.h index 4cfa419..d113f33 100644 --- a/ui/gtk/menu.h +++ b/ui/gtk/menu.h @@ -56,7 +56,8 @@ struct UiActiveMenuItemList { int index; int oldcount; UiVar *var; - ui_getvaluefunc getvalue; + ui_getvaluefunc2 getvalue; + void *getvaluedata; ui_callback callback; void *userdata; }; @@ -95,7 +96,8 @@ struct UiActiveGMenuItemList { int index; int oldcount; UiVar *var; - ui_getvaluefunc getvalue; + ui_getvaluefunc2 getvalue; + void *getvaluedata; ui_callback callback; void *userdata; }; diff --git a/ui/gtk/objs.mk b/ui/gtk/objs.mk index abad5a0..1c79646 100644 --- a/ui/gtk/objs.mk +++ b/ui/gtk/objs.mk @@ -48,6 +48,7 @@ GTKOBJ += dnd.o GTKOBJ += headerbar.o GTKOBJ += webview.o GTKOBJ += widget.o +GTKOBJ += action.o TOOLKITOBJS += $(GTKOBJ:%=$(GTK_OBJPRE)%) TOOLKITSOURCE += $(GTKOBJ:%.o=gtk/%.c) diff --git a/ui/gtk/text.c b/ui/gtk/text.c index 0bcd54d..4ce3a40 100644 --- a/ui/gtk/text.c +++ b/ui/gtk/text.c @@ -54,9 +54,9 @@ static void selection_handler( int sel = gtk_text_buffer_get_selection_bounds (buf, &begin, &end); if(sel != textview->last_selection_state) { if(sel) { - ui_set_state(textview->ctx, UI_GROUP_SELECTION); + ui_set_state(textview->ctx, UI_STATE_SELECTION); } else { - ui_unset_state(textview->ctx, UI_GROUP_SELECTION); + ui_unset_state(textview->ctx, UI_STATE_SELECTION); } } textview->last_selection_state = sel; @@ -102,6 +102,17 @@ static GtkTextBuffer* create_textbuffer(UiTextArea *textarea) { "changed", G_CALLBACK(ui_textbuf_changed), textarea); + + g_signal_connect( + buf, + "insert-text", + G_CALLBACK(ui_textbuf_change_insert), + textarea); + g_signal_connect( + buf, + "delete-range", + G_CALLBACK(ui_textbuf_change_delete), + textarea); } else { fprintf(stderr, "Error: create_textbuffer: textarea == NULL\n"); } @@ -129,8 +140,13 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { uitext->last_selection_state = 0; uitext->onchange = args->onchange; uitext->onchangedata = args->onchangedata; + uitext->onchange_action = args->onchange_action ? strdup(args->onchange_action) : NULL; + uitext->ontextchanged = args->ontextchanged; + uitext->ontextchangeddata = args->ontextchangeddata; + uitext->ontextchanged_action = args->ontextchanged_action ? strdup(args->ontextchanged_action) : NULL; g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext); + g_object_set_data(G_OBJECT(text_area), "ui_textarea_widget", text_area); g_signal_connect( text_area, @@ -144,6 +160,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area); + g_object_set_data(G_OBJECT(scroll_area), "ui_textarea_widget", text_area); ui_widget_size_request(scroll_area, args->width, args->height); @@ -160,6 +177,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, scroll_area, &layout); + uic_widget_set_visibility_states(obj->ctx, scroll_area, args->visibility_states); // bind value if(var) { @@ -174,6 +192,11 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { value->value.free(value->value.ptr); } } + + if(value->readonly) { + gtk_text_view_set_editable(GTK_TEXT_VIEW(text_area), FALSE); + } + gtk_text_view_set_buffer(GTK_TEXT_VIEW(text_area), buf); value->obj = text_area; value->save = ui_textarea_save; @@ -183,11 +206,15 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { value->set = ui_textarea_set; value->getsubstr = ui_textarea_getsubstr; value->insert = ui_textarea_insert; + value->replace = ui_textarea_replace; value->setposition = ui_textarea_setposition; value->position = ui_textarea_position; + value->showposition = ui_textarea_showposition; + value->setselection = ui_textarea_setselection; value->selection = ui_textarea_selection; value->length = ui_textarea_length; value->remove = ui_textarea_remove; + value->setreadonly = ui_textarea_setreadonly; value->data1 = buf; value->data2 = NULL; value->datatype == UI_TEXT_TYPE_BUFFER; @@ -206,11 +233,107 @@ void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea) { if(textarea->var) { ui_destroy_boundvar(textarea->ctx, textarea->var); } + free(textarea->onchange_action); + free(textarea->ontextchanged_action); free(textarea); } +void ui_textarea_scroll_to(UIWIDGET textarea, int pos) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_scroll_to: widget is not a textarea\n"); + return; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + + GtkTextIter offset; + gtk_text_buffer_get_iter_at_offset(buf, &offset, pos); + + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget), &offset, 0.2, FALSE, 0, 0); +} + +void ui_textarea_focus(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_focus: widget is not a textarea\n"); + return; + } + gtk_widget_grab_focus(widget); +} + +void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_selection: widget is not a textarea\n"); + return; + } + + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter ib; + GtkTextIter ie; + gtk_text_buffer_get_iter_at_offset(buf, &ib, begin); + gtk_text_buffer_get_iter_at_offset(buf, &ie, end); + gtk_text_buffer_select_range(buf, &ib, &ie); +} + +void ui_textarea_select_all(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_select_all: widget is not a textarea\n"); + return; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter start; + GtkTextIter end; + gtk_text_buffer_get_bounds(buf, &start, &end); + gtk_text_buffer_select_range(buf, &start, &end); +} + +void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_editable: widget is not a textarea\n"); + return; + } + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), editable); +} + +UiBool ui_textarea_is_editable(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_is_editable: widget is not a textarea\n"); + return 0; + } + return gtk_text_view_get_editable(GTK_TEXT_VIEW(widget)); +} + +void ui_textarea_set_position(UIWIDGET textarea, int pos) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_position: widget is not a textarea\n"); + return; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter iter; + gtk_text_buffer_get_iter_at_offset(buf, &iter, pos); + gtk_text_buffer_place_cursor(buf, &iter); +} + +int ui_textarea_get_position(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_get_position: widget is not a textarea\n"); + return 0; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter begin; + GtkTextIter end; + gtk_text_buffer_get_selection_bounds(buf, &begin, &end); + return gtk_text_iter_get_offset(&begin); +} + UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { - return SCROLLEDWINDOW_GET_CHILD(textarea); + return g_object_get_data(G_OBJECT(textarea), "ui_textarea_widget"); } void ui_textarea_save(UiText *text) { @@ -224,6 +347,7 @@ void ui_textarea_restore(UiText *text) { text->datatype = UI_TEXT_TYPE_BUFFER; } gtk_text_view_set_buffer(GTK_TEXT_VIEW(textarea), text->data1); + gtk_text_view_set_editable(GTK_TEXT_VIEW(textarea), !text->readonly); } void ui_textarea_text_destroy(UiText *text) { @@ -269,7 +393,7 @@ char* ui_textarea_getsubstr(UiText *text, int begin, int end) { return str; } -void ui_textarea_insert(UiText *text, int pos, char *str) { +void ui_textarea_insert(UiText *text, int pos, const char *str) { GtkTextIter offset; gtk_text_buffer_get_iter_at_offset(text->data1, &offset, pos); gtk_text_buffer_insert(text->data1, &offset, str, -1); @@ -280,6 +404,20 @@ void ui_textarea_insert(UiText *text, int pos, char *str) { text->value.free = NULL; } +void ui_textarea_replace(UiText *text, int begin, int end, const char *replacement) { + GtkTextBuffer *buffer = text->data1; + GtkTextIter begin_offset; + GtkTextIter end_offset; + gtk_text_buffer_get_iter_at_offset(buffer, &begin_offset, begin); + gtk_text_buffer_get_iter_at_offset(buffer, &end_offset, end); + gtk_text_buffer_begin_user_action(buffer); + gtk_text_buffer_delete(buffer, &begin_offset, &end_offset); + if(replacement) { + gtk_text_buffer_insert(buffer, &begin_offset, replacement, -1); + } + gtk_text_buffer_end_user_action(buffer); +} + void ui_textarea_setposition(UiText *text, int pos) { GtkTextIter iter; gtk_text_buffer_get_iter_at_offset(text->data1, &iter, pos); @@ -294,6 +432,21 @@ int ui_textarea_position(UiText *text) { return text->pos; } +void ui_textarea_showposition(UiText *text, int pos) { + if(text->obj) { + ui_textarea_scroll_to(text->obj, pos); + } +} + +void ui_textarea_setselection(UiText *text, int begin, int end) { + GtkTextBuffer *buf = text->data1; + GtkTextIter ib; + GtkTextIter ie; + gtk_text_buffer_get_iter_at_offset(text->data1, &ib, begin); + gtk_text_buffer_get_iter_at_offset(text->data1, &ie, end); + gtk_text_buffer_select_range(buf, &ib, &ie); +} + void ui_textarea_selection(UiText *text, int *begin, int *end) { GtkTextIter b; GtkTextIter e; @@ -319,11 +472,72 @@ void ui_textarea_remove(UiText *text, int begin, int end) { gtk_text_buffer_delete(buf, &ib, &ie); } +void ui_textarea_setreadonly(UiText *text, int readonly) { + if(text->obj) { + gtk_text_view_set_editable(GTK_TEXT_VIEW(text->obj), !readonly); + } + text->readonly = readonly; +} + void ui_textarea_realize_event(GtkWidget *widget, gpointer data) { gtk_widget_grab_focus(widget); } +static void textbuf_change_event(UiTextArea *textarea, UiTextChangeEventData *data) { + if(!ui_onchange_events_is_enabled()) { + return; + } + + UiEvent e; + e.obj = textarea->obj; + e.window = e.obj->window; + e.document = textarea->ctx->document; + e.eventdata = data; + e.eventdatatype = UI_EVENT_DATA_TEXT_CHANGED; + e.intval = 0; + e.set = ui_get_setop(); + + if(textarea->onchange) { + textarea->onchange(&e, textarea->onchangedata); + } + + if(textarea->onchange_action) { + uic_action_callback(&e, textarea->onchange_action); + } +} + +void ui_textbuf_change_insert( + GtkTextBuffer *textbuffer, + GtkTextIter *location, + char *text, + int length, + UiTextArea *textarea) +{ + UiTextChangeEventData event; + event.type = UI_TEXT_INSERT; + event.begin = gtk_text_iter_get_offset(location); + event.end = event.begin + length; + event.text = text; + event.length = length; + textbuf_change_event(textarea, &event); +} + +void ui_textbuf_change_delete( + GtkTextBuffer *self, + const GtkTextIter *start, + const GtkTextIter *end, + UiTextArea *textarea) +{ + UiTextChangeEventData event; + event.type = UI_TEXT_DELETE; + event.begin = gtk_text_iter_get_offset(start); + event.end = gtk_text_iter_get_offset(end); + event.text = NULL; + event.length = 0; + textbuf_change_event(textarea, &event); +} + void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) { if(!ui_onchange_events_is_enabled()) { @@ -341,8 +555,12 @@ void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) { e.intval = 0; e.set = ui_get_setop(); - if(textarea->onchange) { - textarea->onchange(&e, textarea->onchangedata); + if(textarea->ontextchanged) { + textarea->ontextchanged(&e, textarea->ontextchangeddata); + } + + if(textarea->ontextchanged_action) { + uic_action_callback(&e, textarea->ontextchanged_action); } if(value->observers) { @@ -436,6 +654,7 @@ void ui_textbuf_delete( if(!value->data2) { value->data2 = ui_create_undomgr(); } + GtkTextBuffer *buf = value->data1; UiUndoMgr *mgr = value->data2; if(!mgr->event) { return; @@ -455,7 +674,7 @@ void ui_textbuf_delete( } } - char *text = gtk_text_buffer_get_text(value->obj, start, end, FALSE); + char *text = gtk_text_buffer_get_text(buf, start, end, FALSE); UiTextBufOp *op = malloc(sizeof(UiTextBufOp)); op->prev = NULL; @@ -531,6 +750,7 @@ int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) { } void ui_text_undo(UiText *value) { + GtkTextBuffer *buf = value->data1; UiUndoMgr *mgr = value->data2; if(mgr->cur) { @@ -540,17 +760,17 @@ void ui_text_undo(UiText *value) { case UI_TEXTBUF_INSERT: { GtkTextIter begin; GtkTextIter end; - gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start); - gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end); - gtk_text_buffer_delete(value->obj, &begin, &end); + gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start); + gtk_text_buffer_get_iter_at_offset(buf, &end, op->end); + gtk_text_buffer_delete(buf, &begin, &end); break; } case UI_TEXTBUF_DELETE: { GtkTextIter begin; GtkTextIter end; - gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start); - gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end); - gtk_text_buffer_insert(value->obj, &begin, op->text, op->len); + gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start); + gtk_text_buffer_get_iter_at_offset(buf, &end, op->end); + gtk_text_buffer_insert(buf, &begin, op->text, op->len); break; } } @@ -560,6 +780,7 @@ void ui_text_undo(UiText *value) { } void ui_text_redo(UiText *value) { + GtkTextBuffer *buf = value->data1; UiUndoMgr *mgr = value->data2; UiTextBufOp *elm = NULL; @@ -578,17 +799,17 @@ void ui_text_redo(UiText *value) { case UI_TEXTBUF_INSERT: { GtkTextIter begin; GtkTextIter end; - gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start); - gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end); - gtk_text_buffer_insert(value->obj, &begin, op->text, op->len); + gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start); + gtk_text_buffer_get_iter_at_offset(buf, &end, op->end); + gtk_text_buffer_insert(buf, &begin, op->text, op->len); break; } case UI_TEXTBUF_DELETE: { GtkTextIter begin; GtkTextIter end; - gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start); - gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end); - gtk_text_buffer_delete(value->obj, &begin, &end); + gtk_text_buffer_get_iter_at_offset(buf, &begin, op->start); + gtk_text_buffer_get_iter_at_offset(buf, &end, op->end); + gtk_text_buffer_delete(buf, &begin, &end); break; } } @@ -614,6 +835,8 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor uitext->onchangedata = args->onchangedata; uitext->onactivate = args->onactivate; uitext->onactivatedata = args->onactivatedata; + uitext->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; + uitext->onchange_action = args->onchange_action ? strdup(args->onchange_action) : NULL; g_signal_connect( textfield, @@ -639,6 +862,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, textfield, &layout); + uic_widget_set_visibility_states(obj->ctx, textfield, args->visibility_states); if(var) { UiString *value = var->value; @@ -656,7 +880,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor value->obj = GTK_ENTRY(textfield); } - if(args->onchange || var) { + if(args->onchange || args->onchange_action || var) { g_signal_connect( textfield, "changed", @@ -664,7 +888,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor uitext); } - if(args->onactivate) { + if(args->onactivate || args->onactivate_action) { g_signal_connect( textfield, "activate", @@ -687,8 +911,45 @@ UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) { return create_textfield(obj, FALSE, TRUE, args); } +void ui_textfield_focus(UIWIDGET textfield) { + gtk_widget_grab_focus(textfield); +} + +void ui_textfield_focus_without_selecting(UIWIDGET textfield) { +#if GTK_CHECK_VERSION(3, 16, 0) + gtk_entry_grab_focus_without_selecting(GTK_ENTRY(textfield)); +#else + gtk_widget_grab_focus(textfield); +#endif +} + +void ui_textfield_set_selection(UIWIDGET textfield, int begin, int end) { + ENTRY_SET_SELECTION(textfield, begin, end); +} + +void ui_textfield_select_all(UIWIDGET textfield) { + ENTRY_SET_SELECTION(textfield, 0, -1); +} + +void ui_textfield_set_editable(UIWIDGET textfield, UiBool editable) { + ENTRY_SET_EDITABLE(textfield, editable); +} + +UiBool ui_textfield_is_editable(UIWIDGET textfield) { + ENTRY_IS_EDITABLE(textfield); +} + +void ui_textfield_set_position(UIWIDGET textfield, int pos) { + ENTRY_SET_POSITION(textfield, pos); +} + +int ui_textfield_get_position(UIWIDGET textfield) { + return ENTRY_GET_POSITION(textfield); +} void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) { + free(textfield->onactivate_action); + free(textfield->onchange_action); free(textfield); } @@ -704,7 +965,7 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) { e.window = e.obj->window; e.document = textfield->obj->ctx->document; e.eventdata = value; - e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0; + e.eventdatatype = value ? UI_EVENT_DATA_STRING_VALUE : 0; e.intval = 0; e.set = ui_get_setop(); @@ -715,22 +976,31 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) { if(textfield->var) { ui_notify_evt(value->observers, &e); } + + if(textfield->onchange_action) { + uic_action_callback(&e, textfield->onchange_action); + } } void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) { - if(textfield->onactivate) { - UiString *value = textfield->var ? textfield->var->value : NULL; + UiString *value = textfield->var ? textfield->var->value : NULL; - UiEvent e; - e.obj = textfield->obj; - e.window = e.obj->window; - e.document = textfield->obj->ctx->document; - e.eventdata = value; - e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0; - e.intval = 0; - e.set = ui_get_setop(); + UiEvent e; + e.obj = textfield->obj; + e.window = e.obj->window; + e.document = textfield->obj->ctx->document; + e.eventdata = value; + e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0; + e.intval = 0; + e.set = ui_get_setop(); + + if(textfield->onactivate) { textfield->onactivate(&e, textfield->onactivatedata); } + + if(textfield->onactivate_action) { + uic_action_callback(&e, textfield->onactivate_action); + } } char* ui_textfield_get(UiString *str) { @@ -964,6 +1234,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, pathtf->stack, &layout); + uic_widget_set_visibility_states(obj->ctx, pathtf->stack, args->visibility_states); pathtf->entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); pathtf->entry = gtk_entry_new(); @@ -1139,6 +1410,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) { UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); ct->add(ct, eventbox, &layout); + uic_widget_set_visibility_states(obj->ctx, eventbox, args->visibility_states); // hbox as parent for the GtkEntry and GtkButtonBox GtkWidget *hbox = ui_gtk_hbox_new(0); diff --git a/ui/gtk/text.h b/ui/gtk/text.h index b7fbda4..cb12ea1 100644 --- a/ui/gtk/text.h +++ b/ui/gtk/text.h @@ -67,6 +67,10 @@ typedef struct UiTextArea { int last_selection_state; ui_callback onchange; void *onchangedata; + char *onchange_action; + ui_callback ontextchanged; + void *ontextchangeddata; + char *ontextchanged_action; } UiTextArea; typedef struct UiTextField { @@ -76,6 +80,8 @@ typedef struct UiTextField { void *onchangedata; ui_callback onactivate; void *onactivatedata; + char *onactivate_action; + char *onchange_action; } UiTextField; typedef struct UiPathTextField { @@ -117,14 +123,31 @@ void ui_textarea_text_destroy(UiText *text); char* ui_textarea_get(UiText *text); void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); -void ui_textarea_insert(UiText *text, int pos, char *str); +void ui_textarea_insert(UiText *text, int pos, const char *str); +void ui_textarea_replace(UiText *text, int begin, int end, const char *replacement); void ui_textarea_setposition(UiText *text, int pos); int ui_textarea_position(UiText *text); +void ui_textarea_showposition(UiText *text, int pos); +void ui_textarea_setselection(UiText *text, int begin, int end); void ui_textarea_selection(UiText *text, int *begin, int *end); int ui_textarea_length(UiText *text); void ui_textarea_remove(UiText *text, int begin, int end); +void ui_textarea_setreadonly(UiText *text, int readonly); void ui_textarea_realize_event(GtkWidget *widget, gpointer data); +//void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea); +void ui_textbuf_change_insert( + GtkTextBuffer *textbuffer, + GtkTextIter *location, + char *text, + int length, + UiTextArea *textarea); +void ui_textbuf_change_delete( + GtkTextBuffer *self, + const GtkTextIter *start, + const GtkTextIter *end, + UiTextArea *textarea); + void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea); void ui_textbuf_insert( diff --git a/ui/gtk/toolbar.c b/ui/gtk/toolbar.c index 33efbcd..1f6cc19 100644 --- a/ui/gtk/toolbar.c +++ b/ui/gtk/toolbar.c @@ -140,13 +140,14 @@ void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) { ui_set_widget_nstates(obj->ctx, GTK_WIDGET(button), item->args.states, item->nstates); - if(item->args.onclick) { + if(item->args.onclick || item->args.action) { UiEventData *event = cxMalloc( obj->ctx->allocator, sizeof(UiEventData)); event->obj = obj; event->callback = item->args.onclick; event->userdata = item->args.onclickdata; + event->action = item->args.action ? ui_strdup(obj->ctx, item->args.action) : NULL; event->customdata = NULL; event->customint = 0; event->value = 0; @@ -202,6 +203,7 @@ void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObj event->obj = obj; event->callback = item->args.onchange; event->userdata = item->args.onchangedata; + event->action = item->args.action ? ui_strdup(obj->ctx, item->args.action) : NULL;; event->var = var; g_signal_connect( @@ -239,6 +241,10 @@ void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event) if(i) { ui_notify_evt(i->observers, &e); } + + if(event->action) { + uic_action_callback(&e, event->action); + } } int64_t ui_tool_toggle_button_get(UiInteger *integer) { diff --git a/ui/gtk/toolbar.h b/ui/gtk/toolbar.h index 7534c63..659e9cb 100644 --- a/ui/gtk/toolbar.h +++ b/ui/gtk/toolbar.h @@ -42,68 +42,6 @@ extern "C" { #if UI_GTK2 || UI_GTK3 -typedef struct UiToolItemI UiToolItemI; -typedef struct UiToolItem UiToolItem; -typedef struct UiStToolItem UiStToolItem; -typedef struct UiToggleToolItem UiToggleToolItem; - -typedef struct UiToolbarComboBox UiToolbarComboBox; -typedef struct UiToolbarComboBoxNV UiToolbarComboBoxNV; - -typedef void(*ui_toolbar_add_f)(GtkToolbar*, UiToolItemI*, UiObject*); - -struct UiToolItemI { - ui_toolbar_add_f add_to; -}; - -struct UiToolItem { - UiToolItemI item; - const char *label; - const char *image; - ui_callback callback; - void *userdata; - const char *varname; - CxList *groups; - int isimportant; -}; - -struct UiStToolItem { - UiToolItemI item; - const char *stockid; - ui_callback callback; - void *userdata; - const char *varname; - CxList *groups; - int isimportant; -}; - -struct UiToggleToolItem { - UiToolItemI item; - const char *label; - const char *image; - const char *stockid; - UiInteger *value; - const char *var; - CxList *groups; - int isimportant; -}; - -struct UiToolbarComboBox { - UiToolItemI item; - UiVar *var; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - -struct UiToolbarComboBoxNV { - UiToolItemI item; - char *listname; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - void ui_toolitem_vstgr( char *name, diff --git a/ui/gtk/toolkit.c b/ui/gtk/toolkit.c index 10cba07..dbdde0a 100644 --- a/ui/gtk/toolkit.c +++ b/ui/gtk/toolkit.c @@ -33,6 +33,7 @@ #include "toolkit.h" #include "toolbar.h" +#include "window.h" #include "icon.h" #include "../common/document.h" #include "../common/properties.h" @@ -61,8 +62,11 @@ static int scale_factor = 1; static UiBool exit_on_shutdown; +// NOOP on most platforms, expect macos +void ui_set_main_thread_error_msg(const char *msg) {} + UIEXPORT void ui_init(const char *appname, int argc, char **argv) { - application_name = appname; + application_name = appname ? strdup(appname) : NULL; uic_init_global_context(); #if GTK_MAJOR_VERSION >= 4 @@ -76,6 +80,7 @@ UIEXPORT void ui_init(const char *appname, int argc, char **argv) { uic_toolbar_init(); ui_image_init(); uic_load_app_properties(); + uic_init_threads(); #if GTK_MAJOR_VERSION >= 4 scale_factor = 1; // TODO @@ -133,6 +138,24 @@ void ui_main() { } } + +void ui_app_ref(void) { +#ifdef UI_APPLICATION + g_application_hold(G_APPLICATION(app)); +#else + // TODO +#endif +} + +void ui_app_unref(void) { +#ifdef UI_APPLICATION + g_application_release(G_APPLICATION(app)); +#else + // TODO +#endif +} + + #ifndef UI_GTK2 void ui_app_quit() { g_application_quit(G_APPLICATION(app)); // TODO: fix, does not work @@ -144,27 +167,24 @@ GtkApplication* ui_get_application() { #endif void ui_show(UiObject *obj) { - gboolean visible = gtk_widget_is_visible(obj->widget); - - uic_check_state_widgets(obj->ctx); + gboolean visible = FALSE; + if(obj->widget) { + visible = gtk_widget_is_visible(obj->widget); #if GTK_MAJOR_VERSION >= 4 - gtk_window_present(GTK_WINDOW(obj->widget)); + gtk_window_present(GTK_WINDOW(obj->widget)); #elif GTK_MAJOR_VERSION <= 3 - gtk_widget_show_all(obj->widget); + gtk_widget_show_all(obj->widget); #endif - + } + uic_check_state_widgets(obj->ctx); + if(!visible) { obj->ref++; } } void ui_close(UiObject *obj) { - uic_context_prepare_close(obj->ctx); -#if GTK_CHECK_VERSION(4, 0, 0) - gtk_window_close(GTK_WINDOW(obj->widget)); -#else - gtk_widget_destroy(obj->widget); -#endif + ui_window_close_request(obj); } @@ -203,6 +223,11 @@ static gboolean ui_idle_func(void *data) { } void ui_call_mainthread(ui_threadfunc tf, void* td) { + if(uic_mainthread_calls_is_buffered()) { + uic_add_buffered_mainthread_call(tf, td); + return; + } + UiJob *job = malloc(sizeof(UiJob)); job->job_func = tf; job->job_data = td; @@ -234,7 +259,7 @@ void ui_set_show_all(UIWIDGET widget, int value) { #endif } -void ui_set_visible(UIWIDGET widget, UiBool visible) { +void ui_set_visible(UIWIDGET widget, int visible) { #if GTK_MAJOR_VERSION >= 4 gtk_widget_set_visible(widget, visible); #else @@ -282,6 +307,11 @@ void ui_destroy_userdata(GtkWidget *object, void *userdata) { free(userdata); } +void ui_destroy_eventdata(GtkWidget *object, UiEventData *data) { + free(data->action); + free(data); +} + void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data) { if(data->var) { ui_destroy_boundvar(data->obj->ctx, data->var); @@ -536,3 +566,16 @@ void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const i ui_set_visible(widget, FALSE); } } + +void ui_open_uri(const char *uri) { +#if GTK_CHECK_VERSION(4, 0, 0) + GtkUriLauncher *launcher = gtk_uri_launcher_new(uri); + gtk_uri_launcher_launch(launcher, NULL, NULL, NULL, NULL); + g_object_unref(launcher); +#elif GTK_CHECK_VERSION(3, 22, 0) + GError *error = NULL; + gtk_show_uri_on_window(NULL, uri, GDK_CURRENT_TIME, &error); +#elif + // TODO: call xdg-open +#endif +} diff --git a/ui/gtk/toolkit.h b/ui/gtk/toolkit.h index 0e421b9..432bebb 100644 --- a/ui/gtk/toolkit.h +++ b/ui/gtk/toolkit.h @@ -65,6 +65,11 @@ extern "C" { #define BOX_REMOVE(box, child) gtk_box_remove(GTK_BOX(box), child) #define ENTRY_SET_TEXT(entry, text) gtk_editable_set_text(GTK_EDITABLE(entry), text) #define ENTRY_GET_TEXT(entry) gtk_editable_get_text(GTK_EDITABLE(entry)) +#define ENTRY_SET_SELECTION(entry, begin, end) gtk_editable_select_region(GTK_EDITABLE(entry), begin, end) +#define ENTRY_SET_EDITABLE(entry, editable) gtk_editable_set_editable(GTK_EDITABLE(entry), editable) +#define ENTRY_IS_EDITABLE(entry) gtk_editable_get_editable(GTK_EDITABLE(entry)) +#define ENTRY_SET_POSITION(entry, pos) gtk_editable_set_position(GTK_EDITABLE(entry), pos) +#define ENTRY_GET_POSITION(entry) gtk_editable_get_position(GTK_EDITABLE(entry)) #define SCROLLEDWINDOW_NEW() gtk_scrolled_window_new() #define SCROLLEDWINDOW_SET_CHILD(sw, child) gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), child) #define SCROLLEDWINDOW_GET_CHILD(sw) gtk_scrolled_window_get_child(GTK_SCROLLED_WINDOW(sw)) @@ -90,6 +95,11 @@ extern "C" { #define BOX_REMOVE(box, child) gtk_container_remove(GTK_CONTAINER(box), child) #define ENTRY_SET_TEXT(entry, text) gtk_entry_set_text(GTK_ENTRY(entry), text) #define ENTRY_GET_TEXT(entry) gtk_entry_get_text(GTK_ENTRY(entry)) +#define ENTRY_SET_SELECTION(entry, begin, end) gtk_editable_select_region(GTK_EDITABLE(entry), begin, end) +#define ENTRY_SET_EDITABLE(entry, editable) gtk_editable_set_editable(GTK_EDITABLE(entry), editable) +#define ENTRY_IS_EDITABLE(entry) gtk_editable_get_editable(GTK_EDITABLE(entry)) +#define ENTRY_SET_POSITION(entry, pos) gtk_editable_set_position(GTK_EDITABLE(entry), pos) +#define ENTRY_GET_POSITION(entry) gtk_editable_get_position(GTK_EDITABLE(entry)) #define SCROLLEDWINDOW_NEW() gtk_scrolled_window_new(NULL, NULL) #define SCROLLEDWINDOW_SET_CHILD(sw, child) gtk_container_add(GTK_CONTAINER(sw), child) #define SCROLLEDWINDOW_GET_CHILD(sw) gtk_bin_get_child(GTK_BIN(sw)) @@ -139,6 +149,7 @@ typedef struct UiEventData { int value; int customint; void *customdata; + char *action; } UiEventData; typedef struct UiEventDataExt { @@ -162,6 +173,7 @@ typedef struct UiVarEventData { UiVar *var; UiObserver **observers; ui_callback callback; + char *action; void *userdata; int customint1; int customint2; @@ -190,6 +202,7 @@ void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const in void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups); void ui_destroy_userdata(GtkWidget *object, void *userdata); +void ui_destroy_eventdata(GtkWidget *object, UiEventData *data); void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data); void ui_destroy_widget_var(GtkWidget *object, UiVar *var); void ui_destroy_boundvar(UiContext *ctx, UiVar *var); diff --git a/ui/gtk/window.c b/ui/gtk/window.c index 1046391..009d432 100644 --- a/ui/gtk/window.c +++ b/ui/gtk/window.c @@ -44,6 +44,8 @@ #include "container.h" #include "headerbar.h" #include "button.h" +#include "window.h" +#include "widget.h" static int nwindows = 0; @@ -80,7 +82,7 @@ void ui_exit_event(GtkWidget *widget, gpointer data) { g_idle_add(ui_window_destroy, data); } -static gboolean ui_window_close_request(UiObject *obj) { +gboolean ui_window_close_request(UiObject *obj) { if(obj->widget) { void *appwindow = g_object_get_data(G_OBJECT(obj->widget), "ui.appwindow"); if(appwindow) { @@ -111,8 +113,12 @@ static gboolean ui_window_close_request(UiObject *obj) { } } - uic_context_prepare_close(obj->ctx); - obj->ref--; + if(obj->ref > 0) { + obj->ref--; + } else { + // warn about invalid reference counting + fprintf(stderr, "Error: UiObject %p ref == 0\n", obj); + } if(obj->ref > 0) { #if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_set_visible(obj->widget, FALSE); @@ -121,16 +127,32 @@ static gboolean ui_window_close_request(UiObject *obj) { #endif return TRUE; } else { + // this cleans up any widget references from the context + uic_context_prepare_close(obj->ctx); + ui_window_widget_destroy(obj); return FALSE; } } +static void window_onclose_callback(UiObject *obj) { + if(obj->onclose) { + UiEvent event; + memset(&event, 0, sizeof(UiEvent)); + event.obj = obj; + event.window = obj->window; + event.document = obj->ctx->document; + obj->onclose(&event, obj->onclosedata); + } +} + #if GTK_MAJOR_VERSION >= 4 static gboolean close_request(GtkWindow* self, UiObject *obj) { + window_onclose_callback(obj); return ui_window_close_request(obj); } #else static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) { + window_onclose_callback(obj); return ui_window_close_request(obj); } #endif @@ -153,6 +175,25 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi obj->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); #endif +#if GTK_MAJOR_VERSION < 4 + const char *window_pos = ui_get_property("ui.gtk.window.position"); + GtkWindowPosition wpos = GTK_WIN_POS_CENTER; + if(window_pos) { + if(!strcmp(window_pos, "none")) { + wpos = GTK_WIN_POS_NONE; + } else if(!strcmp(window_pos, "center")) { + //wpos = GTK_WIN_POS_CENTER; + } else if(!strcmp(window_pos, "mouse")) { + wpos = GTK_WIN_POS_MOUSE; + } else if(!strcmp(window_pos, "center_always")) { + wpos = GTK_WIN_POS_CENTER_ALWAYS; + } else { + fprintf(stderr, "Error: unknown value '%s' for property ui.gtk.window.positionhint", window_pos); + } + } + gtk_window_set_position(GTK_WINDOW(obj->widget), wpos); +#endif + #if GTK_CHECK_VERSION(4, 0, 0) obj->ctx->action_map = G_ACTION_MAP(obj->widget); #endif @@ -246,6 +287,8 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content); g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", vbox); g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_vbox); + g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel_top", toolbar_view); + g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel_top", right_panel); } GtkWidget *content_box = vbox; @@ -273,17 +316,23 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); } else if(!strcmp(show_title, "sidebar")) { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); + } } else if(!strcmp(show_title, "false")) { - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + } adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); } else { fprintf(stderr, "Unknown value '%s' for property ui.gtk.window.showtitle\n", show_title); - adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + if(headerbar_sidebar) { + adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE); + } } } else { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE); - if(sidebar) { + if(headerbar_sidebar) { adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE); } } @@ -342,6 +391,8 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content_paned); g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", content_box); g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_content_box); + g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel_top", content_box); + g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel_top", right_content_box); } else { PANED_SET_CHILD2(paned, content_box); } @@ -366,7 +417,7 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi gtk_container_add(GTK_CONTAINER(frame), content_box); obj->container = ui_box_container(obj, content_box); */ - UiContainerX *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX); + UiContainer *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX); uic_object_push_container(obj, container); nwindows++; @@ -431,10 +482,13 @@ void ui_splitview_window_use_property(UiBool enable) { UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool visible) { GtkWidget *panel = NULL; + CxList *backup_items = NULL; if(pane == 0) { - panel = g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel"); + panel = g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel_top"); + backup_items = g_object_get_data(G_OBJECT(obj->widget), "ui_toolbar_center_backup"); } else if(pane == 1) { - panel = g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel"); + panel = g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel_top"); + // TODO: backup toolbar items } if(panel == NULL) { @@ -443,6 +497,13 @@ UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool vi } gtk_widget_set_visible(panel, visible); + + if(backup_items) { + CxIterator i = cxListIterator(backup_items); + cx_foreach(GtkWidget*, w, i) { + ui_set_visible(w, !visible); + } + } } #ifdef UI_LIBADWAITA @@ -471,6 +532,8 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData * if(data->callback) { data->callback(&evt, data->userdata); } + + ui_app_unref(); } void ui_dialog_create(UiObject *parent, UiDialogArgs *args) { @@ -515,7 +578,8 @@ void ui_dialog_create(UiObject *parent, UiDialogArgs *args) { event); g_signal_connect(dialog, "response", G_CALLBACK(dialog_response), event); - adw_dialog_present(dialog, parent->widget); + ui_app_ref(); + adw_dialog_present(dialog, parent ? parent->widget : NULL); if(entry) { gtk_entry_grab_focus_without_selecting(GTK_ENTRY(entry)); @@ -527,8 +591,14 @@ static void ui_dialog_response (GtkDialog* self, gint response_id, gpointer user UiEventData *data = user_data; UiEvent evt; evt.obj = data->obj; - evt.document = evt.obj->ctx->document; - evt.window = evt.obj->window; + if(evt.obj) { + evt.document = evt.obj->ctx->document; + evt.window = evt.obj->window; + } else { + evt.document = NULL; + evt.window = NULL; + } + evt.eventdata = NULL; evt.intval = 0; @@ -943,7 +1013,7 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) { #endif GtkWidget *content_vbox = ui_gtk_vbox_new(0); - UiContainerX *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX); + UiContainer *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX); uic_object_push_container(obj, container); if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) { #if GTK_CHECK_VERSION(3, 10, 0) @@ -955,7 +1025,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"); @@ -963,7 +1033,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"); @@ -972,7 +1042,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"); @@ -980,7 +1050,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"); @@ -1001,7 +1071,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"); @@ -1009,7 +1079,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"); @@ -1020,7 +1090,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"); @@ -1028,7 +1098,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/gtk/window.h b/ui/gtk/window.h new file mode 100644 index 0000000..1b85fd9 --- /dev/null +++ b/ui/gtk/window.h @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef WINDOW_H +#define WINDOW_H + +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +gboolean ui_window_close_request(UiObject *obj); + + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ + diff --git a/ui/motif/Grid.c b/ui/motif/Grid.c index da74124..23cf424 100644 --- a/ui/motif/Grid.c +++ b/ui/motif/Grid.c @@ -281,11 +281,11 @@ GridClassRec gridClassRec = { NULL, // set_values_hook XtInheritSetValuesAlmost, // set_values_almost NULL, // get_values_hook - (XtAcceptFocusProc)grid_acceptfocus, // accept_focus + (XtAcceptFocusProc)NULL, // accept_focus XtVersion, // version NULL, // callback_offsets //NULL, // tm_table - defaultTranslations, + XtInheritTranslations, //defaultTranslations, XtInheritQueryGeometry, // query_geometry NULL, // display_accelerator NULL, // extension @@ -342,7 +342,7 @@ void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args void grid_realize(Widget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) { Grid grid = (Grid)w; XtMakeResizeRequest(w, 400, 400, NULL, NULL); - (coreClassRec.core_class.realize)((Widget)w, valueMask, attributes); + (*xmManagerClassRec.core_class.realize)(w, valueMask, attributes); grid_place_children(grid); } @@ -363,9 +363,6 @@ Boolean grid_set_values(Widget old, Widget request, Widget neww, ArgList args, C return False; } -Boolean grid_acceptfocus(Widget w, Time *t) { - -} void grid_getfocus(Widget myw, XEvent *event, String *params, Cardinal *nparam) { diff --git a/ui/motif/Makefile b/ui/motif/Makefile index 7f7b420..03add25 100644 --- a/ui/motif/Makefile +++ b/ui/motif/Makefile @@ -26,11 +26,139 @@ # POSSIBILITY OF SUCH DAMAGE. # -$(MOTIF_OBJPRE)%.o: motif/%.c - $(CC) -o $@ -c -I../ucx $(CFLAGS) $(SHLIB_CFLAGS) $(TK_CFLAGS) $< - $(UI_LIB): $(OBJ) $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ) $(UI_SHLIB): $(OBJ) $(CC) -o $(UI_SHLIB) $(LDFLAGS) $(SHLIB_LDFLAGS) $(TK_LDFLAGS) $(OBJ) -L../build/lib -lucx + +FORCE: + +$(MOTIF_OBJPRE)button.o: motif/button.c motif/button.h \ + motif/../ui/button.h motif/../ui/toolkit.h motif/toolkit.h \ + motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/container.h motif/../ui/container.h \ + motif/../common/action.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)container.o: motif/container.c motif/container.h \ + motif/../ui/toolkit.h motif/../ui/container.h motif/../ui/toolkit.h \ + motif/../common/context.h motif/../common/../ui/toolkit.h \ + motif/../common/action.h motif/../common/object.h \ + motif/../common/container.h motif/../common/../ui/container.h \ + motif/Grid.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)dnd.o: motif/dnd.c motif/dnd.h motif/../ui/dnd.h \ + motif/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)entry.o: motif/entry.c motif/entry.h motif/../ui/entry.h \ + motif/../ui/toolkit.h motif/container.h motif/../ui/toolkit.h \ + motif/../ui/container.h motif/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)Fsb.o: motif/Fsb.c motif/Fsb.h motif/FsbP.h \ + motif/pathbar.h motif/../ui/text.h motif/../ui/toolkit.h \ + motif/../common/utils.h motif/../common/../ui/toolkit.h \ + motif/../common/../ui/text.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)graphics.o: motif/graphics.c motif/graphics.h \ + motif/../ui/graphics.h motif/../ui/toolkit.h motif/toolkit.h \ + motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/container.h motif/../ui/container.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)Grid.o: motif/Grid.c motif/Grid.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)image.o: motif/image.c motif/image.h motif/../ui/image.h \ + motif/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)label.o: motif/label.c motif/label.h motif/../ui/display.h \ + motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/container.h motif/../ui/toolkit.h motif/../ui/container.h \ + motif/../common/object.h motif/Grid.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)list.o: motif/list.c motif/container.h \ + motif/../ui/toolkit.h motif/../ui/container.h motif/../ui/toolkit.h \ + motif/list.h motif/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/../ui/list.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)menu.o: motif/menu.c motif/menu.h motif/../ui/menu.h \ + motif/../ui/toolkit.h motif/../common/menu.h \ + motif/../common/../ui/menu.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h motif/button.h \ + motif/../ui/button.h motif/toolkit.h motif/../ui/toolkit.h \ + motif/../common/object.h motif/container.h motif/../ui/container.h \ + motif/../common/types.h motif/../ui/window.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)pathbar.o: motif/pathbar.c motif/pathbar.h \ + motif/../ui/text.h motif/../ui/toolkit.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)range.o: motif/range.c motif/range.h motif/toolkit.h \ + motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/../ui/range.h motif/../ui/toolkit.h \ + motif/container.h motif/../ui/container.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)text.o: motif/text.c motif/text.h motif/../ui/text.h \ + motif/../ui/toolkit.h motif/toolkit.h motif/../ui/toolkit.h \ + motif/../common/context.h motif/../common/../ui/toolkit.h \ + motif/../common/action.h motif/../common/object.h motif/container.h \ + motif/../ui/container.h motif/pathbar.h motif/../common/utils.h \ + motif/../common/../ui/text.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)toolbar.o: motif/toolbar.c motif/toolbar.h \ + motif/../ui/toolbar.h motif/../ui/toolkit.h motif/button.h \ + motif/../ui/button.h motif/toolkit.h motif/../ui/toolkit.h \ + motif/../common/context.h motif/../common/../ui/toolkit.h \ + motif/../common/action.h motif/../common/object.h motif/list.h \ + motif/../ui/list.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)toolkit.o: motif/toolkit.c motif/toolkit.h \ + motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/toolbar.h motif/../ui/toolbar.h \ + motif/../ui/toolkit.h motif/container.h motif/../ui/container.h \ + motif/../common/menu.h motif/../common/../ui/menu.h \ + motif/../common/../ui/toolkit.h motif/../common/toolbar.h \ + motif/../common/../ui/toolbar.h motif/../common/menu.h \ + motif/../common/document.h motif/../common/context.h \ + motif/../common/properties.h motif/../common/../ui/properties.h \ + motif/../common/app.h motif/../common/threadpool.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)widget.o: motif/widget.c motif/../ui/widget.h \ + motif/../ui/toolkit.h motif/container.h motif/../ui/toolkit.h \ + motif/../ui/container.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + +$(MOTIF_OBJPRE)window.o: motif/window.c motif/window.h \ + motif/../ui/window.h motif/../ui/toolkit.h motif/../ui/widget.h \ + motif/toolkit.h motif/../ui/toolkit.h motif/../common/context.h \ + motif/../common/../ui/toolkit.h motif/../common/action.h \ + motif/../common/object.h motif/menu.h motif/../ui/menu.h \ + motif/../common/menu.h motif/../common/../ui/menu.h motif/toolbar.h \ + motif/../ui/toolbar.h motif/container.h motif/../ui/container.h \ + motif/pathbar.h motif/../ui/text.h motif/../common/utils.h \ + motif/../common/../ui/text.h motif/Grid.h motif/Fsb.h + $(CC) -o $@ $(CFLAGS) -I../ucx $(SHLIB_CFLAGS) $(TK_CFLAGS) -c $< + diff --git a/ui/motif/button.c b/ui/motif/button.c index 45e7a1b..8578a63 100644 --- a/ui/motif/button.c +++ b/ui/motif/button.c @@ -32,6 +32,7 @@ #include "button.h" #include "container.h" #include "../common/context.h" +#include "../common/action.h" #include #include @@ -60,6 +61,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { Widget button = XmCreatePushButton(parent, name, xargs, n); XtManageChild(button); ui_container_add(ctn, button); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); ui_set_widget_groups(obj->ctx, button, args->states); @@ -69,6 +71,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { eventdata->userdata = args->onclickdata; eventdata->obj = obj; eventdata->value = 0; + eventdata->action = args->action ? strdup(args->action) : NULL; XtAddCallback( button, XmNactivateCallback, @@ -77,7 +80,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { XtAddCallback( button, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_data, + (XtCallbackProc)ui_destroy_event_data, eventdata); } @@ -94,6 +97,10 @@ void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { e.intval = event->value; e.set = 0; event->callback(&e, event->userdata); + + if(event->action) { + uic_action_callback(&e, event->action); + } } UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) { @@ -117,10 +124,11 @@ UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args) { Widget button = XmCreateToggleButton(parent, name, xargs, n); XtManageChild(button); ui_container_add(ctn, button); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); ui_set_widget_groups(obj->ctx, button, args->states); - ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->enable_state); + ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->action, args->enable_state); XmStringFree(label); return button; @@ -145,10 +153,11 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) { Widget button = XmCreateToggleButton(parent, name, xargs, n); XtManageChild(button); ui_container_add(ctn, button); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); ui_set_widget_groups(obj->ctx, button, args->states); - ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->enable_state); + ui_bind_togglebutton(obj, button, args->varname, args->value, args->onchange, args->onchangedata, args->action, args->enable_state); XmStringFree(label); return button; @@ -181,6 +190,10 @@ static void togglebutton_changed(Widget w, UiVarEventData *event, XmToggleButton event->callback(&e, event->userdata); } + if(event->action) { + uic_action_callback(&e, event->action); + } + if(event->var && event->var->value) { UiInteger *v = event->var->value; v->value = e.intval; @@ -195,6 +208,7 @@ void ui_bind_togglebutton( UiInteger *value, ui_callback onchange, void *onchangedata, + const char *action, int enable_state) { UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); @@ -213,6 +227,7 @@ void ui_bind_togglebutton( event->obj = obj; event->callback = onchange; event->userdata = onchangedata; + event->action = action ? strdup(action) : NULL; event->var = var; event->observers = NULL; event->value = enable_state; @@ -224,7 +239,7 @@ void ui_bind_togglebutton( XtAddCallback( widget, XmNdestroyCallback, - (XtCallbackProc)ui_destroy_data, + (XtCallbackProc)ui_destroy_var_event_data, event); } @@ -291,12 +306,16 @@ static void radiobutton_changed(Widget w, UiVarEventData *event, XmToggleButtonC event->callback(&e, event->userdata); } + if(event->action) { + uic_action_callback(&e, event->action); + } + if(value) { ui_notify_evt(value->observers, &e); } } -void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, int enable_group) { +void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, const char *action, int enable_group) { UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); if(var) { UiInteger *value = var->value; @@ -330,6 +349,7 @@ void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const event->obj = obj; event->callback = onchange; event->userdata = onchangedata; + event->action = action ? strdup(action) : NULL; event->observers = NULL; event->var = var; event->value = enable_group; @@ -364,6 +384,7 @@ UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) { Widget button = XmCreateToggleButton(parent, name, xargs, n); XtManageChild(button); ui_container_add(ctn, button); + uic_widget_set_visibility_states(obj->ctx, button, args->visibility_states); ui_set_widget_groups(obj->ctx, button, args->states); @@ -400,6 +421,7 @@ UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) { event->obj = obj; event->callback = args->onchange; event->userdata = args->onchangedata; + event->action = args->action ? strdup(args->action) : NULL; event->observers = NULL; event->var = var; event->value = args->enable_state; diff --git a/ui/motif/button.h b/ui/motif/button.h index b6dd711..3580091 100644 --- a/ui/motif/button.h +++ b/ui/motif/button.h @@ -45,12 +45,13 @@ void ui_bind_togglebutton( UiInteger *value, ui_callback onchange, void *onchangedata, + const char *action, int enable_state); int64_t ui_togglebutton_get(UiInteger *i); void ui_togglebutton_set(UiInteger *i, int64_t value); -void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, int enable_group); +void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, const char *action, int enable_group); int64_t ui_radiobutton_get(UiInteger *i); void ui_radiobutton_set(UiInteger *i, int64_t value); diff --git a/ui/motif/container.c b/ui/motif/container.c index c5c7c4d..d99581a 100644 --- a/ui/motif/container.c +++ b/ui/motif/container.c @@ -87,9 +87,11 @@ static UIWIDGET box_create(UiObject *obj, UiContainerArgs *args, UiBoxOrientatio Widget grid = XtCreateManagedWidget(args->name ? args->name : "boxcontainer", gridClass, parent, xargs, n); ctn->add(ctn, grid); - UiContainerX *container = ui_box_container(obj, grid, orientation); + UiContainer *container = ui_box_container(obj, grid, orientation); uic_object_push_container(obj, container); + uic_widget_set_visibility_states(obj->ctx, grid, args->visibility_states); + return grid; } @@ -103,14 +105,14 @@ UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) { return box_create(obj, args, UI_BOX_HORIZONTAL); } -UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) { +UiContainer* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) { UiBoxContainer *ctn = ui_malloc(obj->ctx, sizeof(UiBoxContainer)); memset(ctn, 0, sizeof(UiBoxContainer)); ctn->container.prepare = orientation == UI_BOX_VERTICAL ? ui_vbox_prepare : ui_hbox_prepare; ctn->container.add = ui_box_container_add; ctn->container.widget = grid; ctn->n = 0; - return (UiContainerX*)ctn; + return (UiContainer*)ctn; } static Widget ui_box_container_prepare(UiBoxContainer *box, UiLayout *layout, Arg *args, int *n) { @@ -168,13 +170,15 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { Widget grid = XtCreateManagedWidget(args->name ? args->name : "gridcontainer", gridClass, parent, xargs, n); ui_container_add(ctn, grid); - UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill); + UiContainer *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill); uic_object_push_container(obj, container); + uic_widget_set_visibility_states(obj->ctx, grid, args->visibility_states); + return grid; } -UiContainerX* ui_grid_container( +UiContainer* ui_grid_container( UiObject *obj, Widget grid, UiBool def_hexpand, @@ -193,7 +197,7 @@ UiContainerX* ui_grid_container( ctn->def_vexpand = def_vexpand; ctn->def_hfill = def_hfill; ctn->def_vfill = def_vfill; - return (UiContainerX*)ctn; + return (UiContainer*)ctn; } Widget ui_grid_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n) { @@ -271,7 +275,7 @@ UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { XmStringFree(s); } - UiContainerX *container = ui_frame_container(obj, frame); + UiContainer *container = ui_frame_container(obj, frame); uic_object_push_container(obj, container); UiContainerArgs sub_args = { @@ -299,17 +303,18 @@ UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { } } + uic_widget_set_visibility_states(obj->ctx, frame, args->visibility_states); return frame; } -UiContainerX* ui_frame_container(UiObject *obj, Widget frame) { +UiContainer* ui_frame_container(UiObject *obj, Widget frame) { UiContainerPrivate *ctn = ui_malloc(obj->ctx, sizeof(UiContainerPrivate)); memset(ctn, 0, sizeof(UiContainerPrivate)); ctn->prepare = ui_frame_container_prepare; ctn->add = ui_frame_container_add; ctn->widget = frame; - return (UiContainerX*)ctn; + return (UiContainer*)ctn; } Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n) { @@ -467,7 +472,9 @@ UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) { i->set = ui_tabview_set; } - uic_object_push_container(obj, (UiContainerX*)ct); + uic_object_push_container(obj, (UiContainer*)ct); + + uic_widget_set_visibility_states(obj->ctx, form, args->visibility_states); return form; } @@ -549,7 +556,7 @@ UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) { UiObject *newobj = ui_calloc(tabviewdata->obj->ctx, 1, sizeof(UiObject)); newobj->ctx = tabviewdata->obj->ctx; newobj->widget = grid; - UiContainerX *container = ui_box_container(newobj, grid, UI_BOX_VERTICAL); + UiContainer *container = ui_box_container(newobj, grid, UI_BOX_VERTICAL); newobj->container_begin = container; newobj->container_end = container; return newobj; @@ -686,13 +693,13 @@ void ui_scrolledwindow_add(UiContainerPrivate *ctn, Widget widget) { } -static UiContainerX* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) { +static UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) { UiContainerPrivate *ctn = ui_malloc(obj->ctx, sizeof(UiContainerPrivate)); memset(ctn, 0, sizeof(UiContainerPrivate)); ctn->prepare = ui_scrolledwindow_prepare; ctn->add = ui_scrolledwindow_add; ctn->widget = scrolledwindow; - return (UiContainerX*)ctn; + return (UiContainer*)ctn; } UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) { @@ -714,7 +721,7 @@ UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) { Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", xargs, n); ui_container_add(ctn, scrolledwindow); - UiContainerX *container = ui_scrolledwindow_container(obj, scrolledwindow); + UiContainer *container = ui_scrolledwindow_container(obj, scrolledwindow); uic_object_push_container(obj, container); return scrolledwindow; diff --git a/ui/motif/container.h b/ui/motif/container.h index 30262e5..afd2c03 100644 --- a/ui/motif/container.h +++ b/ui/motif/container.h @@ -72,7 +72,7 @@ typedef struct UiContainerPrivate UiContainerPrivate; struct UiContainerPrivate { - UiContainerX container; + UiContainer container; Widget (*prepare)(UiContainerPrivate*, UiLayout *layout, Arg *, int*); void (*add)(UiContainerPrivate*, Widget); Widget widget; @@ -144,13 +144,13 @@ void ui_tabview_set(UiInteger *i, int64_t value); Widget ui_tabview_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n); void ui_tabview_container_add(UiContainerPrivate *ctn, Widget widget); -UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation); +UiContainer* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation); Widget ui_vbox_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n); Widget ui_hbox_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n); void ui_box_container_add(UiContainerPrivate *ctn, Widget widget); -UiContainerX* ui_grid_container( +UiContainer* ui_grid_container( UiObject *obj, Widget grid, UiBool def_hexpand, @@ -160,7 +160,7 @@ UiContainerX* ui_grid_container( Widget ui_grid_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n); void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget); -UiContainerX* ui_frame_container(UiObject *obj, Widget frame); +UiContainer* ui_frame_container(UiObject *obj, Widget frame); Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n); void ui_frame_container_add(UiContainerPrivate *ctn, Widget widget); diff --git a/ui/motif/label.c b/ui/motif/label.c index 2acb2c3..1439966 100644 --- a/ui/motif/label.c +++ b/ui/motif/label.c @@ -65,6 +65,7 @@ static UIWIDGET label_create(UiObject *obj, UiLabelArgs *args, int align) { Widget w = XmCreateLabel(parent, name, xargs, n); XtManageChild(w); ui_container_add(ctn, w); + uic_widget_set_visibility_states(obj->ctx, w, args->visibility_states); XmStringFree(label); @@ -162,6 +163,7 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) { char *name = args->name ? (char*)args->name : "progressbar"; Widget frame = XmCreateFrame(parent, name, xargs, n); ui_container_add(ctn, frame); + uic_widget_set_visibility_states(obj->ctx, frame, args->visibility_states); // create a button and get some informations about the height, shadow, highlight, .... // we want the frame to have the same dimensions as a normal button @@ -252,6 +254,7 @@ UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args Widget w = XmCreateLabel(parent, name, xargs, n); XtManageChild(w); ui_container_add(ctn, w); + uic_widget_set_visibility_states(obj->ctx, w, args->visibility_states); UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER); if(var) { diff --git a/ui/motif/menu.c b/ui/motif/menu.c index 6d935a9..d744bd6 100644 --- a/ui/motif/menu.c +++ b/ui/motif/menu.c @@ -179,7 +179,7 @@ void add_checkitem_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { XmStringFree(s); } - ui_bind_togglebutton(obj, checkbox, it->varname, NULL, it->callback, it->userdata, 0); + ui_bind_togglebutton(obj, checkbox, it->varname, NULL, it->callback, it->userdata, NULL, 0); ui_set_widget_groups(obj->ctx, checkbox, it->states); } @@ -199,7 +199,7 @@ void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) Widget button = XmCreateToggleButton(p, "menuradiobutton", args, n); XtManageChild(button); - ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0); + ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, NULL, 0); } static void menuitem_list_remove_binding(void *obj) { @@ -302,11 +302,14 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) { i++; } - ui_getvaluefunc getvalue = list->getvalue; + int row = 0; + ui_getvaluefunc2 getvalue = list->getvalue; + void *getvaluedata = list->getvaluedata; int pos = list->index; while(elm) { n = 0; - char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + UiBool freeResult = FALSE; + char *label = (char*) (getvalue ? getvalue(ls, elm, row, 0, getvaluedata, &freeResult) : elm); if(label) { s = XmStringCreateLocalized(label); XtSetArg(args[n], XmNlabelString, s); n++; @@ -341,7 +344,12 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) { eventdata); } + if(freeResult) { + free(label); + } + elm = ui_list_next(ls); + row++; i++; } diff --git a/ui/motif/menu.h b/ui/motif/menu.h index 4c40d79..9ab72b4 100644 --- a/ui/motif/menu.h +++ b/ui/motif/menu.h @@ -44,7 +44,8 @@ struct UiActiveMenuItemList { int index; int oldcount; UiVar *var; - ui_getvaluefunc getvalue; + ui_getvaluefunc2 getvalue; + void *getvaluedata; ui_callback callback; void *userdata; bool addseparator; diff --git a/ui/motif/text.c b/ui/motif/text.c index b2c5389..68c4bab 100644 --- a/ui/motif/text.c +++ b/ui/motif/text.c @@ -56,6 +56,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { Widget widget = XmCreateScrolledText(parent, name, xargs, n); XtManageChild(widget); ui_container_add(ctn, widget); + uic_widget_set_visibility_states(obj->ctx, widget, args->visibility_states); UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT); @@ -97,6 +98,10 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { var); } + if(args->onchange || args->onchange_action) { + + } + return widget; } @@ -149,9 +154,9 @@ char* ui_textarea_getsubstr(UiText *text, int begin, int end) { return str; } -void ui_textarea_insert(UiText *text, int pos, char *str) { +void ui_textarea_insert(UiText *text, int pos, const char *str) { text->value.ptr = NULL; - XmTextInsert(text->obj, pos, str); + XmTextInsert(text->obj, pos, (char*)str); if(text->value.ptr) { text->value.free(text->value.ptr); } @@ -213,9 +218,9 @@ void ui_text_selection_callback( int sel = left < right ? 1 : 0; if(sel != textarea->last_selection_state) { if(sel) { - ui_set_state(textarea->obj->ctx, UI_GROUP_SELECTION); + ui_set_state(textarea->obj->ctx, UI_STATE_SELECTION); } else { - ui_unset_state(textarea->obj->ctx, UI_GROUP_SELECTION); + ui_unset_state(textarea->obj->ctx, UI_STATE_SELECTION); } } textarea->last_selection_state = sel; @@ -408,6 +413,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, int frame XtManageChild(textfield); ui_container_add(ctn, textfield); + uic_widget_set_visibility_states(obj->ctx, textfield, args->visibility_states); ui_set_widget_groups(obj->ctx, textfield, args->states); UiEventDataExt *eventdata = malloc(sizeof(UiEventDataExt)); @@ -492,6 +498,39 @@ UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args) { return create_textfield(obj, args, FALSE, FALSE); } +void ui_textfield_focus(UIWIDGET textfield) { + ui_textfield_focus_without_selecting(textfield); + ui_textfield_select_all(textfield); +} + +void ui_textfield_focus_without_selecting(UIWIDGET textfield) { + XmProcessTraversal(textfield, XmTRAVERSE_CURRENT); +} + +void ui_textfield_set_selection(UIWIDGET textfield, int begin, int end) { + XmTextSetSelection(textfield, begin, end, 0); +} + +void ui_textfield_select_all(UIWIDGET textfield) { + XmTextSetSelection(textfield, 0, XmTextGetLastPosition(textfield), 0); +} + +void ui_textfield_set_editable(UIWIDGET textfield, UiBool editable) { + XmTextFieldSetEditable(textfield, editable); +} + +UiBool ui_textfield_is_editable(UIWIDGET textfield) { + return XmTextFieldGetEditable(textfield); +} + +void ui_textfield_set_position(UIWIDGET textfield, int pos) { + XmTextFieldSetInsertionPosition(textfield, pos); +} + +int ui_textfield_get_position(UIWIDGET textfield) { + return (int)XmTextFieldGetInsertionPosition(textfield); +} + char* ui_textfield_get(UiString *str) { if(str->value.free) { str->value.free(str->value.ptr); @@ -554,6 +593,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) { XtManageChild(pathbar->widget); ui_container_add(ctn, pathbar->widget); + uic_widget_set_visibility_states(obj->ctx, pathbar->widget, args->visibility_states); UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING); if (var) { diff --git a/ui/motif/text.h b/ui/motif/text.h index 9f2932e..3c59627 100644 --- a/ui/motif/text.h +++ b/ui/motif/text.h @@ -70,7 +70,7 @@ void ui_textarea_text_destroy(UiText *text); char* ui_textarea_get(UiText *text); void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); -void ui_textarea_insert(UiText *text, int pos, char *str); +void ui_textarea_insert(UiText *text, int pos, const char *str); void ui_textarea_setposition(UiText *text, int pos); int ui_textarea_position(UiText *text); void ui_textarea_selection(UiText *text, int *begin, int *end); diff --git a/ui/motif/toolkit.c b/ui/motif/toolkit.c index fe49df1..2fd1bd2 100644 --- a/ui/motif/toolkit.c +++ b/ui/motif/toolkit.c @@ -39,6 +39,7 @@ #include "../common/document.h" #include "../common/properties.h" #include "../common/app.h" +#include "../common/threadpool.h" #include #include @@ -88,8 +89,11 @@ void ui_motif_set_fallback_resources(String *fallbackres) { fallback_resources = fallbackres; } +// NOOP on most platforms, expect macos +void ui_set_main_thread_error_msg(const char *msg) {} + void ui_init(const char *appname, int argc, char **argv) { - application_name = appname; + application_name = appname ? strdup(appname) : NULL; uic_init_global_context(); XtToolkitInitialize(); @@ -97,7 +101,7 @@ void ui_init(const char *appname, int argc, char **argv) { app = XtCreateApplicationContext(); XtAppSetFallbackResources(app, fallback_resources); - display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); + display = XtOpenDisplay(app, NULL, application_name, application_name, NULL, 0, &argc, argv); uic_menu_init(); uic_toolbar_init(); @@ -141,6 +145,14 @@ void ui_main() { } } +void ui_app_ref(void) { + // TODO +} + +void ui_app_unref(void) { + // TODO +} + void ui_app_quit() { XtAppSetExitFlag(app); } @@ -155,8 +167,12 @@ void ui_secondary_event_loop(int *loop) { void ui_show(UiObject *obj) { uic_check_state_widgets(obj->ctx); - if(!XtIsRealized(obj->widget)) { - XtRealizeWidget(obj->widget); + if(obj->widget) { + if(!XtIsRealized(obj->widget)) { + XtRealizeWidget(obj->widget); + obj->ref++; + } + } else { obj->ref++; } } @@ -221,6 +237,11 @@ static void* ui_jobthread(void *data) { } void ui_call_mainthread(ui_threadfunc tf, void* td) { + if(uic_mainthread_calls_is_buffered()) { + uic_add_buffered_mainthread_call(tf, td); + return; + } + UiJob *job = malloc(sizeof(UiJob)); memset(job, 0, sizeof(UiJob)); job->job_func = tf; @@ -327,6 +348,16 @@ void ui_destroy_data(Widget w, XtPointer data, XtPointer d) { free(data); } +void ui_destroy_event_data(Widget w, UiEventData *data, XtPointer d) { + free(data->action); + free(data); +} + +void ui_destroy_var_event_data(Widget w, UiVarEventData *data, XtPointer d) { + free(data->action); + free(data); +} + void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { if(!groups) { return; diff --git a/ui/motif/toolkit.h b/ui/motif/toolkit.h index 069e31c..8807333 100644 --- a/ui/motif/toolkit.h +++ b/ui/motif/toolkit.h @@ -44,6 +44,7 @@ typedef struct UiEventData { void *userdata; int value; void *customdata; + char *action; } UiEventData; typedef struct UiEventDataExt { @@ -68,6 +69,7 @@ typedef struct UiVarEventData { UiObserver **observers; ui_callback callback; void *userdata; + char *action; int value; } UiVarEventData; @@ -94,6 +96,10 @@ void ui_window_dark_theme(Display *dp, Window window); void ui_destroy_data(Widget w, XtPointer data, XtPointer d); +void ui_destroy_event_data(Widget w, UiEventData *data, XtPointer d); + +void ui_destroy_var_event_data(Widget w, UiVarEventData *data, XtPointer d); + void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) ; void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups); diff --git a/ui/motif/window.c b/ui/motif/window.c index c8d5b1d..dd1c9ba 100644 --- a/ui/motif/window.c +++ b/ui/motif/window.c @@ -142,7 +142,7 @@ static UiObject* create_window(const char *title, Boolean simple) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; Widget vbox = XtCreateManagedWidget("window_vbox", gridClass, form, args, n); - UiContainerX *container = ui_box_container(obj, vbox, UI_BOX_VERTICAL); + UiContainer *container = ui_box_container(obj, vbox, UI_BOX_VERTICAL); uic_object_push_container(obj, container); obj->widget = toplevel; diff --git a/ui/qt/container.cpp b/ui/qt/container.cpp index 36e5b46..fcc6228 100644 --- a/ui/qt/container.cpp +++ b/ui/qt/container.cpp @@ -43,7 +43,7 @@ static void delete_container(UiContainerPrivate *ct) { } void ui_obj_add_container(UiObject *obj, UiContainerPrivate *ct) { - UiContainerX *container = (UiContainerX*)ui_malloc(obj->ctx, sizeof(UiContainerX)); + UiContainer *container = (UiContainer*)ui_malloc(obj->ctx, sizeof(UiContainer)); container->close = 0; container->container = ct; container->prev = NULL; diff --git a/ui/qt/container.h b/ui/qt/container.h index 0adf78a..d9ba67a 100644 --- a/ui/qt/container.h +++ b/ui/qt/container.h @@ -41,11 +41,11 @@ #include #include -#define ui_obj_container(obj) (UiContainerPrivate*)((UiContainerX*)obj->container_end)->container +#define ui_obj_container(obj) (UiContainerPrivate*)((UiContainer*)obj->container_end)->container struct UiContainerPrivate { UIWIDGET current; - UiContainerX *container; + UiContainer *container; virtual void add(QWidget *widget, UiLayout& layout) = 0; virtual void end() {} diff --git a/ui/qt/list.cpp b/ui/qt/list.cpp index a2bac52..899e8c6 100644 --- a/ui/qt/list.cpp +++ b/ui/qt/list.cpp @@ -102,6 +102,9 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { if(args->multiselection) { view->setSelectionMode(QAbstractItemView::ExtendedSelection); } + if(args->hide_header) { + view->setHeaderHidden(true); + } UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); diff --git a/ui/qt/menu.cpp b/ui/qt/menu.cpp index f391753..081bb52 100644 --- a/ui/qt/menu.cpp +++ b/ui/qt/menu.cpp @@ -71,7 +71,7 @@ void add_menu_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { add_menu_items(menu, i, m, obj); } -static UiAction* create_action( +static UiQAction* create_action( UiObject *obj, const char *icon, const char *label, @@ -80,7 +80,7 @@ static UiAction* create_action( int *states) { QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, callback, userdata); + UiQAction *action = new UiQAction(obj, str, callback, userdata); if(icon) { action->setIcon(QIcon::fromTheme(icon)); action->setIconVisibleInMenu(true); @@ -97,7 +97,7 @@ static UiAction* create_action( void add_menuitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { UiMenuItem *it = (UiMenuItem*)item; - UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); + UiQAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); parent->addAction(action); QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); } @@ -109,7 +109,7 @@ void add_menuseparator_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject void add_checkitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { UiMenuCheckItem *it = (UiMenuCheckItem*)item; - UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); + UiQAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); parent->addAction(action); action->setCheckable(true); action->prepare_event = ui_checkableaction_prepare_event; @@ -129,7 +129,7 @@ void add_checkitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { UiMenuRadioItem *it = (UiMenuRadioItem*)item; - UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); + UiQAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->states); parent->addAction(action); action->setCheckable(true); action->prepare_event = ui_actiongroup_prepare_event; @@ -152,7 +152,7 @@ void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject action->var; } -void ui_actiongroup_prepare_event(UiEvent *event, UiAction *action) { +void ui_actiongroup_prepare_event(UiEvent *event, UiQAction *action) { if(action->var) { UiInteger *value = (UiInteger*)action->var->value; event->eventdata = value; @@ -214,7 +214,7 @@ void ui_add_menus(UiObject *obj, QMainWindow *window) { } } -void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action) { +void ui_checkableaction_prepare_event(UiEvent *event, UiQAction *action) { if(action->var) { event->eventdata = action->var->value; event->eventdatatype = UI_EVENT_DATA_INTEGER_VALUE; @@ -223,13 +223,13 @@ void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action) { } int64_t ui_checkableaction_get(UiInteger *value) { - UiAction *action= (UiAction*)value->obj; + UiQAction *action= (UiQAction*)value->obj; value->value = action->isChecked(); return value->value; } void ui_checkableaction_set(UiInteger *value, int64_t i) { - UiAction *action = (UiAction*)value->obj; + UiQAction *action = (UiQAction*)value->obj; value->value = i; if(i != 0) { action->setChecked((bool)i); diff --git a/ui/qt/menu.h b/ui/qt/menu.h index 9903ae0..21079c5 100644 --- a/ui/qt/menu.h +++ b/ui/qt/menu.h @@ -51,11 +51,11 @@ void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject void add_checkitemnv_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); void add_menuitem_list_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); -void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action); +void ui_checkableaction_prepare_event(UiEvent *event, UiQAction *action); int64_t ui_checkableaction_get(UiInteger *value); void ui_checkableaction_set(UiInteger *value, int64_t i); -void ui_actiongroup_prepare_event(UiEvent *event, UiAction *action); +void ui_actiongroup_prepare_event(UiEvent *event, UiQAction *action); int64_t ui_actiongroup_get(UiInteger *value); void ui_actiongroup_set(UiInteger *value, int64_t i); diff --git a/ui/qt/model.cpp b/ui/qt/model.cpp index 361da2f..c74c43f 100644 --- a/ui/qt/model.cpp +++ b/ui/qt/model.cpp @@ -99,6 +99,10 @@ QVariant ListModel::data(const QModelIndex &index, int role) const { } void ListModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { + if(!ui_selection_events_is_enabled()) { + return; + } + UiListSelection sel; if(listview) { sel = ui_selection_model_to_selection(listview->selectionModel()); diff --git a/ui/qt/text.cpp b/ui/qt/text.cpp index 32871a2..bdac8ce 100644 --- a/ui/qt/text.cpp +++ b/ui/qt/text.cpp @@ -96,6 +96,10 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { return textarea; } +UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { + return textarea; +} + void ui_textarea_save(UiText *text) { // NOOP } @@ -154,7 +158,7 @@ char* ui_textarea_getsubstr(UiText *text, int begin, int end) { return cstr ? strdup(cstr) : NULL; } -void ui_textarea_insert(UiText *text, int pos, char *str) { +void ui_textarea_insert(UiText *text, int pos, const char *str) { QTextDocument *doc = (QTextDocument*)text->data1; QTextCursor cursor(doc); cursor.setPosition(pos); @@ -189,10 +193,7 @@ void ui_textarea_selection(UiText *text, int *begin, int *end) { void ui_textarea_setselection(UiText *text, int begin, int end) { QTextEdit *textview = (QTextEdit*)text->obj; - QTextCursor cursor = textview->textCursor(); - cursor.setPosition(begin, QTextCursor::MoveAnchor); - cursor.setPosition(end, QTextCursor::KeepAnchor); - textview->setTextCursor(cursor); + ui_textarea_set_selection(textview, begin, end); } int ui_textarea_length(UiText *text) { @@ -208,6 +209,56 @@ void ui_textarea_remove(UiText *text, int begin, int end) { cursor.removeSelectedText(); } + +void ui_textarea_focus(UIWIDGET textarea) { + QTextEdit *edit = static_cast(textarea); + edit->setFocus(); +} + +void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end) { + QTextEdit *edit = static_cast(textarea); + QTextCursor cursor = edit->textCursor(); + cursor.setPosition(begin, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + edit->setTextCursor(cursor); +} + +void ui_textarea_select_all(UIWIDGET textarea) { + QTextEdit *edit = static_cast(textarea); + edit->selectAll(); +} + +void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable) { + QTextEdit *edit = static_cast(textarea); + edit->setReadOnly(!editable); +} + +UiBool ui_textarea_is_editable(UIWIDGET textarea) { + QTextEdit *edit = static_cast(textarea); + return !edit->isReadOnly(); +} + +void ui_textarea_set_position(UIWIDGET textarea, int pos) { + QTextEdit *edit = static_cast(textarea); + QTextCursor cursor = edit->textCursor(); + cursor.setPosition(pos); + edit->setTextCursor(cursor); +} + +int ui_textarea_get_position(UIWIDGET textarea) { + QTextEdit *edit = static_cast(textarea); + QTextCursor cursor = edit->textCursor(); + return cursor.position(); +} + +void ui_textarea_scroll_to(UIWIDGET textarea, int pos) { + QTextEdit *edit = static_cast(textarea); + QTextCursor cursor = edit->textCursor(); + cursor.setPosition(pos); + edit->setTextCursor(cursor); + edit->ensureCursorVisible(); +} + /* ------------------------------ TextField ------------------------------ */ static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, bool password, bool frameless) { @@ -278,3 +329,50 @@ void ui_textfield_set(UiString *str, const char *value) { } str->value.ptr = NULL; } + +void ui_textfield_focus(UIWIDGET textfield) { + QLineEdit *edit = static_cast(textfield); + edit->setFocus(); + edit->selectAll(); +} + +void ui_textfield_focus_without_selecting(UIWIDGET textfield) { + QLineEdit *edit = static_cast(textfield); + edit->setFocus(); +} + +void ui_textfield_set_selection(UIWIDGET textfield, int begin, int end) { + QLineEdit *edit = static_cast(textfield); + if (begin < 0) { + begin = 0; + } + if (end < begin) { + end = begin; + } + edit->setSelection(begin, end - begin); +} + +void ui_textfield_select_all(UIWIDGET textfield) { + QLineEdit *edit = static_cast(textfield); + edit->selectAll(); +} + +void ui_textfield_set_editable(UIWIDGET textfield, UiBool editable) { + QLineEdit *edit = static_cast(textfield); + edit->setReadOnly(!editable); +} + +UiBool ui_textfield_is_editable(UIWIDGET textfield) { + QLineEdit *edit = static_cast(textfield); + return !edit->isReadOnly(); +} + +void ui_textfield_set_position(UIWIDGET textfield, int pos) { + QLineEdit *edit = static_cast(textfield); + edit->setCursorPosition(pos); +} + +int ui_textfield_get_position(UIWIDGET textfield) { + QLineEdit *edit = static_cast(textfield); + return edit->cursorPosition(); +} diff --git a/ui/qt/text.h b/ui/qt/text.h index fcfe612..5ecee2a 100644 --- a/ui/qt/text.h +++ b/ui/qt/text.h @@ -43,7 +43,7 @@ void ui_textarea_text_destroy(UiText *text); char* ui_textarea_get(UiText *text); void ui_textarea_set(UiText *text, const char *str); char* ui_textarea_getsubstr(UiText *text, int begin, int end); -void ui_textarea_insert(UiText *text, int pos, char *str); +void ui_textarea_insert(UiText *text, int pos, const char *str); void ui_textarea_setposition(UiText *text, int pos); int ui_textarea_position(UiText *text); void ui_textarea_setselection(UiText *text, int begin, int end); diff --git a/ui/qt/toolkit.cpp b/ui/qt/toolkit.cpp index bc355d0..548cfdd 100644 --- a/ui/qt/toolkit.cpp +++ b/ui/qt/toolkit.cpp @@ -48,8 +48,11 @@ static QApplication *application = NULL; static UiBool exit_on_shutdown; +// NOOP on most platforms, expect macos +extern "C" UIEXPORT void ui_set_main_thread_error_msg(const char *msg) {} + void ui_init(const char *appname, int argc, char **argv) { - application_name = appname; + application_name = appname ? strdup(appname) : NULL; app_argc = argc; app_argv = argv; @@ -83,6 +86,14 @@ void ui_main() { } } +void ui_app_ref(void) { + // TODO +} + +void ui_app_unref(void) { + // TODO +} + void ui_show(UiObject *obj) { obj->widget->show(); } @@ -138,17 +149,17 @@ void UiEventWrapper::destroy() { /* --------------------- Implemtation UiAction --------------------- */ -UiAction::UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata) : QAction(label, NULL) { +UiQAction::UiQAction(UiObject *obj, QString &label, ui_callback f, void *userdata) : QAction(label, NULL) { this->obj = obj; this->callback = f; this->userdata = userdata; } -UiAction::~UiAction() { +UiQAction::~UiQAction() { // TODO: unbind var } -void UiAction::trigger() { +void UiQAction::trigger() { if(!callback) { return; } @@ -170,7 +181,7 @@ void UiAction::trigger() { } // ui_enablefunc for UiAction -void ui_action_enable(UiAction *action, int enable) { +void ui_action_enable(UiQAction *action, int enable) { action->setEnabled((bool)enable); } diff --git a/ui/qt/toolkit.h b/ui/qt/toolkit.h index 1db8df7..6108596 100644 --- a/ui/qt/toolkit.h +++ b/ui/qt/toolkit.h @@ -63,11 +63,11 @@ public slots: void destroy(); }; -class UiAction; +class UiQAction; -typedef void (*ui_prepare_action_event_func)(UiEvent *event, UiAction *action); +typedef void (*ui_prepare_action_event_func)(UiEvent *event, UiQAction *action); -class UiAction : public QAction { +class UiQAction : public QAction { Q_OBJECT UiObject *obj; @@ -83,14 +83,14 @@ public: int customvalue1 = 0; int customvalue2 = 0; - UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata); - ~UiAction(); + UiQAction(UiObject *obj, QString &label, ui_callback f, void *userdata); + ~UiQAction(); private slots: void trigger(); }; -void ui_action_enable(UiAction *action, int enable); +void ui_action_enable(UiQAction *action, int enable); #endif /* TOOLKIT_H */ diff --git a/ui/qt/window.cpp b/ui/qt/window.cpp index 6e4c1c8..1c69606 100644 --- a/ui/qt/window.cpp +++ b/ui/qt/window.cpp @@ -43,7 +43,6 @@ static UiObject* create_window(const char *title, bool simple, bool sidebar = false) { UiObject *obj = uic_object_new_toplevel(); - obj->next = NULL; QMainWindow *window = new QMainWindow(); window->setWindowTitle(title); diff --git a/ui/ui/button.h b/ui/ui/button.h index 55367f1..ae9155f 100644 --- a/ui/ui/button.h +++ b/ui/ui/button.h @@ -63,9 +63,11 @@ typedef struct UiButtonArgs { const char *tooltip; UiLabelType labeltype; ui_callback onclick; - void *onclickdata; + void *onclickdata; + const char *action; const int *states; + const int *visibility_states; } UiButtonArgs; typedef struct UiToggleArgs { @@ -85,19 +87,58 @@ typedef struct UiToggleArgs { const char *name; const char *style_class; - const char *label; - const char *icon; - const char *tooltip; + const char *label; + const char *icon; + const char *tooltip; UiLabelType labeltype; - UiInteger *value; - const char *varname; + UiInteger *value; + const char *varname; ui_callback onchange; - void *onchangedata; - int enable_state; + void *onchangedata; + const char *action; + int enable_state; - const int *states; + const int *states; + const int *visibility_states; } UiToggleArgs; +typedef struct UiContentToggleArgs { + UiBool fill; + UiBool hexpand; + UiBool vexpand; + UiBool hfill; + UiBool vfill; + UiBool override_defaults; + int margin; + int margin_left; + int margin_right; + int margin_top; + int margin_bottom; + int colspan; + int rowspan; + const char *name; + const char *style_class; + + const char *label0; + const char *icon0; + const char *tooltip0; + const char *label1; + const char *icon1; + const char *tooltip1; + UiLabelType labeltype; + UiInteger *value; + const char *varname; + ui_callback onchange; + void *onchangedata; + const char *action; + UiBool istogglebutton; + int enable_state; + int toggled_by_state; + + const int *states; + const int *visibility_states; +} UiContentToggleArgs; + typedef struct UiLinkButtonArgs { UiBool fill; UiBool hexpand; @@ -121,16 +162,19 @@ typedef struct UiLinkButtonArgs { const char *varname; ui_callback onclick; void *onclickdata; + const char *action; UiBool nofollow; UiLinkType type; const int *states; + const int *visibility_states; } UiLinkButtonArgs; #define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } ) #define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } ) #define ui_checkbox(obj, ...) ui_checkbox_create(obj, &(UiToggleArgs){ __VA_ARGS__ } ) #define ui_switch(obj, ...) ui_switch_create(obj, &(UiToggleArgs){ __VA_ARGS__ } ) +#define ui_content_togglebutton(obj, ...) ui_content_togglebutton_create(obj, &(UiContentToggleArgs){ __VA_ARGS__ } ) #define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } ) #define ui_linkbutton(obj, ...) ui_linkbutton_create(obj, &(UiLinkButtonArgs){ __VA_ARGS__ }) @@ -138,11 +182,25 @@ UIEXPORT UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args); UIEXPORT UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args); UIEXPORT UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args); UIEXPORT UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args); +UIEXPORT UIWIDGET ui_content_togglebutton_create(UiObject *obj, UiContentToggleArgs *args); UIEXPORT UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args); UIEXPORT UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args); UIEXPORT void ui_button_set_label(UIWIDGET button, const char *label); UIEXPORT void ui_button_set_icon(UIWIDGET button, const char *icon); +UIEXPORT void ui_button_set_tooltip(UIWIDGET button, const char *tooltip); + +UIEXPORT void ui_togglebutton_set_label(UIWIDGET button, const char *label); +UIEXPORT void ui_togglebutton_set_icon(UIWIDGET button, const char *icon); +UIEXPORT void ui_togglebutton_set_tooltip(UIWIDGET button, const char *tooltip); + +UIEXPORT void ui_checkbox_set_label(UIWIDGET button, const char *label); +UIEXPORT void ui_checkbox_set_icon(UIWIDGET button, const char *icon); +UIEXPORT void ui_checkbox_set_tooltip(UIWIDGET button, const char *tooltip); + +UIEXPORT void ui_radiobutton_set_label(UIWIDGET button, const char *label); +UIEXPORT void ui_radiobutton_set_icon(UIWIDGET button, const char *icon); +UIEXPORT void ui_radiobutton_set_tooltip(UIWIDGET button, const char *tooltip); UIEXPORT void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri); UIEXPORT void ui_linkbutton_value_set_label(UiString *str, const char *label); diff --git a/ui/ui/container.h b/ui/ui/container.h index dc2aa29..187f221 100644 --- a/ui/ui/container.h +++ b/ui/ui/container.h @@ -82,6 +82,8 @@ typedef struct UiContainerArgs { UiBool def_vfill; UiBool def_hexpand; UiBool def_vexpand; + + const int *visibility_states; } UiContainerArgs; typedef struct UiFrameArgs { @@ -112,6 +114,8 @@ typedef struct UiFrameArgs { const char* label; UiBool isexpanded; + + const int *visibility_states; } UiFrameArgs; typedef struct UiTabViewArgs { @@ -144,6 +148,8 @@ typedef struct UiTabViewArgs { int spacing; int columnspacing; int rowspacing; + + const int *visibility_states; } UiTabViewArgs; typedef struct UiHeaderbarArgs { @@ -207,6 +213,8 @@ typedef struct UiSplitPaneArgs { UiInteger *value; const char* varname; int max_panes; + + const int *visibility_states; } UiSplitPaneArgs; typedef struct UiItemListContainerArgs { @@ -277,12 +285,12 @@ struct UiLayout { int rowspan; }; -struct UiContainerX { +struct UiContainer { void *container; UiBool close; UiBool newline; - UiContainerX *prev; - UiContainerX *next; + UiContainer *prev; + UiContainer *next; }; @@ -373,10 +381,6 @@ UIEXPORT void ui_newline(UiObject *obj); typedef void(*ui_addwidget_func)(UiObject *obj, UIWIDGET parent, UIWIDGET child, void *userdata); UIEXPORT void ui_custom_container_create(UiObject *obj, UIWIDGET widget, ui_addwidget_func add_child, void *userdata); -// TODO -UIEXPORT UiTabbedPane* ui_tabbed_document_view(UiObject *obj); -UIEXPORT UiObject* ui_document_tab(UiTabbedPane *view); - /* used for macro */ diff --git a/ui/ui/display.h b/ui/ui/display.h index 1ed1235..a9c585a 100644 --- a/ui/ui/display.h +++ b/ui/ui/display.h @@ -71,6 +71,8 @@ typedef struct UiLabelArgs { UiLabelStyle style; UiString* value; const char* varname; + + const int *visibility_states; } UiLabelArgs; typedef struct UiProgressbarArgs { @@ -95,6 +97,8 @@ typedef struct UiProgressbarArgs { double max; UiDouble* value; const char* varname; + + const int *visibility_states; } UiProgressbarArgs; typedef struct UiProgressbarSpinnerArgs { @@ -116,6 +120,8 @@ typedef struct UiProgressbarSpinnerArgs { UiInteger* value; const char* varname; + + const int *visibility_states; } UiProgressbarSpinnerArgs; /* label widgets */ diff --git a/ui/ui/entry.h b/ui/ui/entry.h index 9ee26d3..2b89876 100644 --- a/ui/ui/entry.h +++ b/ui/ui/entry.h @@ -66,6 +66,7 @@ typedef struct UiSpinBoxArgs { void* onchangedata; const int *states; + const int *visibility_states;; } UiSpinBoxArgs; diff --git a/ui/ui/icons.h b/ui/ui/icons.h index 9bc86a4..2b5540f 100644 --- a/ui/ui/icons.h +++ b/ui/ui/icons.h @@ -38,23 +38,139 @@ extern "C" { #ifdef UI_GTK #define UI_ICON_HOME "go-home" -#define UI_ICON_NEW_WINDOW "list-add" -#define UI_ICON_REFRESH "view-refresh" +#define UI_ICON_NEW_WINDOW "window-new" +#define UI_ICON_NEW_TAB "tab-new" #define UI_ICON_NEW_FOLDER "folder-new" -#define UI_ICON_ADD "document-new" +#define UI_ICON_NEW_DOCUMENT "document-new" +#define UI_ICON_NEW_APPOINTMENT "appointment-new" +#define UI_ICON_NEW_CHAT_MESSAGE "chat-message-new" +#define UI_ICON_NEW_CONTACT "contact-new" +#define UI_ICON_NEW_MAIL "mail-message-new" +#define UI_ICON_ADD_BOOKMARK "bookmark-new" +#define UI_ICON_ADD_IMAGE "insert-image" +#define UI_ICON_ADD_LINK "insert-link" +#define UI_ICON_ADD_TEXT "insert-text" +#define UI_ICON_ADD "list-add" +#define UI_ICON_REMOVE "list-remove" +#define UI_ICON_REFRESH "view-refresh" #define UI_ICON_UPLOAD "document-open" #define UI_ICON_SAVE_LOCAL "document-save-as" -#define UI_ICON_DELETE "edit-delete" -#define UI_ICON_DOCK_LEFT "" -#define UI_ICON_DOCK_RIGHT "" +#define UI_ICON_EDIT_COPY "edit-copy" +#define UI_ICON_EDIT_CUT "edit-cut" +#define UI_ICON_EDIT_DELETE "edit-delete" +#define UI_ICON_EDIT_PASTE "edit-paste" +#define UI_ICON_UNDO "edit-undo" +#define UI_ICON_REDO "edit-redo" +#define UI_ICON_SIDEBAR_LEFT "sidebar-show" +#define UI_ICON_SIDEBAR_RIGHT "sidebar-show-right" #define UI_ICON_GO_BACK "go-previous" #define UI_ICON_GO_FORWARD "go-next" #define UI_ICON_GO_UP "go-up" #define UI_ICON_GO_DOWN "go-down" +#define UI_ICON_VIEW_LIST "view-list" +#define UI_ICON_VIEW_GRID "view-grid" +#define UI_ICON_VIEW_DUAL "view-dual" +#define UI_ICON_VIEW_FULLSCREEN "view-fullscreen" +#define UI_ICON_VIEW_RESTORE "view-restore" +#define UI_ICON_TEXT_BOLD "format-text-bold" +#define UI_ICON_TEXT_ITALIC "format-text-italic" +#define UI_ICON_TEXT_UNDERLINE "format-text-underline" +#define UI_ICON_LIST_BULLET "view-list-bullet" +#define UI_ICON_LIST_ORDERED "view-list-ordered" +#define UI_ICON_LIST_CHECK "checkbox-checked" +#define UI_ICON_CHECKBOX "checkbox-checked" +#define UI_ICON_STAR "starred" +#define UI_ICON_VIEW_REVEAL "view-reveal" +#define UI_ICON_VIEW_CONCEAL "view-conceal" +#define UI_ICON_SETTINGS "applications-system" +#define UI_ICON_MEDIA_PLAY "media-playback-start" +#define UI_ICON_MEDIA_STOP "media-playback-stop" +#define UI_ICON_MEDIA_PAUSE "media-playback-pause" +#define UI_ICON_MEDIA_SEEK_BACKWARD "media-seek-backward" +#define UI_ICON_MEDIA_SEEK_FORWARD "media-seek-forward" +#define UI_ICON_MEDIA_SKIP_BACKWARD "media-skip-backward" +#define UI_ICON_MEDIA_SKIP_FORWARD "media-skip-forward" +#define UI_ICON_CALL_START "call-start" +#define UI_ICON_CALL_STOP "call-stop" +#define UI_ICON_CALL_INCOMING "call-incoming" +#define UI_ICON_CALL_OUTGOING "call-outgoing" +#define UI_ICON_MICROPHONE_ON "microphone-sensitivity-high" +#define UI_ICON_MICROPHONE_OFF "microphone-disabled" +#define UI_ICON_LOCKED "changes-allow" +#define UI_ICON_UNLOCKED "changes-prevent" +#define UI_ICON_SECURE "channel-secure" +#define UI_ICON_INSECURE "channel-insecure" + #endif /* UI_GTK */ +#ifdef UI_QT + +#define UI_ICON_HOME "go-home" +#define UI_ICON_NEW_WINDOW "window-new" +#define UI_ICON_NEW_TAB "tab-new" +#define UI_ICON_NEW_FOLDER "folder-new" +#define UI_ICON_NEW_DOCUMENT "document-new" +#define UI_ICON_NEW_APPOINTMENT "appointment-new" +#define UI_ICON_NEW_CHAT_MESSAGE "chat-message-new" +#define UI_ICON_NEW_CONTACT "contact-new" +#define UI_ICON_NEW_MAIL "mail-message-new" +#define UI_ICON_ADD_BOOKMARK "bookmark-new" +#define UI_ICON_ADD_IMAGE "insert-image" +#define UI_ICON_ADD_LINK "insert-link" +#define UI_ICON_ADD_TEXT "insert-text" +#define UI_ICON_ADD "list-add" +#define UI_ICON_REMOVE "list-remove" +#define UI_ICON_REFRESH "view-refresh" +#define UI_ICON_UPLOAD "document-open" +#define UI_ICON_SAVE_LOCAL "document-save-as" +#define UI_ICON_EDIT_COPY "edit-copy" +#define UI_ICON_EDIT_CUT "edit-cut" +#define UI_ICON_EDIT_DELETE "edit-delete" +#define UI_ICON_EDIT_PASTE "edit-paste" +#define UI_ICON_UNDO "edit-undo" +#define UI_ICON_REDO "edit-redo" +#define UI_ICON_SIDEBAR_LEFT "sidebar-show" +#define UI_ICON_SIDEBAR_RIGHT "sidebar-show-right" +#define UI_ICON_GO_BACK "go-previous" +#define UI_ICON_GO_FORWARD "go-next" +#define UI_ICON_GO_UP "go-up" +#define UI_ICON_GO_DOWN "go-down" +#define UI_ICON_VIEW_LIST "view-list" +#define UI_ICON_VIEW_GRID "view-grid" +#define UI_ICON_VIEW_DUAL "view-dual" +#define UI_ICON_VIEW_FULLSCREEN "view-fullscreen" +#define UI_ICON_VIEW_RESTORE "view-restore" +#define UI_ICON_TEXT_BOLD "format-text-bold" +#define UI_ICON_TEXT_ITALIC "format-text-italic" +#define UI_ICON_TEXT_UNDERLINE "format-text-underline" +#define UI_ICON_LIST_BULLET "view-list-bullet" +#define UI_ICON_LIST_ORDERED "view-list-ordered" +#define UI_ICON_LIST_CHECK "checkbox-checked" +#define UI_ICON_CHECKBOX "checkbox-checked" +#define UI_ICON_STAR "starred" +#define UI_ICON_VIEW_REVEAL "view-reveal" +#define UI_ICON_VIEW_CONCEAL "view-conceal" +#define UI_ICON_SETTINGS "applications-system" +#define UI_ICON_MEDIA_PLAY "media-playback-start" +#define UI_ICON_MEDIA_STOP "media-playback-stop" +#define UI_ICON_MEDIA_PAUSE "media-playback-pause" +#define UI_ICON_MEDIA_SEEK_BACKWARD "media-seek-backward" +#define UI_ICON_MEDIA_SEEK_FORWARD "media-seek-forward" +#define UI_ICON_MEDIA_SKIP_BACKWARD "media-skip-backward" +#define UI_ICON_MEDIA_SKIP_FORWARD "media-skip-forward" +#define UI_ICON_CALL_START "call-start" +#define UI_ICON_CALL_STOP "call-stop" +#define UI_ICON_CALL_INCOMING "call-incoming" +#define UI_ICON_CALL_OUTGOING "call-outgoing" +#define UI_ICON_MICROPHONE_ON "microphone-sensitivity-high" +#define UI_ICON_MICROPHONE_OFF "microphone-disabled" +#define UI_ICON_LOCKED "changes-allow" +#define UI_ICON_UNLOCKED "changes-prevent" +#define UI_ICON_SECURE "channel-secure" +#define UI_ICON_INSECURE "channel-insecure" +#endif /* UI_QT */ #ifdef UI_WINUI @@ -72,9 +188,280 @@ extern "C" { #define UI_ICON_GO_FORWARD "Forward" #define UI_ICON_GO_UP "Up" #define UI_ICON_GO_DOWN "" // TODO: implement workaround for missing down symbol +#define UI_ICON_LIST "List" #endif /* UI_WINUI */ + +#ifdef UI_COCOA + +#define UI_ICON_HOME "go-home" +#define UI_ICON_NEW_WINDOW "macwindow.badge.plus" +#define UI_ICON_NEW_TAB "plus.square" +#define UI_ICON_NEW_FOLDER "folder.badge.plus" +#define UI_ICON_NEW_DOCUMENT "document.badge.plus" +#define UI_ICON_NEW_APPOINTMENT "calendar.badge.plus" +#define UI_ICON_NEW_CHAT_MESSAGE "plus.bubble" +#define UI_ICON_NEW_CONTACT "person.badge.plus" +#define UI_ICON_NEW_MAIL "envelope.badge.plus" +#define UI_ICON_ADD_BOOKMARK "book.badge.plus" +#define UI_ICON_ADD_IMAGE "photo.badge.plus" +#define UI_ICON_ADD_LINK "link.badge.plus" +#define UI_ICON_ADD_TEXT "text.badge.plus" +#define UI_ICON_ADD "plus" +#define UI_ICON_REMOVE "minus" +#define UI_ICON_REFRESH "arrow.clockwise" +#define UI_ICON_UPLOAD "square.and.arrow.up" +#define UI_ICON_SAVE_LOCAL "square.and.arrow.down" +#define UI_ICON_EDIT_COPY "document.on.document" +#define UI_ICON_EDIT_CUT "scissors" +#define UI_ICON_EDIT_DELETE "minus.circle" +#define UI_ICON_EDIT_PASTE "document.on.clipboard" +#define UI_ICON_UNDO "arrow.uturn.backward" +#define UI_ICON_REDO "arrow.uturn.forward" +#define UI_ICON_SIDEBAR_LEFT "sidebar.left" +#define UI_ICON_SIDEBAR_RIGHT "sidebar.right" +#define UI_ICON_GO_BACK "chevron.left" +#define UI_ICON_GO_FORWARD "chevron.right" +#define UI_ICON_GO_UP "chevron.up" +#define UI_ICON_GO_DOWN "chevron.down" +#define UI_ICON_VIEW_LIST "list.bullet" +#define UI_ICON_VIEW_GRID "square.grid.2x2" +#define UI_ICON_VIEW_DUAL "rectangle.split.2x1" +#define UI_ICON_VIEW_FULLSCREEN "arrow.up.left.and.arrow.down.right.rectangle" +#define UI_ICON_VIEW_RESTORE "arrow.down.forward.and.arrow.up.backward.rectangle" +#define UI_ICON_TEXT_BOLD "bold" +#define UI_ICON_TEXT_ITALIC "italic" +#define UI_ICON_TEXT_UNDERLINE "underline" +#define UI_ICON_LIST_BULLET "list.bullet" +#define UI_ICON_LIST_ORDERED "list.number" +#define UI_ICON_LIST_CHECK "checklist" +#define UI_ICON_CHECKBOX "checkmark.square" +#define UI_ICON_STAR "star" +#define UI_ICON_VIEW_REVEAL "eye" +#define UI_ICON_VIEW_CONCEAL "eye.slash" +#define UI_ICON_SETTINGS "gearshape" +#define UI_ICON_MEDIA_PLAY "play.fill" +#define UI_ICON_MEDIA_STOP "stop.fill" +#define UI_ICON_MEDIA_PAUSE "pause.fill" +#define UI_ICON_MEDIA_SEEK_BACKWARD "backward.fill" +#define UI_ICON_MEDIA_SEEK_FORWARD "forward.fill" +#define UI_ICON_MEDIA_SKIP_BACKWARD "backward.end.fill" +#define UI_ICON_MEDIA_SKIP_FORWARD "forward.end.fill" +#define UI_ICON_CALL_START "phone" +#define UI_ICON_CALL_STOP "phone.down" +#define UI_ICON_CALL_INCOMING "phone.arrow.down.left" +#define UI_ICON_CALL_OUTGOING "phone.arrow.up.right" +#define UI_ICON_MICROPHONE_ON "microphone" +#define UI_ICON_MICROPHONE_OFF "microphone.slash" +#define UI_ICON_LOCKED "lock" +#define UI_ICON_UNLOCKED "lock.open" +#define UI_ICON_SECURE "lock" +#define UI_ICON_INSECURE "lock.trianglebadge.exclamationmark" + +#endif /* UI_COCOA */ + +#ifdef UI_MOTIF + +#define UI_ICON_HOME "" +#define UI_ICON_NEW_WINDOW "" +#define UI_ICON_NEW_TAB "" +#define UI_ICON_NEW_FOLDER "" +#define UI_ICON_NEW_DOCUMENT "" +#define UI_ICON_NEW_APPOINTMENT "" +#define UI_ICON_NEW_CHAT_MESSAGE "" +#define UI_ICON_NEW_CONTACT "" +#define UI_ICON_NEW_MAIL "" +#define UI_ICON_ADD_BOOKMARK "" +#define UI_ICON_ADD_IMAGE "" +#define UI_ICON_ADD_LINK "" +#define UI_ICON_ADD_TEXT "" +#define UI_ICON_ADD "" +#define UI_ICON_REMOVE "" +#define UI_ICON_REFRESH "" +#define UI_ICON_UPLOAD "" +#define UI_ICON_SAVE_LOCAL "" +#define UI_ICON_EDIT_COPY "" +#define UI_ICON_EDIT_CUT "" +#define UI_ICON_EDIT_DELETE "" +#define UI_ICON_EDIT_PASTE "" +#define UI_ICON_UNDO "" +#define UI_ICON_REDO "" +#define UI_ICON_SIDEBAR_LEFT "" +#define UI_ICON_SIDEBAR_RIGHT "" +#define UI_ICON_GO_BACK "" +#define UI_ICON_GO_FORWARD "" +#define UI_ICON_GO_UP "" +#define UI_ICON_GO_DOWN "" +#define UI_ICON_VIEW_LIST "" +#define UI_ICON_VIEW_GRID "" +#define UI_ICON_VIEW_DUAL "" +#define UI_ICON_VIEW_FULLSCREEN "" +#define UI_ICON_VIEW_RESTORE "" +#define UI_ICON_TEXT_BOLD "" +#define UI_ICON_TEXT_ITALIC "" +#define UI_ICON_TEXT_UNDERLINE "" +#define UI_ICON_LIST_BULLET "" +#define UI_ICON_LIST_ORDERED "" +#define UI_ICON_LIST_CHECK "" +#define UI_ICON_CHECKBOX "" +#define UI_ICON_STAR "" +#define UI_ICON_VIEW_REVEAL "" +#define UI_ICON_VIEW_CONCEAL "" +#define UI_ICON_SETTINGS "" +#define UI_ICON_MEDIA_PLAY "" +#define UI_ICON_MEDIA_STOP "" +#define UI_ICON_MEDIA_PAUSE "" +#define UI_ICON_MEDIA_SEEK_BACKWARD "" +#define UI_ICON_MEDIA_SEEK_FORWARD "" +#define UI_ICON_MEDIA_SKIP_BACKWARD "" +#define UI_ICON_MEDIA_SKIP_FORWARD "" +#define UI_ICON_CALL_START "" +#define UI_ICON_CALL_STOP "" +#define UI_ICON_CALL_INCOMING "" +#define UI_ICON_CALL_OUTGOING "" +#define UI_ICON_MICROPHONE_ON "" +#define UI_ICON_MICROPHONE_OFF "" +#define UI_ICON_LOCKED "" +#define UI_ICON_UNLOCKED "" +#define UI_ICON_SECURE "" +#define UI_ICON_INSECURE "" +#endif /* UI_MOTIF */ + +#ifdef UI_WIN32 + +#define UI_ICON_HOME "" +#define UI_ICON_NEW_WINDOW "" +#define UI_ICON_NEW_TAB "" +#define UI_ICON_NEW_FOLDER "" +#define UI_ICON_NEW_DOCUMENT "" +#define UI_ICON_NEW_APPOINTMENT "" +#define UI_ICON_NEW_CHAT_MESSAGE "" +#define UI_ICON_NEW_CONTACT "" +#define UI_ICON_NEW_MAIL "" +#define UI_ICON_ADD_BOOKMARK "" +#define UI_ICON_ADD_IMAGE "" +#define UI_ICON_ADD_LINK "" +#define UI_ICON_ADD_TEXT "" +#define UI_ICON_ADD "" +#define UI_ICON_REMOVE "" +#define UI_ICON_REFRESH "" +#define UI_ICON_UPLOAD "" +#define UI_ICON_SAVE_LOCAL "" +#define UI_ICON_EDIT_COPY "" +#define UI_ICON_EDIT_CUT "" +#define UI_ICON_EDIT_DELETE "" +#define UI_ICON_EDIT_PASTE "" +#define UI_ICON_UNDO "" +#define UI_ICON_REDO "" +#define UI_ICON_SIDEBAR_LEFT "" +#define UI_ICON_SIDEBAR_RIGHT "" +#define UI_ICON_GO_BACK "" +#define UI_ICON_GO_FORWARD "" +#define UI_ICON_GO_UP "" +#define UI_ICON_GO_DOWN "" +#define UI_ICON_VIEW_LIST "" +#define UI_ICON_VIEW_GRID "" +#define UI_ICON_VIEW_DUAL "" +#define UI_ICON_VIEW_FULLSCREEN "" +#define UI_ICON_VIEW_RESTORE "" +#define UI_ICON_TEXT_BOLD "" +#define UI_ICON_TEXT_ITALIC "" +#define UI_ICON_TEXT_UNDERLINE "" +#define UI_ICON_LIST_BULLET "" +#define UI_ICON_LIST_ORDERED "" +#define UI_ICON_LIST_CHECK "" +#define UI_ICON_CHECKBOX "" +#define UI_ICON_STAR "" +#define UI_ICON_VIEW_REVEAL "" +#define UI_ICON_VIEW_CONCEAL "" +#define UI_ICON_SETTINGS "" +#define UI_ICON_MEDIA_PLAY "" +#define UI_ICON_MEDIA_STOP "" +#define UI_ICON_MEDIA_PAUSE "" +#define UI_ICON_MEDIA_SEEK_BACKWARD "" +#define UI_ICON_MEDIA_SEEK_FORWARD "" +#define UI_ICON_MEDIA_SKIP_BACKWARD "" +#define UI_ICON_MEDIA_SKIP_FORWARD "" +#define UI_ICON_CALL_START "" +#define UI_ICON_CALL_STOP "" +#define UI_ICON_CALL_INCOMING "" +#define UI_ICON_CALL_OUTGOING "" +#define UI_ICON_MICROPHONE_ON "" +#define UI_ICON_MICROPHONE_OFF "" +#define UI_ICON_LOCKED "" +#define UI_ICON_UNLOCKED "" +#define UI_ICON_SECURE "" +#define UI_ICON_INSECURE "" + +#endif /* UI_MOTIF */ + + +enum UiIconId { + UI_ICON_ID_HOME, + UI_ICON_ID_NEW_WINDOW, + UI_ICON_ID_NEW_TAB, + UI_ICON_ID_NEW_FOLDER, + UI_ICON_ID_NEW_DOCUMENT, + UI_ICON_ID_NEW_APPOINTMENT, + UI_ICON_ID_NEW_CHAT_MESSAGE, + UI_ICON_ID_NEW_CONTACT, + UI_ICON_ID_NEW_MAIL, + UI_ICON_ID_ADD_BOOKMARK, + UI_ICON_ID_ADD_IMAGE, + UI_ICON_ID_ADD_LINK, + UI_ICON_ID_ADD_TEXT, + UI_ICON_ID_ADD, + UI_ICON_ID_REMOVE, + UI_ICON_ID_REFRESH, + UI_ICON_ID_UPLOAD, + UI_ICON_ID_SAVE_LOCAL, + UI_ICON_ID_EDIT_COPY, + UI_ICON_ID_EDIT_CUT, + UI_ICON_ID_EDIT_DELETE, + UI_ICON_ID_EDIT_PASTE, + UI_ICON_ID_UNDO, + UI_ICON_ID_REDO, + UI_ICON_ID_SIDEBAR_LEFT, + UI_ICON_ID_SIDEBAR_RIGHT, + UI_ICON_ID_GO_BACK, + UI_ICON_ID_GO_FORWARD, + UI_ICON_ID_GO_UP, + UI_ICON_ID_GO_DOWN, + UI_ICON_ID_VIEW_LIST, + UI_ICON_ID_VIEW_GRID, + UI_ICON_ID_VIEW_DUAL, + UI_ICON_ID_VIEW_FULLSCREEN, + UI_ICON_ID_VIEW_RESTORE, + UI_ICON_ID_TEXT_BOLD, + UI_ICON_ID_TEXT_ITALIC, + UI_ICON_ID_TEXT_UNDERLINE, + UI_ICON_ID_LIST_BULLET, + UI_ICON_ID_LIST_ORDERED, + UI_ICON_ID_LIST_CHECK, + UI_ICON_ID_CHECKBOX, + UI_ICON_ID_STAR, + UI_ICON_ID_VIEW_REVEAL, + UI_ICON_ID_VIEW_CONCEAL, + UI_ICON_ID_SETTINGS, + UI_ICON_ID_MEDIA_PLAY, + UI_ICON_ID_MEDIA_STOP, + UI_ICON_ID_MEDIA_PAUSE, + UI_ICON_ID_MEDIA_SEEK_BACKWARD, + UI_ICON_ID_MEDIA_SEEK_FORWARD, + UI_ICON_ID_MEDIA_SKIP_BACKWARD, + UI_ICON_ID_MEDIA_SKIP_FORWARD, + UI_ICON_ID_CALL_START, + UI_ICON_ID_CALL_STOP, + UI_ICON_ID_CALL_INCOMING, + UI_ICON_ID_CALL_OUTGOING, + UI_ICON_ID_MICROPHONE_ON, + UI_ICON_ID_MICROPHONE_OFF, + UI_ICON_ID_LOCKED, + UI_ICON_ID_UNLOCKED, + UI_ICON_ID_SECURE, + UI_ICON_ID_INSECURE +}; UIEXPORT UiIcon* ui_icon(const char* name, size_t size); UIEXPORT UiIcon* ui_icon_unscaled(const char *name, int size); @@ -85,6 +472,8 @@ UIEXPORT UiIcon* ui_foldericon(size_t size); UIEXPORT UiIcon* ui_fileicon(size_t size); +UIEXPORT const char* ui_icon_name(enum UiIconId icon_id); + #ifdef __cplusplus } #endif diff --git a/ui/ui/list.h b/ui/ui/list.h index 7cfbfbb..35de753 100644 --- a/ui/ui/list.h +++ b/ui/ui/list.h @@ -166,20 +166,27 @@ struct UiListArgs { void *getstyledata; ui_callback onactivate; void *onactivatedata; + const char *onactivate_action; ui_callback onselection; void *onselectiondata; + const char *onselection_action; ui_callback ondragstart; void *ondragstartdata; + const char *ondragstart_action; ui_callback ondragcomplete; void *ondragcompletedata; + const char *ondragcomplete_action; ui_callback ondrop; void *ondropdata; + const char *ondrop_action; UiBool multiselection; + UiBool hide_header; UiMenuBuilder *contextmenu; ui_list_savefunc onsave; void *onsavedata; const int *states; + const int *visibility_states; }; typedef void (*ui_sublist_getvalue_func)(UiList *list, void *sublist_userdata, void *rowdata, int index, UiSubListItem *item, void *userdata); @@ -295,6 +302,8 @@ struct UiSourceListArgs { void *onbuttonclickdata; UiMenuBuilder *contextmenu; + + const int *visibility_states;; }; #define UI_SUBLIST(...) (UiSubList){ __VA_ARGS__ } diff --git a/ui/ui/menu.h b/ui/ui/menu.h index 43cca7e..5ad8776 100644 --- a/ui/ui/menu.h +++ b/ui/ui/menu.h @@ -37,31 +37,40 @@ extern "C" { typedef struct UiMenuItemArgs { - const char* label; - const char* icon; - + const char *label; + const char *icon; + ui_callback onclick; - void* onclickdata; + void *onclickdata; + const char *action; + const char *accelerator; + const char *accelerator_text; - const int* states; + const int *states; } UiMenuItemArgs; typedef struct UiMenuToggleItemArgs { - const char* label; - const char* icon; + const char *label; + const char *icon; - const char* varname; + const char *varname; ui_callback onchange; - void* onchangedata; + void *onchangedata; + const char *action; + const char *accelerator; + const char *accelerator_text; - const int* nstates; + const int *nstates; } UiMenuToggleItemArgs; typedef struct UiMenuItemListArgs { - const char* varname; + const char *varname; ui_getvaluefunc getvalue; + ui_getvaluefunc2 getvalue2; + void *getvaluedata; ui_callback onselect; - void* onselectdata; + void *onselectdata; + const char *action; UiBool addseparator; } UiMenuItemListArgs; diff --git a/ui/ui/text.h b/ui/ui/text.h index c102f0b..793d8ee 100644 --- a/ui/ui/text.h +++ b/ui/ui/text.h @@ -58,9 +58,27 @@ typedef struct UiTextAreaArgs { const char *varname; ui_callback onchange; void *onchangedata; + const char *onchange_action; + ui_callback ontextchanged; + void *ontextchangeddata; + const char *ontextchanged_action; const int *states; + const int *visibility_states; } UiTextAreaArgs; + +typedef enum UiTextChangedEventType { + UI_TEXT_INSERT = 0, + UI_TEXT_DELETE +} UiTextChangedEventType; + +typedef struct UiTextChangeEventData { + UiTextChangedEventType type; + int begin; + int end; + const char *text; + int length; +} UiTextChangeEventData; typedef struct UiTextFieldArgs { UiBool fill; @@ -86,8 +104,11 @@ typedef struct UiTextFieldArgs { void *onchangedata; ui_callback onactivate; void *onactivatedata; + const char *onactivate_action; + const char *onchange_action; const int *states; + const int *visibility_states; } UiTextFieldArgs; typedef struct UiPathElmRet { @@ -127,6 +148,7 @@ typedef struct UiPathTextFieldArgs { ui_callback onactivate; void *onactivatedata; + const char *action; ui_callback ondragstart; void *ondragstartdata; @@ -134,6 +156,8 @@ typedef struct UiPathTextFieldArgs { void *ondragcompletedata; ui_callback ondrop; void *ondropsdata; + + const int *visibility_states; } UiPathTextFieldArgs; #define ui_textarea(obj, ...) ui_textarea_create(obj, &(UiTextAreaArgs) { __VA_ARGS__ }) @@ -145,6 +169,15 @@ UIEXPORT UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea); UIEXPORT void ui_text_undo(UiText *value); UIEXPORT void ui_text_redo(UiText *value); +UIEXPORT void ui_textarea_focus(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end); +UIEXPORT void ui_textarea_select_all(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable); +UIEXPORT UiBool ui_textarea_is_editable(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_position(UIWIDGET textarea, int pos); +UIEXPORT int ui_textarea_get_position(UIWIDGET textarea); +UIEXPORT void ui_textarea_scroll_to(UIWIDGET textarea, int pos); + #define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) #define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) #define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) @@ -155,6 +188,15 @@ UIEXPORT UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs * UIEXPORT UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs *args); UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args); + +UIEXPORT void ui_textfield_focus(UIWIDGET textfield); +UIEXPORT void ui_textfield_focus_without_selecting(UIWIDGET textfield); +UIEXPORT void ui_textfield_set_selection(UIWIDGET textfield, int begin, int end); +UIEXPORT void ui_textfield_select_all(UIWIDGET textfield); +UIEXPORT void ui_textfield_set_editable(UIWIDGET textfield, UiBool editable); +UIEXPORT UiBool ui_textfield_is_editable(UIWIDGET textfield); +UIEXPORT void ui_textfield_set_position(UIWIDGET textfield, int pos); +UIEXPORT int ui_textfield_get_position(UIWIDGET textfield); #ifdef __cplusplus } diff --git a/ui/ui/toolbar.h b/ui/ui/toolbar.h index 2e230df..d525231 100644 --- a/ui/ui/toolbar.h +++ b/ui/ui/toolbar.h @@ -42,7 +42,10 @@ typedef struct UiToolbarItemArgs { const char *tooltip; ui_callback onclick; - void* onclickdata; + void *onclickdata; + const char *action; + const char *accelerator; + const char *accelerator_text; const int *states; const int *visibility_states; @@ -56,11 +59,36 @@ typedef struct UiToolbarToggleItemArgs { const char *varname; ui_callback onchange; void *onchangedata; + const char *action; + const char *accelerator; + const char *accelerator_text; const int *states; const int *visibility_states; } UiToolbarToggleItemArgs; +typedef struct UiToolbarContentToggleItemArgs { + const char *label0; + const char *icon0; + const char *tooltip0; + const char *label1; + const char *icon1; + const char *tooltip1; + + const char *varname; + ui_callback onchange; + void *onchangedata; + const char *action; + const char *accelerator; + const char *accelerator_text; + + int toggled_by_state; + UiBool istogglebutton; + + const int *states; + const int *visibility_states; +} UiToolbarContentToggleItemArgs; + typedef struct UiToolbarMenuArgs { const char *label; const char *icon; @@ -81,6 +109,7 @@ enum UiToolbarPos { #define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, &(UiToolbarItemArgs){ __VA_ARGS__ } ) #define ui_toolbar_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } ) +#define ui_toolbar_content_toggleitem(name, ...) ui_toolbar_toggleitem_create(name, &(UiToolbarToggleItemArgs){ __VA_ARGS__ } ) #define ui_toolbar_menu(name, ...) for(ui_toolbar_menu_create(name, &(UiToolbarMenuArgs){ __VA_ARGS__ });ui_menu_is_open();ui_menu_close()) #define ui_toolbar_appmenu() for(ui_toolbar_menu_create(NULL, &(UiToolbarMenuArgs){ 0 });ui_menu_is_open();ui_menu_close()) @@ -88,6 +117,7 @@ enum UiToolbarPos { UIEXPORT void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args); UIEXPORT void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args); +UIEXPORT void ui_toolbar_content_toggleitem_create(const char* name, UiToolbarContentToggleItemArgs *args); UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args); UIEXPORT void ui_toolbar_add_default(const char *name, enum UiToolbarPos pos); diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index 94c77f0..0537d58 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -47,6 +47,7 @@ typedef void* UIMENU; // NSMenu* #include #define UIWIDGET GtkWidget* +#define UIWINDOW void* #if UI_GTK2 || UI_GTK3 #define UIMENU GtkMenu* @@ -83,6 +84,7 @@ typedef void* UIMENU; // NSMenu* #include #define UIWIDGET Widget +#define UIWINDOW void* #define UIMENU Widget @@ -154,6 +156,13 @@ typedef struct UiWidget UiWidget; #define UIWINDOW UiWidget* #define UIMENU void* +#else + +#define UI_GENERIC +#define UIWIDGET void* +#define UIWINDOW void* +#define UIMENU void* + #endif #ifndef TRUE @@ -171,9 +180,9 @@ typedef struct UiWidget UiWidget; extern "C" { #endif -#define UI_GROUP_SELECTION 20000 +#define UI_STATE_SELECTION 20000 -#define UI_GROUPS(...) (const int[]){ __VA_ARGS__, -1 } +#define UI_STATES(...) (const int[]){ __VA_ARGS__, -1 } /* public types */ #ifndef __cplusplus @@ -183,7 +192,6 @@ typedef bool UiBool; #endif typedef struct UiObject UiObject; -typedef struct UiContainerX UiContainerX; typedef struct UiEvent UiEvent; typedef struct UiMouseEvent UiMouseEvent; typedef struct UiObserver UiObserver; @@ -205,6 +213,8 @@ typedef struct UiListSelection UiListSelection; typedef struct UiTextStyle UiTextStyle; typedef struct UiColor UiColor; +typedef enum UiEventType UiEventType; + /* begin opaque types */ typedef struct UiContext UiContext; typedef struct UiContainer UiContainer; @@ -218,8 +228,6 @@ typedef struct UiDnD UiDnD; typedef struct UiThreadpool UiThreadpool; /* end opaque types */ -typedef struct UiTabbedPane UiTabbedPane; - typedef enum UiTri { UI_DEFAULT = 0, UI_ON, @@ -273,12 +281,10 @@ struct UiObject { */ UIWIDGET widget; -#if defined(UI_COCOA) || defined(UI_WINUI) /* * native window object */ UIWINDOW wobj; -#endif /* * user window data @@ -292,15 +298,15 @@ struct UiObject { /* * container list - * TODO: remove old UiContainer and rename UiContainerX to UiContainer */ - UiContainerX *container_begin; - UiContainerX *container_end; + UiContainer *container_begin; + UiContainer *container_end; /* - * next container object + * called when someone requests to close the window */ - UiObject *next; + void (*onclose)(UiEvent *event, void *userdata); + void *onclosedata; /* * obj destroy func @@ -313,31 +319,32 @@ struct UiObject { unsigned int ref; }; -struct UiTabbedPane { - /* - * native widget - */ - UIWIDGET widget; - - /* - * current document - */ - void *document; - - /* - * parent context - */ - UiContext *ctx; +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 { @@ -392,20 +399,23 @@ struct UiText { void (*set)(UiText*, const char*); char* (*get)(UiText*); char* (*getsubstr)(UiText*, int, int); /* text, begin, end */ - void (*insert)(UiText*, int, char*); + void (*insert)(UiText*, int, const char*); + void (*replace)(UiText*, int, int, const char*); void (*setposition)(UiText*,int); int (*position)(UiText*); + void (*showposition)(UiText*, int); void (*setselection)(UiText*, int, int); /* text, begin, end */ void (*selection)(UiText*, int*, int*); /* text, begin, end */ int (*length)(UiText*); void (*remove)(UiText*, int, int); /* text, begin, end */ + void (*setreadonly)(UiText*, int); UiStr value; int pos; + int readonly; void *obj; int datatype; void *data1; void *data2; - // TODO: replacefunc, ... UiObserver *observers; }; @@ -431,27 +441,33 @@ typedef void (*ui_list_destroy_func)(UiContext *ctx, UiList *list, void *userdat * abstract list */ struct UiList { - /* get the first element */ + // destructor + ui_list_destroy_func destroy; + // get the first element void*(*first)(UiList *list); - /* get the next element */ + // get the next element void*(*next)(UiList *list); - /* get the nth element */ + // get the nth element void*(*get)(UiList *list, int i); - /* get the number of elements */ + // get the number of elements int(*count)(UiList *list); - /* iterator changes after first() next() and get() */ + // iterator changes after first() next() and get() void *iter; - /* private - implementation dependent */ + // private - implementation dependent void *data; - /* binding functions */ + // binding functions void (*update)(UiList *list, int i); UiListSelection (*getselection)(UiList *list); void (*setselection)(UiList *list, UiListSelection selection); - /* binding object */ + // binding object void *obj; + // saved selection after unbind + UiListSelection *saved_selection; + // enable selection saving + UiBool save_selection; - /* list of observers */ + // list of observers UiObserver *observers; }; @@ -492,21 +508,11 @@ typedef struct UiCondVar { 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_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 { @@ -527,7 +533,7 @@ struct UiTextStyle { UIEXPORT void ui_init(const char *appname, int argc, char **argv); -UIEXPORT const char* ui_appname(); +UIEXPORT const char* ui_appname(void); UIEXPORT void ui_add_styledata(const char *styledata, int len); @@ -535,17 +541,19 @@ UIEXPORT UiContext* ui_global_context(void); UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata); -UIEXPORT void ui_context_destroy(UiContext *ctx); - UIEXPORT UiContext* ui_context_parent(UiContext *ctx); +UIEXPORT UiContext* ui_context_toplevel_parent(UiContext *ctx); UIEXPORT void ui_object_ref(UiObject *obj); UIEXPORT int ui_object_unref(UiObject *obj); UIEXPORT void ui_onstartup(ui_callback f, void *userdata); +UIEXPORT void ui_onnewwindow(ui_callback f, void *userdata); UIEXPORT void ui_onopen(ui_callback f, void *userdata); UIEXPORT void ui_onexit(ui_callback f, void *userdata); +UIEXPORT void ui_newwindow(void); + UIEXPORT int ui_app_save_settings(void); UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp); @@ -554,18 +562,36 @@ UIEXPORT void ui_app_quit(void); UIEXPORT void ui_show(UiObject *obj); UIEXPORT void ui_close(UiObject *obj); +UIEXPORT UiObject* ui_dummy_object(void); + UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd); UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td); + +UIEXPORT void ui_buffer_mainthread_calls(UiBool enable_buffering); +UIEXPORT void ui_exec_buffered_mainthread_calls(void); +UIEXPORT void ui_exec_buffered_mainthread_calls_wait(int timeout); + UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads); 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_document_onattach(void *doc, ui_callback cb, void *data); +UIEXPORT void ui_document_ondetach(void *doc, ui_callback cb, void *data); +UIEXPORT void ui_document_onattachmentstatuschange(void *doc, ui_callback cb, void *data); +UIEXPORT void ui_document_onattach_action(void *doc, const char *action); +UIEXPORT void ui_document_ondetach_action(void *doc, const char *action); +UIEXPORT void ui_document_onattachmentstatuschange_action(void *doc, const char *action); -UIEXPORT void* ui_get_subdocument(void *document); // deprecated +UIEXPORT int ui_document_is_attached(void *doc); +UIEXPORT int ui_document_is_attached_to_obj(void *doc); 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); @@ -576,8 +602,30 @@ UIEXPORT void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefun UIEXPORT void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates); UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates); +UIEXPORT void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata); +UIEXPORT void ui_add_action_with_accelerator( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text); +UIEXPORT void ui_update_action_bindings(UiContext *ctx); +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_broadcast_action3(const char *action_name, void *ptr, uint64_t type_id); +UIEXPORT void ui_mainthread_broadcast(const char *action_name); +UIEXPORT void ui_mainthread_broadcast2(const char *action_name, void *eventdata, int intval); +UIEXPORT void ui_mainthread_broadcast3(const char *action_name, void *ptr, uint64_t type_id); +UIEXPORT void ui_call_action_on(UiContext *ctx, const char *action); + UIEXPORT void ui_set_state(UiContext *ctx, int state); UIEXPORT void ui_unset_state(UiContext *ctx, int state); +UIEXPORT void ui_suppress_state(UiContext *ctx, int state); +UIEXPORT void ui_unsuppress_state(UiContext *ctx, int state); UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates); UIEXPORT void* ui_allocator(UiContext *ctx); @@ -589,6 +637,7 @@ UIEXPORT void ui_free(UiContext *ctx, void *ptr); UIEXPORT void* ui_realloc(UiContext *ctx, void *ptr, size_t size); UIEXPORT char* ui_strdup(UiContext *ctx, const char *str); UIEXPORT void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr); +UIEXPORT void ui_remove_destructor(UiContext *ctx, void *data); UIEXPORT void ui_set_destructor(void *mem, ui_destructor_func destr); // types @@ -671,16 +720,22 @@ UIEXPORT void* ui_list_get(UiList *list, int i); UIEXPORT int ui_list_count(UiList *list); UIEXPORT void ui_list_append(UiList *list, void *data); UIEXPORT void ui_list_prepend(UiList *list, void *data); +UIEXPORT void ui_list_insert(UiList *list, int index, void *data); UIEXPORT void ui_list_remove(UiList *list, int i); UIEXPORT void ui_list_clear(UiList *list); UIEXPORT void ui_list_update(UiList *list); UIEXPORT void ui_list_update_row(UiList *list, int row); UIEXPORT UiListSelection ui_list_get_selection(UiList *list); +UIEXPORT void ui_list_set_selection(UiList *list, UiListSelection sel); UIEXPORT void ui_list_addobsv(UiList *list, ui_callback f, void *data); UIEXPORT void ui_list_notify(UiList *list); +UIEXPORT void ui_list_clear_saved_selection(UiList *list); -UIEXPORT UiListSelection ui_list_getselection(UiList *list); +UIEXPORT int ui_list_getselection(UiList *list); UIEXPORT void ui_list_setselection(UiList *list, int index); +UIEXPORT void ui_list_setselection2(UiList *list, int index, UiBool selection_event); + +UIEXPORT void ui_listselection_free(UiListSelection selection); UIEXPORT UiFileList ui_filelist_copy(UiFileList list); UIEXPORT void ui_filelist_free(UiFileList list); @@ -690,16 +745,24 @@ UIEXPORT char* ui_clipboard_get(); UIEXPORT void ui_add_image(char *imgname, char *filename); // TODO: remove? - - -UIEXPORT void ui_listselection_free(UiListSelection selection); - +UIEXPORT char* ui_text_getsubstr(UiText *text, int begin, int end); +UIEXPORT void ui_text_insert(UiText *text, int pos, const char *str); +UIEXPORT void ui_text_replace(UiText *text, int begin, int end, const char *str); +UIEXPORT void ui_text_setposition(UiText *text, int pos); +UIEXPORT int ui_text_position(UiText *text); +UIEXPORT void ui_text_showposition(UiText *text, int pos); +UIEXPORT void ui_text_setselection(UiText *text, int begin, int end); +UIEXPORT void ui_text_selection(UiText *text, int *begin, int *end); +UIEXPORT int ui_text_length(UiText *text); +UIEXPORT void ui_text_remove(UiText *text, int begin, int end); +UIEXPORT void ui_text_setreadonly(UiText *text, int readonly); UIEXPORT UiStr ui_str(char *cstr); UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v)); UIEXPORT char* ui_getappdir(void); +UIEXPORT void ui_setappdir(const char *path); UIEXPORT char* ui_configfile(const char *name); UIEXPORT UiCondVar* ui_condvar_create(void); @@ -711,10 +774,13 @@ UIEXPORT void ui_setop_enable(int set); UIEXPORT int ui_get_setop(void); UIEXPORT void ui_onchange_events_enable(UiBool enable); UIEXPORT UiBool ui_onchange_events_is_enabled(void); +UIEXPORT void ui_selection_events_enable(UiBool enable); +UIEXPORT UiBool ui_selection_events_is_enabled(void); UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata); UIEXPORT void ui_global_list_destructor(ui_list_destroy_func func, void *userdata); +UIEXPORT void ui_list_class_set_destructor(UiList *list, ui_list_destroy_func destroy); UIEXPORT void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)); UIEXPORT void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list)); UIEXPORT void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i)); @@ -725,6 +791,11 @@ UIEXPORT void ui_list_class_set_iter(UiList *list, void *iter); UIEXPORT void ui_object_set(UiObject *obj, const char *key, void *data); UIEXPORT void* ui_object_get(UiObject *obj, const char *key); +UIEXPORT void ui_app_ref(void); +UIEXPORT void ui_app_unref(void); + +UIEXPORT void ui_open_uri(const char *uri); + #ifdef __cplusplus } #endif diff --git a/ui/ui/webview.h b/ui/ui/webview.h index d5a243d..65ca139 100644 --- a/ui/ui/webview.h +++ b/ui/ui/webview.h @@ -69,6 +69,7 @@ typedef struct UiWebviewArgs { const char *varname; const int* states; + const int *visibility_states; } UiWebviewArgs; #define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } ) diff --git a/ui/ui/widget.h b/ui/ui/widget.h index 40503ba..62c5c63 100644 --- a/ui/ui/widget.h +++ b/ui/ui/widget.h @@ -52,6 +52,8 @@ typedef struct UiWidgetArgs { const char *style_class; } UiWidgetArgs; +#ifndef UI_GENERIC + #ifdef UI_GTK typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs *args, void *userdata); #elif defined(UI_QT) @@ -71,6 +73,7 @@ UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func cre #define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, &(UiWidgetArgs) { __VA_ARGS__ }) +#endif UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);