summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redo/basicctrls_unix.go186
-rw-r--r--redo/basicctrls_windows.go232
-rw-r--r--redo/button_darwin.go52
-rw-r--r--redo/button_unix.go63
-rw-r--r--redo/button_windows.go77
-rw-r--r--redo/checkbox_darwin.go27
-rw-r--r--redo/checkbox_unix.go48
-rw-r--r--redo/checkbox_windows.go59
-rw-r--r--redo/label_darwin.go (renamed from redo/basicctrls_darwin.go)95
-rw-r--r--redo/label_unix.go71
-rw-r--r--redo/label_windows.go68
-rw-r--r--redo/objc_darwin.h2
-rw-r--r--redo/tab_darwin.go (renamed from redo/containerctrls_darwin.go)0
-rw-r--r--redo/tab_darwin.m (renamed from redo/containerctrls_darwin.m)0
-rw-r--r--redo/tab_unix.go (renamed from redo/containerctrls_unix.go)0
-rw-r--r--redo/tab_windows.c (renamed from redo/containerctrls_windows.c)0
-rw-r--r--redo/tab_windows.go (renamed from redo/containerctrls_windows.go)0
-rw-r--r--redo/textfield_darwin.go38
-rw-r--r--redo/textfield_unix.go47
-rw-r--r--redo/textfield_windows.go50
20 files changed, 601 insertions, 514 deletions
diff --git a/redo/basicctrls_unix.go b/redo/basicctrls_unix.go
deleted file mode 100644
index 734388c..0000000
--- a/redo/basicctrls_unix.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// +build !windows,!darwin
-
-// 7 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "gtk_unix.h"
-// extern void buttonClicked(GtkButton *, gpointer);
-// extern void checkboxToggled(GtkToggleButton *, gpointer);
-import "C"
-
-// TODOs:
-// - standalone label on its own: should it be centered or not?
-
-type button struct {
- *controlbase
- button *C.GtkButton
- clicked *event
-}
-
-// shared code for setting up buttons, check boxes, etc.
-func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button {
- b := &button{
- controlbase: newControl(widget),
- button: (*C.GtkButton)(unsafe.Pointer(widget)),
- clicked: newEvent(),
- }
- g_signal_connect(
- C.gpointer(unsafe.Pointer(b.button)),
- 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)
-}
-
-//export buttonClicked
-func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
- b := (*button)(unsafe.Pointer(data))
- b.clicked.fire()
- println("button clicked")
-}
-
-func (b *button) Text() string {
- return fromgstr(C.gtk_button_get_label(b.button))
-}
-
-func (b *button) SetText(text string) {
- ctext := togstr(text)
- 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))
-}
-
-type textField struct {
- *controlbase
- entry *C.GtkEntry
-}
-
-func startNewTextField() *textField {
- w := C.gtk_entry_new()
- return &textField{
- controlbase: newControl(w),
- entry: (*C.GtkEntry)(unsafe.Pointer(w)),
- }
-}
-
-func newTextField() *textField {
- return startNewTextField()
-}
-
-func newPasswordField() *textField {
- t := startNewTextField()
- C.gtk_entry_set_visibility(t.entry, C.FALSE)
- return t
-}
-
-func (t *textField) Text() string {
- return fromgstr(C.gtk_entry_get_text(t.entry))
-}
-
-func (t *textField) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_entry_set_text(t.entry, ctext)
-}
-
-type label struct {
- *controlbase
- misc *C.GtkMisc
- label *C.GtkLabel
- standalone bool
- supercommitResize func(c *allocation, d *sizing)
-}
-
-func finishNewLabel(text string, standalone bool) *label {
- ctext := togstr(text)
- defer freegstr(ctext)
- widget := C.gtk_label_new(ctext)
- l := &label{
- controlbase: newControl(widget),
- misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
- label: (*C.GtkLabel)(unsafe.Pointer(widget)),
- standalone: standalone,
- }
- l.supercommitResize = l.fcommitResize
- l.fcommitResize = l.labelcommitResize
- return l
-}
-
-func newLabel(text string) Label {
- return finishNewLabel(text, false)
-}
-
-func newStandaloneLabel(text string) Label {
- return finishNewLabel(text, true)
-}
-
-func (l *label) Text() string {
- return fromgstr(C.gtk_label_get_text(l.label))
-}
-
-func (l *label) SetText(text string) {
- ctext := togstr(text)
- defer freegstr(ctext)
- C.gtk_label_set_text(l.label, ctext)
-}
-
-func (l *label) labelcommitResize(c *allocation, d *sizing) {
- if !l.standalone && c.neighbor != nil {
- c.neighbor.getAuxResizeInfo(d)
- if d.shouldVAlignTop {
- // don't bother aligning it to the first line of text in the control; this is harder than it's worth (thanks gregier in irc.gimp.net/#gtk+)
- C.gtk_misc_set_alignment(l.misc, 0, 0)
- } else {
- C.gtk_misc_set_alignment(l.misc, 0, 0.5)
- }
- }
- l.supercommitResize(c, d)
-}
diff --git a/redo/basicctrls_windows.go b/redo/basicctrls_windows.go
deleted file mode 100644
index 9f5fe54..0000000
--- a/redo/basicctrls_windows.go
+++ /dev/null
@@ -1,232 +0,0 @@
-// 15 july 2014
-
-package ui
-
-import (
- "unsafe"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-type button struct {
- *controlbase
- clicked *event
-}
-
-var buttonclass = toUTF16("BUTTON")
-
-func startNewButton(text string, style C.DWORD) *button {
- c := newControl(buttonclass,
- style | C.WS_TABSTOP,
- 0)
- c.setText(text)
- C.controlSetControlFont(c.hwnd)
- b := &button{
- controlbase: c,
- clicked: newEvent(),
- }
- return b
-}
-
-func newButton(text string) *button {
- b := startNewButton(text, C.BS_PUSHBUTTON)
- C.setButtonSubclass(b.hwnd, unsafe.Pointer(b))
- b.fpreferredSize = b.buttonpreferredSize
- return b
-}
-
-func (b *button) OnClicked(e func()) {
- b.clicked.set(e)
-}
-
-func (b *button) Text() string {
- return b.text()
-}
-
-func (b *button) SetText(text string) {
- b.setText(text)
-}
-
-//export buttonClicked
-func buttonClicked(data unsafe.Pointer) {
- b := (*button)(data)
- b.clicked.fire()
- println("button clicked")
-}
-
-const (
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- buttonHeight = 14
-)
-
-func (b *button) buttonpreferredSize(d *sizing) (width, height int) {
- // common controls 6 thankfully provides a method to grab this...
- var size C.SIZE
-
- size.cx = 0 // explicitly ask for ideal size
- size.cy = 0
- if C.SendMessageW(b.hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
- return int(size.cx), int(size.cy)
- }
- // that failed, fall back
-println("message failed; falling back")
- // don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such)
- xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
- return xmargins + int(b.textlen), fromdlgunitsY(buttonHeight, d)
-}
-
-type checkbox struct {
- *button
-}
-
-func newCheckbox(text string) *checkbox {
- c := &checkbox{
- // don't use BS_AUTOCHECKBOX here because it creates problems when refocusing (see http://blogs.msdn.com/b/oldnewthing/archive/2014/05/22/10527522.aspx)
- // we'll handle actually toggling the check state ourselves (see controls_windows.c)
- button: startNewButton(text, C.BS_CHECKBOX),
- }
- c.fpreferredSize = c.checkboxpreferredSize
- C.setCheckboxSubclass(c.hwnd, unsafe.Pointer(c))
- return c
-}
-
-func (c *checkbox) Checked() bool {
- if C.checkboxChecked(c.hwnd) == C.FALSE {
- return false
- }
- return true
-}
-
-func (c *checkbox) SetChecked(checked bool) {
- if checked {
- C.checkboxSetChecked(c.hwnd, C.TRUE)
- return
- }
- C.checkboxSetChecked(c.hwnd, C.FALSE)
-}
-
-//export checkboxToggled
-func checkboxToggled(data unsafe.Pointer) {
- c := (*checkbox)(data)
- c.clicked.fire()
- println("checkbox toggled")
-}
-
-const (
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- checkboxHeight = 10
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
- checkboxXFromLeftOfBoxToLeftOfLabel = 12
-)
-
-func (c *checkbox) checkboxpreferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c.textlen),
- fromdlgunitsY(checkboxHeight, d)
-}
-
-type textField struct {
- *controlbase
-}
-
-var editclass = toUTF16("EDIT")
-
-func startNewTextField(style C.DWORD) *textField {
- c := newControl(editclass,
- style | C.ES_AUTOHSCROLL | C.ES_LEFT | C.ES_NOHIDESEL | C.WS_TABSTOP,
- C.WS_EX_CLIENTEDGE) // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
- C.controlSetControlFont(c.hwnd)
- t := &textField{
- controlbase: c,
- }
- t.fpreferredSize = t.textfieldpreferredSize
- return t
-}
-
-func newTextField() *textField {
- return startNewTextField(0)
-}
-
-func newPasswordField() *textField {
- return startNewTextField(C.ES_PASSWORD)
-}
-
-func (t *textField) Text() string {
- return t.text()
-}
-
-func (t *textField) SetText(text string) {
- t.setText(text)
-}
-
-const (
- // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- textfieldWidth = 107 // this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary
- textfieldHeight = 14
-)
-
-func (t *textField) textfieldpreferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
-}
-
-type label struct {
- *controlbase
- standalone bool
- supercommitResize func(c *allocation, d *sizing)
-}
-
-var labelclass = toUTF16("STATIC")
-
-func finishNewLabel(text string, standalone bool) *label {
- c := newControl(labelclass,
- // SS_NOPREFIX avoids accelerator translation; SS_LEFTNOWORDWRAP clips text past the end
- // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi)
- C.SS_NOPREFIX | C.SS_LEFTNOWORDWRAP,
- 0)
- c.setText(text)
- C.controlSetControlFont(c.hwnd)
- l := &label{
- controlbase: c,
- standalone: standalone,
- }
- l.fpreferredSize = l.labelpreferredSize
- l.supercommitResize = l.fcommitResize
- l.fcommitResize = l.labelcommitResize
- return l
-}
-
-func newLabel(text string) Label {
- return finishNewLabel(text, false)
-}
-
-func newStandaloneLabel(text string) Label {
- return finishNewLabel(text, true)
-}
-
-func (l *label) Text() string {
- return l.text()
-}
-
-func (l *label) SetText(text string) {
- l.setText(text)
-}
-
-const (
- // via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
- labelHeight = 8
- labelYOffset = 3
- // TODO the label is offset slightly by default...
-)
-
-func (l *label) labelpreferredSize(d *sizing) (width, height int) {
- return int(l.textlen), fromdlgunitsY(labelHeight, d)
-}
-
-func (l *label) labelcommitResize(c *allocation, d *sizing) {
- if !l.standalone {
- yoff := fromdlgunitsY(labelYOffset, d)
- c.y += yoff
- c.height -= yoff
- }
- l.supercommitResize(c, d)
-}
diff --git a/redo/button_darwin.go b/redo/button_darwin.go
new file mode 100644
index 0000000..e5a7f5b
--- /dev/null
+++ b/redo/button_darwin.go
@@ -0,0 +1,52 @@
+// 16 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "objc_darwin.h"
+import "C"
+
+type button struct {
+ *controlbase
+ clicked *event
+}
+
+func finishNewButton(id C.id, text string) *button {
+ ctext := C.CString(text)
+ defer C.free(unsafe.Pointer(ctext))
+ b := &button{
+ controlbase: newControl(id),
+ clicked: newEvent(),
+ }
+ C.buttonSetText(b.id, ctext)
+ C.buttonSetDelegate(b.id, unsafe.Pointer(b))
+ return b
+}
+
+func newButton(text string) *button {
+ return finishNewButton(C.newButton(), text)
+}
+
+func (b *button) OnClicked(e func()) {
+ b.clicked.set(e)
+}
+
+//export buttonClicked
+func buttonClicked(xb unsafe.Pointer) {
+ b := (*button)(unsafe.Pointer(xb))
+ b.clicked.fire()
+ println("button clicked")
+}
+
+func (b *button) Text() string {
+ return C.GoString(C.buttonText(b.id))
+}
+
+func (b *button) SetText(text string) {
+ ctext := C.CString(text)
+ defer C.free(unsafe.Pointer(ctext))
+ C.buttonSetText(b.id, ctext)
+}
diff --git a/redo/button_unix.go b/redo/button_unix.go
new file mode 100644
index 0000000..9811bda
--- /dev/null
+++ b/redo/button_unix.go
@@ -0,0 +1,63 @@
+// +build !windows,!darwin
+
+// 7 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "gtk_unix.h"
+// extern void buttonClicked(GtkButton *, gpointer);
+// extern void checkboxToggled(GtkToggleButton *, gpointer);
+import "C"
+
+type button struct {
+ *controlbase
+ button *C.GtkButton
+ clicked *event
+}
+
+// shared code for setting up buttons, check boxes, etc.
+func finishNewButton(widget *C.GtkWidget, event string, handler unsafe.Pointer) *button {
+ b := &button{
+ controlbase: newControl(widget),
+ button: (*C.GtkButton)(unsafe.Pointer(widget)),
+ clicked: newEvent(),
+ }
+ g_signal_connect(
+ C.gpointer(unsafe.Pointer(b.button)),
+ 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)
+}
+
+//export buttonClicked
+func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
+ b := (*button)(unsafe.Pointer(data))
+ b.clicked.fire()
+ println("button clicked")
+}
+
+func (b *button) Text() string {
+ return fromgstr(C.gtk_button_get_label(b.button))
+}
+
+func (b *button) SetText(text string) {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ C.gtk_button_set_label(b.button, ctext)
+}
diff --git a/redo/button_windows.go b/redo/button_windows.go
new file mode 100644
index 0000000..aa7a60a
--- /dev/null
+++ b/redo/button_windows.go
@@ -0,0 +1,77 @@
+// 15 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "winapi_windows.h"
+import "C"
+
+type button struct {
+ *controlbase
+ clicked *event
+}
+
+var buttonclass = toUTF16("BUTTON")
+
+func startNewButton(text string, style C.DWORD) *button {
+ c := newControl(buttonclass,
+ style | C.WS_TABSTOP,
+ 0)
+ c.setText(text)
+ C.controlSetControlFont(c.hwnd)
+ b := &button{
+ controlbase: c,
+ clicked: newEvent(),
+ }
+ return b
+}
+
+func newButton(text string) *button {
+ b := startNewButton(text, C.BS_PUSHBUTTON)
+ C.setButtonSubclass(b.hwnd, unsafe.Pointer(b))
+ b.fpreferredSize = b.buttonpreferredSize
+ return b
+}
+
+func (b *button) OnClicked(e func()) {
+ b.clicked.set(e)
+}
+
+func (b *button) Text() string {
+ return b.text()
+}
+
+func (b *button) SetText(text string) {
+ b.setText(text)
+}
+
+//export buttonClicked
+func buttonClicked(data unsafe.Pointer) {
+ b := (*button)(data)
+ b.clicked.fire()
+ println("button clicked")
+}
+
+const (
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
+ buttonHeight = 14
+)
+
+func (b *button) buttonpreferredSize(d *sizing) (width, height int) {
+ // common controls 6 thankfully provides a method to grab this...
+ var size C.SIZE
+
+ size.cx = 0 // explicitly ask for ideal size
+ size.cy = 0
+ if C.SendMessageW(b.hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
+ return int(size.cx), int(size.cy)
+ }
+ // that failed, fall back
+println("message failed; falling back")
+ // don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such)
+ xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
+ return xmargins + int(b.textlen), fromdlgunitsY(buttonHeight, d)
+}
diff --git a/redo/checkbox_darwin.go b/redo/checkbox_darwin.go
new file mode 100644
index 0000000..ee7e88c
--- /dev/null
+++ b/redo/checkbox_darwin.go
@@ -0,0 +1,27 @@
+// 16 july 2014
+
+package ui
+
+// #include "objc_darwin.h"
+import "C"
+
+type checkbox struct {
+ *button
+}
+
+func newCheckbox(text string) *checkbox {
+ return &checkbox{
+ button: finishNewButton(C.newCheckbox(), text),
+ }
+}
+
+// we don't need to define our own event here; we can just reuse Button's
+// (it's all target-action anyway)
+
+func (c *checkbox) Checked() bool {
+ return fromBOOL(C.checkboxChecked(c.id))
+}
+
+func (c *checkbox) SetChecked(checked bool) {
+ C.checkboxSetChecked(c.id, toBOOL(checked))
+}
diff --git a/redo/checkbox_unix.go b/redo/checkbox_unix.go
new file mode 100644
index 0000000..45048d1
--- /dev/null
+++ b/redo/checkbox_unix.go
@@ -0,0 +1,48 @@
+// +build !windows,!darwin
+
+// 7 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "gtk_unix.h"
+// extern void buttonClicked(GtkButton *, gpointer);
+// extern void checkboxToggled(GtkToggleButton *, gpointer);
+import "C"
+
+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/checkbox_windows.go b/redo/checkbox_windows.go
new file mode 100644
index 0000000..633f8e7
--- /dev/null
+++ b/redo/checkbox_windows.go
@@ -0,0 +1,59 @@
+// 15 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "winapi_windows.h"
+import "C"
+
+type checkbox struct {
+ *button
+}
+
+func newCheckbox(text string) *checkbox {
+ c := &checkbox{
+ // don't use BS_AUTOCHECKBOX here because it creates problems when refocusing (see http://blogs.msdn.com/b/oldnewthing/archive/2014/05/22/10527522.aspx)
+ // we'll handle actually toggling the check state ourselves (see controls_windows.c)
+ button: startNewButton(text, C.BS_CHECKBOX),
+ }
+ c.fpreferredSize = c.checkboxpreferredSize
+ C.setCheckboxSubclass(c.hwnd, unsafe.Pointer(c))
+ return c
+}
+
+func (c *checkbox) Checked() bool {
+ if C.checkboxChecked(c.hwnd) == C.FALSE {
+ return false
+ }
+ return true
+}
+
+func (c *checkbox) SetChecked(checked bool) {
+ if checked {
+ C.checkboxSetChecked(c.hwnd, C.TRUE)
+ return
+ }
+ C.checkboxSetChecked(c.hwnd, C.FALSE)
+}
+
+//export checkboxToggled
+func checkboxToggled(data unsafe.Pointer) {
+ c := (*checkbox)(data)
+ c.clicked.fire()
+ println("checkbox toggled")
+}
+
+const (
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
+ checkboxHeight = 10
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
+ checkboxXFromLeftOfBoxToLeftOfLabel = 12
+)
+
+func (c *checkbox) checkboxpreferredSize(d *sizing) (width, height int) {
+ return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c.textlen),
+ fromdlgunitsY(checkboxHeight, d)
+}
diff --git a/redo/basicctrls_darwin.go b/redo/label_darwin.go
index 13470f5..2e73b2e 100644
--- a/redo/basicctrls_darwin.go
+++ b/redo/label_darwin.go
@@ -2,104 +2,9 @@
package ui
-import (
- "unsafe"
-)
-
// #include "objc_darwin.h"
import "C"
-type button struct {
- *controlbase
- clicked *event
-}
-
-func finishNewButton(id C.id, text string) *button {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- b := &button{
- controlbase: newControl(id),
- clicked: newEvent(),
- }
- C.buttonSetText(b.id, ctext)
- C.buttonSetDelegate(b.id, unsafe.Pointer(b))
- return b
-}
-
-func newButton(text string) *button {
- return finishNewButton(C.newButton(), text)
-}
-
-func (b *button) OnClicked(e func()) {
- b.clicked.set(e)
-}
-
-//export buttonClicked
-func buttonClicked(xb unsafe.Pointer) {
- b := (*button)(unsafe.Pointer(xb))
- b.clicked.fire()
- println("button clicked")
-}
-
-func (b *button) Text() string {
- return C.GoString(C.buttonText(b.id))
-}
-
-func (b *button) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.buttonSetText(b.id, ctext)
-}
-
-type checkbox struct {
- *button
-}
-
-func newCheckbox(text string) *checkbox {
- return &checkbox{
- button: finishNewButton(C.newCheckbox(), text),
- }
-}
-
-// we don't need to define our own event here; we can just reuse Button's
-// (it's all target-action anyway)
-
-func (c *checkbox) Checked() bool {
- return fromBOOL(C.checkboxChecked(c.id))
-}
-
-func (c *checkbox) SetChecked(checked bool) {
- C.checkboxSetChecked(c.id, toBOOL(checked))
-}
-
-type textField struct {
- *controlbase
-}
-
-func finishNewTextField(id C.id) *textField {
- return &textField{
- controlbase: newControl(id),
- }
-}
-
-func newTextField() *textField {
- return finishNewTextField(C.newTextField())
-}
-
-func newPasswordField() *textField {
- return finishNewTextField(C.newPasswordField())
-}
-
-func (t *textField) Text() string {
- return C.GoString(C.textFieldText(t.id))
-}
-
-func (t *textField) SetText(text string) {
- ctext := C.CString(text)
- defer C.free(unsafe.Pointer(ctext))
- C.textFieldSetText(t.id, ctext)
-}
-
// cheap trick
type label struct {
*textField
diff --git a/redo/label_unix.go b/redo/label_unix.go
new file mode 100644
index 0000000..1776b73
--- /dev/null
+++ b/redo/label_unix.go
@@ -0,0 +1,71 @@
+// +build !windows,!darwin
+
+// 7 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "gtk_unix.h"
+// extern void buttonClicked(GtkButton *, gpointer);
+// extern void checkboxToggled(GtkToggleButton *, gpointer);
+import "C"
+
+// TODOs:
+// - standalone label on its own: should it be centered or not?
+
+type label struct {
+ *controlbase
+ misc *C.GtkMisc
+ label *C.GtkLabel
+ standalone bool
+ supercommitResize func(c *allocation, d *sizing)
+}
+
+func finishNewLabel(text string, standalone bool) *label {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ widget := C.gtk_label_new(ctext)
+ l := &label{
+ controlbase: newControl(widget),
+ misc: (*C.GtkMisc)(unsafe.Pointer(widget)),
+ label: (*C.GtkLabel)(unsafe.Pointer(widget)),
+ standalone: standalone,
+ }
+ l.supercommitResize = l.fcommitResize
+ l.fcommitResize = l.labelcommitResize
+ return l
+}
+
+func newLabel(text string) Label {
+ return finishNewLabel(text, false)
+}
+
+func newStandaloneLabel(text string) Label {
+ return finishNewLabel(text, true)
+}
+
+func (l *label) Text() string {
+ return fromgstr(C.gtk_label_get_text(l.label))
+}
+
+func (l *label) SetText(text string) {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ C.gtk_label_set_text(l.label, ctext)
+}
+
+func (l *label) labelcommitResize(c *allocation, d *sizing) {
+ if !l.standalone && c.neighbor != nil {
+ c.neighbor.getAuxResizeInfo(d)
+ if d.shouldVAlignTop {
+ // don't bother aligning it to the first line of text in the control; this is harder than it's worth (thanks gregier in irc.gimp.net/#gtk+)
+ C.gtk_misc_set_alignment(l.misc, 0, 0)
+ } else {
+ C.gtk_misc_set_alignment(l.misc, 0, 0.5)
+ }
+ }
+ l.supercommitResize(c, d)
+}
diff --git a/redo/label_windows.go b/redo/label_windows.go
new file mode 100644
index 0000000..e6b3e7f
--- /dev/null
+++ b/redo/label_windows.go
@@ -0,0 +1,68 @@
+// 15 july 2014
+
+package ui
+
+// #include "winapi_windows.h"
+import "C"
+
+type label struct {
+ *controlbase
+ standalone bool
+ supercommitResize func(c *allocation, d *sizing)
+}
+
+var labelclass = toUTF16("STATIC")
+
+func finishNewLabel(text string, standalone bool) *label {
+ c := newControl(labelclass,
+ // SS_NOPREFIX avoids accelerator translation; SS_LEFTNOWORDWRAP clips text past the end
+ // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi)
+ C.SS_NOPREFIX | C.SS_LEFTNOWORDWRAP,
+ 0)
+ c.setText(text)
+ C.controlSetControlFont(c.hwnd)
+ l := &label{
+ controlbase: c,
+ standalone: standalone,
+ }
+ l.fpreferredSize = l.labelpreferredSize
+ l.supercommitResize = l.fcommitResize
+ l.fcommitResize = l.labelcommitResize
+ return l
+}
+
+func newLabel(text string) Label {
+ return finishNewLabel(text, false)
+}
+
+func newStandaloneLabel(text string) Label {
+ return finishNewLabel(text, true)
+}
+
+func (l *label) Text() string {
+ return l.text()
+}
+
+func (l *label) SetText(text string) {
+ l.setText(text)
+}
+
+const (
+ // via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
+ labelHeight = 8
+ labelYOffset = 3
+ // TODO the label is offset slightly by default...
+)
+
+func (l *label) labelpreferredSize(d *sizing) (width, height int) {
+ return int(l.textlen), fromdlgunitsY(labelHeight, d)
+}
+
+func (l *label) labelcommitResize(c *allocation, d *sizing) {
+ if !l.standalone {
+ yoff := fromdlgunitsY(labelYOffset, d)
+ c.y += yoff
+ c.height -= yoff
+ }
+ l.supercommitResize(c, d)
+}
diff --git a/redo/objc_darwin.h b/redo/objc_darwin.h
index c745d1e..fd79c43 100644
--- a/redo/objc_darwin.h
+++ b/redo/objc_darwin.h
@@ -52,7 +52,7 @@ extern id newLabel(void);
/* sizing_darwin.m */
extern void moveControl(id, intptr_t, intptr_t, intptr_t, intptr_t);
-/* containerctrls_darwin.m */
+/* tab_darwin.m */
extern id newTab(void *);
extern id tabAppend(id, char *);
diff --git a/redo/containerctrls_darwin.go b/redo/tab_darwin.go
index ef834ad..ef834ad 100644
--- a/redo/containerctrls_darwin.go
+++ b/redo/tab_darwin.go
diff --git a/redo/containerctrls_darwin.m b/redo/tab_darwin.m
index c99e275..c99e275 100644
--- a/redo/containerctrls_darwin.m
+++ b/redo/tab_darwin.m
diff --git a/redo/containerctrls_unix.go b/redo/tab_unix.go
index 60978ea..60978ea 100644
--- a/redo/containerctrls_unix.go
+++ b/redo/tab_unix.go
diff --git a/redo/containerctrls_windows.c b/redo/tab_windows.c
index 5a998b5..5a998b5 100644
--- a/redo/containerctrls_windows.c
+++ b/redo/tab_windows.c
diff --git a/redo/containerctrls_windows.go b/redo/tab_windows.go
index e9d116b..e9d116b 100644
--- a/redo/containerctrls_windows.go
+++ b/redo/tab_windows.go
diff --git a/redo/textfield_darwin.go b/redo/textfield_darwin.go
new file mode 100644
index 0000000..0b248a7
--- /dev/null
+++ b/redo/textfield_darwin.go
@@ -0,0 +1,38 @@
+// 16 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "objc_darwin.h"
+import "C"
+
+type textField struct {
+ *controlbase
+}
+
+func finishNewTextField(id C.id) *textField {
+ return &textField{
+ controlbase: newControl(id),
+ }
+}
+
+func newTextField() *textField {
+ return finishNewTextField(C.newTextField())
+}
+
+func newPasswordField() *textField {
+ return finishNewTextField(C.newPasswordField())
+}
+
+func (t *textField) Text() string {
+ return C.GoString(C.textFieldText(t.id))
+}
+
+func (t *textField) SetText(text string) {
+ ctext := C.CString(text)
+ defer C.free(unsafe.Pointer(ctext))
+ C.textFieldSetText(t.id, ctext)
+}
diff --git a/redo/textfield_unix.go b/redo/textfield_unix.go
new file mode 100644
index 0000000..4d710b1
--- /dev/null
+++ b/redo/textfield_unix.go
@@ -0,0 +1,47 @@
+// +build !windows,!darwin
+
+// 7 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "gtk_unix.h"
+// extern void buttonClicked(GtkButton *, gpointer);
+// extern void checkboxToggled(GtkToggleButton *, gpointer);
+import "C"
+
+type textField struct {
+ *controlbase
+ entry *C.GtkEntry
+}
+
+func startNewTextField() *textField {
+ w := C.gtk_entry_new()
+ return &textField{
+ controlbase: newControl(w),
+ entry: (*C.GtkEntry)(unsafe.Pointer(w)),
+ }
+}
+
+func newTextField() *textField {
+ return startNewTextField()
+}
+
+func newPasswordField() *textField {
+ t := startNewTextField()
+ C.gtk_entry_set_visibility(t.entry, C.FALSE)
+ return t
+}
+
+func (t *textField) Text() string {
+ return fromgstr(C.gtk_entry_get_text(t.entry))
+}
+
+func (t *textField) SetText(text string) {
+ ctext := togstr(text)
+ defer freegstr(ctext)
+ C.gtk_entry_set_text(t.entry, ctext)
+}
diff --git a/redo/textfield_windows.go b/redo/textfield_windows.go
new file mode 100644
index 0000000..d325a18
--- /dev/null
+++ b/redo/textfield_windows.go
@@ -0,0 +1,50 @@
+// 15 july 2014
+
+package ui
+
+// #include "winapi_windows.h"
+import "C"
+
+type textField struct {
+ *controlbase
+}
+
+var editclass = toUTF16("EDIT")
+
+func startNewTextField(style C.DWORD) *textField {
+ c := newControl(editclass,
+ style | C.ES_AUTOHSCROLL | C.ES_LEFT | C.ES_NOHIDESEL | C.WS_TABSTOP,
+ C.WS_EX_CLIENTEDGE) // WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
+ C.controlSetControlFont(c.hwnd)
+ t := &textField{
+ controlbase: c,
+ }
+ t.fpreferredSize = t.textfieldpreferredSize
+ return t
+}
+
+func newTextField() *textField {
+ return startNewTextField(0)
+}
+
+func newPasswordField() *textField {
+ return startNewTextField(C.ES_PASSWORD)
+}
+
+func (t *textField) Text() string {
+ return t.text()
+}
+
+func (t *textField) SetText(text string) {
+ t.setText(text)
+}
+
+const (
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
+ textfieldWidth = 107 // this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary
+ textfieldHeight = 14
+)
+
+func (t *textField) textfieldpreferredSize(d *sizing) (width, height int) {
+ return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
+}