Wed, 01 Jan 2025 11:39:42 +0100
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);