]> uap-core.de Git - note.git/commitdiff
update toolkit, adjust ui code main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 24 Aug 2025 13:28:03 +0000 (15:28 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 24 Aug 2025 13:28:03 +0000 (15:28 +0200)
56 files changed:
application/window.c
ui/cocoa/GridLayout.m
ui/cocoa/ListDataSource.h [moved from ui/qt/tree.cpp with 75% similarity]
ui/cocoa/ListDataSource.m [new file with mode: 0644]
ui/cocoa/ListDelegate.h [new file with mode: 0644]
ui/cocoa/ListDelegate.m [new file with mode: 0644]
ui/cocoa/MainWindow.m
ui/cocoa/Toolbar.h [new file with mode: 0644]
ui/cocoa/Toolbar.m [new file with mode: 0644]
ui/cocoa/UiThread.h [moved from ui/cocoa/UiJob.m with 80% similarity]
ui/cocoa/UiThread.m [new file with mode: 0644]
ui/cocoa/button.m
ui/cocoa/container.h
ui/cocoa/container.m
ui/cocoa/image.h [moved from ui/qt/tree.h with 88% similarity]
ui/cocoa/image.m [new file with mode: 0644]
ui/cocoa/label.h [moved from ui/cocoa/UiJob.h with 89% similarity]
ui/cocoa/label.m [new file with mode: 0644]
ui/cocoa/list.h [new file with mode: 0644]
ui/cocoa/list.m [new file with mode: 0644]
ui/cocoa/menu.h
ui/cocoa/menu.m
ui/cocoa/objs.mk
ui/cocoa/text.m
ui/cocoa/toolkit.h
ui/cocoa/toolkit.m
ui/common/args.c
ui/common/args.h
ui/common/properties.c
ui/common/types.c
ui/common/wrapper.c
ui/common/wrapper.h
ui/gtk/button.c
ui/gtk/button.h
ui/gtk/display.c
ui/gtk/headerbar.c
ui/gtk/list.c
ui/gtk/list.h
ui/gtk/text.c
ui/gtk/toolkit.c
ui/gtk/webview.c
ui/gtk/window.c
ui/motif/toolkit.c
ui/qt/button.cpp
ui/qt/container.cpp
ui/qt/list.cpp
ui/qt/model.cpp
ui/qt/model.h
ui/qt/qt4.pro [deleted file]
ui/qt/toolkit.cpp
ui/qt/window.cpp
ui/ui/button.h
ui/ui/display.h
ui/ui/toolkit.h
ui/ui/tree.h
ui/ui/window.h

index 6bf6754c00dbd011ddcdfe5221d8a46fceb09570..0cff93e640b8ca3131e04d973169b6782fb072ee 100644 (file)
@@ -64,11 +64,11 @@ void window_create() {
         // 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,
index c937948cae3b196754670f1b0bde048d3b5459d4..3e97cf45d241b6e8b8f8c9de2bae865986dca3ac 100644 (file)
     return self.preferredSize;
 }
 
-- (void) addView:(NSView*)view fill:(BOOL)fill {
+- (void) addView:(NSView*)view {
     if(_newline) {
         _y++;
         _x = 0;
similarity index 75%
rename from ui/qt/tree.cpp
rename to ui/cocoa/ListDataSource.h
index 336041adc5cc8e148690213c844b0710d3e262df..4dc142fc3caf00cadb6c036246f4a14cf870aa10 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
diff --git a/ui/cocoa/ListDataSource.m b/ui/cocoa/ListDataSource.m
new file mode 100644 (file)
index 0000000..3be08f7
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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
diff --git a/ui/cocoa/ListDelegate.h b/ui/cocoa/ListDelegate.h
new file mode 100644 (file)
index 0000000..27762f7
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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);
diff --git a/ui/cocoa/ListDelegate.m b/ui/cocoa/ListDelegate.m
new file mode 100644 (file)
index 0000000..7e15f3d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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;
+}
index 27f34fdcae6986701cce4a93c465dfb19c9be0a9..45c8e3076f0d70ad013a71a1e5fa5418ca410315 100644 (file)
@@ -34,6 +34,7 @@
 
 #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;
+        }
     }
 }
 
diff --git a/ui/cocoa/Toolbar.h b/ui/cocoa/Toolbar.h
new file mode 100644 (file)
index 0000000..4e50e7c
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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);
diff --git a/ui/cocoa/Toolbar.m b/ui/cocoa/Toolbar.m
new file mode 100644 (file)
index 0000000..747b469
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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;
+}
similarity index 80%
rename from ui/cocoa/UiJob.m
rename to ui/cocoa/UiThread.h
index b3e0830f9e15495b0f3361225c28a79b39d34951..1c4120d590ae41ea2f0b79c10f912f3c24f0a76c 100644 (file)
  * 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
diff --git a/ui/cocoa/UiThread.m b/ui/cocoa/UiThread.m
new file mode 100644 (file)
index 0000000..2916d2f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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
+
index 06793f30cf0fa0dfda8004483ca5757e6599b8eb..e8e753d4795f42270a76c449397eeb8a0e46b21b 100644 (file)
@@ -47,7 +47,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
     }
     
     UiLayout layout = UI_INIT_LAYOUT(args);
-    ui_container_add(obj, button, &layout, FALSE);
+    ui_container_add(obj, button, &layout);
     
     return (__bridge void*)button;
 }
@@ -89,7 +89,7 @@ UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs *args, enum NSButtonTyp
     }
     
     UiLayout layout = UI_INIT_LAYOUT(args);
-    ui_container_add(obj, button, &layout, FALSE);
+    ui_container_add(obj, button, &layout);
     
     return (__bridge void*)button;
 }
@@ -150,7 +150,7 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
     }
     
     UiLayout layout = UI_INIT_LAYOUT(args);
-    ui_container_add(obj, button, &layout, FALSE);
+    ui_container_add(obj, button, &layout);
     
     return (__bridge void*)button;
 }
@@ -242,7 +242,7 @@ UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) {
     }
     
     UiLayout layout = UI_INIT_LAYOUT(args);
-    ui_container_add(obj, button, &layout, FALSE);
+    ui_container_add(obj, button, &layout);
     
     return (__bridge void*)button;
 }
index d969fa8cf6186d9feb1fca0afcf2cbb0a2521e43..1ff66b12d560f08af46befc48f7ccbefdd03cab3 100644 (file)
@@ -71,7 +71,7 @@ struct UiLayout {
 @property const char *label;
 @property UiBool newline;
 
-- (void) addView:(NSView*)view fill:(BOOL)fill;
+- (void) addView:(NSView*)view;
 
 @end
 
@@ -87,4 +87,4 @@ struct UiLayout {
 
 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);
index 6e9b46619e8a27c72a23d3b46b4035475f326e28..c73c429f90b3bfd2c0462de459fca8ae2c0d77a8 100644 (file)
     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];
     
@@ -101,7 +99,7 @@ static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterf
     
     // 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));
@@ -123,7 +121,7 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
     
     // 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));
@@ -157,11 +155,11 @@ UiContainerX* ui_create_container(UiObject *obj, id<Container> container) {
     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 ----------------------- */
similarity index 88%
rename from ui/qt/tree.h
rename to ui/cocoa/image.h
index 664b32b5f40bd1aea4bf7c193ba82d5d0b062100..2e1a05b76cad9d2b6bcff190e8d15d712bc4951b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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);
diff --git a/ui/cocoa/image.m b/ui/cocoa/image.m
new file mode 100644 (file)
index 0000000..e00c39a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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
+}
similarity index 89%
rename from ui/cocoa/UiJob.h
rename to ui/cocoa/label.h
index a4c598865022ea9dc9d2acc82717111d94ca1447..bb7e97c0f2a5d187b517b879e4958800ad40d382 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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:
@@ -27,4 +27,7 @@
  */
 
 #import "toolkit.h"
+#import "../ui/display.h"
 
+char* ui_label_get(UiString *s);
+void ui_label_set(UiString *s, const char *str);
diff --git a/ui/cocoa/label.m b/ui/cocoa/label.m
new file mode 100644 (file)
index 0000000..f29a650
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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];
+}
diff --git a/ui/cocoa/list.h b/ui/cocoa/list.h
new file mode 100644 (file)
index 0000000..03557b7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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);
diff --git a/ui/cocoa/list.m b/ui/cocoa/list.m
new file mode 100644 (file)
index 0000000..6c4e39b
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * 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];
+    }
+}
index be58c9f46e1650e3ab02e9081438281f5a35a60a..d1cd280d31e6579ab50951b0b0df922918067bca 100644 (file)
 
 @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);
