This commit is contained in:
Ben Campbell 2021-01-02 10:21:29 -05:00 committed by GitHub
commit bcb58c2e7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 0 deletions

29
ui.h
View File

@ -1383,6 +1383,9 @@ struct uiTableParams {
// If CellValue() for this column for any row returns NULL, that
// row will also use the default background color.
int RowBackgroundColorModelColumn;
// MultiSelect sets selection mode for the table.
// 0=single selection, 1=allow multiple rows to be selected
int MultiSelect;
};
// uiTable is a uiControl that shows tabular data, allowing users to
@ -1455,6 +1458,32 @@ _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.
// it's safe to fiddle with the Items data in place (eg a caller
// might want to sort them - that's ok). But probably best not to
// change NumItems or try to reallocate Items.
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);

View File

@ -18,6 +18,8 @@ struct uiTable {
// TODO document this properly
GHashTable *indeterminatePositions;
guint indeterminateTimer;
void (*onSelectionChanged)(uiTable *, void *);
void *onSelectionChangedData;
};
// use the same size as GtkFileChooserWidget's treeview
@ -494,9 +496,82 @@ static void uiTableDestroy(uiControl *c)
uiFreeControl(uiControl(t));
}
static void onChanged(GtkTreeSelection *sel, gpointer data)
{
uiTable* t = uiTable(data);
(*(t->onSelectionChanged))(t, t->onSelectionChangedData);
}
static void defaultOnSelectionChanged(uiTable *t, void *data)
{
// do nothing
}
void uiTableOnSelectionChanged(uiTable *t, void (*f)(uiTable *, void *), void *data)
{
t->onSelectionChanged = f;
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;
GtkTreeSelection* sel;
GtkSelectionMode selMode;
uiUnixNewControl(uiTable, t);
@ -520,5 +595,13 @@ uiTable *uiNewTable(uiTableParams *p)
t->indeterminatePositions = g_hash_table_new_full(rowcolHash, rowcolEqual,
uiprivFree, uiprivFree);
sel = gtk_tree_view_get_selection(t->tv);
selMode = GTK_SELECTION_SINGLE;
if (p->MultiSelect == 1)
selMode = GTK_SELECTION_MULTIPLE;
gtk_tree_selection_set_mode(sel, selMode);
g_signal_connect(sel, "changed", G_CALLBACK(onChanged), t);
uiTableOnSelectionChanged(t, defaultOnSelectionChanged, NULL);
return t;
}