--- 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; +}