index 5395d0ad9b04ec1b7668f5e3682135db456556b0..eae8a50960689564dd88e24415cbffdf9c415166 100644 (file)
@@ -50,6 +50,28 @@ static NSMutableArray *bindingItems;
     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[] = {
@@ -63,61 +85,84 @@ 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];
@@ -132,11 +177,11 @@ void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item) {
     [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) {
     
 }
 
@@ -154,7 +199,7 @@ void ui_menu_init(void) {
             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++;
@@ -164,3 +209,20 @@ void ui_menu_init(void) {
 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;
+    }
+}
index f3f20c7c290a16ade1ab843c230c53a295b9797d..a9a0b4b69397d72d454c3dde94d681fe50c8cf45 100644 (file)
@@ -41,6 +41,7 @@ COCOAOBJ += Container.o
 COCOAOBJ += button.o
 COCOAOBJ += text.o
 COCOAOBJ += menu.o
+COCOAOBJ += Toolbar.o
 
 TOOLKITOBJS += $(COCOAOBJ:%=$(COCOA_OBJPRE)%)
 TOOLKITSOURCE += $(COCOAOBJ:%.o=cocoa/%.m)
index 1fe0ce379111dc2708d30eb4182ce7b5b3d7bfc7..366f7a37987bb0bb82e5d79100f2cc3a956c2ef9 100644 (file)
@@ -42,7 +42,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
     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);
@@ -85,7 +85,6 @@ void ui_textarea_restore(UiText *text) {
     NSTextStorage *textStorage;
     if(text->data1) {
         textStorage = (__bridge NSTextStorage*)text->data1;
-        
     } else {
         textStorage = [[NSTextStorage alloc] init];
     }
@@ -94,43 +93,83 @@ void ui_textarea_restore(UiText *text) {
 }
 
 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];
 }
 
 
@@ -150,7 +189,7 @@ static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs *args, BOOL pass
     }
     
     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) {
index b44ba19d440f112474ffd9fccf2decfc0f102ba6..fd003336bffc4f380f95504b466e36fafcc46375 100644 (file)
 #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);
index 2501a3f65ffc7260262812f24a4d2f5768396307..4df07900165582799b2a8159c36dc375e49c79f8 100644 (file)
 #include "../common/toolbar.h"
 #include "../common/threadpool.h"
 
+#import "image.h"
 #import "menu.h"
+#import "Toolbar.h"
+#import "UiThread.h"
 
 #import "AppDelegate.h"
 
@@ -46,9 +49,11 @@ static const char **app_argv;
 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 ------------------- */
 
@@ -68,6 +73,10 @@ void ui_init(const char *appname, int argc, char **argv) {
     [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() {
@@ -89,6 +98,10 @@ void ui_onexit(ui_callback f, void *userdata) {
     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;
@@ -127,6 +140,9 @@ void ui_cocoa_onexit(void) {
 
 void ui_main(void) {
     NSApplicationMain(app_argc, app_argv);
+    if(exit_on_shutdown) {
+        exit(0);
+    }
 }
 
 /* ------------------- Window Visibility functions ------------------- */
@@ -145,9 +161,33 @@ void ui_close(UiObject *obj) {
 /* ------------------- 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];
 }
index e799889fa8fbddc5086976badfcbe5c0cbc8f424..3ef591fae8f138f6f1a2f47fff71e5882f9b38dd 100644 (file)
 
 #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) {
@@ -608,6 +758,71 @@ void ui_splitpane_args_free(UiSplitPaneArgs *args) {
 }
 
 
+/* ------------------------- 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 ----------------------------*/
 
 
@@ -1059,6 +1274,111 @@ void ui_toggle_args_free(UiToggleArgs *args) {
     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 ----------------------------*/
 
index 04e7063b7246005f8bac1bada2ad8c3a258c236c..a4bebe8fcce8c489708ad6c0bcbb525bf8b965d7 100644 (file)
@@ -29,6 +29,7 @@
 #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);
@@ -162,6 +196,19 @@ UIEXPORT void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *valu
 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);
@@ -255,6 +302,28 @@ UIEXPORT void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group);
 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);
index 629112f7777380f46d86f3503447814b17e6518a..0866923d505c63f9767978011b28e9977b977cdb 100644 (file)
@@ -191,6 +191,11 @@ int uic_store_app_properties() {
     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);
index b3f55d19215332f39759f5db34d69081fe26d3d7..5f5685f231d2002fd3babd4d089fc23c45ad39c9 100644 (file)
@@ -165,12 +165,26 @@ void ui_list_clear(UiList *list) {
     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);
 }
index ea8855336f921e77ff16a074d5511dc7fe582be2..6d5be8190d337fb0ce79a009476cf8fae78a0283 100644 (file)
@@ -218,3 +218,38 @@ void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge) {
 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;
+}
index d190fc8609b4c74b42e92e5fe4f8bf21562bb0ac..ec8d2d9c928906ced4ae1ba066dd211c34836952 100644 (file)
@@ -74,6 +74,13 @@ UIEXPORT int ui_event_get_eventdatatype(UiEvent *event);
 UIEXPORT int ui_event_get_int(UiEvent *event);
 UIEXPORT int ui_event_get_set(UiEvent *event);
 
+UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list);
+UIEXPORT 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
index 6f6ad0ba2daf126cccc937f4a9bb6b9518836df5..84d9608e76fcb82ab6511264c1cc728660afc0e6 100644 (file)
@@ -32,6 +32,8 @@
 #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"
 
@@ -120,6 +122,14 @@ void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
     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);
@@ -594,3 +604,280 @@ void ui_radiobutton_set(UiInteger *value, int64_t i) {
     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;
+}
index c855b355a3d878f43ca339816fecc3bf90c53ad5..4b60f494e52adead5fe76b1effcdfeb761689e89 100644 (file)
 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*);
@@ -89,6 +99,9 @@ void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event);
 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
index 40fcde1e376fcbb2774cc2d79d9d0e990a3c26f6..32c4afd78472e6b68fc446c036b842c9e5e62736 100644 (file)
@@ -101,7 +101,7 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
         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;
     }
     
 
index e1b80b5617aee5853c5ea62b428ef97906d0866a..f53dbd56dafd8be6469495cf371b6b467439209e 100644 (file)
@@ -162,9 +162,10 @@ void ui_add_headerbar_menu(
     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
     
index be9c00ae911ee2d606c27983fe459f7d0e877955..41ed5d0711db1c86062ce67e616eeb619585a651 100644 (file)
 #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;
 }
 
@@ -74,6 +75,37 @@ static void listview_copy_static_elements(UiListView *listview, char **elm, size
     }
 }
 
+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)
 
 
@@ -131,16 +163,17 @@ static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item,
     }
 }
 
-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) {
@@ -172,7 +205,7 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
             
         }
         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;
             }
@@ -199,55 +232,32 @@ static GtkSelectionModel* create_selection_model(UiListView *listview, GListStor
         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);
@@ -280,7 +290,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
         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);
     }
     
@@ -320,19 +330,15 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
     // 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;
@@ -370,7 +376,7 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
         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);
     }
     
@@ -626,14 +632,20 @@ void ui_listview_update2(UiList *list, int i) {
         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);
         }
     }
 }
@@ -695,12 +707,13 @@ void ui_combobox_setselection(UiList *list, UiListSelection selection) {
 
 #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]) {
@@ -765,7 +778,7 @@ static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *mod
                 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) {
@@ -779,7 +792,8 @@ static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *mod
     }
 }
 
-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;
@@ -807,7 +821,7 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
             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);
@@ -841,36 +855,29 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
 #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;
@@ -921,7 +928,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     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
@@ -1006,36 +1013,23 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     
     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;
@@ -1098,7 +1092,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     }
     
     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
@@ -1112,7 +1106,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
 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 {
@@ -1120,7 +1114,7 @@ void ui_listview_update(UiList *list, int i) {
         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);
         }
     }
 }
@@ -1150,46 +1144,41 @@ void ui_listview_setselection(UiList *list, UiListSelection selection) {
 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);
         }
     }
@@ -1199,23 +1188,6 @@ GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **
         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(
@@ -1227,13 +1199,13 @@ GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **
     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,
@@ -1268,7 +1240,7 @@ void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
 
 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);
 }
@@ -1709,19 +1681,6 @@ void ui_listview_destroy(GtkWidget *w, UiListView *v) {
     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 ------------------------------ */
 
@@ -1801,16 +1760,16 @@ static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *subli
     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) {
@@ -1883,6 +1842,11 @@ 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,
@@ -1952,11 +1916,37 @@ void ui_listbox_update(UiListBox *listbox, int from, int to) {
         }
         
         // 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) {
@@ -1966,7 +1956,9 @@ static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *subli
     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);
     
@@ -1991,6 +1983,34 @@ static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *subli
     
     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;
 }
 
@@ -2005,6 +2025,9 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
     sublist->numitems = 0;
     
     // create items for each UiList element
