add table widget (Cocoa)

Sun, 24 Aug 2025 09:31:09 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 24 Aug 2025 09:31:09 +0200
changeset 715
2082c80fb010
parent 714
3905f542e150
child 716
99386f34efc9

add table widget (Cocoa)

make/xcode/toolkit/toolkit/main.m file | annotate | diff | comparison | revisions
ui/cocoa/list.m file | annotate | diff | comparison | revisions
ui/ui/tree.h file | annotate | diff | comparison | revisions
--- a/make/xcode/toolkit/toolkit/main.m	Sat Aug 23 18:41:20 2025 +0200
+++ b/make/xcode/toolkit/toolkit/main.m	Sun Aug 24 09:31:09 2025 +0200
@@ -77,6 +77,10 @@
     printf("activate\n");
 }
 
+static void* table_getvalue(void *elm, int col) {
+    return elm;
+}
+
 void application_startup(UiEvent *event, void *data) {
     UiObject *obj = ui_window("My Window", NULL);
     //WindowData *wdata = ui_malloc(obj->ctx, sizeof(WindowData));
@@ -85,9 +89,10 @@
     MyDocument *doc = create_doc();
     ui_attach_document(obj->ctx, doc);
     
+    UiModel *model = ui_model(obj->ctx, UI_STRING, "Column 1", UI_STRING, "Column 2", UI_STRING, "Column 3", -1);
     
     ui_grid(obj, .columnspacing = 10, .rowspacing = 10) {
-        ui_listview(obj, .fill = UI_ON, .varname = "list1", .onactivate = action_list_activate, .onselection = action_list_selection, .multiselection = TRUE);
+        ui_table(obj, .fill = UI_ON, .varname = "list1", .model = model, .getvalue = table_getvalue, .onactivate = action_list_activate, .onselection = action_list_selection, .multiselection = TRUE);
     }
     
     
--- a/ui/cocoa/list.m	Sat Aug 23 18:41:20 2025 +0200
+++ b/ui/cocoa/list.m	Sun Aug 24 09:31:09 2025 +0200
@@ -39,6 +39,31 @@
     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];
     
@@ -55,23 +80,12 @@
     UiLayout layout = UI_INIT_LAYOUT(args);
     ui_container_add(obj, scrollview, &layout, TRUE);
     
-    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;
+    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;
-        list->obj = (__bridge void*)tableview;
-        list->update = ui_tableview_update;
-        list->getselection = ui_tableview_getselection;
-        list->setselection = ui_tableview_setselection;
+        bind_list_to_tableview(list, tableview);
         
         ui_getvaluefunc2 getvalue = args->getvalue2;
         void *getvaluedata = args->getvalue2data;
@@ -85,7 +99,6 @@
         }
         
         NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"column"];
-        column.width = 400;
         [tableview addTableColumn:column];
         
         ListDataSource *dataSource = [[ListDataSource alloc] init:tableview.tableColumns var:var getvalue:getvalue getvaluedata:getvaluedata];
@@ -99,6 +112,80 @@
     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;
+    
+    if(args->multiselection) {
+        tableview.allowsMultipleSelection = YES;
+    }
+    
+    UiLayout layout = UI_INIT_LAYOUT(args);
+    ui_container_add(obj, scrollview, &layout, TRUE);
+    
+    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;
+            if(width > 0) {
+                column.width = width;
+            }
+            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) {
@@ -121,3 +208,5 @@
     }
     [tableview selectRowIndexes:indexSet byExtendingSelection:NO];
 }
+
+
--- a/ui/ui/tree.h	Sat Aug 23 18:41:20 2025 +0200
+++ b/ui/ui/tree.h	Sun Aug 24 09:31:09 2025 +0200
@@ -256,6 +256,15 @@
 #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);

mercurial