diff --git a/basicctrls.go b/basicctrls.go index 8e4e926..82caada 100644 --- a/basicctrls.go +++ b/basicctrls.go @@ -146,7 +146,6 @@ func NewTextbox() Textbox { // - TODO set increment? (work on windows) // - TODO set page step? // - TODO wrapping -// - TODO set/get integer value // - TODO negative values // - TODO ensuring values entered in text box stay within bounds type Spinbox interface { @@ -156,6 +155,10 @@ type Spinbox interface { // For SetValue, if the new value is outside the current range of the Spinbox, it is set to the nearest extremity. Value() int SetValue(value int) + + // OnChanged sets the event handler for when the Spinbox's value is changed. + // Under what conditions this event is raised when the user types into the Spinbox's edit field is platform-defined. + OnChanged(func()) } // NewSpinbox creates a new Spinbox with the given minimum and maximum. diff --git a/spinbox_darwin.go b/spinbox_darwin.go index 0d0d858..65274bd 100644 --- a/spinbox_darwin.go +++ b/spinbox_darwin.go @@ -21,12 +21,14 @@ import "C" // - proper spacing between edit and spinner: Interface Builder isn't clear; NSDatePicker doesn't spill the beans type spinbox struct { - id C.id + id C.id + changed *event } func newSpinbox(min int, max int) Spinbox { s := new(spinbox) s.id = C.newSpinbox(unsafe.Pointer(s), C.intmax_t(min), C.intmax_t(max)) + s.changed = newEvent() return s } @@ -38,6 +40,16 @@ func (s *spinbox) SetValue(value int) { C.spinboxSetValue(s.id, C.intmax_t(value)) } +func (s *spinbox) OnChanged(e func()) { + s.changed.set(e) +} + +//export spinboxChanged +func spinboxChanged(data unsafe.Pointer) { + s := (*spinbox)(data) + s.changed.fire() +} + func (s *spinbox) textfield() C.id { return C.spinboxTextField(s.id) } diff --git a/spinbox_darwin.m b/spinbox_darwin.m index 9693669..fddfbfd 100644 --- a/spinbox_darwin.m +++ b/spinbox_darwin.m @@ -84,11 +84,13 @@ - (IBAction)stepperClicked:(id)sender { [self setValue:[self->stepper integerValue]]; + spinboxChanged(self->gospinbox); } - (void)controlTextDidChange:(NSNotification *)note { [self setValue:[self->textfield integerValue]]; + spinboxChanged(self->gospinbox); } @end diff --git a/spinbox_unix.go b/spinbox_unix.go index b6b2ec3..ca84b28 100644 --- a/spinbox_unix.go +++ b/spinbox_unix.go @@ -9,6 +9,7 @@ import ( ) // #include "gtk_unix.h" +// extern void spinboxChanged(GtkSpinButton *, gpointer); import "C" // TODO preferred width may be too wide @@ -16,6 +17,7 @@ import "C" type spinbox struct { *controlSingleWidget spinbutton *C.GtkSpinButton + changed *event } func newSpinbox(min int, max int) Spinbox { @@ -24,9 +26,18 @@ func newSpinbox(min int, max int) Spinbox { s := &spinbox{ controlSingleWidget: newControlSingleWidget(widget), spinbutton: (*C.GtkSpinButton)(unsafe.Pointer(widget)), + changed: newEvent(), } C.gtk_spin_button_set_digits(s.spinbutton, 0) // integers C.gtk_spin_button_set_numeric(s.spinbutton, C.TRUE) // digits only + // this isn't specifically documented as the signal to connect to until 3.14 + // it has existed as far back as 3.4, though, if not earlier + // there's also ::change-value which is for keyboard changing + g_signal_connect( + C.gpointer(unsafe.Pointer(s.spinbutton)), + "value-changed", + C.GCallback(C.spinboxChanged), + C.gpointer(unsafe.Pointer(s))) return s } @@ -46,3 +57,13 @@ func (s *spinbox) SetValue(value int) { } C.gtk_spin_button_set_value(s.spinbutton, C.gdouble(value)) } + +func (s *spinbox) OnChanged(e func()) { + s.changed.set(e) +} + +//export spinboxChanged +func spinboxChanged(swid *C.GtkSpinButton, data C.gpointer) { + s := (*spinbox)(unsafe.Pointer(data)) + s.changed.fire() +} diff --git a/zz_test.go b/zz_test.go index afe3c04..bf11488 100644 --- a/zz_test.go +++ b/zz_test.go @@ -150,15 +150,11 @@ func (tw *testwin) addfe() { tw.festack.SetStretchy(4) tw.festack.SetStretchy(6) sb := NewSpinbox(0, 100) - cbutton := NewButton("Set to Invalid Low") - cbutton.OnClicked(func() { - sb.SetValue(-500) + sl := NewLabel("") + sb.OnChanged(func() { + sl.SetText(fmt.Sprintf("%d", sb.Value())) }) - dbutton := NewButton("Set to Invalid High") - dbutton.OnClicked(func() { - sb.SetValue(500) - }) - tw.festack2 = newVerticalStack(sb, cbutton, dbutton, Space(), NewTextbox()) + tw.festack2 = newVerticalStack(sb, sl, Space(), Space(), NewTextbox()) tw.festack2.SetStretchy(3) tw.festack2.SetStretchy(4) tw.festack = newHorizontalStack(tw.festack, tw.festack2)