+    if(!sublist->var) {
+        return;
+    }
     UiList *list = sublist->var->value;
     if(!list) {
         return;
@@ -2012,6 +2035,20 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
     
     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) {
@@ -2055,6 +2092,14 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
 
 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) {
index bd490ab3250bcc8dd8f8d1bb2bd70be2cb5eda9e..7878b4f67fcbaac650f75d9ecde3655cce105226 100644 (file)
@@ -45,6 +45,8 @@ typedef struct UiListView {
     GtkWidget         *widget;
     UiVar             *var;
     UiModel           *model;
+    ui_getvaluefunc2  getvalue;
+    void              *getvaluedata;
     char              **elements;
     size_t            nelm;
 #if GTK_CHECK_VERSION(4, 10, 0)
@@ -91,6 +93,7 @@ typedef struct UiListBoxSubList {
     UiListBox   *listbox;
     void        *userdata;
     size_t      index;
+    size_t      startpos;
 } UiListBoxSubList;
 
 struct UiListBox {
index 9ea0c4ca2c55bd58b44dc0ff6463b060e379c91b..ef07daf37d1eee1700a1f524acdbcde7ab707c4a 100644 (file)
@@ -1118,7 +1118,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
             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);
index 7a26a708dc98cb6fa1eb20bf83b7d4559b2d6f43..d64246c14b70c89b13dcdee06482ec96821663dc 100644 (file)
@@ -66,6 +66,8 @@ static UiObject      *active_window;
 
 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();
@@ -110,8 +112,11 @@ void ui_onexit(ui_callback f, void *userdata) {
     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);
@@ -119,8 +124,16 @@ static void app_startup(GtkApplication* app, gpointer userdata) {
 }
 
 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() {
@@ -130,6 +143,7 @@ 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);
@@ -140,11 +154,14 @@ void ui_main() {
         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
@@ -378,6 +395,15 @@ static const char *ui_gtk_css =
 "  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
@@ -411,6 +437,15 @@ static const char *ui_gtk_css =
 "  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
 
index 3b9a94661a2356a1a6e27212fcfb26afea5eb2e5..b9b93c7374dc070909397456c2bd00d13ab6d485 100644 (file)
@@ -55,7 +55,7 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
         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);
         }
     }
     
index cdafae3d4678470360648ad225bd672240b4ba7b..d0cabe30794a815e9d7b923aec8ced423596727e 100644 (file)
@@ -313,7 +313,6 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
     evt.window = evt.obj->window;
     evt.eventdata = NULL;
     evt.eventdatatype = 0;
-    evt.eventdatatype = 0;
     evt.intval = 0;
     
     if(!strcmp(response, "btn1")) {
@@ -333,35 +332,35 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
     }
 }
 
-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;
@@ -410,47 +409,47 @@ static void ui_dialog_response (GtkDialog* self, gint response_id, gpointer user
     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;
     
@@ -749,18 +748,18 @@ static void ui_dialogwindow_response(GtkDialog* self, gint response_id, gpointer
 
 
 
-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);
     }
     
@@ -770,15 +769,15 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
     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;
 
@@ -816,44 +815,44 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
     
     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);
                 }
@@ -871,18 +870,18 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
         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);
             }
@@ -890,18 +889,18 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
         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);
             }
index 25ea5465c93851512f1b183572d2744623796a17..b6ffc845af40e903b902b8fd43cb3eefd77972f3 100644 (file)
@@ -52,17 +52,18 @@ static const char *application_name;
 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*:",                 
@@ -139,6 +140,10 @@ void ui_onexit(ui_callback f, void *userdata) {
     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);
@@ -148,6 +153,9 @@ void ui_main() {
         exit_func(NULL, exit_data);
     }
     uic_store_app_properties();
+    if(exit_on_shutdown) {
+        exit(0);
+    }
 }
 
 void ui_exit_mainloop() {
index 5e04f274aae8ed38d4d09cf12cc978c39c5d7c52..6036cd6dc63215658f6502cb30777e778f2fd5a2 100644 (file)
@@ -48,6 +48,16 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
     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();
index 07ac46afc40038bf1657d64f928837239518ce19..1313ab6f1b61301c2a19028f9084bb55d2e15a12 100644 (file)
@@ -35,6 +35,7 @@
 #include <QSpacerItem>
 #include <QStackedWidget>
 #include <QLabel>
+#include <QDockWidget>
 
 static void delete_container(UiContainerPrivate *ct) {
     delete ct;
@@ -228,7 +229,7 @@ void UiGridContainer::end() {
     }
 }
 
-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);
     
@@ -251,6 +252,25 @@ UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *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 -------------------- */
 
