// splitpane left: table
UiModel* model = ui_model(obj->ctx, UI_STRING, "Name", UI_STRING_FREE, "Last Modified", -1);
model->columnsize[0] = -1;
- model->getvalue = window_notelist_getvalue;
ui_table(obj,
.model = model,
.varname = "notes",
+ .getvalue = window_notelist_getvalue,
.contextmenu = get_notelist_context_menu(),
.multiselection = TRUE,
.onselection = action_note_selected,
return self.preferredSize;
}
-- (void) addView:(NSView*)view fill:(BOOL)fill {
+- (void) addView:(NSView*)view {
if(_newline) {
_y++;
_x = 0;
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * Copyright 2025 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:
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "tree.h"
-#include "container.h"
+#import "toolkit.h"
+#import "../ui/tree.h"
-#include <QTreeView>
-#include <QTreeWidgetItem>
-#include <QListView>
+@interface ListDataSource : NSObject <NSTableViewDataSource>
+@property NSArray<NSTableColumn*> *columns;
+@property UiVar *var;
+@property ui_getvaluefunc2 getvalue;
+@property void *getvaluedata;
+@property UiModel *model;
+- (id) init:(NSArray<NSTableColumn*>*) columns var:(UiVar*)var getvalue:(ui_getvaluefunc2) getvaluefunc getvaluedata:(void*)userdata;
+
+@end
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "ListDataSource.h"
+
+@implementation ListDataSource
+
+- (id) init:(NSArray<NSTableColumn*>*) columns var:(UiVar*)var getvalue:(ui_getvaluefunc2) getvaluefunc getvaluedata:(void*)userdata {
+ _columns = columns;
+ _var = var;
+ _getvalue = getvaluefunc;
+ _getvaluedata = userdata;
+ return self;
+}
+
+- (NSInteger) numberOfRowsInTableView:(NSTableView *) tableView {
+ if(_var) {
+ UiList *list = _var->value;
+ if(list->count) {
+ return list->count(list);
+ }
+ }
+ return 0;
+}
+
+- (id) tableView:(NSTableView *) tableView
+objectValueForTableColumn:(NSTableColumn *) tableColumn
+ row:(NSInteger) row
+{
+ id ret = nil;
+ UiList *list = _var->value;
+ void *elm = list->get(list, (int)row);
+ if(elm) {
+ // get column index
+ NSUInteger colIndex = [_columns indexOfObject:tableColumn];
+ if(colIndex == NSNotFound) {
+ return nil;
+ }
+
+ // get UI model type for this column
+ UiModelType type = UI_STRING;
+ UiModel *model = _model;
+ if(model) {
+ if(colIndex >= model->columns) {
+ return nil;
+ }
+ type = model->types[colIndex];
+ }
+
+ // convert the list element
+ UiBool freeResult = FALSE;
+ void *data = _getvalue(list, elm, (int)row, (int)colIndex, _getvaluedata, &freeResult);
+
+ switch(type) {
+ case UI_STRING: {
+ ret = [[NSString alloc] initWithUTF8String:data];
+ break;
+ }
+ case UI_STRING_FREE: {
+ ret = [[NSString alloc] initWithUTF8String:data];
+ freeResult = TRUE;
+ break;
+ }
+ case UI_INTEGER: {
+ break;
+ }
+ case UI_ICON: {
+ break;
+ }
+ case UI_ICON_TEXT: {
+ break;
+ }
+ case UI_ICON_TEXT_FREE: {
+ break;
+ }
+ }
+
+ if(freeResult) {
+ free(data);
+ }
+ }
+ return ret;
+}
+
+@end
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "toolkit.h"
+
+@interface ListDelegate : NSObject <NSTableViewDelegate>
+
+@property (weak) NSTableView *tableview;
+@property UiObject *obj;
+@property ui_callback onselection;
+@property void *onselectiondata;
+@property ui_callback onactivate;
+@property void *onactivatedata;
+
+- (id)init:(NSTableView*) tableview obj:(UiObject*)obj;
+
+- (void)activateEvent:(id)sender;
+
+@end
+
+UiListSelection ui_tableview_selection(NSTableView *tableview);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "ListDelegate.h"
+
+@implementation ListDelegate
+
+- (id)init:(NSTableView*) tableview obj:(UiObject*)obj {
+ _tableview = tableview;
+ _obj = obj;
+ return self;
+}
+
+- (void)activateEvent:(id)sender {
+ NSTableView *table = sender;
+ 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);
+ }
+}
+
+- (void) tableViewSelectionDidChange:(NSNotification *) notification {
+ if(_onselection) {
+ UiListSelection sel = ui_tableview_selection(_tableview);
+
+ 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 = 0;
+ event.set = ui_get_setop();
+
+ _onselection(&event, _onselectiondata);
+ }
+}
+
+@end
+
+UiListSelection ui_tableview_selection(NSTableView *tableview) {
+ NSIndexSet *indexSet = tableview.selectedRowIndexes;
+ NSUInteger count = [indexSet count];
+
+ if(count == 0) {
+ return (UiListSelection){0, NULL};
+ }
+
+ int *rows = calloc(count, sizeof(int));
+
+ __block NSUInteger i = 0;
+ [indexSet enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
+ rows[i++] = (int)index;
+ }];
+
+ UiListSelection sel;
+ sel.count = (int)count;
+ sel.rows = rows;
+ return sel;
+}
#import "EventData.h"
#import "menu.h"
+#import "Toolbar.h"
@implementation MainWindow
backing:NSBackingStoreBuffered
defer:false];
+ if(uic_toolbar_isenabled()) {
+ UiToolbar *toolbar = [[UiToolbar alloc]initWithObject:obj];
+ [self setToolbar:toolbar];
+ }
+
+
// create a vertical stackview as default container
BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0];
//GridLayout *vbox = [[GridLayout alloc] init];
- (void)menuItemAction:(id)sender {
EventData *event = objc_getAssociatedObject(sender, "eventdata");
if(event) {
- event.obj = self.uiobj; // temporary set the event object
- [event handleEvent:sender];
+ if(event.obj) {
+ [event handleEvent:sender];
+ } else {
+ event.obj = self.uiobj;
+ [event handleEvent:sender];
+ event.obj = NULL;
+ }
}
}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "toolkit.h"
+#import "../common/toolbar.h"
+
+/*
+ * UiToolbarDelegate
+ */
+@interface UiToolbarDelegate : NSObject <NSToolbarDelegate> {
+ NSMutableArray<NSString*> *allowedItems;
+ NSMutableArray<NSString*> *defaultItems;
+}
+
+- (UiToolbarDelegate*) init;
+
+@end
+
+/*
+ * UiToolbar
+ */
+@interface UiToolbar : NSToolbar <NSToolbarDelegate> {
+ NSMutableArray<NSString*> *allowedItems;
+ NSMutableArray<NSString*> *defaultItems;
+}
+
+@property UiObject *obj;
+
+- (UiToolbar*) initWithObject:(UiObject*)object;
+
+@end
+
+
+@interface UiToolbarToggleEventHandler : NSObject
+@property UiObject *obj;
+@property UiVar *var;
+@property ui_callback callback;
+@property void *userdata;
+
+- (UiToolbarToggleEventHandler*)init;
+- (void)handleEvent:(id)sender;
+
+@end
+
+void ui_toolbar_init(void);
+
+NSToolbarItem* ui_nstoolbaritem_create_item(UiObject *obj, UiToolbarItem *item, NSString *identifier);
+NSToolbarItem* ui_nstoolbaritem_create_toggle(UiObject *obj, UiToolbarToggleItem *item, NSString *identifier);
+NSToolbarItem* ui_nstoolbaritem_create_menu(UiObject *obj, UiToolbarMenuItem *item, NSString *identifier);
+
+int64_t ui_toolbar_seg_toggleitem_get(UiInteger *i);
+void ui_toolbar_seg_toggleitem_set(UiInteger *i, int64_t value);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "Toolbar.h"
+#import "EventData.h"
+#import "image.h"
+#import "menu.h"
+#import <objc/runtime.h>
+
+#include "../common/toolbar.h"
+
+
+void ui_toolbar_init(void) {
+
+}
+
+
+
+/* --------------------- UiToolbar --------------------- */
+
+@implementation UiToolbar
+
+- (UiToolbar*) initWithObject:(UiObject*)object {
+ self = [super initWithIdentifier:@"UiToolbar"];
+ _obj = object;
+
+ allowedItems = [[NSMutableArray alloc]initWithCapacity:16];
+ defaultItems = [[NSMutableArray alloc]initWithCapacity:16];
+
+ CxMap *toolbarItems = uic_get_toolbar_items();
+ CxMapIterator i = cxMapIteratorKeys(toolbarItems);
+ cx_foreach(CxHashKey *, key, i) {
+ NSString *s = [[NSString alloc]initWithBytes:key->data length:key->len encoding:NSUTF8StringEncoding];
+ [allowedItems addObject:s];
+ }
+ [allowedItems addObject: NSToolbarFlexibleSpaceItemIdentifier];
+ [allowedItems addObject: NSToolbarSpaceItemIdentifier];
+
+ CxList *tbitems[3];
+ tbitems[0] = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT);
+ tbitems[1] = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER);
+ tbitems[2] = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT);
+ for(int t=0;t<3;t++) {
+ CxIterator iter = cxListIterator(tbitems[t]);
+ cx_foreach(char *, name, iter) {
+ NSString *s = [[NSString alloc] initWithUTF8String:name];
+ [defaultItems addObject:s];
+ }
+ }
+
+ [self setDelegate:self];
+ [self setAllowsUserCustomization:YES];
+ return self;
+}
+
+// implementation of NSToolbarDelegate methods
+
+- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
+ return allowedItems;
+}
+
+- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
+ return defaultItems;
+}
+
+- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
+ itemForItemIdentifier:(NSString *)itemIdentifier
+ willBeInsertedIntoToolbar:(BOOL)flag {
+ CxMap *items = uic_get_toolbar_items();
+ UiToolbarItemI *item = cxMapGet(items, itemIdentifier.UTF8String);
+ if(!item) {
+ return nil;
+ }
+
+ switch(item->type) {
+ default: return nil;
+ case UI_TOOLBAR_ITEM: {
+ return ui_nstoolbaritem_create_item(_obj, (UiToolbarItem*)item, itemIdentifier);
+ }
+ case UI_TOOLBAR_TOGGLEITEM: {
+ return ui_nstoolbaritem_create_toggle(_obj, (UiToolbarToggleItem*)item, itemIdentifier);
+ }
+ case UI_TOOLBAR_MENU: {
+ return ui_nstoolbaritem_create_menu(_obj, (UiToolbarMenuItem*)item, itemIdentifier);
+ }
+ }
+
+ return nil;
+}
+
+@end
+
+@implementation UiToolbarToggleEventHandler
+
+- (UiToolbarToggleEventHandler*)init {
+ return self;
+}
+
+- (void)handleEvent:(id)sender {
+ if(_callback == nil) {
+ return;
+ }
+
+ UiEvent event;
+ event.obj = _obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = 0;
+ event.set = ui_get_setop();
+
+ if([sender isKindOfClass:[NSSegmentedControl class]]) {
+ NSSegmentedControl *seg = (NSSegmentedControl*)sender;
+ event.intval = [seg isSelectedForSegment:0];
+ }
+
+ _callback(&event, _userdata);
+}
+
+@end
+
+NSToolbarItem* ui_nstoolbaritem_create_item(UiObject *obj, UiToolbarItem *item, NSString *identifier) {
+ NSToolbarItem *button = [[NSToolbarItem alloc] initWithItemIdentifier: identifier];
+ button.bordered = YES;
+
+ if(item->args.label) {
+ NSString *label = [[NSString alloc] initWithUTF8String:item->args.label];
+ button.paletteLabel = label;
+ button.label = label;
+ }
+ if(item->args.icon) {
+ 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];
+ event.obj = obj;
+ button.target = event;
+ button.action = @selector(handleEvent:);
+ objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+ }
+ return button;
+}
+
+NSToolbarItem* ui_nstoolbaritem_create_toggle(UiObject *obj, UiToolbarToggleItem *item, NSString *identifier) {
+ UiToolbarToggleEventHandler *event = [[UiToolbarToggleEventHandler alloc]init];
+ event.obj = obj;
+ event.callback = item->args.onchange;
+ event.userdata = item->args.onchangedata;
+
+ NSToolbarItem *button = [[NSToolbarItem alloc] initWithItemIdentifier:identifier];
+ if(item->args.label) {
+ NSString *label = [[NSString alloc] initWithUTF8String:item->args.label];
+ button.paletteLabel = label;
+ button.label = label;
+ }
+ objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+
+ NSSegmentedControl *seg;
+ 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;
+ } else {
+ NSArray *images = @[ui_cocoa_named_icon(item->args.icon)];
+ seg = [NSSegmentedControl segmentedControlWithImages:images trackingMode:NSSegmentSwitchTrackingSelectAny target:event action:@selector(handleEvent:)];
+ }
+ button.view = seg;
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER);
+ if(var) {
+ event.var = var;
+ UiInteger *i = var->value;
+ if(i->get) {
+ if(ui_get(i) != 0) {
+ [seg setEnabled:YES forSegment:0];
+ }
+
+ }
+ i->obj = (__bridge void*)seg;
+ i->get = ui_toolbar_seg_toggleitem_get;
+ i->set = ui_toolbar_seg_toggleitem_set;
+ }
+
+ return button;
+}
+
+int64_t ui_toolbar_seg_toggleitem_get(UiInteger *i) {
+ NSSegmentedControl *seg = (__bridge NSSegmentedControl*)i->obj;
+ i->value = [seg isSelectedForSegment:0];
+ return i->value;
+}
+
+void ui_toolbar_seg_toggleitem_set(UiInteger *i, int64_t value) {
+ NSSegmentedControl *seg = (__bridge NSSegmentedControl*)i->obj;
+ i->value = value;
+ [seg setSelected:value != 0 forSegment:0];
+}
+
+NSToolbarItem* ui_nstoolbaritem_create_menu(UiObject *obj, UiToolbarMenuItem *item, NSString *identifier) {
+ NSMenuToolbarItem *button = [[NSMenuToolbarItem alloc] initWithItemIdentifier: identifier];
+ button.bordered = YES;
+
+ if(item->args.label) {
+ NSString *label = [[NSString alloc] initWithUTF8String:item->args.label];
+ button.paletteLabel = label;
+ button.label = label;
+ }
+ if(item->args.icon) {
+ button.image = ui_cocoa_named_icon(item->args.icon);
+ }
+
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+ ui_add_menu_items(obj, menu, 0, &item->menu);
+
+ button.menu = menu;
+
+ return button;
+}
* POSSIBILITY OF SUCH DAMAGE.
*/
-#import "UiJob.h"
+#import "toolkit.h"
+
+@interface UiThread : NSObject
+
+@property UiObject *obj;
+@property ui_threadfunc job;
+@property void *jobdata;
+@property ui_callback finish_callback;
+@property void *finish_userdata;
+
+- (id)init:(UiObject*)obj jobfunc:(ui_threadfunc)job jobdata:(void*)jobdata;
+
+- (void)start;
+- (void) runJob:(id)n;
+- (void) finish:(id)n;
+
+@end
--- /dev/null
+/*
+ * 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 "UiThread.h"
+
+
+@implementation UiThread
+
+- (id) init:(UiObject*)obj jobfunc:(ui_threadfunc)job jobdata:(void*)jobdata {
+ _obj = obj;
+ _job = job;
+ _jobdata = jobdata;
+ return self;
+}
+
+- (void) start {
+ [NSThread detachNewThreadSelector:@selector(runJob:)
+ toTarget:self
+ withObject:nil];
+}
+
+
+- (void) runJob:(id)n {
+ int result = _job(_jobdata);
+ if(!result) {
+ [self performSelectorOnMainThread:@selector(finish:)
+ withObject:nil
+ waitUntilDone:NO];
+ }
+}
+
+- (void) finish:(id)n {
+ UiEvent event;
+ event.obj = _obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.intval = 0;
+ _finish_callback(&event, _finish_userdata);
+}
+
+@end
+
}
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, button, &layout, FALSE);
+ ui_container_add(obj, button, &layout);
return (__bridge void*)button;
}
}
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, button, &layout, FALSE);
+ ui_container_add(obj, button, &layout);
return (__bridge void*)button;
}
}
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, button, &layout, FALSE);
+ ui_container_add(obj, button, &layout);
return (__bridge void*)button;
}
}
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, button, &layout, FALSE);
+ ui_container_add(obj, button, &layout);
return (__bridge void*)button;
}
@property const char *label;
@property UiBool newline;
-- (void) addView:(NSView*)view fill:(BOOL)fill;
+- (void) addView:(NSView*)view;
@end
UiContainerX* ui_create_container(UiObject *obj, id<Container> container);
-void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout, UiBool fill);
+void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout);
return self;
}
-- (void) addView:(NSView*)view fill:(BOOL)fill {
- if(_uilayout.fill != UI_LAYOUT_UNDEFINED) {
- fill = ui_lb2bool(_uilayout.fill);
- }
+- (void) addView:(NSView*)view {
+ UiBool fill = _uilayout.fill;
[self addArrangedSubview:view];
// add box to the parent
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, box, &layout, TRUE);
+ ui_container_add(obj, box, &layout);
// add new box to the obj container chain
uic_object_push_container(obj, ui_create_container(obj, box));
// add box to the parent
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, grid, &layout, TRUE);
+ ui_container_add(obj, grid, &layout);
// add new box to the obj container chain
uic_object_push_container(obj, ui_create_container(obj, grid));
return ctn;
}
-void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout, UiBool fill) {
+void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) {
UiContainerX *ctn = obj->container_end;
id<Container> container = (__bridge id<Container>)ctn->container;
container.uilayout = *layout;
- [container addView:view fill:fill];
+ [container addView:view];
}
/* ---------------------- public layout functions ----------------------- */
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * Copyright 2025 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:
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TREE_H
-#define TREE_H
+#include "../ui/image.h"
-#include "../ui/tree.h"
-#include "model.h"
+#include "Container.h"
-#include <QTableView>
-
-
-
-#endif /* TREE_H */
+void ui_icon_init(void);
+NSImage* ui_cocoa_named_icon(const char *name);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "image.h"
+
+static NSDictionary *standardIconNames;
+
+void ui_icon_init(void) {
+ standardIconNames = @{
+ @"NSImageNameActionTemplate": NSImageNameActionTemplate,
+ @"NSImageNameAddTemplate": NSImageNameAddTemplate,
+ @"NSImageNameAdvanced": NSImageNameAdvanced,
+ @"NSImageNameApplicationIcon": NSImageNameApplicationIcon,
+ @"NSImageNameBluetoothTemplate": NSImageNameBluetoothTemplate,
+ @"NSImageNameBonjour": NSImageNameBonjour,
+ @"NSImageNameBookmarksTemplate": NSImageNameBookmarksTemplate,
+ @"NSImageNameCaution": NSImageNameCaution,
+ // TODO
+ @"NSImageNameRefreshTemplate": NSImageNameRefreshTemplate,
+ @"NSImageNameFolder": NSImageNameFolder,
+ @"NSImageNameGoForwardTemplate": NSImageNameGoForwardTemplate,
+ @"NSImageNameGoBackTemplate": NSImageNameGoBackTemplate
+ };
+}
+
+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];
+}
+
+
+void ui_image_ref(UIIMAGE img) {
+ // TODO
+}
+
+void ui_image_unref(UIIMAGE img) {
+ // TODO
+}
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright 2024 Olaf Wintermann. All rights reserved.
+ * Copyright 2025 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:
*/
#import "toolkit.h"
+#import "../ui/display.h"
+char* ui_label_get(UiString *s);
+void ui_label_set(UiString *s, const char *str);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "label.h"
+#import "container.h"
+
+#import <string.h>
+
+static UIWIDGET create_label(UiObject *obj, UiLabelArgs *args) {
+ NSTextField *label = [[NSTextField alloc] init];
+ label.editable = NO;
+ label.bezeled = NO;
+ label.drawsBackground = NO;
+ label.selectable = NO;
+
+ NSTextAlignment alignment;
+ switch(args->align) {
+ case UI_ALIGN_LEFT: alignment = NSTextAlignmentLeft; break;
+ case UI_ALIGN_RIGHT: alignment = NSTextAlignmentRight; break;
+ default: alignment = NSTextAlignmentCenter;
+ }
+ label.alignment = alignment;
+
+ if(args->label) {
+ NSString *str = [[NSString alloc] initWithUTF8String:args->label];
+ label.stringValue = str;
+ }
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, label, &layout);
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
+ if(var) {
+ UiString *s = var->value;
+ s->obj = (__bridge void*)label;
+ s->get = ui_label_get;
+ s->set = ui_label_set;
+
+ if(s->value.ptr) {
+ label.stringValue = [[NSString alloc]initWithUTF8String:s->value.ptr];
+ }
+ }
+
+ return (__bridge void*)label;
+}
+
+
+UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs *args) {
+ return create_label(obj, args);
+}
+
+UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_LEFT;
+ return create_label(obj, args);
+}
+
+UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
+ args->align = UI_ALIGN_RIGHT;
+ return create_label(obj, args);
+}
+
+
+char* ui_label_get(UiString *s) {
+ NSTextField *label = (__bridge NSTextField*)s->obj;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = strdup(label.stringValue.UTF8String);
+ return s->value.ptr;
+}
+
+void ui_label_set(UiString *s, const char *str) {
+ NSTextField *label = (__bridge NSTextField*)s->obj;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = NULL;
+ label.stringValue = [[NSString alloc] initWithUTF8String:str];
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "toolkit.h"
+#import "Container.h"
+#import "../ui/tree.h"
+
+#import "ListDataSource.h"
+
+@interface UiDropDown : NSObject<NSComboBoxDelegate>
+
+@property UiObject *obj;
+@property ui_callback onactivate;
+@property void *onactivatedata;
+@property ui_callback onselection;
+@property void *onselectiondata;
+@property ui_getvaluefunc2 getvalue;
+@property void *getvaluedata;
+@property UiVar *var;
+@property (weak) NSComboBox *combobox;
+
+- (id)init:(UiObject*)obj;
+
+@end
+
+void ui_tableview_update(UiList *list, int i);
+UiListSelection ui_tableview_getselection(UiList *list);
+void ui_tableview_setselection(UiList *list, UiListSelection selection);
+
+void ui_dropdown_update(UiList *list, int i);
+UiListSelection ui_dropdown_getselection(UiList *list);
+void ui_dropdown_setselection(UiList *list, UiListSelection selection);
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 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 "list.h"
+#import "ListDelegate.h"
+#import <objc/runtime.h>
+
+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;
+}
+
+/* --------------------------- ListView --------------------------- */
+
+/*
+ * adds a NSTableViewDelegate that handles all events and calls
+ * callbacks specified in the UiListArgs
+ */
+static void add_listdelegate(UiObject *obj, NSTableView *tableview, UiListArgs *args) {
+ ListDelegate *delegate = [[ListDelegate alloc] init:tableview obj:obj];
+ delegate.onactivate = args->onactivate;
+ delegate.onactivatedata = args->onactivatedata;
+ delegate.onselection = args->onselection;
+ delegate.onselectiondata = args->onselectiondata;
+ tableview.delegate = delegate;
+ objc_setAssociatedObject(tableview, "ui_listdelegate", delegate, OBJC_ASSOCIATION_RETAIN);
+ tableview.doubleAction = @selector(activateEvent:);
+ tableview.target = delegate;
+}
+
+static void bind_list_to_tableview(UiList *list, NSTableView *tableview) {
+ list->obj = (__bridge void*)tableview;
+ list->update = ui_tableview_update;
+ list->getselection = ui_tableview_getselection;
+ list->setselection = ui_tableview_setselection;
+}
+
+UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args) {
+ NSScrollView *scrollview = [[NSScrollView alloc] init];
+
+ NSTableView *tableview = [[NSTableView alloc] init];
+ tableview.autoresizingMask = NSViewWidthSizable;
+ tableview.headerView = nil;
+
+ if(args->multiselection) {
+ tableview.allowsMultipleSelection = YES;
+ }
+
+ scrollview.documentView = tableview;
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, scrollview, &layout);
+
+ add_listdelegate(obj, tableview, args);
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+ if(var) {
+ UiList *list = var->value;
+ bind_list_to_tableview(list, tableview);
+
+ ui_getvaluefunc2 getvalue = args->getvalue2;
+ void *getvaluedata = args->getvalue2data;
+ if(!getvalue) {
+ if(args->getvalue) {
+ getvalue = getvalue_wrapper;
+ getvaluedata = (void*)args->getvalue;
+ } else {
+ getvalue = str_getvalue; // by default list values are interpreted as strings
+ }
+ }
+
+ NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"column"];
+ [tableview addTableColumn:column];
+
+ ListDataSource *dataSource = [[ListDataSource alloc] init:tableview.tableColumns var:var getvalue:getvalue getvaluedata:getvaluedata];
+
+ tableview.dataSource = dataSource;
+ [tableview reloadData];
+
+ objc_setAssociatedObject(tableview, "ui_datasource", dataSource, OBJC_ASSOCIATION_RETAIN);
+ }
+
+ return (__bridge void*)scrollview;
+}
+
+/* --------------------------- TableView --------------------------- */
+
+UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args) {
+ NSScrollView *scrollview = [[NSScrollView alloc] init];
+
+ NSTableView *tableview = [[NSTableView alloc] init];
+ tableview.autoresizingMask = NSViewWidthSizable;
+ tableview.columnAutoresizingStyle = NSTableViewSequentialColumnAutoresizingStyle;
+
+ if(args->multiselection) {
+ tableview.allowsMultipleSelection = YES;
+ }
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, scrollview, &layout);
+
+ add_listdelegate(obj, tableview, args);
+
+ // convert model
+ NSMutableArray<NSTableColumn*> *cols = [[NSMutableArray alloc] init];
+ UiModel *model = args->model;
+ if(model) {
+ for(int i=0;i<model->columns;i++) {
+ char *title = model->titles[i];
+ UiModelType type = model->types[i];
+ int width = model->columnsize[i];
+ NSString *identifier = [[NSString alloc] initWithUTF8String:title];
+ NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:identifier];
+ column.title = identifier;
+ column.resizingMask = NSTableColumnUserResizingMask;
+ if(width > 0) {
+ column.width = width;
+ } else if(width < 0) {
+ column.resizingMask = NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask;
+ }
+ if(type >= UI_ICON) {
+ // TODO
+ }
+ [tableview addTableColumn:column];
+ [cols addObject:column];
+ }
+ }
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+ if(var) {
+ UiList *list = var->value;
+ bind_list_to_tableview(list, tableview);
+
+ ui_getvaluefunc2 getvalue = args->getvalue2;
+ void *getvaluedata = args->getvalue2data;
+ if(!getvalue) {
+ if(args->getvalue) {
+ getvalue = getvalue_wrapper;
+ getvaluedata = (void*)args->getvalue;
+ } else {
+ fprintf(stderr, "Error: tableview requires getvalue or getvalue2 func\n");
+ return (__bridge void*)scrollview;
+ }
+ }
+
+ ListDataSource *dataSource = [[ListDataSource alloc] init:cols var:var getvalue:getvalue getvaluedata:getvaluedata];
+ if(model) {
+ dataSource.model = ui_model_copy(obj->ctx, model);
+ }
+
+ tableview.dataSource = dataSource;
+ [tableview reloadData];
+
+ objc_setAssociatedObject(tableview, "ui_datasource", dataSource, OBJC_ASSOCIATION_RETAIN);
+ }
+
+ scrollview.documentView = tableview;
+
+ return (__bridge void*)scrollview;
+}
+
+/* ------ common functions ------ */
+
+void ui_tableview_update(UiList *list, int i) {
+ NSTableView *tableview = (__bridge NSTableView*)list->obj;
+ if(i < 0) {
+ [tableview reloadData];
+ } else {
+ [tableview reloadData]; // TODO: optimize
+ }
+}
+
+UiListSelection ui_tableview_getselection(UiList *list) {
+ NSTableView *tableview = (__bridge NSTableView*)list->obj;
+ return ui_tableview_selection(tableview);
+}
+
+void ui_tableview_setselection(UiList *list, UiListSelection selection) {
+ NSTableView *tableview = (__bridge NSTableView*)list->obj;
+ NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
+ for(int i=0;i<selection.count;i++) {
+ [indexSet addIndex:selection.rows[i]];
+ }
+ [tableview selectRowIndexes:indexSet byExtendingSelection:NO];
+}
+
+
+/* --------------------------- DropDown --------------------------- */
+
+@implementation UiDropDown
+
+- (id)init:(UiObject*)obj {
+ _obj = obj;
+ return self;
+}
+
+- (void) comboBoxSelectionDidChange:(NSNotification *) notification {
+ int index = (int)_combobox.indexOfSelectedItem;
+
+ void *eventdata = NULL;
+ if(_var) {
+ UiList *list = _var->value;
+ if(index >= 0) {
+ eventdata = list->get(list, index);
+ }
+ } else {
+ NSString *str = _combobox.objectValueOfSelectedItem;
+ if(str) {
+ eventdata = (void*)str.UTF8String;
+ }
+ }
+
+ UiEvent event;
+ event.obj = _obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = eventdata;
+ event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
+ event.intval = index;
+
+ if(_onselection) {
+ _onselection(&event, _onselectiondata);
+ }
+
+ if(_onactivate) {
+ _onactivate(&event, _onactivatedata);
+ }
+}
+
+@end
+
+UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args) {
+ NSComboBox *dropdown = [[NSComboBox alloc] init];
+ dropdown.editable = NO;
+
+ UiDropDown *uidropdown = [[UiDropDown alloc] init:obj];
+ objc_setAssociatedObject(dropdown, "ui_dropdown", uidropdown, OBJC_ASSOCIATION_RETAIN);
+ uidropdown.onactivate = args->onactivate;
+ uidropdown.onactivatedata = args->onactivatedata;
+ uidropdown.onselection = args->onselection;
+ uidropdown.onselectiondata = args->onselectiondata;
+ uidropdown.combobox = dropdown;
+
+ if(!args->getvalue2) {
+ if(args->getvalue) {
+ args->getvalue2 = getvalue_wrapper;
+ args->getvalue2data = (void*)args->getvalue;
+ } else {
+ args->getvalue2 = str_getvalue;
+ }
+ }
+ uidropdown.getvalue = args->getvalue2;
+ uidropdown.getvaluedata = args->getvalue2data;
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, dropdown, &layout);
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+ if(var) {
+ UiList *list = var->value;
+ list->obj = (__bridge void*)dropdown;
+ list->update = ui_dropdown_update;
+ list->getselection = ui_dropdown_getselection;
+ list->setselection = ui_dropdown_setselection;
+ ui_dropdown_update(list, -1);
+ } else {
+ for(int i=0;i<args->static_nelm;i++) {
+ char *str = args->static_elements[i];
+ NSString *item = [[NSString alloc] initWithUTF8String:str];
+ [dropdown addItemWithObjectValue:item];
+ }
+ }
+
+ uidropdown.var = var;
+
+ return (__bridge void*)dropdown;
+}
+
+void ui_dropdown_update(UiList *list, int i) {
+ NSComboBox *combobox = (__bridge NSComboBox*)list->obj;
+ UiDropDown *dropdown = objc_getAssociatedObject(combobox, "ui_dropdown");
+ if(dropdown) {
+ [combobox removeAllItems];
+
+ ui_getvaluefunc2 getvalue = dropdown.getvalue;
+ void *getvaluedata = dropdown.getvaluedata;
+
+ int index = 0;
+ void *elm = list->first(list);
+ while(elm) {
+ UiBool freeResult = FALSE;
+ char *str = getvalue(list, elm, index, 0, getvaluedata, &freeResult);
+ if(str) {
+ NSString *item = [[NSString alloc] initWithUTF8String:str];
+ [combobox addItemWithObjectValue:item];
+ }
+ if(freeResult) {
+ free(str);
+ }
+ elm = list->next(list);
+ index++;
+ }
+ } else {
+ fprintf(stderr, "Error: obj is not a dropdown\n");
+ }
+}
+
+UiListSelection ui_dropdown_getselection(UiList *list) {
+ UiListSelection sel = { 0, NULL };
+ NSComboBox *combobox = (__bridge NSComboBox*)list->obj;
+ NSInteger index = combobox.indexOfSelectedItem;
+ if(index >= 0) {
+ sel.rows = malloc(sizeof(int));
+ sel.count = 1;
+ sel.rows[0] = (int)index;
+ }
+ return sel;
+}
+
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
+ NSComboBox *combobox = (__bridge NSComboBox*)list->obj;
+ if(selection.count > 0) {
+ [combobox selectItemAtIndex:selection.rows[0]];
+ } else {
+ [combobox selectItemAtIndex: -1];
+ }
+}
@interface MenuItem : NSObject
+@property (weak) NSMenuItem *menuItem;
@property (strong) NSString *itemId;
-@property UiMenuCheckItem *checkItem;
-@property UiMenuRadioItem *radioItem;
-@property ui_callback callback;
-@property void *userdata;
+@property UiMenuCheckItem *checkItem;
+@property UiMenuRadioItem *radioItem;
+@property ui_callback callback;
+@property void *userdata;
+@property (strong) NSString *varname;
+@property UiObject *obj;
+@property UiVar *var;
+@property BOOL state;
- (MenuItem*)init:(int)itId;
+- (void)handleToggleEvent:(id)sender;
+
@end
void ui_menu_init(void);
-typedef void(*ui_menu_add_f)(NSMenu*, int, UiMenuItemI*);
+typedef void(*ui_menu_add_f)(UiObject*, NSMenu*, int, UiMenuItemI*);
+
+void add_menu_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
+void add_menuitem_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
+void add_menuseparator_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
+void add_checkitem_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
+void add_radioitem_widget(UiObject *obj, NSMenu *parent, int index, UiMenuItemI *item);
+void add_checkitemnv_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
+void add_menuitem_list_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item);
-void add_menu_widget(NSMenu *parent, int i, UiMenuItemI *item);
-void add_menuitem_widget(NSMenu *parent, int i, UiMenuItemI *item);
-void add_menuseparator_widget(NSMenu *parent, int i, UiMenuItemI *item);
-void add_checkitem_widget(NSMenu *parent, int i, UiMenuItemI *item);
-void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item);
-void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item);
-void add_menuitem_list_widget(NSMenu *parent, int i, UiMenuItemI *item);
+void ui_add_menu_items(UiObject *obj, NSMenu *parent, int i, UiMenu *menu);
NSArray* ui_get_binding_items(void);
+
+int64_t ui_menu_toggleitem_get(UiInteger *i);
+void ui_menu_toggleitem_set(UiInteger *i, int64_t value);
return self;
}
+- (void)handleToggleEvent:(id)sender {
+ NSMenuItem *item = (NSMenuItem*)sender;
+ if(!_state) {
+ item.state = NSControlStateValueOn;
+ } else {
+ item.state = NSControlStateValueOff;
+ }
+ _state = !_state;
+
+ if(_callback) {
+ UiEvent event;
+ event.obj = _obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = _state;
+ event.set = ui_get_setop();
+ _callback(&event, _userdata);
+ }
+}
+
@end
static ui_menu_add_f createMenuItem[] = {
/* UI_MENU_SEPARATOR */ add_menuseparator_widget
};
-static void add_menu_items(NSMenu *parent, int i, UiMenu *menu) {
+void ui_add_menu_items(UiObject *obj, NSMenu *parent, int i, UiMenu *menu) {
UiMenuItemI *it = menu->items_begin;
int index = 0;
while(it) {
- createMenuItem[it->type](parent, index, it);
+ createMenuItem[it->type](obj, parent, index, it);
it = it->next;
index++;
}
}
-void add_menu_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+void add_menu_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item) {
UiMenu *it = (UiMenu*)item;
NSString *str = [[NSString alloc] initWithUTF8String:it->label];
NSMenu *menu = [[NSMenu alloc] initWithTitle: str];
NSMenuItem *menuItem = [parent addItemWithTitle:str action:nil keyEquivalent:@""];
[parent setSubmenu:menu forItem:menuItem];
- add_menu_items(menu, i, it);
+ ui_add_menu_items(obj, menu, i, it);
}
-void add_menuitem_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+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];
+ if(obj) {
+ event.obj = obj;
+ menuItem.target = event;
+ menuItem.action = @selector(handleEvent:);
+ }
objc_setAssociatedObject(menuItem, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
}
}
-void add_menuseparator_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+void add_menuseparator_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item) {
NSMenuItem *menuItem = [NSMenuItem separatorItem];
[parent addItem:menuItem];
}
static int nItem = 0;
-void add_checkitem_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+void add_checkitem_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item) {
UiMenuCheckItem *it = (UiMenuCheckItem*)item;
NSString *str = [[NSString alloc] initWithUTF8String:it->label];
NSMenuItem *menuItem = [parent addItemWithTitle:str action:@selector(menuCheckItemAction:) keyEquivalent:@""];
MenuItem *mItem = [[MenuItem alloc] init:nItem++];
+ mItem.menuItem = menuItem;
+ mItem.obj = obj;
mItem.callback = it->callback;
mItem.userdata = it->userdata;
mItem.checkItem = it;
+ if(it->varname) {
+ mItem.varname = [[NSString alloc] initWithUTF8String:it->varname];
+ }
objc_setAssociatedObject(menuItem, "menuitem", mItem, OBJC_ASSOCIATION_RETAIN);
- [bindingItems addObject:mItem];
+
+ if(!obj) {
+ [bindingItems addObject:mItem];
+ } else {
+ mItem.var = uic_widget_var(obj->ctx, obj->ctx, NULL, it->varname, UI_VAR_INTEGER);
+ if(mItem.var) {
+ UiInteger *i = mItem.var->value;
+ i->obj = (__bridge void*)mItem;
+ i->get = ui_menu_toggleitem_get;
+ i->set = ui_menu_toggleitem_set;
+ }
+ menuItem.target = mItem;
+ menuItem.action = @selector(handleToggleEvent:);
+ }
}
-void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item) {
+void add_radioitem_widget(UiObject *obj, NSMenu *parent, int index, UiMenuItemI *item) {
UiMenuRadioItem *it = (UiMenuRadioItem*)item;
NSString *str = [[NSString alloc] initWithUTF8String:it->label];
[bindingItems addObject:mItem];
}
-void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+void add_checkitemnv_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item) {
}
-void add_menuitem_list_widget(NSMenu *parent, int i, UiMenuItemI *item) {
+void add_menuitem_list_widget(UiObject *obj, NSMenu *parent, int i, UiMenuItemI *item) {
}
NSMenuItem *menuItem = [[NSApp mainMenu] insertItemWithTitle:str action:nil keyEquivalent:@"" atIndex:index];
[[NSApp mainMenu] setSubmenu:menu forItem:menuItem];
- add_menu_items(menu, 0, ls);
+ ui_add_menu_items(NULL, menu, 0, ls);
}
ls = (UiMenu*)ls->item.next;
index++;
NSArray* ui_get_binding_items(void) {
return bindingItems;
}
+
+
+int64_t ui_menu_toggleitem_get(UiInteger *i) {
+ MenuItem *item = (__bridge MenuItem*)i->obj;
+ i->value = item.state;
+ return i->value;
+}
+
+void ui_menu_toggleitem_set(UiInteger *i, int64_t value) {
+ MenuItem *item = (__bridge MenuItem*)i->obj;
+ i->value = value;
+ if(value != 0) {
+ item.menuItem.state = NSControlStateValueOn;
+ } else {
+ item.menuItem.state = NSControlStateValueOff;
+ }
+}
COCOAOBJ += button.o
COCOAOBJ += text.o
COCOAOBJ += menu.o
+COCOAOBJ += Toolbar.o
TOOLKITOBJS += $(COCOAOBJ:%=$(COCOA_OBJPRE)%)
TOOLKITSOURCE += $(COCOAOBJ:%.o=cocoa/%.m)
scrollview.documentView = textview;
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, scrollview, &layout, TRUE);
+ ui_container_add(obj, scrollview, &layout);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT);
NSTextStorage *textStorage;
if(text->data1) {
textStorage = (__bridge NSTextStorage*)text->data1;
-
} else {
textStorage = [[NSTextStorage alloc] init];
}
}
void ui_textarea_set(UiText *text, const char *str) {
-
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ if(text->value.free) {
+ text->value.free(text->value.ptr);
+ }
+ text->value.ptr = strdup(str);
+ text->value.free = free;
+ textview.string = [[NSString alloc] initWithUTF8String:str];
}
char* ui_textarea_get(UiText *text) {
- return NULL;
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ if(text->value.free) {
+ text->value.free(text->value.ptr);
+ }
+ text->value.ptr = strdup(textview.string.UTF8String);
+ text->value.free = free;
+ return text->value.ptr;
}
char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
- return NULL;
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSString *str = textview.string;
+ NSRange range = NSMakeRange(begin, end-begin);
+ NSString *sub = [str substringWithRange:range];
+ return strdup(sub.UTF8String);
}
void ui_textarea_insert(UiText *text, int pos, char *str) {
-
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSString *s = [[NSString alloc] initWithUTF8String:str];
+ NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithString:s];
+ [textview.textStorage insertAttributedString:attributedStr atIndex:pos];
}
void ui_textarea_setposition(UiText *text, int pos) {
-
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSRange range = NSMakeRange(pos, 0);
+ [textview setSelectedRange:range];
}
int ui_textarea_position(UiText *text) {
- return 0;
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSRange range = textview.selectedRange;
+ return (int)range.location;
}
void ui_textarea_setselection(UiText *text, int begin, int end) {
-
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSRange range = NSMakeRange(begin, end-begin);
+ [textview setSelectedRange:range];
}
void ui_textarea_selection(UiText *text, int *begin, int *end) {
-
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSRange range = textview.selectedRange;
+ if(begin) {
+ *begin = (int)range.location;
+ }
+ if(end) {
+ *end = (int)(range.location+range.length);
+ }
}
int ui_textarea_length(UiText *text) {
- return 0;
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ return (int)textview.string.length;
}
void ui_textarea_remove(UiText *text, int begin, int end) {
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+
+ if (begin < 0 || end < begin || end > textview.string.length) {
+ return;
+ }
+ NSRange range = NSMakeRange(begin, end - begin);
+ [[textview textStorage] deleteCharactersInRange:range];
}
}
UiLayout layout = UI_INIT_LAYOUT(args);
- ui_container_add(obj, textfield, &layout, FALSE);
+ ui_container_add(obj, textfield, &layout);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
#include "../common/context.h"
#include "../common/object.h"
+@interface UiAppCallback : NSObject {
+ ui_threadfunc callback;
+ void *userdata;
+}
+
+- (id) initWithCallback:(ui_threadfunc)func userdata:(void*)userdata;
+
+- (void) callMainThread;
+
+- (void) mainThread:(id)n;
+
+@end
+
void ui_cocoa_onstartup(void);
void ui_cocoa_onopen(const char *file);
void ui_cocoa_onexit(void);
#include "../common/toolbar.h"
#include "../common/threadpool.h"
+#import "image.h"
#import "menu.h"
+#import "Toolbar.h"
+#import "UiThread.h"
#import "AppDelegate.h"
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
+
+static UiBool exit_on_shutdown;
/* ------------------- App Init / Event Loop functions ------------------- */
[NSApplication sharedApplication];
//[NSBundle loadNibNamed:@"MainMenu" owner:NSApp ];
//[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:&topLevelObjects];
+
+ ui_icon_init();
+ ui_toolbar_init();
+
}
const char* ui_appname() {
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_cocoa_onstartup(void) {
UiEvent e;
e.obj = NULL;
void ui_main(void) {
NSApplicationMain(app_argc, app_argv);
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
/* ------------------- Window Visibility functions ------------------- */
/* ------------------- Job Control / Threadpool functions ------------------- */
void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) {
+ UiThread *thread = [[UiThread alloc]init:obj jobfunc:tf jobdata:td];
+ thread.finish_callback = f;
+ thread.finish_userdata = fd;
+ [thread start];
+}
+@implementation UiAppCallback
+
+- (id) initWithCallback:(ui_threadfunc)func userdata:(void*)userdata {
+ self->callback = func;
+ self->userdata = userdata;
+ return self;
}
-void ui_call_mainthread(ui_threadfunc tf, void* td) {
+- (void) callMainThread {
+ [self performSelectorOnMainThread:@selector(mainThread:)
+ withObject:nil
+ waitUntilDone:NO];
+}
+- (void) mainThread:(id)n {
+ callback(userdata);
+}
+
+@end
+
+void ui_call_mainthread(ui_threadfunc tf, void* td) {
+ UiAppCallback *cb = [[UiAppCallback alloc]initWithCallback:tf userdata:td];
+ [cb callMainThread];
}
#include "../ui/container.h"
+
+/* ---------------------------- UiDialogArgs ---------------------------- */
+
+UiDialogArgs* ui_dialog_args_new(void) {
+ UiDialogArgs *args = malloc(sizeof(UiDialogArgs));
+ memset(args, 0, sizeof(UiDialogArgs));
+ return args;
+}
+
+void ui_dialog_args_set_title(UiDialogArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialog_args_set_content(UiDialogArgs *args, const char *str) {
+ args->content = strdup(str);
+}
+
+void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label) {
+ args->button1_label = strdup(label);
+}
+
+void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label) {
+ args->button2_label = strdup(label);
+}
+
+void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label) {
+ args->closebutton_label = strdup(label);
+}
+
+void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value) {
+ args->input_value = strdup(value);
+}
+
+void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input) {
+ args->input = input;
+}
+
+void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password) {
+ args->password = password;
+}
+
+void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb) {
+ args->result = cb;
+}
+
+void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata) {
+ args->resultdata = userdata;
+}
+
+void ui_dialog_args_free(UiDialogArgs *args) {
+ free((void*)args->title);
+ free((void*)args->button1_label);
+ free((void*)args->button2_label);
+ free((void*)args->content);
+ free((void*)args->closebutton_label);
+ free((void*)args->input_value);
+ free(args);
+}
+
+
+/* -------------------------- UiDialogWindowArgs -------------------------- */
+
+UiDialogWindowArgs* ui_dialogwindow_args_new(void) {
+ UiDialogWindowArgs *args = malloc(sizeof(UiDialogWindowArgs));
+ memset(args, 0, sizeof(UiDialogWindowArgs));
+ return args;
+}
+
+void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value) {
+ args->modal = value;
+}
+
+void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value) {
+ args->titlebar_buttons = value;
+}
+
+void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value) {
+ args->show_closebutton = value;
+}
+
+void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton1 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton2 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton3 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton4 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button) {
+ args->default_button = button;
+}
+
+void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width) {
+ args->width = width;
+}
+
+void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height) {
+ args->height = height;
+}
+
+void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb) {
+ args->onclick = cb;
+}
+
+void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata) {
+ args->onclickdata = userdata;
+}
+
+void ui_dialogwindow_args_free(UiDialogWindowArgs *args) {
+ free((void*)args->title);
+ free((void*)args->lbutton1);
+ free((void*)args->lbutton2);
+ free((void*)args->rbutton3);
+ free((void*)args->rbutton4);
+ free((void*)args->lbutton1_groups);
+ free((void*)args->lbutton2_groups);
+ free((void*)args->rbutton3_groups);
+ free((void*)args->rbutton4_groups);
+ free(args);
+}
+
+
/* ---------------------------- UiMenuItemArgs ---------------------------- */
UiMenuItemArgs* ui_menuitem_args_new(void) {
}
+/* ------------------------- UiWidgetArgs ----------------------------*/
+
+UiWidgetArgs* ui_widget_args_new(void) {
+ UiWidgetArgs *args = malloc(sizeof(UiWidgetArgs));
+ memset(args, 0, sizeof(UiWidgetArgs));
+ return args;
+}
+
+
+void ui_widget_args_set_fill(UiWidgetArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_widget_args_set_hexpand(UiWidgetArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_widget_args_set_vexpand(UiWidgetArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_widget_args_set_hfill(UiWidgetArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_widget_args_set_vfill(UiWidgetArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_widget_args_set_override_defaults(UiWidgetArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_widget_args_set_colspan(UiWidgetArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_widget_args_set_rowspan(UiWidgetArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_widget_args_set_name(UiWidgetArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_widget_args_set_style_class(UiWidgetArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_widget_args_free(UiWidgetArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free(args);
+}
+
+
/* ------------------------- UiLabelArgs ----------------------------*/
free(args);
}
+/* ------------------------- UiLinkButtonArgs ----------------------------*/
+
+
+UiLinkButtonArgs* ui_linkbutton_args_new(void) {
+ UiLinkButtonArgs *args = malloc(sizeof(UiLinkButtonArgs));
+ memset(args, 0, sizeof(UiLinkButtonArgs));
+ return args;
+}
+
+
+void ui_linkbutton_args_set_fill(UiLinkButtonArgs *args, UiBool fill) {
+ args->fill = fill ? UI_ON : UI_OFF;
+}
+
+
+void ui_linkbutton_args_set_hexpand(UiLinkButtonArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_linkbutton_args_set_vexpand(UiLinkButtonArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_linkbutton_args_set_hfill(UiLinkButtonArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_linkbutton_args_set_vfill(UiLinkButtonArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_linkbutton_args_set_override_defaults(UiLinkButtonArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+
+void ui_linkbutton_args_set_colspan(UiLinkButtonArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_linkbutton_args_set_rowspan(UiLinkButtonArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_linkbutton_args_set_name(UiLinkButtonArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_linkbutton_args_set_style_class(UiLinkButtonArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *label){
+ args->label = strdup(label);
+}
+
+void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri) {
+ args->uri = strdup(uri);
+}
+
+void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback) {
+ args->onclick = callback;
+}
+
+void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata) {
+ args->onclickdata = userdata;
+}
+
+void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value) {
+ args->nofollow = value;
+}
+
+void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type) {
+ args->type = type;
+}
+
+void ui_linkbutton_args_set_varname(UiLinkButtonArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_linkbutton_args_set_value(UiLinkButtonArgs *args, UiString *value) {
+ args->value = value;
+}
+
+void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *groups){
+ // TODO
+}
+
+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->varname);
+ free((void*)args->groups);
+ free(args);
+}
+
/* ------------------------- UiListArgs ----------------------------*/
#ifndef UIC_ARGS_H
#define UIC_ARGS_H
+#include "../ui/window.h"
#include "../ui/container.h"
#include "../ui/display.h"
#include "../ui/button.h"
#include "../ui/tree.h"
#include "../ui/text.h"
#include "../ui/webview.h"
+#include "../ui/widget.h"
#ifdef __cplusplus
extern "C" {
#endif
+UIEXPORT UiDialogArgs* ui_dialog_args_new(void);
+UIEXPORT void ui_dialog_args_set_title(UiDialogArgs *args, const char *title);
+UIEXPORT void ui_dialog_args_set_content(UiDialogArgs *args, const char *str);
+UIEXPORT void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value);
+UIEXPORT void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input);
+UIEXPORT void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password);
+UIEXPORT void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb);
+UIEXPORT void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata);
+UIEXPORT void ui_dialog_args_free(UiDialogArgs *args);
+
+UIEXPORT UiDialogWindowArgs* ui_dialogwindow_args_new(void);
+UIEXPORT void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button);
+UIEXPORT void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width);
+UIEXPORT void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height);
+UIEXPORT void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb);
+UIEXPORT void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata);
+UIEXPORT void ui_dialogwindow_args_free(UiDialogWindowArgs *args);
UIEXPORT UiMenuItemArgs* ui_menuitem_args_new(void);
UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label);
UIEXPORT void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max);
UIEXPORT void ui_splitpane_args_free(UiSplitPaneArgs *args);
+UIEXPORT UiWidgetArgs* ui_widget_args_new(void);
+UIEXPORT void ui_widget_args_set_fill(UiWidgetArgs *args, UiBool fill);
+UIEXPORT void ui_widget_args_set_hexpand(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_vexpand(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_hfill(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_vfill(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_override_defaults(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_colspan(UiWidgetArgs *args, int colspan);
+UIEXPORT void ui_widget_args_set_rowspan(UiWidgetArgs *args, int rowspan);
+UIEXPORT void ui_widget_args_set_name(UiWidgetArgs *args, const char *name);
+UIEXPORT void ui_widget_args_set_style_class(UiWidgetArgs *args, const char *classname);
+UIEXPORT void ui_widget_args_free(UiWidgetArgs *args);
+
UIEXPORT UiLabelArgs* ui_label_args_new(void);
UIEXPORT void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill);
UIEXPORT void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value);
UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *groups);
UIEXPORT void ui_toggle_args_free(UiToggleArgs *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);
+UIEXPORT void ui_linkbutton_args_set_vexpand(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_hfill(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_vfill(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_override_defaults(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_colspan(UiLinkButtonArgs *args, int colspan);
+UIEXPORT void ui_linkbutton_args_set_rowspan(UiLinkButtonArgs *args, int rowspan);
+UIEXPORT void ui_linkbutton_args_set_name(UiLinkButtonArgs *args, const char *name);
+UIEXPORT void ui_linkbutton_args_set_style_class(UiLinkButtonArgs *args, const char *classname);
+UIEXPORT void ui_linkbutton_args_set_varname(UiLinkButtonArgs *args, const char *varname);
+UIEXPORT void ui_linkbutton_args_set_value(UiLinkButtonArgs *args, UiString *value);
+UIEXPORT void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *label);
+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_nofollow(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type);
+UIEXPORT void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *groups);
+UIEXPORT void ui_linkbutton_args_free(UiLinkButtonArgs *args);
+
UIEXPORT UiListArgs* ui_list_args_new(void);
UIEXPORT void ui_list_args_set_fill(UiListArgs *args, UiBool fill);
UIEXPORT void ui_list_args_set_hexpand(UiListArgs *args, UiBool value);
return ret;
}
+// public
+int ui_app_save_settings(void) {
+ return uic_store_app_properties();
+}
+
const char* ui_get_property(const char *name) {
return cxMapGet(application_properties, name);
cxListClear(list->data);
}
-UIEXPORT void ui_list_update(UiList *list) {
+void ui_list_update(UiList *list) {
if(list->update) {
list->update(list, -1);
}
}
+void ui_list_update_row(UiList *list, int row) {
+ if(list->update) {
+ list->update(list, row);
+ }
+}
+
+UiListSelection ui_list_get_selection(UiList *list) {
+ if(list->getselection) {
+ return list->getselection(list);
+ } else {
+ return (UiListSelection){0, NULL};
+ }
+}
+
void ui_list_addobsv(UiList *list, ui_callback f, void *data) {
list->observers = ui_add_observer(list->observers, f, data);
}
void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) {
item->eventdata = NULL;
}
+
+/* ---------------------------- 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;
+}
+
+int* ui_list_selection_get_rows(UiListSelection *sel) {
+ return sel->rows;
+}
+
+void ui_list_selection_free(UiListSelection *sel) {
+ ui_listselection_free(*sel);
+ free(sel);
+}
+
+/* ---------------------------- UiFileList ---------------------------- */
+
+int ui_filelist_count(UiFileList *flist) {
+ return flist->nfiles;
+}
+
+char* ui_filelist_get(UiFileList *flist, int index) {
+ if(index >= 0 && index < flist->nfiles) {
+ return flist->files[index];
+ }
+ return NULL;
+}
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 int ui_list_selection_get_count(UiListSelection *sel);
+UIEXPORT int* ui_list_selection_get_rows(UiListSelection *sel);
+UIEXPORT void ui_list_selection_free(UiListSelection *sel);
+
+UIEXPORT int ui_filelist_count(UiFileList *flist);
+UIEXPORT char* ui_filelist_get(UiFileList *flist, int index);
#ifdef __cplusplus
#include "button.h"
#include "container.h"
#include <cx/allocator.h>
+#include <cx/buffer.h>
+#include <cx/json.h>
#include "../common/context.h"
#include "../common/object.h"
event->callback(&e, event->userdata);
}
+void ui_button_set_label(UIWIDGET button, const char *label) {
+ gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_button_set_icon(UIWIDGET button, const char *icon) {
+ ui_button_set_icon_name(button, icon);
+}
+
int64_t ui_toggle_button_get(UiInteger *integer) {
GtkToggleButton *button = integer->obj;
integer->value = (int)gtk_toggle_button_get_active(button);
value->value = i;
}
#endif
+
+
+static void ui_destroy_linkbutton(GtkWidget *widget, UiLinkButton *data) {
+ free(data->link);
+ free(data);
+}
+
+static const char* linkbutton_get_uri(UiLinkButton *link) {
+ if(link->type == UI_LINK_BUTTON) {
+ return link->link;
+ } else {
+ return gtk_link_button_get_uri(GTK_LINK_BUTTON(link->widget));
+ }
+}
+
+static void linkbutton_set_uri(UiLinkButton *link, const char *uri) {
+ if(link->type == UI_LINK_BUTTON) {
+ free(link->link);
+ link->link = uri ? strdup(uri) : NULL;
+ } else {
+ gtk_link_button_set_uri(GTK_LINK_BUTTON(link->widget), uri);
+ }
+}
+
+static gboolean linkbutton_get_visited(UiLinkButton *link) {
+ if(link->type == UI_LINK_BUTTON) {
+ return FALSE;
+ } else {
+ gtk_link_button_get_visited(GTK_LINK_BUTTON(link->widget));
+ }
+}
+
+static void linkbutton_set_visited(UiLinkButton *link, gboolean visited) {
+ if(link->type != UI_LINK_BUTTON) {
+ gtk_link_button_set_visited(GTK_LINK_BUTTON(link->widget), visited);
+ }
+}
+
+/*
+ * Apply linkbutton settings from json. Expects jsonvalue to be a valid
+ * json object.
+ *
+ * {
+ * "label": "label text",
+ * "uri": "http://example.com",
+ * "visited": true
+ * }
+ *
+ */
+static void linkbutton_apply_value(UiLinkButton *link, const char *jsonvalue) {
+ CxJson json;
+ cxJsonInit(&json, NULL);
+ cxJsonFill(&json, jsonvalue);
+
+ CxJsonValue *value;
+ if(cxJsonNext(&json, &value) == CX_JSON_NO_ERROR) {
+ if(cxJsonIsObject(value)) {
+ CxJsonValue *label = cxJsonObjGet(value, "label");
+ CxJsonValue *uri = cxJsonObjGet(value, "uri");
+ CxJsonValue *visited = cxJsonObjGet(value, "visited");
+ if(label) {
+ gtk_button_set_label(GTK_BUTTON(link->widget), cxJsonIsString(label) ? cxJsonAsString(label) : NULL);
+ }
+ if(uri) {
+ linkbutton_set_uri(link, cxJsonIsString(uri) ? cxJsonAsString(uri) : NULL);
+
+ }
+ if(visited) {
+ linkbutton_set_visited(link, cxJsonIsBool(visited) ? cxJsonAsBool(visited) : FALSE);
+ }
+ }
+ cxJsonValueFree(value);
+ }
+ cxJsonDestroy(&json);
+}
+
+static char* create_linkbutton_jsonvalue(const char *label, const char *uri, gboolean include_null, gboolean visited, gboolean set_visited) {
+ CxJsonValue *obj = cxJsonCreateObj(NULL);
+ if(label) {
+ cxJsonObjPutString(obj, CX_STR("label"), label);
+ } else if(include_null) {
+ cxJsonObjPutLiteral(obj, CX_STR("label"), CX_JSON_NULL);
+ }
+
+ if(uri) {
+ cxJsonObjPutString(obj, CX_STR("uri"), uri);
+ } else if(include_null) {
+ cxJsonObjPutLiteral(obj, CX_STR("uri"), CX_JSON_NULL);
+ }
+
+ if(set_visited) {
+ cxJsonObjPutLiteral(obj, CX_STR("visited"), visited ? CX_JSON_TRUE : CX_JSON_FALSE);
+ }
+
+ CxJsonWriter writer = cxJsonWriterCompact();
+ CxBuffer buf;
+ cxBufferInit(&buf, NULL, 128, NULL, CX_BUFFER_AUTO_EXTEND);
+ cxJsonWrite(&buf, obj, (cx_write_func)cxBufferWrite, &writer);
+ cxJsonValueFree(obj);
+ cxBufferTerminate(&buf);
+
+ return buf.space;
+}
+
+static char* linkbutton_get_value(UiLinkButton *link) {
+ const char *label = gtk_button_get_label(GTK_BUTTON(link->widget));
+ const char *uri = linkbutton_get_uri(link);
+ gboolean visited = linkbutton_get_visited(link);
+ return create_linkbutton_jsonvalue(label, uri, TRUE, visited, TRUE);
+}
+
+static void linkbutton_clicked(GtkWidget *widget, UiLinkButton *data) {
+ if(data->onclick) {
+ UiEvent e;
+ e.obj = data->obj;
+ e.document = e.obj->ctx->document;
+ e.window = e.obj->window;
+ e.eventdata = (char*)linkbutton_get_uri(data);
+ e.eventdatatype = UI_EVENT_DATA_STRING;
+ e.intval = 0;
+ e.set = ui_get_setop();
+ data->onclick(&e, data->onclickdata);
+ }
+}
+
+static gboolean linkbutton_activate_link(GtkLinkButton *self, UiLinkButton *data) {
+ linkbutton_clicked(data->widget, data);
+ return data->nofollow;
+}
+
+UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args) {
+ UiLinkButton *data = malloc(sizeof(UiLinkButton));
+ memset(data, 0, sizeof(UiLinkButton));
+ data->obj = obj;
+ data->type = args->type;
+ data->nofollow = args->nofollow;
+ data->onclick = args->onclick;
+ data->onclickdata = args->onclickdata;
+
+ GtkWidget *button;
+ if(args->type == UI_LINK_BUTTON) {
+ button = gtk_button_new();
+ g_signal_connect(
+ button,
+ "clicked",
+ G_CALLBACK(linkbutton_clicked),
+ data);
+ } else {
+ button = gtk_link_button_new("file:///");
+ g_signal_connect(
+ button,
+ "activate-link",
+ G_CALLBACK(linkbutton_activate_link),
+ data);
+ }
+ gtk_button_set_label(GTK_BUTTON(button), args->label);
+ g_object_set_data(G_OBJECT(button), "ui_linkbutton", data);
+ g_signal_connect(
+ button,
+ "destroy",
+ G_CALLBACK(ui_destroy_linkbutton),
+ data);
+
+ data->widget = button;
+
+ UiObject* current = uic_current_obj(obj);
+ UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+ if(var) {
+ UiString *str = var->value;
+ char *current_value = ui_get(str);
+ if(current_value) {
+ linkbutton_apply_value(data, current_value);
+ }
+
+ str->obj = data;
+ str->get = ui_linkbutton_get;
+ str->set = ui_linkbutton_set;
+ }
+
+ ui_set_name_and_style(button, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
+ UI_APPLY_LAYOUT2(current, args);
+ current->container->add(current->container, button);
+
+ return button;
+}
+
+char* ui_linkbutton_get(UiString *s) {
+ UiLinkButton *link = s->obj;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = linkbutton_get_value(link);
+ s->value.free = free;
+ return s->value.ptr;
+}
+
+void ui_linkbutton_set(UiString *s, const char *str) {
+ linkbutton_apply_value(s->obj, str);
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+}
+
+
+void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri) {
+ char *value = create_linkbutton_jsonvalue(label, uri, TRUE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_label(UiString *str, const char *label) {
+ char *value = create_linkbutton_jsonvalue(label, NULL, FALSE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_uri(UiString *str, const char *uri) {
+ char *value = create_linkbutton_jsonvalue(NULL, uri, FALSE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_visited(UiString *str, UiBool visited) {
+ char *value = create_linkbutton_jsonvalue(NULL, NULL, FALSE, visited, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+
+void ui_linkbutton_set_label(UIWIDGET button, const char *label) {
+ gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_linkbutton_set_uri(UIWIDGET button, const char *label) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ linkbutton_set_uri(link, label);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+}
+
+void ui_linkbutton_set_visited(UIWIDGET button, UiBool visited) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ linkbutton_set_visited(link, visited);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+}
+
+char* ui_linkbutton_get_label(UIWIDGET button) {
+ const char *label = gtk_button_get_label(GTK_BUTTON(button));
+ return label ? strdup(label) : NULL;
+}
+
+char* ui_linkbutton_get_uri(UIWIDGET button) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ const char *uri = linkbutton_get_uri(link);
+ return uri ? strdup(uri) : NULL;
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+ return NULL;
+}
+
+UiBool ui_linkbutton_get_visited(UIWIDGET button) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ return linkbutton_get_visited(link);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+ return FALSE;
+}
extern "C" {
#endif
+typedef struct UiLinkButton {
+ UiObject *obj;
+ GtkWidget *widget;
+ UiLinkType type;
+ UiBool nofollow;
+ char *link;
+ ui_callback onclick;
+ void *onclickdata;
+} UiLinkButton;
+
void ui_button_set_icon_name(GtkWidget *button, const char *icon_name);
typedef void (*ui_toggled_func)(void*, void*);
int64_t ui_radiobutton_get(UiInteger *value);
void ui_radiobutton_set(UiInteger *value, int64_t i);
+char* ui_linkbutton_get(UiString *s);
+void ui_linkbutton_set(UiString *s, const char *str);
+
#ifdef __cplusplus
}
#endif
case UI_ALIGN_DEFAULT: break;
case UI_ALIGN_LEFT: set_alignment(widget, 0, .5); break;
case UI_ALIGN_RIGHT: set_alignment(widget, 1, .5); break;
- case UI_ALIGN_CENTER: break; // TODO
+ case UI_ALIGN_CENTER: set_alignment(widget, .5, .5); break;
}
gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(menubutton), G_MENU_MODEL(menu));
#else
GtkWidget *menubutton = gtk_menu_button_new();
-
- // TODO
-
+ GtkWidget *menu = gtk_menu_new();
+ ui_add_menu_items(menu, 0, &item->menu, obj);
+ gtk_widget_show_all(menu);
+ gtk_menu_button_set_popup(GTK_MENU_BUTTON(menubutton), menu);
#endif
#include <cx/linked_list.h>
#include "list.h"
+#include "button.h"
#include "icon.h"
#include "menu.h"
#include "dnd.h"
-void* ui_strmodel_getvalue(void *elm, int column) {
- return column == 0 ? elm : NULL;
+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* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
- if(model->getvalue2) {
- return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
- } else if(model->getvalue) {
- return model->getvalue(elm, col);
- }
+static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ return elm;
+}
+
+static void* null_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
return NULL;
}
}
}
+static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
+ UiListView *tableview = malloc(sizeof(UiListView));
+ memset(tableview, 0, sizeof(UiListView));
+ tableview->obj = obj;
+ tableview->model = args->model;
+ tableview->onactivate = args->onactivate;
+ tableview->onactivatedata = args->onactivatedata;
+ tableview->onselection = args->onselection;
+ tableview->onselectiondata = args->onselectiondata;
+ tableview->ondragstart = args->ondragstart;
+ tableview->ondragstartdata = args->ondragstartdata;
+ tableview->ondragcomplete = args->ondragcomplete;
+ tableview->ondragcompletedata = args->ondragcompletedata;
+ tableview->ondrop = args->ondrop;
+ tableview->ondropdata = args->ondropdata;
+ tableview->selection.count = 0;
+ tableview->selection.rows = NULL;
+
+ if(args->getvalue2) {
+ tableview->getvalue = args->getvalue2;
+ tableview->getvaluedata = args->getvalue2data;
+ } else if(args->getvalue) {
+ tableview->getvalue = getvalue_wrapper;
+ tableview->getvaluedata = (void*)args->getvalue;
+ } else {
+ tableview->getvalue = null_getvalue;
+ }
+
+ return tableview;
+}
+
#if GTK_CHECK_VERSION(4, 10, 0)
}
}
-static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+static void column_factory_bind(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
UiColData *col = userdata;
UiList *list = col->listview->var ? col->listview->var->value : NULL;
+ UiListView *listview = col->listview;
ObjWrapper *obj = gtk_list_item_get_item(item);
UiModel *model = col->listview->model;
UiModelType type = model->types[col->model_column];
UiBool freevalue = FALSE;
- void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
+ void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
GtkWidget *child = gtk_list_item_get_child(item);
switch(type) {
}
case UI_ICON_TEXT_FREE: {
- void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
+ void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue);
if(type == UI_ICON_TEXT_FREE) {
freevalue = TRUE;
}
selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(liststore)));
} else {
selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore)));
+ gtk_single_selection_set_can_unselect(GTK_SINGLE_SELECTION(selection_model), TRUE);
+ gtk_single_selection_set_autoselect(GTK_SINGLE_SELECTION(selection_model), FALSE);
}
g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview);
return selection_model;
}
-static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
- UiListView *tableview = malloc(sizeof(UiListView));
- memset(tableview, 0, sizeof(UiListView));
- tableview->obj = obj;
- tableview->model = args->model;
- tableview->onactivate = args->onactivate;
- tableview->onactivatedata = args->onactivatedata;
- tableview->onselection = args->onselection;
- tableview->onselectiondata = args->onselectiondata;
- tableview->ondragstart = args->ondragstart;
- tableview->ondragstartdata = args->ondragstartdata;
- tableview->ondragcomplete = args->ondragcomplete;
- tableview->ondragcompletedata = args->ondragcompletedata;
- tableview->ondrop = args->ondrop;
- tableview->ondropdata = args->ondropdata;
- tableview->selection.count = 0;
- tableview->selection.rows = NULL;
- return tableview;
-}
-
UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
// to simplify things and share code with ui_table_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
listview->columns = malloc(sizeof(UiColData));
listview->columns->listview = listview;
listview->columns->data_column = 0;
listview->columns->model_column = 0;
-
+
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
ui_update_liststore(ls, list);
} else if (args->static_elements && args->static_nelm > 0) {
listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
- listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+ listview->getvalue = str_getvalue; // force string values
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
// to simplify things and share code with ui_tableview_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
+
listview->columns = malloc(sizeof(UiColData));
listview->columns->listview = listview;
listview->columns->data_column = 0;
ui_update_liststore(ls, list);
} else if (args->static_elements && args->static_nelm > 0) {
listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
- listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+ listview->getvalue = str_getvalue; // force string values
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
void *value = list->get(list, i);
if(value) {
ObjWrapper *obj = obj_wrapper_new(value, i);
+ UiListSelection sel = list->getselection(list);
// TODO: if index i is selected, the selection is lost
// is it possible to update the item without removing it?
+ // workaround: save selection and reapply it
int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
if(count <= i) {
g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1);
} else {
g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
}
+ if(sel.count > 0) {
+ list->setselection(list, sel);
+ }
+ ui_listselection_free(sel);
}
}
}
#else
-static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
+static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIter *iter, UiList *list, void *elm, int row) {
+ UiModel *model = listview->model;
// set column values
int c = 0;
for(int i=0;i<model->columns;i++,c++) {
UiBool freevalue = FALSE;
- void *data = model_getvalue(model, list, elm, row, c, &freevalue);
+ void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
GValue value = G_VALUE_INIT;
switch(model->types[i]) {
c++;
freevalue = FALSE;
- char *str = model_getvalue(model, list, elm, row, c, &freevalue);
+ char *str = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
g_value_init(&value, G_TYPE_STRING);
g_value_set_string(&value, str);
if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
}
}
-static GtkListStore* create_list_store(UiList *list, UiModel *model) {
+static GtkListStore* create_list_store(UiListView *listview, UiList *list) {
+ UiModel *model = listview->model;
int columns = model->columns;
GType types[2*columns];
int c = 0;
GtkTreeIter iter;
gtk_list_store_insert (store, &iter, -1);
- update_list_row(store, &iter, model, list, elm, i++);
+ update_list_row(listview, store, &iter, list, elm, i++);
// next row
elm = list->next(list);
#endif
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
-
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
- g_object_unref(listmodel);
-
- UiListView *listview = malloc(sizeof(UiListView));
- memset(listview, 0, sizeof(UiListView));
- listview->obj = obj;
- listview->widget = view;
- listview->var = var;
+ UiListView *listview = create_listview(obj, args);
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
listview->model = model;
- listview->selection.count = 0;
- listview->selection.rows = NULL;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
listview);
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+
+ // init listview
+ listview->widget = view;
+ listview->var = var;
+
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(listview, list);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+ g_object_unref(listmodel);
+
// bind var
list->update = ui_listview_update;
list->getselection = ui_listview_getselection;
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area, FALSE);
+ current->container->add(current->container, scroll_area);
// ct->current should point to view, not scroll_area, to make it possible
// to add a context menu
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
- g_object_unref(listmodel);
-
//g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL);
//g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL);
// add TreeView as observer to the UiList to update the TreeView if the
// data changes
- UiListView *tableview = malloc(sizeof(UiListView));
- memset(tableview, 0, sizeof(UiListView));
- tableview->obj = obj;
- tableview->widget = view;
- tableview->var = var;
- tableview->model = model;
- tableview->ondragstart = args->ondragstart;
- tableview->ondragstartdata = args->ondragstartdata;
- tableview->ondragcomplete = args->ondragcomplete;
- tableview->ondragcompletedata = args->ondragcompletedata;
- tableview->ondrop = args->ondrop;
- tableview->ondropdata = args->ondropdata;
- tableview->selection.count = 0;
- tableview->selection.rows = NULL;
+ UiListView *tableview = create_listview(obj, args);
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
tableview);
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(tableview, list);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+ g_object_unref(listmodel);
+
// bind var
list->update = ui_listview_update;
list->getselection = ui_listview_getselection;
}
UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area, FALSE);
+ current->container->add(current->container, scroll_area);
// ct->current should point to view, not scroll_area, to make it possible
// to add a context menu
void ui_listview_update(UiList *list, int i) {
UiListView *view = list->obj;
if(i < 0) {
- GtkListStore *store = create_list_store(list, view->model);
+ GtkListStore *store = create_list_store(view, list);
gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
} else {
GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
GtkTreeIter iter;
if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
- update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
+ update_list_row(view, GTK_LIST_STORE(store), &iter, list, elm, i);
}
}
}
UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
UiObject* current = uic_current_obj(obj);
- UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
-
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+ GtkWidget *combobox = gtk_combo_box_new();
- GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
ui_set_name_and_style(combobox, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, combobox, args->groups);
UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, combobox, FALSE);
+ current->container->add(current->container, combobox);
current->container->current = combobox;
- return combobox;
-}
-
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata) {
- GtkWidget *combobox = gtk_combo_box_new();
-
- UiListView *uicbox = malloc(sizeof(UiListView));
- memset(uicbox, 0, sizeof(UiListView));
- uicbox->obj = obj;
- uicbox->widget = combobox;
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
+ UiListView *listview = create_listview(obj, args);
+ listview->widget = combobox;
+ listview->model = ui_model(obj->ctx, UI_STRING, "", -1);
+ g_signal_connect(
+ combobox,
+ "destroy",
+ G_CALLBACK(ui_listview_destroy),
+ listview);
- if(!list && elm && nelm > 0) {
- listview_copy_static_elements(uicbox, elm, nelm);
- for(int i=0;i<nelm;i++) {
+ UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(listview, list);
+ if(var) {
+ listview->var = var;
+ list->update = ui_combobox_modelupdate;
+ list->getselection = ui_combobox_getselection;
+ list->setselection = ui_combobox_setselection;
+ list->obj = listview;
+ list->update(list, -1);
+ } else if(args->static_nelm > 0) {
+ listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
+ for(int i=0;i<args->static_nelm;i++) {
GtkTreeIter iter;
GValue value = G_VALUE_INIT;
gtk_list_store_insert(listmodel, &iter, -1);
g_value_init(&value, G_TYPE_STRING);
- g_value_set_string(&value, uicbox->elements[i]);
+ g_value_set_string(&value, listview->elements[i]);
gtk_list_store_set_value(listmodel, &iter, 0, &value);
}
}
g_object_unref(listmodel);
}
- uicbox->var = var;
- uicbox->model = model;
-
- g_signal_connect(
- combobox,
- "destroy",
- G_CALLBACK(ui_combobox_destroy),
- uicbox);
-
- // bind var
- if(list) {
- list->update = ui_combobox_modelupdate;
- list->getselection = ui_combobox_getselection;
- list->setselection = ui_combobox_setselection;
- list->obj = uicbox;
- }
-
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
gtk_cell_layout_set_attributes(
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
// add callback
- if(f) {
+ if(args->onactivate) {
UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
event->obj = obj;
- event->userdata = udata;
- event->callback = f;
+ event->userdata = args->onactivatedata;
+ event->callback = args->onactivate;
event->value = 0;
- event->customdata = uicbox;
+ event->customdata = listview;
g_signal_connect(
combobox,
void ui_combobox_modelupdate(UiList *list, int i) {
UiListView *view = list->obj;
- GtkListStore *store = create_list_store(view->var->value, view->model);
+ GtkListStore *store = create_list_store(view, list);
gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
g_object_unref(store);
}
free(v);
}
-void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
- if(v->var) {
- ui_destroy_boundvar(v->obj->ctx, v->var);
- }
- if(v->elements) {
- for(int i=0;i<v->nelm;i++) {
- free(v->elements[i]);
- }
- free(v->elements);
- }
- free(v);
-}
-
/* ------------------------------ Source List ------------------------------ */
uisublist.listbox = uilistbox;
uisublist.userdata = sublist->userdata;
uisublist.index = cxListSize(sublists);
-
+ uisublist.startpos = 0;
+ cxListAdd(sublists, &uisublist);
+
// bind UiList
UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1);
- UiList *list = uisublist.var->value;
- if(list) {
+ if(uisublist.var && uisublist.var->value) {
+ UiList *list = uisublist.var->value;
list->obj = sublist_ptr;
list->update = ui_listbox_list_update;
}
-
- cxListAdd(sublists, &uisublist);
}
UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
g_object_set_data(G_OBJECT(scroll_area), "ui_listbox", uilistbox);
g_object_set_data(G_OBJECT(listbox), "ui_listbox", uilistbox);
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, listbox);
+ ui_widget_set_contextmenu(listbox, menu);
+ }
+
// signals
g_signal_connect(
listbox,
}
// reload sublist
+ sublist->startpos = pos;
ui_listbox_update_sublist(listbox, sublist, pos);
pos += sublist->numitems;
}
}
+static void listbox_button_clicked(GtkWidget *widget, UiEventDataExt *data) {
+ UiListBoxSubList *sublist = data->customdata0;
+
+ UiSubListEventData eventdata;
+ eventdata.list = sublist->var->value;
+ eventdata.sublist_index = sublist->index;
+ eventdata.row_index = data->value0;
+ eventdata.sublist_userdata = sublist->userdata;
+ eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
+ eventdata.event_data = data->customdata2;
+
+ UiEvent event;
+ event.obj = data->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = &eventdata;
+ event.eventdatatype = UI_EVENT_DATA_SUBLIST;
+ event.intval = data->value0;
+ event.set = ui_get_setop();
+
+ if(data->callback2) {
+ data->callback2(&event, data->userdata2);
+ }
+}
+
static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
if(item->icon) {
GtkWidget *label = gtk_label_new(item->label);
gtk_widget_set_halign(label, GTK_ALIGN_START);
BOX_ADD_EXPAND(hbox, label);
- // TODO: badge, button
+ if(item->badge) {
+
+ }
GtkWidget *row = gtk_list_box_row_new();
LISTBOX_ROW_SET_CHILD(row, hbox);
g_object_set_data(G_OBJECT(row), "ui-listbox-row-eventdata", event);
+ // badge
+ if(item->badge) {
+ GtkWidget *badge = gtk_label_new(item->badge);
+ WIDGET_ADD_CSS_CLASS(badge, "ui-badge");
+#if GTK_CHECK_VERSION(4, 0, 0)
+ gtk_widget_set_valign(badge, GTK_ALIGN_CENTER);
+ BOX_ADD(hbox, badge);
+#else
+ GtkWidget *align = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_container_add(GTK_CONTAINER(align), badge);
+ BOX_ADD(hbox, align);
+#endif
+ }
+ // button
+ if(item->button_icon || item->button_label) {
+ GtkWidget *button = gtk_button_new();
+ gtk_button_set_label(GTK_BUTTON(button), item->button_label);
+ ui_button_set_icon_name(button, item->button_icon);
+ WIDGET_ADD_CSS_CLASS(button, "flat");
+ BOX_ADD(hbox, button);
+ g_signal_connect(
+ button,
+ "clicked",
+ G_CALLBACK(listbox_button_clicked),
+ event
+ );
+ }
+
return row;
}
sublist->numitems = 0;
// create items for each UiList element
+ if(!sublist->var) {
+ return;
+ }
UiList *list = sublist->var->value;
if(!list) {
return;
size_t index = 0;
void *elm = list->first(list);
+
+ if(!elm && sublist->header) {
+ // empty row for header
+ GtkWidget *row = gtk_list_box_row_new();
+ cxListAdd(sublist->widgets, row);
+ g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
+ g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist);
+ intptr_t rowindex = listbox_insert_index + index;
+ g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
+ gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index);
+ sublist->numitems = 1;
+ return;
+ }
+
while(elm) {
UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
if(listbox->getvalue) {
void ui_listbox_list_update(UiList *list, int i) {
UiListBoxSubList *sublist = list->obj;
+ ui_listbox_update_sublist(sublist->listbox, sublist, sublist->startpos);
+ size_t pos = 0;
+ CxIterator it = cxListIterator(sublist->listbox->sublists);
+ cx_foreach(UiListBoxSubList *, ls, it) {
+ ls->startpos = pos;
+ pos += sublist->numitems;
+ }
+
}
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
GtkWidget *widget;
UiVar *var;
UiModel *model;
+ ui_getvaluefunc2 getvalue;
+ void *getvaluedata;
char **elements;
size_t nelm;
#if GTK_CHECK_VERSION(4, 10, 0)
UiListBox *listbox;
void *userdata;
size_t index;
+ size_t startpos;
} UiListBoxSubList;
struct UiListBox {
pathtf);
UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, eventbox, FALSE);
+ current->container->add(current->container, eventbox);
// hbox as parent for the GtkEntry and GtkButtonBox
GtkWidget *hbox = ui_gtk_hbox_new(0);
static int scale_factor = 1;
+static UiBool exit_on_shutdown;
+
UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
uic_init_global_context();
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
-#ifndef UI_GTK2
+#ifdef UI_APPLICATION
static void app_startup(GtkApplication* app, gpointer userdata) {
if(startup_func) {
startup_func(NULL, startup_data);
}
static void app_activate(GtkApplication* app, gpointer userdata) {
- printf("activate\n");
+ //printf("activate\n");
+}
+
+static void app_shutdown(GtkApplication *app, gpointer userdata) {
+ if(exit_func) {
+ exit_func(NULL, exit_data);
+ }
+ ui_app_save_settings();
}
+
#endif
void ui_main() {
application_name ? application_name : "application1");
app = UI_APPLICATION_NEW(appid.ptr);
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
+ g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_application_run(G_APPLICATION (app), 0, NULL);
g_object_unref (app);
startup_func(NULL, startup_data);
}
gtk_main();
-#endif
if(exit_func) {
exit_func(NULL, exit_data);
}
- uic_store_app_properties();
+ ui_app_save_settings();
+#endif
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
#ifndef UI_GTK2
" margin-top: 4px;\n"
" margin-bottom: 10px;\n"
"}\n"
+".ui-badge {\n"
+" background-color: #e53935;\n"
+" color: white;\n"
+" border-radius: 9999px;\n"
+" padding: 0px 10px 0px 10px;\n"
+" font-weight: bold;\n"
+" margin-left: 4px;"
+" margin-right: 4px;"
+"}\n"
;
#elif GTK_MAJOR_VERSION == 3
" margin-top: 4px;\n"
" margin-bottom: 10px;\n"
"}\n"
+".ui-badge {\n"
+" background-color: #e53935;\n"
+" color: white;\n"
+" border-radius: 9999px;\n"
+" padding: 0px 10px 0px 10px;\n"
+" font-weight: bold;\n"
+" margin-left: 4px;"
+" margin-right: 4px;"
+"}\n"
;
#endif
value->set = ui_webview_set;
value->obj = data;
if(value->value && value->type && !strcmp(value->type, UI_WEBVIEW_OBJECT_TYPE)) {
- // TODO
+ ui_webview_set(value, value->value, UI_WEBVIEW_OBJECT_TYPE);
}
}
evt.window = evt.obj->window;
evt.eventdata = NULL;
evt.eventdatatype = 0;
- evt.eventdatatype = 0;
evt.intval = 0;
if(!strcmp(response, "btn1")) {
}
}
-void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
- AdwDialog *dialog = adw_alert_dialog_new(args.title, args.content);
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
+ AdwDialog *dialog = adw_alert_dialog_new(args->title, args->content);
UiEventData *event = malloc(sizeof(UiEventData));
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->customdata = NULL;
event->customint = 0;
event->value = 0;
event->obj = parent;
- if(args.button1_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args.button1_label);
+ if(args->button1_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args->button1_label);
}
- if(args.button2_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args.button2_label);
+ if(args->button2_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args->button2_label);
}
- if(args.closebutton_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args.closebutton_label);
+ if(args->closebutton_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args->closebutton_label);
adw_alert_dialog_set_close_response(ADW_ALERT_DIALOG(dialog), "close");
}
GtkWidget *entry = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
entry = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(entry, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(entry, args->input_value);
}
adw_alert_dialog_set_extra_child(ADW_ALERT_DIALOG(dialog), entry);
event->customdata = entry;
WINDOW_DESTROY(GTK_WIDGET(self));
}
-void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new());
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget));
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
GtkWidget *dialog_w = GTK_WIDGET(dialog);
- if(args.title) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
- if(args.button1_label) {
- gtk_dialog_add_button(dialog, args.button1_label, 1);
+ if(args->button1_label) {
+ gtk_dialog_add_button(dialog, args->button1_label, 1);
}
- if(args.button2_label) {
- gtk_dialog_add_button(dialog, args.button2_label, 2);
+ if(args->button2_label) {
+ gtk_dialog_add_button(dialog, args->button2_label, 2);
}
- if(args.closebutton_label) {
- gtk_dialog_add_button(dialog, args.closebutton_label, 0);
+ if(args->closebutton_label) {
+ gtk_dialog_add_button(dialog, args->closebutton_label, 0);
}
GtkWidget *content_area = gtk_dialog_get_content_area(dialog);
- if(args.content) {
- GtkWidget *label = gtk_label_new(args.content);
+ if(args->content) {
+ GtkWidget *label = gtk_label_new(args->content);
BOX_ADD(content_area, label);
}
GtkWidget *textfield = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
textfield = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(textfield, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(textfield, args->input_value);
}
BOX_ADD(content_area, textfield);
}
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = parent;
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->value = 0;
event->customdata = textfield;
-UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
+UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
GtkWidget *dialog = DIALOG_NEW();
- if(args.width > 0 || args.height > 0) {
+ if(args->width > 0 || args->height > 0) {
gtk_window_set_default_size(
GTK_WINDOW(dialog),
- args.width,
- args.height);
+ args->width,
+ args->height);
}
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget));
- if(args.modal != UI_OFF) {
+ if(args->modal != UI_OFF) {
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
}
obj->destroy = ui_window_widget_destroy;
nwindows++;
- if(args.title != NULL) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title != NULL) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
#if ! GTK_CHECK_VERSION(4, 10, 0)
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = obj;
- event->userdata = args.onclickdata;
- event->callback = args.onclick;
+ event->userdata = args->onclickdata;
+ event->callback = args->onclick;
event->value = 0;
event->customdata = NULL;
GtkWidget *content_vbox = ui_gtk_vbox_new(0);
obj->container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
- if(args.lbutton1 || args.lbutton2 || args.rbutton3 || args.rbutton4) {
+ if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) {
#if GTK_CHECK_VERSION(3, 10, 0)
- if(args.titlebar_buttons != UI_OFF) {
+ if(args->titlebar_buttons != UI_OFF) {
GtkWidget *headerbar = gtk_header_bar_new();
gtk_window_set_titlebar(GTK_WINDOW(dialog), headerbar);
- if(args.show_closebutton == UI_OFF) {
+ if(args->show_closebutton == UI_OFF) {
HEADERBAR_SHOW_CLOSEBUTTON(headerbar, FALSE);
}
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton3) {
- GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
GtkWidget *widget = ui_box_set_margin(grid, 16);
gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
GtkWidget *space = gtk_label_new(NULL);
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, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
static ui_callback appclose_fnc;
static void *appclose_udata;
static int is_toplevel_realized = 0;
-int event_pipe[2];
+static int event_pipe[2];
+static UiBool exit_on_shutdown;
static String fallback[] = {
//"*fontList: -dt-interface system-medium-r-normal-s*utf*:",
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_main() {
if(startup_func) {
startup_func(NULL, startup_data);
exit_func(NULL, exit_data);
}
uic_store_app_properties();
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
void ui_exit_mainloop() {
return button;
}
+void ui_button_set_label(UIWIDGET button, const char *label) {
+ QString str = QString::fromUtf8(label);
+ QAbstractButton *b = (QAbstractButton*)button;
+ b->setText(str);
+}
+
+void ui_button_set_icon(UIWIDGET button, const char *icon) {
+ // TODO
+}
+
static void togglebutton_event(UiEvent *event, UiEventWrapper *wrapper) {
QPushButton *button = (QPushButton*)wrapper->customdata1;
event->intval = button->isChecked();
#include <QSpacerItem>
#include <QStackedWidget>
#include <QLabel>
+#include <QDockWidget>
static void delete_container(UiContainerPrivate *ct) {
delete ct;
}
}
-UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
}
+/* ---------------------------- UiSidebar ---------------------------- */
+
+UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
+ QVariant v = obj->widget->property("ui_sidebar");
+ QDockWidget *dock = (QDockWidget*)v.value<void*>();
+ if(!dock) {
+ fprintf(stderr, "Error: window is not configured for sidebar\n");
+ return nullptr;
+ }
+
+ QWidget *widget = new QWidget();
+ QBoxLayout *box = new QBoxLayout(QBoxLayout::TopToBottom);
+ widget->setLayout(box);
+ dock->setWidget(widget);
+
+ ui_container_add(obj, new UiBoxContainer(box));
+
+ return dock;
+}
/* -------------------- Container Helper Functions -------------------- */
return getvalue(elm, col);
}
+static void* null_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ return NULL;
+}
+
UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args) {
UiContainerPrivate *ctn = ui_obj_container(obj);
UI_APPLY_LAYOUT(ctn->layout, args);
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
- TableModel *model = new TableModel(obj, view, var, args->model);
+ ui_getvaluefunc2 getvalue = args->getvalue2;
+ void *getvaluedata = args->getvalue2data;
+ if(!getvalue) {
+ if(args->getvalue) {
+ getvalue = getvalue_wrapper;
+ getvaluedata = (void*)args->getvalue;
+ } else {
+ getvalue = null_getvalue;
+ }
+ }
+ TableModel *model = new TableModel(obj, view, var, args->model, getvalue, getvaluedata);
view->setModel(model);
if(var) {
#include "model.h"
-static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
- if(model->getvalue2) {
- return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
- } else if(model->getvalue) {
- return model->getvalue(elm, col);
- }
- return NULL;
-}
ListModel::ListModel(UiObject *obj, QListView *view, UiVar *var, ui_getvaluefunc2 getvalue, void *getvaluedata){
this->obj = obj;
-TableModel::TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model){
+TableModel::TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model, ui_getvaluefunc2 getvalue, void *getvaluedata){
this->obj = obj;
this->view = view;
this->var = var;
this->model = model;
+ this->getvalue = getvalue;
+ this->getvaluedata = getvaluedata;
this->onactivate = nullptr;
this->onactivatedata = nullptr;
this->onselection = nullptr;
if(rowData) {
int col = index.column();
UiBool freeResult = false;
- void *value = model_getvalue(model, ls, rowData, index.row(), col, &freeResult);
+ void *value = getvalue(ls, rowData, index.row(), col, getvaluedata, &freeResult);
if(value) {
UiModelType type = model->types[col];
switch(type) {
Q_OBJECT
ui_getvaluefunc2 getvalue;
- void *getvaluedata;
+ void *getvaluedata;
ui_callback onactivate;
void *onactivatedata;
ui_callback onselection;
class TableModel : public QAbstractListModel {
Q_OBJECT
- UiModel *model;
- ui_callback onactivate;
- void *onactivatedata;
- ui_callback onselection;
- void *onselectiondata;
+ UiModel *model;
+ ui_getvaluefunc2 getvalue;
+ void *getvaluedata;
+ ui_callback onactivate;
+ void *onactivatedata;
+ ui_callback onselection;
+ void *onselectiondata;
public:
- UiObject *obj;
- UiVar *var;
- QTreeView *view;
+ UiObject *obj;
+ UiVar *var;
+ QTreeView *view;
- TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model);
+ TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model, ui_getvaluefunc2 getvalue, void *getvaluedata);
void setActivationCallback(ui_callback f, void *userdata);
void setSelectionCallback(ui_callback f, void *userdata);
+++ /dev/null
-#
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-#
-# Copyright 2014 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.
-#
-
-TARGET = uitk
-TEMPLATE = lib
-CONFIG += staticlib warn_off debug
-DESTDIR = ../build/lib
-MOC_DIR = ../build/ui/qt
-OBJECTS_DIR = ../build/ui/qt
-
-DEFINES += UI_QT4
-
-SOURCES += toolkit.cpp
-SOURCES += window.cpp
-SOURCES += menu.cpp
-SOURCES += toolbar.cpp
-SOURCES += stock.cpp
-SOURCES += container.cpp
-SOURCES += text.cpp
-SOURCES += model.cpp
-SOURCES += tree.cpp
-SOURCES += button.cpp
-SOURCES += label.cpp
-SOURCES += graphics.cpp
-
-HEADERS += toolkit.h
-HEADERS += window.h
-HEADERS += menu.h
-HEADERS += toolbar.h
-HEADERS += stock.h
-HEADERS += container.h
-HEADERS += text.h
-HEADERS += model.h
-HEADERS += tree.h
-HEADERS += button.h
-HEADERS += label.h
-HEADERS += graphics.h
-
static ui_callback startup_func;
static void *startup_data;
static ui_callback open_func;
-void *open_data;
+static void *open_data;
static ui_callback exit_func;
-void *exit_data;
+static void *exit_data;
static int is_toplevel_realized = 0;
-int app_argc;
-char **app_argv;
-QApplication *application = NULL;
+static int app_argc;
+static char **app_argv;
+static QApplication *application = NULL;
+
+static UiBool exit_on_shutdown;
void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
+
void ui_main() {
if(startup_func) {
startup_func(NULL, startup_data);
uic_store_app_properties();
delete application;
+
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
void ui_show(UiObject *obj) {
#include <QVBoxLayout>
#include <QFileDialog>
#include <QPushButton>
+#include <QDockWidget>
+#include <QMessageBox>
-static UiObject* create_window(const char *title, void *window_data, bool simple) {
+static UiObject* create_window(const char *title, void *window_data, bool simple, bool sidebar = false) {
UiObject *obj = uic_object_new_toplevel();
obj->window = window_data;
obj->next = NULL;
boxWidget->setLayout(box);
window->setCentralWidget(boxWidget);
ui_container_add(obj, new UiBoxContainer(box));
+ if(sidebar) {
+ QDockWidget *dock = new QDockWidget();
+ window->addDockWidget(Qt::LeftDockWidgetArea, dock);
+ window->setProperty("ui_sidebar", QVariant::fromValue((void*)dock));
+ }
obj->widget = window;
return obj;
}
UiObject* ui_window(const char *title, void *window_data) {
- return create_window(title, window_data, FALSE);
+ return create_window(title, window_data, false);
}
UiObject* ui_simplewindow(char *title, void *window_data) {
- return create_window(title, window_data, TRUE);
+ return create_window(title, window_data, true);
+}
+
+UiObject *ui_sidebar_window(const char *title, void *window_data) {
+ return create_window(title, window_data, false, true);
}
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
+ if(args->input || args->password) {
+ // TODO: QInputDialog
+ } else {
+ QMessageBox msgBox;
+ if(args->title) {
+ msgBox.setWindowTitle(args->title);
+ }
+ if(args->content) {
+ msgBox.setText(args->content);
+ }
+ QPushButton *btn1;
+ QPushButton *btn2;
+ if(args->button1_label) {
+ btn1 = msgBox.addButton(args->button1_label, QMessageBox::ActionRole);
+ }
+ if(args->button2_label) {
+ btn2 = msgBox.addButton(args->button2_label, QMessageBox::ActionRole);
+ }
+ if(args->closebutton_label) {
+ msgBox.addButton(args->closebutton_label, QMessageBox::DestructiveRole);
+ }
+
+ msgBox.exec();
+
+ UiEvent evt;
+ evt.obj = parent;
+ evt.document = evt.obj->ctx->document;
+ evt.window = evt.obj->window;
+ evt.eventdata = NULL;
+ evt.eventdatatype = 0;
+ evt.intval = 0;
+ if(msgBox.clickedButton() == btn1) {
+ evt.intval = 1;
+ } else if(msgBox.clickedButton() == btn2) {
+ evt.intval = 2;
+ }
+ if(args->result) {
+ args->result(&evt, args->resultdata);
+ }
+ }
+}
char* ui_openfiledialog(UiObject *obj) {
QString fileName = QFileDialog::getOpenFileName(obj->widget);
extern "C" {
#endif
+enum UiLinkType {
+ UI_LINK_TEXT = 0,
+ UI_LINK_BUTTON
+};
+typedef enum UiLinkType UiLinkType;
+
typedef struct UiButtonArgs {
UiBool fill;
UiBool hexpand;
const int* groups;
} UiToggleArgs;
+
+typedef struct UiLinkButtonArgs {
+ UiBool fill;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int colspan;
+ int rowspan;
+ const char *name;
+ const char *style_class;
+
+ const char *label;
+ const char *uri;
+ UiString *value;
+ const char *varname;
+ ui_callback onclick;
+ void *onclickdata;
+ UiBool nofollow;
+ UiLinkType type;
+
+ const int* groups;
+} 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_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_linkbutton(obj, ...) ui_linkbutton_create(obj, &(UiLinkButtonArgs){ __VA_ARGS__ })
-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_radiobutton_create(UiObject* obj, UiToggleArgs *args);
+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_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_linkbutton_value_set(UiString *str, const char *label, const char *uri);
+UIEXPORT void ui_linkbutton_value_set_label(UiString *str, const char *label);
+UIEXPORT void ui_linkbutton_value_set_uri(UiString *str, const char *uri);
+UIEXPORT void ui_linkbutton_value_set_visited(UiString *str, UiBool visited);
+UIEXPORT void ui_linkbutton_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_linkbutton_set_uri(UIWIDGET button, const char *label);
+UIEXPORT void ui_linkbutton_set_visited(UIWIDGET button, UiBool visited);
+UIEXPORT char* ui_linkbutton_get_label(UIWIDGET button);
+UIEXPORT char* ui_linkbutton_get_uri(UIWIDGET button);
+UIEXPORT UiBool ui_linkbutton_get_visited(UIWIDGET button);
#ifdef __cplusplus
}
#ifdef __cplusplus
extern "C" {
#endif
-
-enum UiAlignment {
- UI_ALIGN_DEFAULT = 0,
- UI_ALIGN_LEFT,
- UI_ALIGN_RIGHT,
- UI_ALIGN_CENTER
-};
-
-typedef enum UiAlignment UiAlignment;
+
enum UiLabelStyle {
UI_LABEL_STYLE_DEFAULT = 0,
UI_DND_ACTION_LINK,
UI_DND_ACTION_CUSTOM
} UiDnDAction;
-
+
+enum UiAlignment {
+ UI_ALIGN_DEFAULT = 0,
+ UI_ALIGN_LEFT,
+ UI_ALIGN_RIGHT,
+ UI_ALIGN_CENTER
+};
+
+typedef enum UiAlignment UiAlignment;
+
typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
typedef void*(*ui_getvaluefunc)(void *elm, int col);
UIEXPORT void ui_onopen(ui_callback f, void *userdata);
UIEXPORT void ui_onexit(ui_callback f, void *userdata);
+UIEXPORT int ui_app_save_settings(void);
+UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
+
UIEXPORT void ui_main(void);
UIEXPORT void ui_show(UiObject *obj);
UIEXPORT void ui_close(UiObject *obj);
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_addobsv(UiList *list, ui_callback f, void *data);
UIEXPORT void ui_list_notify(UiList *list);
* array of column size hints
*/
int *columnsize;
-
- /*
- * void*(*ui_getvaluefunc)(void *elm, int col);
- *
- * function for translating model data to view data
- * first argument is the pointer returned by UiList first|next|get
- * second argument is the column index
- * TODO: return
- */
- ui_getvaluefunc getvalue;
-
- /*
- * void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata)
- *
- * alternative for getvalue
- */
- ui_getvaluefunc2 getvalue2;
-
- void *getvalue2data;
};
struct UiListCallbacks {
*/
ui_callback onbuttonclick;
void *onbuttonclickdata;
+
+ UiMenuBuilder *contextmenu;
};
#define UI_SUBLIST(...) (UiSubList){ __VA_ARGS__ }
#define UI_SUBLISTS(...) (UiSubList[]){ __VA_ARGS__, (UiSubList){NULL,NULL,NULL,0} }
+/*
+ * Creates an UiModel, that specifies columns for a table widget.
+ *
+ * For each column a column type (UiModelType) and a title string
+ * (char*) must be specified. The column list must be terminated
+ * with -1.
+ *
+ * UiModel *model = ui_model(ctx, UI_STRING, "Column 1", UI_STRING, "Column 2", -1);
+ */
UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
UIEXPORT UiObject *ui_window(const char *title, void *window_data);
UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data);
UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data);
-UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args);
+UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args);
-#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, (UiDialogWindowArgs){ __VA_ARGS__ });
-#define ui_dialog_window0(parent) ui_dialog_window_create(parent, (UiDialogWindowArgs){ 0 });
+#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ __VA_ARGS__ });
+#define ui_dialog_window0(parent) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ 0 });
UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
-#define ui_dialog(parent, ...) ui_dialog_create(parent, (UiDialogArgs){ __VA_ARGS__ } )
+#define ui_dialog(parent, ...) ui_dialog_create(parent, &(UiDialogArgs){ __VA_ARGS__ } )
-UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs args);
+UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs *args);
UIEXPORT void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata);
UIEXPORT void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata);