ui/win32/list.c

changeset 919
d9018dcd4e2d
parent 918
7d3dd5aacfda
child 936
d40a72210be8
--- a/ui/win32/list.c	Wed Nov 19 12:17:59 2025 +0100
+++ b/ui/win32/list.c	Wed Nov 19 13:02:55 2025 +0100
@@ -26,6 +26,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cx/array_list.h>
+
 #include "list.h"
 #include "container.h"
 
@@ -52,11 +57,14 @@
     return NULL;
 }
 
-
+/*
+ * Creates an UiListView widget object and initializes it from the UiListArgs
+ */
 static UiListView* create_listview_widget(UiObject *obj, HWND hwnd, UiListArgs *args, UiBool table) {
     UiListView *listview = w32_widget_create(&listview_widget_class, hwnd, sizeof(UiListView));
     listview->widget.hwnd = hwnd;
-    listview->preferred_width = args->width ? args->width : 300;
+    listview->obj = obj;
+    listview->preferred_width = args->width ? args->width : 300; // 300: default width/height
     listview->preferred_height = args->height ? args->height : 300;
     listview->onactivate = args->onactivate;
     listview->onactivatedata = args->onactivatedata;
@@ -70,6 +78,7 @@
     listview->ondropdata = args->ondropdata;
     listview->istable = table;
 
+    // convert ui_getvaluefunc into ui_getvaluefunc2 if necessary
     ui_getvaluefunc2 getvalue = args->getvalue2;
     void *getvaluedata = args->getvalue2data;
     if(!getvalue) {
@@ -105,7 +114,6 @@
             hInstance,
             NULL);
     ui_win32_set_ui_font(hwnd);
-
     ListView_SetExtendedListViewStyle(
         hwnd,
         LVS_EX_FULLROWSELECT //| LVS_EX_GRIDLINES
@@ -114,7 +122,8 @@
     UiListView *listview = create_listview_widget(obj, hwnd, args, table);
     ui_container_add(container, (W32Widget*)listview, &layout);
 
-    // model
+    // init list model
+    // always initialize listview->model
     int numcolumns = 0;
     if (table) {
         if (args->model) {
@@ -130,6 +139,7 @@
         numcolumns = 1;
     }
 
+    // create columns
     UiModel *model = listview->model;
     for (int i=0;i<numcolumns;i++) {
         LVCOLUMN col;
@@ -151,6 +161,7 @@
         ListView_InsertColumn(hwnd, i, &col);
     }
 
+    // bind the listview to the provided UiList
     if (listview->var) {
         UiList *list = listview->var->value;
         list->obj = listview;
@@ -164,8 +175,80 @@
     return (W32Widget*)listview;
 }
 
+static UiListSelection listview_get_selection(UiListView *listview) {
+    UiListSelection sel = { 0, NULL };
+    HWND hwnd = listview->widget.hwnd;
+
+    CX_ARRAY_DECLARE(int, indices);
+    cx_array_initialize(indices, 8);
+
+    int index = -1;
+    while ((index = ListView_GetNextItem(hwnd, index, LVNI_SELECTED)) != -1) {
+        cx_array_simple_add(indices, index);
+    }
+
+    if (indices_size > 0) {
+        sel.rows = indices;
+        sel.count = indices_size;
+    }
+
+    return sel;
+}
+
+// listview class event proc
 void ui_listview_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+    UiListView *listview = (UiListView*)widget;
+    switch (uMsg) {
+        case WM_NOTIFY: {
+            LPNMHDR hdr = (LPNMHDR)lParam;
+            switch (hdr->code) {
+                case LVN_ITEMCHANGED: {
+                    LPNMLISTVIEW lv = (LPNMLISTVIEW)lParam;
+                    int row = lv->iItem;
+                    if ((lv->uChanged & LVIF_STATE) && (lv->uNewState & LVIS_SELECTED) && listview->onselection) {
+                        UiListSelection sel = listview_get_selection(listview);
 
+                        UiEvent event;
+                        event.obj = listview->obj;
+                        event.window = listview->obj->window;
+                        event.document = listview->obj->ctx->document;
+                        event.eventdata = &sel;
+                        event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
+                        event.intval = row;
+                        event.set = ui_get_setop();
+                        listview->onselection(&event, listview->onselectiondata);
+
+                        ui_listselection_free(sel);
+                    }
+                    break;
+                }
+                case LVN_ITEMACTIVATE: {
+                    LPNMLISTVIEW lv = (LPNMLISTVIEW)lParam;
+                    int row = lv->iItem;
+                    if (listview->onactivate) {
+                        UiEvent event;
+                        event.obj = listview->obj;
+                        event.window = listview->obj->window;
+                        event.document = listview->obj->ctx->document;
+                        event.eventdata = NULL;
+                        event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
+                        event.intval = row;
+                        event.set = ui_get_setop();
+
+                        if (listview->var) {
+                            UiList *list = listview->var->value;
+                            event.eventdata = list->get(list, row);
+                            event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
+                        }
+
+                        listview->onactivate(&event, listview->onactivatedata);
+                    }
+                    break;
+                }
+            }
+            break;
+        }
+    }
 }
 
 W32Size ui_listview_get_preferred_size(W32Widget *widget) {
@@ -176,6 +259,13 @@
     return size;
 }
 
+/*
+ * Creates and inserts an LVITEM
+ *
+ * list: An UiList bound to an UiListView
+ * row: row index
+ * elm: list element (same as list->get(list, row))
+ */
 static void insert_item(UiList *list, int row, void *elm) {
     UiListView *listview = (UiListView*)list->obj;
     HWND hwnd = listview->widget.hwnd;
@@ -188,6 +278,8 @@
     int idx = -1;
     for (int col=0;col<model->columns;col++) {
         UiBool freeResult = FALSE;
+        // convert the list element to a value, that can be displayed in the list view
+        // TODO: handle all model types
         char *str = listview->getvalue(list, elm, row, col, listview->getvaluedata, &freeResult);
         if (col == 0) {
             item.pszText = str;
@@ -202,6 +294,12 @@
     }
 }
 
+/*
+ * UiList->update function
+ *
+ * Updates one or all rows
+ * row: list index or -1 for updating all rows
+ */
 void ui_listview_update(UiList *list, int row) {
     UiListView *listview = (UiListView*)list->obj;
     HWND hwnd = listview->widget.hwnd;
@@ -221,24 +319,27 @@
         insert_item(list, row, elm);
     }
 
+    // re-adjust all columns
     for (int i=0;i<model->columns;i++) {
         ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE);
     }
 }
 
 UiListSelection ui_listview_getselection(UiList *list) {
-    UiListSelection sel = { 0, NULL };
-    return sel;
+    UiListView *listview = (UiListView*)list->obj;
+    return listview_get_selection(listview);
 }
 
 void ui_listview_setselection(UiList *list, UiListSelection selection) {
 
 }
 
+// public API
 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
     return listview_create(obj, args, FALSE);
 }
 
+// public API
 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
     return listview_create(obj, args, TRUE);
 }

mercurial