index a44a93dd3c01d1da5ffa377a02da401037e7fb17..6ce56e16aa7f0fa67d6ce94d88f25fcc68c22666 100644 (file)
@@ -42,6 +42,10 @@ static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *u
     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);
@@ -102,7 +106,17 @@ UIWIDGET ui_table_create(UiObject* obj, UiListArgs *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) {
index e4846b8a74d807c28ebdff2aa21b4cb4358009d8..7b991344beff7e6b0bbff9b312bf8cf3ae2bc9c3 100644 (file)
 
 #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;
@@ -116,11 +108,13 @@ void ListModel::selectionChanged(const QItemSelection& selected, const QItemSele
 
 
 
-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;
@@ -162,7 +156,7 @@ QVariant TableModel::data(const QModelIndex &index, int role) const {
         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) {
index faec52af590141befa586213aa79e903ab54e607..8fa513e0cb7deea73d41093e86159fca33748e37 100644 (file)
@@ -45,7 +45,7 @@ class ListModel : public QAbstractListModel {
     Q_OBJECT
     
     ui_getvaluefunc2 getvalue;
-    void *getvaluedata;
+    void        *getvaluedata;
     ui_callback onactivate;
     void        *onactivatedata;
     ui_callback onselection;
@@ -75,18 +75,20 @@ public slots:
 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);
diff --git a/ui/qt/qt4.pro b/ui/qt/qt4.pro
deleted file mode 100644 (file)
index efc299d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# 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
-
index 1d1a15ecd890ce070812e0ea7e916cf2ce5987a0..2dd98b812335c287b491a16001c0c708860fda63 100644 (file)
@@ -43,15 +43,17 @@ static const char *application_name;
 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;
@@ -87,6 +89,10 @@ void ui_onexit(ui_callback f, void *userdata) {
     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);
@@ -98,6 +104,10 @@ void ui_main() {
     uic_store_app_properties();
     
     delete application;
+    
+    if(exit_on_shutdown) {
+        exit(0);
+    }
 }
 
 void ui_show(UiObject *obj) {
index 5a9f18996046f7ceae5d1248a444b4a5940c57aa..bdc8b4e1613f51db8c71a29092808efa6143bd6c 100644 (file)
 #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;
@@ -61,19 +63,70 @@ static UiObject* create_window(const char *title, void *window_data, bool simple
     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);
index fb578f787621d2482f3e20ae1086332943270c53..fff9383b0af59bdb877aea8d2fb4a672a271a994 100644 (file)
 extern "C" {
 #endif
 
+enum UiLinkType {
+    UI_LINK_TEXT = 0,
+    UI_LINK_BUTTON
+};
+typedef enum UiLinkType UiLinkType;
+    
 typedef struct UiButtonArgs {
     UiBool fill;
     UiBool hexpand;
@@ -81,21 +87,59 @@ typedef struct UiToggleArgs {
     
     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
 }
index 3cb3d6597f50a62e631f367915cc3766210a9117..3e0522241add5930c699005ff1b0b49cfe58948b 100644 (file)
 #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,
index 7b5474272f293da0f7ea5567b894f57afd542294..d412156cafaea5c164520a71a5d6f0b0263647c1 100644 (file)
@@ -237,7 +237,16 @@ typedef enum UiDnDAction {
     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);
@@ -514,6 +523,9 @@ UIEXPORT void ui_onstartup(ui_callback f, void *userdata);
 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);
@@ -608,6 +620,8 @@ UIEXPORT void ui_list_prepend(UiList *list, void *data);
 UIEXPORT void ui_list_remove(UiList *list, int i);
 UIEXPORT void ui_list_clear(UiList *list);
 UIEXPORT void ui_list_update(UiList *list);
+UIEXPORT void ui_list_update_row(UiList *list, int row);
+UIEXPORT UiListSelection ui_list_get_selection(UiList *list);
 UIEXPORT void ui_list_addobsv(UiList *list, ui_callback f, void *data);
 UIEXPORT void ui_list_notify(UiList *list);
 
index af51d086ae5ab5f11926e2b58858a07110ede641..4a1e59014b6bbdf8f28b05e6574f7d1238fc5d01 100644 (file)
@@ -76,25 +76,6 @@ struct UiModel {
      * 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 {
@@ -248,12 +229,23 @@ struct UiSourceListArgs {
      */
     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);
index 352abb79720dfa5a2b33fcf400e0d2da428c2f3b..78703c2c616eed7157be58289bc1b61202c1a492 100644 (file)
@@ -75,16 +75,16 @@ typedef struct UiDialogWindowArgs {
 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);