implement listview (Motif) newapi

Wed, 01 Jan 2025 11:39:42 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 01 Jan 2025 11:39:42 +0100
branch
newapi
changeset 427
7ead63398a50
parent 426
3eb26df703bf
child 428
c7dcd2ab2d3d

implement listview (Motif)

application/main.c file | annotate | diff | comparison | revisions
ui/motif/list.c file | annotate | diff | comparison | revisions
ui/motif/list.h file | annotate | diff | comparison | revisions
ui/motif/toolkit.c file | annotate | diff | comparison | revisions
ui/motif/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Tue Dec 31 17:57:43 2024 +0100
+++ b/application/main.c	Wed Jan 01 11:39:42 2025 +0100
@@ -546,9 +546,33 @@
 
 typedef struct WData {
     UiString *path;
+    UiList *list;
 } WData;
 
 
+int lsitems = 4;
+
+void action_button2(UiEvent *event, void *data) {
+    WData *wdata = event->window;
+    char *newitem = malloc(32);
+    snprintf(newitem, 32, "List Item %d", ++lsitems);
+    ui_list_append(wdata->list, newitem);
+    ui_list_update(wdata->list);
+    UiListSelection sel;
+    int index = lsitems-1;
+    sel.count = 1;
+    sel.rows = &index;
+    wdata->list->setselection(wdata->list, sel);
+}
+
+void action_listevent(UiEvent *event, void *data) {
+    printf("%s: %d\n", data, event->intval);
+    UiListSelection *sel = event->eventdata;
+    for(int i=0;i<sel->count;i++) {
+        printf("sel: %d\n", sel->rows[i]);
+    }
+    printf("\n");
+}
 
 void application_startup(UiEvent *event, void *data) {
     
@@ -562,41 +586,20 @@
     
     WData *wdata = ui_malloc(obj->ctx, sizeof(WData));
     wdata->path = ui_string_new(obj->ctx, NULL);
+    wdata->list = ui_list_new(obj->ctx, NULL);
     obj->window = wdata;
     
-    /*
-    ui_button(obj, .label = "Add Item", .onclick = action_button, .name = "mybutton1");
-    ui_button(obj, .label = "Test2", .name = "mybutton2");
-    ui_button(obj, .label = "Test3", .name = "mybutton3");
-    ui_hbox0(obj) {
-        ui_button(obj, .label = "hbutton1");
-        ui_button(obj, .label = "hbutton2");
-        ui_button(obj, .label = "hbutton3", .fill = UI_ON);
-        ui_button(obj, .label = "hbutton4");
-        ui_button(obj, .label = "hbutton5");
-        
-    }
-    ui_button(obj, .label = "Test4", .name = "mybutton4", .fill = UI_ON);
-    ui_button(obj, .label = "end");
-    */
+    ui_list_append(wdata->list, "List Item 1");
+    ui_list_append(wdata->list, "List Item 2");
+    ui_list_append(wdata->list, "List Item 3");
+    ui_list_append(wdata->list, "List Item 4");
     
-    ui_grid(obj, .columnspacing = 10, .rowspacing = 20, .fill = UI_ON) {
-        ui_button(obj, .label = "Add Item", .onclick = action_button, .name = "mybutton1");
-        ui_newline(obj);
-        ui_button(obj, .label = "Line 2 B1");
-        ui_button(obj, .label = "Line 2 B2");
-        ui_button(obj, .label = "Line 2 B3");
-        ui_newline(obj);
-        ui_button(obj, .label = "Line 3", .colspan = 3, .hfill = TRUE, .vexpand = TRUE, .vfill = TRUE);
-        ui_newline(obj);
-        ui_button(obj, .label = "Line 4 B1");
-        ui_button(obj, .label = "Line 4 B2");
-        ui_button(obj, .label = "Line 4 B3");
-        ui_button(obj, .label = "Line 4 B4", .hexpand = TRUE, .hfill = TRUE);
-        ui_button(obj, .label = "Line EOL");
-        ui_newline(obj);
-        ui_button(obj, .colspan = 5, .hfill = TRUE, .label = "EOL");
-    }
+    ui_button(obj, .label = "Add Menu Item", .onclick = action_button, .name = "mybutton1");
+    ui_button(obj, .label = "Add List Item", .onclick = action_button2);
+    ui_listview(obj, .list = wdata->list, .fill = UI_ON, .multiselection = TRUE,
+            .onactivate = action_listevent, .onactivatedata = "activate",
+            .onselection = action_listevent, .onselectiondata = "selection");
+    
     
     ui_show(obj);
 }
--- a/ui/motif/list.c	Tue Dec 31 17:57:43 2024 +0100
+++ b/ui/motif/list.c	Wed Jan 01 11:39:42 2025 +0100
@@ -34,3 +34,165 @@
 #include "list.h"
 #include "../common/object.h"
 
+UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) {
+    Arg xargs[16];
+    int n = 0;
+    
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
+    
+    if(args.multiselection) {
+        XtSetArg(xargs[n], XmNselectionPolicy, XmEXTENDED_SELECT); n++;
+    } else {
+        XtSetArg(xargs[n], XmNselectionPolicy, XmSINGLE_SELECT); n++;
+    }
+    
+    char *name = args.name ? (char*)args.name : "listview";
+    Widget parent = ctn->prepare(ctn, xargs, &n);
+    Widget widget = XmCreateScrolledList(parent, name, xargs, n);
+    XtManageChild(widget);
+    
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.list, args.varname, UI_VAR_LIST);
+    
+    UiListView *listview = malloc(sizeof(UiListView));
+    memset(listview, 0, sizeof(UiListView));
+    listview->obj = obj;
+    listview->widget = widget;
+    listview->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue;
+    listview->var = var;
+    listview->onactivate = args.onactivate;
+    listview->onactivatedata = args.onactivatedata;
+    listview->onselection = args.onselection;
+    listview->onselectiondata = args.onselectiondata;
+    
+    if(var) {
+        UiList *list = var->value;
+        list->obj = listview;
+        list->update = ui_listview_update;
+        list->getselection = ui_listview_getselection;
+        list->setselection = ui_listview_setselection;
+        ui_listview_update(list, 0);
+    }
+    
+    XtAddCallback(
+                widget,
+                XmNdestroyCallback,
+                (XtCallbackProc)ui_listview_destroy,
+                listview);
+    
+    XtAddCallback(
+                widget,
+                XmNdefaultActionCallback,
+                (XtCallbackProc)ui_listview_activate,
+                listview);
+    XtAddCallback(
+                widget,
+                XmNextendedSelectionCallback,
+                (XtCallbackProc)ui_listview_selection,
+                listview);
+    XtAddCallback(
+                widget,
+                XmNsingleSelectionCallback,
+                (XtCallbackProc)ui_listview_selection,
+                listview);
+    
+    return widget;
+}
+
+void ui_listview_destroy(Widget w, UiListView *listview, XtPointer d) {
+    // TODO
+}
+
+static void list_callback(UiObject *obj, UiListSelection sel, ui_callback callback, void *userdata) {
+    UiEvent event;
+    event.obj = obj;
+    event.window = obj->window;
+    event.document = obj->ctx->document;
+    event.eventdata = &sel;
+    event.intval = sel.count > 0 ? sel.rows[0] : -1;
+    callback(&event, userdata);
+}
+
+static void listview_save_selection(UiListView *listview, XmListCallbackStruct *cb) {
+    UiListSelection sel = { cb->selected_item_count, NULL };
+    if(sel.count > 0) {
+        sel.rows = calloc(sel.count, sizeof(int));
+        for(int i=0;i<sel.count;i++) {
+            sel.rows[i] = cb->selected_item_positions[i]-1;
+        }
+    }
+    free(listview->current_selection.rows);
+    listview->current_selection = sel;
+}
+
+void ui_listview_activate(Widget w, UiListView *listview, XmListCallbackStruct *cb) {
+    listview_save_selection(listview, cb);
+    if(listview->onactivate) {
+        list_callback(listview->obj, listview->current_selection, listview->onactivate, listview->onactivatedata);
+    }
+}
+
+void ui_listview_selection(Widget w, UiListView *listview, XmListCallbackStruct *cb) {
+    listview_save_selection(listview, cb);
+    if(listview->onselection) {
+        list_callback(listview->obj, listview->current_selection, listview->onselection, listview->onselectiondata);
+    }
+}
+
+static XmStringTable create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count) { 
+    int num = list->count(list);
+    XmStringTable items = (XmStringTable)XtMalloc(num * sizeof(XmString));
+    void *data = list->first(list);
+    for(int i=0;i<num;i++) {
+        char *s = getvalue(data, 0);
+        items[i] = XmStringCreateLocalized(s ? s : "");
+        data = list->next(list);
+    }
+    
+    *count = num;
+    return items;
+}
+
+void ui_listview_update(UiList *list, int i) {
+    UiListView *listview = list->obj;
+    
+    int count;
+    XmStringTable items = create_stringlist(
+            list,
+            listview->getvalue,
+            &count);
+    
+    XtVaSetValues(
+            listview->widget,
+            XmNitems, count == 0 ? NULL : items,
+            XmNitemCount,
+            count,
+            NULL);
+    
+    for (int i=0;i<count;i++) {
+        XmStringFree(items[i]);
+    }
+    XtFree((char *)items);
+}
+
+UiListSelection ui_listview_getselection(UiList *list) {
+    UiListView *listview = list->obj;
+    UiListSelection sel = { listview->current_selection.count, NULL };
+    if(sel.count > 0) {
+        sel.rows = calloc(sel.count, sizeof(int));
+        memcpy(sel.rows, listview->current_selection.rows, sel.count*sizeof(int));
+    }
+    return sel;
+}
+
+void ui_listview_setselection(UiList *list, UiListSelection selection) {
+    UiListView *listview = list->obj;
+    XmListDeselectAllItems(listview->widget);
+    for(int i=0;i<selection.count;i++) {
+        XmListSelectPos(listview->widget, selection.rows[i]+1, False);
+    }
+}
+
+void* ui_strmodel_getvalue(void *elm, int column) {
+    return column == 0 ? elm : NULL;
+}
--- a/ui/motif/list.h	Tue Dec 31 17:57:43 2024 +0100
+++ b/ui/motif/list.h	Wed Jan 01 11:39:42 2025 +0100
@@ -37,7 +37,38 @@
 extern "C" {
 #endif
 
+typedef struct UiListView {
+    UiObject *obj;
+    Widget widget;
+    UiVar *var;
+    UiModel* model;
+    ui_getvaluefunc getvalue;
     
+    UiListSelection current_selection;
+    
+    ui_callback onactivate;
+    void* onactivatedata;
+    ui_callback onselection;
+    void* onselectiondata;
+    ui_callback ondragstart;
+    void* ondragstartdata;
+    ui_callback ondragcomplete;
+    void* ondragcompletedata;
+    ui_callback ondrop;
+    void* ondropsdata;
+    UiBool multiselection;
+} UiListView;
+
+void ui_listview_destroy(Widget w, UiListView *listview, XtPointer d);
+
+void ui_listview_activate(Widget w, UiListView *listview, XmListCallbackStruct *cb);
+void ui_listview_selection(Widget w, UiListView *listview, XmListCallbackStruct *cb);
+
+void ui_listview_update(UiList *list, int i);
+UiListSelection ui_listview_getselection(UiList *list);
+void ui_listview_setselection(UiList *list, UiListSelection selection);
+
+void* ui_strmodel_getvalue(void *elm, int column);
 
 #ifdef	__cplusplus
 }
--- a/ui/motif/toolkit.c	Tue Dec 31 17:57:43 2024 +0100
+++ b/ui/motif/toolkit.c	Wed Jan 01 11:39:42 2025 +0100
@@ -309,7 +309,7 @@
             4);
 }
 
-void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d) {
+void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) {
     free(data);
 }
 
--- a/ui/motif/toolkit.h	Tue Dec 31 17:57:43 2024 +0100
+++ b/ui/motif/toolkit.h	Wed Jan 01 11:39:42 2025 +0100
@@ -92,7 +92,7 @@
 void ui_secondary_event_loop(int *loop);
 void ui_window_dark_theme(Display *dp, Window window);
 
-void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d);
+void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d);
 
 void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) ;
 void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups);

mercurial