diff options
| -rw-r--r-- | redo/gtk_unix.h | 2 | ||||
| -rw-r--r-- | redo/imagelist_unix.go | 77 | ||||
| -rw-r--r-- | redo/table_unix.c | 21 | ||||
| -rw-r--r-- | redo/table_unix.go | 46 |
4 files changed, 124 insertions, 22 deletions
diff --git a/redo/gtk_unix.h b/redo/gtk_unix.h index a2883cd..98b9637 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 *, gint, gchar *); +extern void tableAppendColumn(GtkTreeView *, gint, gchar *, GtkCellRenderer *, gchar *); typedef struct goTableModel goTableModel; typedef struct goTableModelClass goTableModelClass; struct goTableModel { diff --git a/redo/imagelist_unix.go b/redo/imagelist_unix.go new file mode 100644 index 0000000..7c45bd4 --- /dev/null +++ b/redo/imagelist_unix.go @@ -0,0 +1,77 @@ + + +// 16 august 2014 + +package ui + +import ( + "fmt" + "unsafe" + "image" +) + +// #include "gtk_unix.h" +import "C" + +type imagelist struct { + list []*C.GdkPixbuf +} + +func newImageList() ImageList { + return new(imagelist) +} + +// this seems to be best (TODO see what other programs use) +const scaleTo = C.GTK_ICON_SIZE_MENU + +func (i *imagelist) Append(img *image.RGBA) { + var width, height C.gint + + surface := C.cairo_image_surface_create(C.CAIRO_FORMAT_ARGB32, + C.int(img.Rect.Dx()), + C.int(img.Rect.Dy())) + if status := C.cairo_surface_status(surface); status != C.CAIRO_STATUS_SUCCESS { + panic(fmt.Errorf("cairo_create_image_surface() failed in ImageList.Append(): %s\n", + C.GoString(C.cairo_status_to_string(status)))) + } + C.cairo_surface_flush(surface) + toARGB(img, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))), + int(C.cairo_image_surface_get_stride(surface))) + C.cairo_surface_mark_dirty(surface) + basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy())) + if basepixbuf == nil { + panic(fmt.Errorf("gdk_pixbuf_get_from_surface() failed in ImageList.Append() (no reason available)")) + } + + if C.gtk_icon_size_lookup(scaleTo, &width, &height) == C.FALSE { + panic(fmt.Errorf("gtk_icon_size_lookup() failed in ImageList.Append() (no reason available)")) + } + if int(width) == img.Rect.Dx() && int(height) == img.Rect.Dy() { + // just add the base pixbuf; we're good + i.list = append(i.list, basepixbuf) + C.cairo_surface_destroy(surface) + return + } + // else scale + pixbuf := C.gdk_pixbuf_scale_simple(basepixbuf, C.int(width), C.int(height), C.GDK_INTERP_NEAREST) + if pixbuf == nil { + panic(fmt.Errorf("gdk_pixbuf_scale_simple() failed in ImageList.Append() (no reason available)")) + } + + i.list = append(i.list, pixbuf) + C.gdk_pixbuf_unref(basepixbuf) + C.cairo_surface_destroy(surface) +} + +func (i *imagelist) Len() ImageIndex { + return ImageIndex(len(i.list)) +} + +type imageListApply interface { + apply(*[]*C.GdkPixbuf) +} + +func (i *imagelist) apply(out *[]*C.GdkPixbuf) { + *out = make([]*C.GdkPixbuf, len(i.list)) + copy(*out, i.list) +} diff --git a/redo/table_unix.c b/redo/table_unix.c index 8e29c72..ed06bb6 100644 --- a/redo/table_unix.c +++ b/redo/table_unix.c @@ -5,14 +5,12 @@ #include "gtk_unix.h" #include "_cgo_export.h" -void tableAppendColumn(GtkTreeView *table, gint index, gchar *name) +void tableAppendColumn(GtkTreeView *table, gint index, gchar *name, GtkCellRenderer *renderer, gchar *attribute) { GtkTreeViewColumn *col; - GtkCellRenderer *renderer; - renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes(name, renderer, - "text", index, + attribute, index, NULL); // allow columns to be resized gtk_tree_view_column_set_resizable(col, TRUE); @@ -57,12 +55,7 @@ static GtkTreeModelFlags goTableModel_get_flags(GtkTreeModel *model) return GTK_TREE_MODEL_LIST_ONLY; } -// get_n_columns in Go - -static GType goTableModel_get_column_type(GtkTreeModel *model, gint column) -{ - return G_TYPE_STRING; -} +// get_n_columns and get_column_type in Go static gboolean goTableModel_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) { @@ -95,16 +88,10 @@ static GtkTreePath *goTableModel_get_path(GtkTreeModel *model, GtkTreeIter *iter static void goTableModel_get_value(GtkTreeModel *model, GtkTreeIter *iter, gint column, GValue *value) { goTableModel *t = (goTableModel *) model; - gchar *str; if (iter->stamp != GOOD_STAMP) return; // this is what both GtkListStore and GtkTreeStore do - // 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, FROM(iter->user_data), column); - // value is uninitialized - g_value_init(value, G_TYPE_STRING); - g_value_set_string(value, str); - free(str); + goTableModel_do_get_value(t->gotable, FROM(iter->user_data), column, value); } static gboolean goTableModel_iter_next(GtkTreeModel *model, GtkTreeIter *iter) diff --git a/redo/table_unix.go b/redo/table_unix.go index d618663..1d2aaf2 100644 --- a/redo/table_unix.go +++ b/redo/table_unix.go @@ -23,11 +23,19 @@ type table struct { model *C.goTableModel modelgtk *C.GtkTreeModel + pixbufs []*C.GdkPixbuf + // stuff required by GtkTreeModel nColumns C.gint old C.gint + types []C.GType } +var ( + attribText = togstr("text") + attribPixbuf = togstr("pixbuf") +) + func finishNewTable(b *tablebase, ty reflect.Type) Table { widget := C.gtk_tree_view_new() t := &table{ @@ -42,7 +50,17 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table { 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, C.gint(i), cname) + switch ty.Field(i).Type { + case reflect.TypeOf(ImageIndex(0)): + // can't use GDK_TYPE_PIXBUF here because it's a macro that expands to a function and cgo hates that + t.types = append(t.types, C.gdk_pixbuf_get_type()) + C.tableAppendColumn(t.treeview, C.gint(i), cname, + C.gtk_cell_renderer_pixbuf_new(), attribPixbuf) + default: + t.types = append(t.types, C.G_TYPE_STRING) + C.tableAppendColumn(t.treeview, C.gint(i), cname, + C.gtk_cell_renderer_text_new(), attribText) + } freegstr(cname) // free now (not deferred) to conserve memory } // and for some GtkTreeModel boilerplate @@ -71,6 +89,10 @@ func (t *table) Unlock() { }() } +func (t *table) LoadImageList(i ImageList) { + i.apply(&t.pixbufs) +} + //export goTableModel_get_n_columns func goTableModel_get_n_columns(model *C.GtkTreeModel) C.gint { tm := (*C.goTableModel)(unsafe.Pointer(model)) @@ -78,15 +100,31 @@ func goTableModel_get_n_columns(model *C.GtkTreeModel) C.gint { return t.nColumns } +//export goTableModel_get_column_type +func goTableModel_get_column_type(model *C.GtkTreeModel, column C.gint) C.GType { + tm := (*C.goTableModel)(unsafe.Pointer(model)) + t := (*table)(tm.gotable) + return t.types[column] +} + //export goTableModel_do_get_value -func goTableModel_do_get_value(data unsafe.Pointer, row C.gint, col C.gint) *C.gchar { +func goTableModel_do_get_value(data unsafe.Pointer, row C.gint, col C.gint, value *C.GValue) { 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) + switch d := datum.Interface().(type) { + case ImageIndex: + C.g_value_init(value, C.gdk_pixbuf_get_type()) + C.g_value_set_object(value, C.gpointer(unsafe.Pointer(t.pixbufs[d]))) + default: + s := fmt.Sprintf("%v", datum) + str := togstr(s) + defer freegstr(str) + C.g_value_init(value, C.G_TYPE_STRING) + C.g_value_set_string(value, str) + } } //export goTableModel_getRowCount |
