Implemented ImageList and Table ImageIndex on GTK+.
This commit is contained in:
parent
98647eb573
commit
37069eadcb
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue