summaryrefslogtreecommitdiff
path: root/redo
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-07-29 03:07:11 -0400
committerPietro Gagliardi <[email protected]>2014-07-29 03:07:11 -0400
commit24f5a91ff42031d65b64be724bc0237af96d6c05 (patch)
tree6639b890a3b19c6c4c6f1e08aa0f112f62036aa1 /redo
parent92539e10e90e197494a19324378cfb3815520f63 (diff)
Wrote the GTK+ Table model code. Mostly working; now it just needs an update mechanism...
Diffstat (limited to 'redo')
-rw-r--r--redo/gtk_unix.h2
-rw-r--r--redo/table_unix.c181
-rw-r--r--redo/table_unix.go44
3 files changed, 196 insertions, 31 deletions
diff --git a/redo/gtk_unix.h b/redo/gtk_unix.h
index 874e0f2..48b9918 100644
--- a/redo/gtk_unix.h
+++ b/redo/gtk_unix.h
@@ -23,7 +23,7 @@ Thanks to desrt in irc.gimp.net/#gtk+
#include <gtk/gtk.h>
/* table_unix.c */
-extern void tableAppendColumn(GtkTreeView *, gchar *);
+extern void tableAppendColumn(GtkTreeView *, gint, gchar *);
typedef struct goTableModel goTableModel;
typedef struct goTableModelClass goTableModelClass;
struct goTableModel {
diff --git a/redo/table_unix.c b/redo/table_unix.c
index 73902e1..0bd84de 100644
--- a/redo/table_unix.c
+++ b/redo/table_unix.c
@@ -3,18 +3,27 @@
#include "gtk_unix.h"
#include "_cgo_export.h"
-void tableAppendColumn(GtkTreeView *table, gchar *name)
+void tableAppendColumn(GtkTreeView *table, gint index, gchar *name)
{
GtkTreeViewColumn *col;
GtkCellRenderer *renderer;
renderer = gtk_cell_renderer_text_new();
col = gtk_tree_view_column_new_with_attributes(name, renderer,
- /* TODO */
+ "text", index,
NULL);
gtk_tree_view_append_column(table, col);
}
+/*
+how our GtkTreeIters are stored:
+ stamp: either GOOD_STAMP or BAD_STAMP
+ user_data: row index
+TODO verify range of gint
+*/
+#define GOOD_STAMP 0x1234
+#define BAD_STAMP 0x5678
+
static void goTableModel_initGtkTreeModel(GtkTreeModelIface *);
G_DEFINE_TYPE_WITH_CODE(goTableModel, goTableModel, G_TYPE_OBJECT,
@@ -42,35 +51,153 @@ static GtkTreeModelFlags goTableModel_get_flags(GtkTreeModel *model)
return GTK_TREE_MODEL_LIST_ONLY;
}
-static void goTableModel_initGtkTreeModel(GtkTreeModelIface *interface)
+/* get_n_columns in Go */
+
+static GType goTableModel_get_column_type(GtkTreeModel *model, gint column)
+{
+ /* TODO change when we get more column types */
+ return G_TYPE_STRING;
+}
+
+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 = (gpointer) index;
+ return TRUE;
+bad:
+ iter->stamp = BAD_STAMP;
+ return FALSE;
+}
+
+static GtkTreePath *goTableModel_get_path(GtkTreeModel *model, GtkTreeIter *iter)
+{
+ if (iter->stamp != GOOD_STAMP)
+ return NULL; /* TODO is this right? */
+ return gtk_tree_path_new_from_indices((gint) iter->user_data, -1);
+}
+
+static void goTableModel_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value)
+{
+ goTableModel *t = (goTableModel *) model;
+ gchar *str;
+
+ /* TODO what if iter is invalid? */
+ /* we (actually cgo) allocated str with malloc(), not g_malloc(), so let's free it explicitly and give the GValue a copy to be safe */
+ str = goTableModel_do_get_value(t->gotable, (gint) iter->user_data, column);
+ g_value_set_string(value, str);
+ free(str);
+}
+
+static gboolean goTableModel_iter_next(GtkTreeModel *model, GtkTreeIter *iter)
+{
+ goTableModel *t = (goTableModel *) model;
+ gint index;
+
+ if (iter->stamp != GOOD_STAMP)
+ return FALSE; /* TODO correct? */
+ index = (gint) iter->user_data;
+ index++;
+ iter->user_data = (gpointer) index;
+ if (index >= goTableModel_getRowCount(t->gotable)) {
+ iter->stamp = BAD_STAMP;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean goTableModel_iter_previous(GtkTreeModel *model, GtkTreeIter *iter)
+{
+ goTableModel *t = (goTableModel *) model;
+ gint index;
+
+ if (iter->stamp != GOOD_STAMP)
+ return FALSE; /* TODO correct? */
+ index = (gint) iter->user_data;
+ index--;
+ iter->user_data = (gpointer) index;
+ if (index < 0) {
+ iter->stamp = BAD_STAMP;
+ return FALSE;
+ }
+ 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 = (gpointer) n;
+ return TRUE;
+ }
+ child->stamp = BAD_STAMP;
+ return FALSE;
+}
+
+static gboolean goTableModel_iter_parent(GtkTreeModel *model, GtkTreeIter *parent, GtkTreeIter *child)
{
- GtkTreeModelIface *chain;
+ parent->stamp = BAD_STAMP;
+ return FALSE;
+}
- chain = (GtkTreeModelIface *) g_type_interface_peek_parent(interface);
+/* 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;
-#define CHAIN(x) interface->x = chain->x;
- /* signals */
- CHAIN(row_changed)
- CHAIN(row_inserted)
- CHAIN(row_has_child_toggled)
- CHAIN(row_deleted)
- CHAIN(rows_reordered)
- /* vtable */
DEF(get_flags)
- CHAIN(get_n_columns)
- CHAIN(get_column_type)
- CHAIN(get_iter)
- CHAIN(get_path)
- CHAIN(get_value)
- CHAIN(iter_next)
- CHAIN(iter_previous)
- CHAIN(iter_children)
- CHAIN(iter_has_child)
- CHAIN(iter_n_children)
- CHAIN(iter_nth_child)
- CHAIN(iter_parent)
- CHAIN(ref_node)
- CHAIN(unref_node)
+ 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];
diff --git a/redo/table_unix.go b/redo/table_unix.go
index 049945c..99a8a01 100644
--- a/redo/table_unix.go
+++ b/redo/table_unix.go
@@ -3,7 +3,7 @@
package ui
import (
-// "fmt"
+ "fmt"
"reflect"
"unsafe"
)
@@ -20,6 +20,12 @@ type table struct {
scrollc *C.GtkContainer
scrollwindow *C.GtkScrolledWindow
+
+ model *C.goTableModel
+ modelgtk *C.GtkTreeModel
+
+ // stuff required by GtkTreeModel
+ nColumns C.gint
}
func finishNewTable(b *tablebase, ty reflect.Type) Table {
@@ -37,12 +43,17 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
// give the scrolled window a border (thanks to jlindgren in irc.gimp.net/#gtk+)
C.gtk_scrolled_window_set_shadow_type(t.scrollwindow, C.GTK_SHADOW_IN)
C.gtk_container_add(t.scrollc, t.treewidget)
- // TODO model
+ model := C.newTableModel(unsafe.Pointer(t))
+ t.model = model
+ t.modelgtk = (*C.GtkTreeModel)(unsafe.Pointer(model))
+ C.gtk_tree_view_set_model(t.treeview, t.modelgtk)
for i := 0; i < ty.NumField(); i++ {
cname := togstr(ty.Field(i).Name)
- C.tableAppendColumn(t.treeview, cname)
+ C.tableAppendColumn(t.treeview, C.gint(i), cname)
freegstr(cname) // free now (not deferred) to conserve memory
}
+ // and for some GtkTreeModel boilerplate
+ t.nColumns = C.gint(ty.NumField())
return t
}
@@ -62,3 +73,30 @@ func (t *table) Unlock() {
defer t.RUnlock()
// TODO
}
+
+//export goTableModel_get_n_columns
+func goTableModel_get_n_columns(model *C.GtkTreeModel) C.gint {
+ tm := (*C.goTableModel)(unsafe.Pointer(model))
+ t := (*table)(tm.gotable)
+ return t.nColumns
+}
+
+//export goTableModel_do_get_value
+func goTableModel_do_get_value(data unsafe.Pointer, row C.gint, col C.gint) *C.gchar {
+ t := (*table)(data)
+ t.RLock()
+ defer t.RUnlock()
+ d := reflect.Indirect(reflect.ValueOf(t.data))
+ datum := d.Index(int(row)).Field(int(col))
+ s := fmt.Sprintf("%v", datum)
+ return togstr(s)
+}
+
+//export goTableModel_getRowCount
+func goTableModel_getRowCount(data unsafe.Pointer) C.gint {
+ t := (*table)(data)
+ t.RLock()
+ defer t.RUnlock()
+ d := reflect.Indirect(reflect.ValueOf(t.data))
+ return C.gint(d.Len())
+}