diff --git a/ui.h b/ui.h index b6be8358..1064e2aa 100644 --- a/ui.h +++ b/ui.h @@ -1458,6 +1458,29 @@ _UI_EXTERN void uiTableAppendButtonColumn(uiTable *t, int buttonModelColumn, int buttonClickableModelColumn); +// uiTableOnSelectionChanged sets a callback to invoke upon changes +// in the set of selected items in the table. +_UI_EXTERN void uiTableOnSelectionChanged(uiTable *t, void (*f)(uiTable *t, void *data), void *data); + +// uiTableSelection holds an array of row indexes for a table. +typedef struct uiTableSelection uiTableSelection; +struct uiTableSelection +{ + int NumItems; + int* Items; +}; + +// uiTableCurrentSelection returns a uiTableSelection containing +// an array of all the selected rows in the table. +// If no rows are selected, a uiTableSelection will still be +// returned, with NumItems set to 0. +// The caller is responsible for calling uiFreeTableSelection() +// when finished with the uiTableSelection. +_UI_EXTERN uiTableSelection* uiTableCurrentSelection(uiTable* t); + +// uiFreeTableSelection frees any memory allocated to a uiTableSelection +_UI_EXTERN void uiFreeTableSelection(uiTableSelection* sel); + // uiNewTable() creates a new uiTable with the specified parameters. _UI_EXTERN uiTable *uiNewTable(uiTableParams *params); diff --git a/unix/table.c b/unix/table.c index f6b2328f..67d18343 100644 --- a/unix/table.c +++ b/unix/table.c @@ -511,6 +511,62 @@ void uiTableOnSelectionChanged(uiTable *t, void (*f)(uiTable *, void *), void *d t->onSelectionChangedData = data; } +// internal implementation of uiTableSelection (growable, because we +// don't know the size of the selection in advance under Gtk+) +// So we have extra stuff hanging on to the end of the public +// uiTableSelection we return, but callers don't have to care. +// Yay C! +struct growableTableSelection +{ + uiTableSelection sel; + int cap; + // TODO: could have an int here for single-selection case to avoid extra alloc... +}; + +static void collectSelection( GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + struct growableTableSelection* it = (struct growableTableSelection*)data; + int depth = gtk_tree_path_get_depth(path); + gint* indices = gtk_tree_path_get_indices(path); + if (depth < 1) { + return; + } + + // append to collection + if (it->sel.NumItems == it->cap) { + // initial alloc or grow + if (it->cap == 0) { + it->cap = 16; + } else { + it->cap *= 2; + } + it->sel.Items = uiprivRealloc(it->sel.Items, sizeof(int) * it->cap, "int[]"); + } + it->sel.Items[it->sel.NumItems++] = (int)indices[0]; +} + +uiTableSelection* uiTableCurrentSelection(uiTable* t) +{ + struct growableTableSelection* g = uiprivAlloc(sizeof(struct growableTableSelection), "uiTableSelection"); + g->sel.NumItems = 0; + g->sel.Items = NULL; + g->cap = 0; + gtk_tree_selection_selected_foreach( gtk_tree_view_get_selection(t->tv), collectSelection, (gpointer)g); + return (uiTableSelection*)g; +} + +void uiFreeTableSelection(uiTableSelection* sel) +{ + struct growableTableSelection* g = (struct growableTableSelection*)sel; + if (g->sel.Items) { + uiprivFree(g->sel.Items); + } + uiprivFree(g); +} + uiTable *uiNewTable(uiTableParams *p) { uiTable *t;