From 0856e953be71f13e4062c4e2ca44002ca4a68ac3 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 16 Feb 2014 23:50:54 -0500 Subject: [PATCH] Added GTK+ listboxes... sort of. This whole thing is so broken it's funny. --- gtkcalls_unix.go | 134 +++++++++++++++++++++++++++++++++++++++++++++++ sysdata_unix.go | 39 +++++++++----- 2 files changed, 161 insertions(+), 12 deletions(-) diff --git a/gtkcalls_unix.go b/gtkcalls_unix.go index c283034..f7c319e 100644 --- a/gtkcalls_unix.go +++ b/gtkcalls_unix.go @@ -13,6 +13,10 @@ import ( // #include // /* because cgo is flaky with macros */ // void gSignalConnect(GtkWidget *widget, char *signal, GCallback callback, void *data) { g_signal_connect(widget, signal, callback, data); } +// /* because cgo seems to choke on ... */ +// void gtkTreeModelGet(GtkTreeModel *model, GtkTreeIter *iter, gchar **gs) { gtk_tree_model_get(model, iter, 0, gs, -1); } +// GtkListStore *gtkListStoreNew(void) { return gtk_list_store_new(1, G_TYPE_STRING); } +// void gtkListStoreSet(GtkListStore *ls, GtkTreeIter *iter, char *gs) { gtk_list_store_set(ls, iter, 0, (gchar *) gs, -1); } import "C" // BIG TODO reduce the amount of explicit casting @@ -200,3 +204,133 @@ func gtk_label_set_text(widget *gtkWidget, text string) { func gtk_label_get_text(widget *gtkWidget) string { return C.GoString((*C.char)(unsafe.Pointer(C.gtk_label_get_text((*C.GtkLabel)(unsafe.Pointer(widget)))))) } + +func gListboxNew(multisel bool) *gtkWidget { + store := C.gtkListStoreNew() + widget := C.gtk_tree_view_new_with_model((*C.GtkTreeModel)(unsafe.Pointer(store))) + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + sel := C.GTK_SELECTION_SINGLE + if multisel { + sel = C.GTK_SELECTION_MULTIPLE + } + C.gtk_tree_selection_set_mode(C.gtk_tree_view_get_selection(tv), C.GtkSelectionMode(sel)) + return (*gtkWidget)(unsafe.Pointer(widget)) +} + +func gListboxNewSingle() *gtkWidget { + return gListboxNew(false) +} + +func gListboxNewMulti() *gtkWidget { + return gListboxNew(true) +} + +func gListboxText(widget *gtkWidget) string { + var model *C.GtkTreeModel + var iter C.GtkTreeIter + var gs *C.gchar + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + sel := C.gtk_tree_view_get_selection(tv) + if !fromgbool(C.gtk_tree_selection_get_selected(sel, &model, &iter)) { + return "" + } + C.gtkTreeModelGet(model, &iter, &gs) + return C.GoString((*C.char)(unsafe.Pointer(gs))) +} + +func gListboxAppend(widget *gtkWidget, what string) { + var iter C.GtkTreeIter + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv))) + C.gtk_list_store_append(ls, &iter) + cwhat := C.CString(what) + defer C.free(unsafe.Pointer(cwhat)) + C.gtkListStoreSet(ls, &iter, cwhat) +} + +func gListboxInsert(widget *gtkWidget, index int, what string) { + var iter C.GtkTreeIter + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv))) + C.gtk_list_store_insert(ls, &iter, C.gint(index)) + cwhat := C.CString(what) + defer C.free(unsafe.Pointer(cwhat)) + C.gtkListStoreSet(ls, &iter, cwhat) +} + +func gListboxSelected(widget *gtkWidget) int { + var model *C.GtkTreeModel + var iter C.GtkTreeIter + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + sel := C.gtk_tree_view_get_selection(tv) + if !fromgbool(C.gtk_tree_selection_get_selected(sel, &model, &iter)) { + return -1 + } + path := C.gtk_tree_model_get_path(model, &iter) + return int(*C.gtk_tree_path_get_indices(path)) +} + +func gListboxSelectedMulti(widget *gtkWidget) (indices []int) { + var model *C.GtkTreeModel + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + sel := C.gtk_tree_view_get_selection(tv) + rows := C.gtk_tree_selection_get_selected_rows(sel, &model) + defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free))) + len := C.g_list_length(rows) + if len == 0 { + return nil + } + indices = make([]int, len) + for i := C.guint(0); i < len; i++ { + d := (*C.GtkTreeRowReference)(unsafe.Pointer(rows.data)) + path := C.gtk_tree_row_reference_get_path(d) + indices[i] = int(*C.gtk_tree_path_get_indices(path)) + rows = rows.next + } + return indices +} + +func gListboxSelMultiTexts(widget *gtkWidget) (texts []string) { + var model *C.GtkTreeModel + var iter C.GtkTreeIter + var gs *C.gchar + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + sel := C.gtk_tree_view_get_selection(tv) + rows := C.gtk_tree_selection_get_selected_rows(sel, &model) + defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free))) + len := C.g_list_length(rows) + if len == 0 { + return nil + } + texts = make([]string, len) + for i := C.guint(0); i < len; i++ { + d := (*C.GtkTreeRowReference)(unsafe.Pointer(rows.data)) + path := C.gtk_tree_row_reference_get_path(d) + if !fromgbool(C.gtk_tree_model_get_iter(model, &iter, path)) { + // TODO + return + } + C.gtkTreeModelGet(model, &iter, &gs) + texts[i] = C.GoString((*C.char)(unsafe.Pointer(gs))) + rows = rows.next + } + return texts +} + +func gListboxDelete(widget *gtkWidget, index int) { + var iter C.GtkTreeIter + + tv := (*C.GtkTreeView)(unsafe.Pointer(widget)) + ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv))) + if !fromgbool(C.gtk_tree_model_iter_nth_child((*C.GtkTreeModel)(unsafe.Pointer(ls)), &iter, (*C.GtkTreeIter)(nil), C.gint(index))) { // no such index + // TODO + return + } + C.gtk_list_store_remove(ls, &iter) +} diff --git a/sysdata_unix.go b/sysdata_unix.go index fd15e1b..d2e6d16 100644 --- a/sysdata_unix.go +++ b/sysdata_unix.go @@ -23,7 +23,8 @@ type classData struct { append func(widget *gtkWidget, text string) insert func(widget *gtkWidget, index int, text string) selected func(widget *gtkWidget) int - // ... + selMulti func(widget *gtkWidget) []int + smtexts func(widget *gtkWidget) []string delete func(widget *gtkWidget, index int) // ... signals map[string]func(*sysData) func() bool @@ -98,6 +99,16 @@ var classTypes = [nctypes]*classData{ text: gtk_label_get_text, }, c_listbox: &classData{ + make: gListboxNewSingle, + makeAlt: gListboxNewMulti, + // TODO setText + text: gListboxText, + append: gListboxAppend, + insert: gListboxInsert, + selected: gListboxSelected, + selMulti: gListboxSelectedMulti, + smtexts: gListboxSelMultiTexts, + delete: gListboxDelete, }, } @@ -173,7 +184,9 @@ func (s *sysData) hide() error { } func (s *sysData) setText(text string) error { -if classTypes[s.ctype] == nil || classTypes[s.ctype].setText == nil { return nil } + if classTypes[s.ctype].setText == nil { // does not have concept of text + return nil + } ret := make(chan struct{}) defer close(ret) uitask <- func() { @@ -185,7 +198,6 @@ if classTypes[s.ctype] == nil || classTypes[s.ctype].setText == nil { return nil } func (s *sysData) setRect(x int, y int, width int, height int) error { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } ret := make(chan struct{}) defer close(ret) uitask <- func() { @@ -207,7 +219,6 @@ func (s *sysData) isChecked() bool { } func (s *sysData) text() string { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { println(s.ctype,"unsupported text()"); return "" } ret := make(chan string) defer close(ret) uitask <- func() { @@ -217,7 +228,6 @@ if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { println(s.cty } func (s *sysData) append(what string) error { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } ret := make(chan struct{}) defer close(ret) uitask <- func() { @@ -229,7 +239,6 @@ if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } } func (s *sysData) insertBefore(what string, before int) error { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } ret := make(chan struct{}) defer close(ret) uitask <- func() { @@ -241,7 +250,6 @@ if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } } func (s *sysData) selectedIndex() int { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return -1 } ret := make(chan int) defer close(ret) uitask <- func() { @@ -251,13 +259,21 @@ if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return -1 } } func (s *sysData) selectedIndices() []int { - // TODO - return nil + ret := make(chan []int) + defer close(ret) + uitask <- func() { + ret <- classTypes[s.ctype].selMulti(s.widget) + } + return <-ret } func (s *sysData) selectedTexts() []string { - // TODO - return nil + ret := make(chan []string) + defer close(ret) + uitask <- func() { + ret <- classTypes[s.ctype].smtexts(s.widget) + } + return <-ret } func (s *sysData) setWindowSize(width int, height int) error { @@ -272,7 +288,6 @@ func (s *sysData) setWindowSize(width int, height int) error { } func (s *sysData) delete(index int) error { -if classTypes[s.ctype] == nil || classTypes[s.ctype].make == nil { return nil } ret := make(chan struct{}) defer close(ret) uitask <- func() {