ui/motif/list.c

branch
newapi
changeset 427
7ead63398a50
parent 406
0ebf9d7b23e8
--- 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;
+}

mercurial