From d57d2aa2de674039938080d78d9addf53dd6f3e0 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 21 Jul 2014 21:07:14 -0400 Subject: [PATCH] Added Checkbox on the GTK+ backend, added a checkbox to the test program, and fixed a small error in the GTK+ widgetbase.parent() that kept the new widget hidden. --- redo/common_unix.go | 11 +++++++++ redo/controls.go | 6 ++--- redo/controls_unix.go | 53 ++++++++++++++++++++++++++++++++++++++----- redo/zz_test.go | 7 ++++++ 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/redo/common_unix.go b/redo/common_unix.go index aab80bf..d88afbb 100644 --- a/redo/common_unix.go +++ b/redo/common_unix.go @@ -32,6 +32,17 @@ func freegstr(s *C.gchar) { C.free(unsafe.Pointer(s)) } +func fromgbool(b C.gboolean) bool { + return b != C.FALSE +} + +func togbool(b bool) C.gboolean { + if b == true { + return C.TRUE + } + return C.FALSE +} + func g_signal_connect(object C.gpointer, name string, to C.GCallback, data C.gpointer) { cname := togstr(name) defer freegstr(cname) diff --git a/redo/controls.go b/redo/controls.go index 38aca16..9752924 100644 --- a/redo/controls.go +++ b/redo/controls.go @@ -34,7 +34,7 @@ type Checkbox interface { Control // OnClicked sets the event handler for when the Checkbox is clicked (to change its toggle state). - // TODO change to OnCheckChanged or OnToggled? + // TODO change to OnToggled() or OnChecked()? OnClicked(func()) // Text and SetText are Requests that get and set the Checkbox's label text. @@ -49,7 +49,5 @@ type Checkbox interface { // NewCheckbox creates a new Checkbox with the given label text. // The Checkbox will be initially unchecked. func NewCheckbox(text string) Checkbox { -// return newCheckbox(text) -return nil -//TODO add checkbox after resolving other TODOs + return newCheckbox(text) } diff --git a/redo/controls_unix.go b/redo/controls_unix.go index 730e42b..42068d7 100644 --- a/redo/controls_unix.go +++ b/redo/controls_unix.go @@ -10,6 +10,7 @@ import ( // #include "gtk_unix.h" // extern void buttonClicked(GtkButton *, gpointer); +// extern void checkboxToggled(GtkToggleButton *, gpointer); import "C" type widgetbase struct { @@ -45,6 +46,8 @@ func (w *widgetbase) parent(win *window) { C.g_object_unref(C.gpointer(unsafe.Pointer(w.widget))) w.floating = false } + // make sure the new widget is shown + C.gtk_widget_show_all(w.widget) } type button struct { @@ -53,10 +56,8 @@ type button struct { clicked *event } -func newButton(text string) *button { - ctext := togstr(text) - defer freegstr(ctext) - widget := C.gtk_button_new_with_label(ctext) +// shared code for setting up buttons, check boxes, etc. +func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button { b := &button{ widgetbase: newWidget(widget), button: (*C.GtkButton)(unsafe.Pointer(widget)), @@ -64,12 +65,19 @@ func newButton(text string) *button { } g_signal_connect( C.gpointer(unsafe.Pointer(b.button)), - "clicked", - C.GCallback(C.buttonClicked), + event, + C.GCallback(handler), C.gpointer(unsafe.Pointer(b))) return b } +func newButton(text string) *button { + ctext := togstr(text) + defer freegstr(ctext) + widget := C.gtk_button_new_with_label(ctext) + return finishNewButton(widget, "clicked", C.buttonClicked) +} + func (b *button) OnClicked(e func()) { b.clicked.set(e) } @@ -90,3 +98,36 @@ func (b *button) SetText(text string) { defer freegstr(ctext) C.gtk_button_set_label(b.button, ctext) } + +type checkbox struct { + // embed button so its methods and events carry over + *button + toggle *C.GtkToggleButton + checkbox *C.GtkCheckButton +} + +func newCheckbox(text string) *checkbox { + ctext := togstr(text) + defer freegstr(ctext) + widget := C.gtk_check_button_new_with_label(ctext) + return &checkbox{ + button: finishNewButton(widget, "toggled", C.checkboxToggled), + toggle: (*C.GtkToggleButton)(unsafe.Pointer(widget)), + checkbox: (*C.GtkCheckButton)(unsafe.Pointer(widget)), + } +} + +//export checkboxToggled +func checkboxToggled(bwid *C.GtkToggleButton, data C.gpointer) { + // note that the finishNewButton() call uses the embedded *button as data + // this is fine because we're only deferring to buttonClicked() anyway + buttonClicked(nil, data) +} + +func (c *checkbox) Checked() bool { + return fromgbool(C.gtk_toggle_button_get_active(c.toggle)) +} + +func (c *checkbox) SetChecked(checked bool) { + C.gtk_toggle_button_set_active(c.toggle, togbool(checked)) +} diff --git a/redo/zz_test.go b/redo/zz_test.go index 1ea1276..f71fe5f 100644 --- a/redo/zz_test.go +++ b/redo/zz_test.go @@ -5,6 +5,7 @@ package ui // This file is called zz_test.go to keep it separate from the other files in this package (and because go test won't accept just test.go) import ( + "fmt" "flag" "testing" ) @@ -39,6 +40,12 @@ func init() { w.Close() Stop() done <- struct{}{} + } else { + c := NewCheckbox("You Should Now See Me Instead") + w.SetControl(c) + c.OnClicked(func() { + w.SetTitle(fmt.Sprint(c.Checked())) + }) } }) w.Show()