diff options
| author | Pietro Gagliardi <[email protected]> | 2014-08-30 23:02:02 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-08-30 23:02:02 -0400 |
| commit | 77bf566ebbcb62acd4d08d905d9542d6ff9b6b80 (patch) | |
| tree | eeb8e72bc3bf57f5be7f0c0af4319189ac6de838 /table_unix.c | |
| parent | 155899c65ed32245e2ccad4197a10c77017d835b (diff) | |
...in with the new.
Diffstat (limited to 'table_unix.c')
| -rw-r--r-- | table_unix.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/table_unix.c b/table_unix.c new file mode 100644 index 0000000..ed06bb6 --- /dev/null +++ b/table_unix.c @@ -0,0 +1,270 @@ +// +build !windows,!darwin + +// 29 july 2014 + +#include "gtk_unix.h" +#include "_cgo_export.h" + +void tableAppendColumn(GtkTreeView *table, gint index, gchar *name, GtkCellRenderer *renderer, gchar *attribute) +{ + GtkTreeViewColumn *col; + + col = gtk_tree_view_column_new_with_attributes(name, renderer, + attribute, index, + NULL); + // allow columns to be resized + gtk_tree_view_column_set_resizable(col, TRUE); + gtk_tree_view_append_column(table, col); +} + +/* +how our GtkTreeIters are stored: + stamp: either GOOD_STAMP or BAD_STAMP + user_data: row index +Thanks to Company in irc.gimp.net/#gtk+ for suggesting the GSIZE_TO_POINTER() trick. +*/ +#define GOOD_STAMP 0x1234 +#define BAD_STAMP 0x5678 +#define FROM(x) ((gint) GPOINTER_TO_SIZE((x))) +#define TO(x) GSIZE_TO_POINTER((gsize) (x)) + +static void goTableModel_initGtkTreeModel(GtkTreeModelIface *); + +G_DEFINE_TYPE_WITH_CODE(goTableModel, goTableModel, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, goTableModel_initGtkTreeModel)) + +static void goTableModel_init(goTableModel *t) +{ + // do nothing +} + +static void goTableModel_dispose(GObject *obj) +{ + G_OBJECT_CLASS(goTableModel_parent_class)->dispose(obj); +} + +static void goTableModel_finalize(GObject *obj) +{ + G_OBJECT_CLASS(goTableModel_parent_class)->finalize(obj); +} + +// and now for the interface function definitions + +static GtkTreeModelFlags goTableModel_get_flags(GtkTreeModel *model) +{ + return GTK_TREE_MODEL_LIST_ONLY; +} + +// get_n_columns and get_column_type in Go + +static gboolean goTableModel_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) +{ + goTableModel *t = (goTableModel *) model; + gint index; + + if (gtk_tree_path_get_depth(path) != 1) + goto bad; + index = gtk_tree_path_get_indices(path)[0]; + if (index < 0) + goto bad; + if (index >= goTableModel_getRowCount(t->gotable)) + goto bad; + iter->stamp = GOOD_STAMP; + iter->user_data = TO(index); + return TRUE; +bad: + iter->stamp = BAD_STAMP; + return FALSE; +} + +static GtkTreePath *goTableModel_get_path(GtkTreeModel *model, GtkTreeIter *iter) +{ + // note: from this point forward, the GOOD_STAMP checks ensure that the index stored in iter is nonnegative + if (iter->stamp != GOOD_STAMP) + return NULL; // this is what both GtkListStore and GtkTreeStore do + return gtk_tree_path_new_from_indices(FROM(iter->user_data), -1); +} + +static void goTableModel_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value) +{ + goTableModel *t = (goTableModel *) model; + + if (iter->stamp != GOOD_STAMP) + return; // this is what both GtkListStore and GtkTreeStore do + goTableModel_do_get_value(t->gotable, FROM(iter->user_data), column, value); +} + +static gboolean goTableModel_iter_next(GtkTreeModel *model, GtkTreeIter *iter) +{ + goTableModel *t = (goTableModel *) model; + gint index; + + if (iter->stamp != GOOD_STAMP) + return FALSE; // this is what both GtkListStore and GtkTreeStore do + index = FROM(iter->user_data); + index++; + if (index >= goTableModel_getRowCount(t->gotable)) { + iter->stamp = BAD_STAMP; + return FALSE; + } + iter->user_data = TO(index); + return TRUE; +} + +static gboolean goTableModel_iter_previous(GtkTreeModel *model, GtkTreeIter *iter) +{ + goTableModel *t = (goTableModel *) model; + gint index; + + if (iter->stamp != GOOD_STAMP) + return FALSE; // this is what both GtkListStore and GtkTreeStore do + index = FROM(iter->user_data); + if (index <= 0) { + iter->stamp = BAD_STAMP; + return FALSE; + } + index--; + iter->user_data = TO(index); + return TRUE; +} + +static gboolean goTableModel_iter_children(GtkTreeModel *model, GtkTreeIter *child, GtkTreeIter *parent) +{ + goTableModel *t = (goTableModel *) model; + + if (parent == NULL && goTableModel_getRowCount(t->gotable) > 0) { + child->stamp = GOOD_STAMP; + child->user_data = 0; + return TRUE; + } + child->stamp = BAD_STAMP; + return FALSE; +} + +static gboolean goTableModel_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter) +{ + return FALSE; +} + +static gint goTableModel_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter) +{ + goTableModel *t = (goTableModel *) model; + + if (iter == NULL) + return goTableModel_getRowCount(t->gotable); + return 0; +} + +static gboolean goTableModel_iter_nth_child(GtkTreeModel *model, GtkTreeIter *child, GtkTreeIter *parent, gint n) +{ + goTableModel *t = (goTableModel *) model; + + if (parent == NULL && n >= 0 && n < goTableModel_getRowCount(t->gotable)) { + child->stamp = GOOD_STAMP; + child->user_data = TO(n); + return TRUE; + } + child->stamp = BAD_STAMP; + return FALSE; +} + +static gboolean goTableModel_iter_parent(GtkTreeModel *model, GtkTreeIter *parent, GtkTreeIter *child) +{ + parent->stamp = BAD_STAMP; + return FALSE; +} + +// end of interface definitions + +static void goTableModel_initGtkTreeModel(GtkTreeModelIface *interface) +{ + // don't chain; we have nothing to chain to +#define DEF(x) interface->x = goTableModel_ ## x; + DEF(get_flags) + DEF(get_n_columns) + DEF(get_column_type) + DEF(get_iter) + DEF(get_path) + DEF(get_value) + DEF(iter_next) + DEF(iter_previous) + DEF(iter_children) + DEF(iter_has_child) + DEF(iter_n_children) + DEF(iter_nth_child) + DEF(iter_parent) + // no need for ref_node and unref_node +} + +static GParamSpec *goTableModelProperties[2]; + +static void goTableModel_set_property(GObject *obj, guint id, const GValue *value, GParamSpec *pspec) +{ + goTableModel *t = (goTableModel *) obj; + + if (id == 1) { + t->gotable = (void *) g_value_get_pointer(value); + return; + } + G_OBJECT_WARN_INVALID_PROPERTY_ID(t, id, pspec); +} + +static void goTableModel_get_property(GObject *obj, guint id, GValue *value, GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID((goTableModel *) obj, id, pspec); +} + +static void goTableModel_class_init(goTableModelClass *class) +{ + G_OBJECT_CLASS(class)->dispose = goTableModel_dispose; + G_OBJECT_CLASS(class)->finalize = goTableModel_finalize; + G_OBJECT_CLASS(class)->set_property = goTableModel_set_property; + G_OBJECT_CLASS(class)->get_property = goTableModel_get_property; + + goTableModelProperties[1] = g_param_spec_pointer( + "gotable", + "go-table", + "Go-side *table value", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(G_OBJECT_CLASS(class), 2, goTableModelProperties); +} + +goTableModel *newTableModel(void *gotable) +{ + return (goTableModel *) g_object_new(goTableModel_get_type(), "gotable", (gpointer) gotable, NULL); +} + +// somewhat naive, but the only alternatives seem to be unloading/reloading the model (or the view!), which is bleh +void tableUpdate(goTableModel *t, gint old, gint new) +{ + gint i; + gint nUpdate; + GtkTreePath *path; + GtkTreeIter iter; + + iter.stamp = GOOD_STAMP; + // first, append extra items + if (old < new) { + for (i = old; i < new; i++) { + path = gtk_tree_path_new_from_indices(i, -1); + iter.user_data = TO(i); + g_signal_emit_by_name(t, "row-inserted", path, &iter); + } + nUpdate = old; + } else + nUpdate = new; + // next, update existing items + for (i = 0; i < nUpdate; i++) { + path = gtk_tree_path_new_from_indices(i, -1); + iter.user_data = TO(i); + g_signal_emit_by_name(t, "row-updated", path, &iter); + } + // finally, remove deleted items + if (old > new) + for (i = new; i < old; i++) { + // note that we repeatedly remove the row at index new, as that changes with each removal; NOT i + path = gtk_tree_path_new_from_indices(new, -1); + // row-deleted has no iter + g_signal_emit_by_name(t, "row-deleted", path); + } +} |
