From d018953d7ef1b276cc3229e04ba6fc75018c888a Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 2 Aug 2014 22:35:58 -0400 Subject: [PATCH] Split all the Control implementations into their own files and renamed the containerctrls implementation files to say tab instead as they only hold Tab. This is the first part of what should hopefully be the final restructuring. --- redo/basicctrls_unix.go | 186 -------------- redo/basicctrls_windows.go | 232 ------------------ redo/button_darwin.go | 52 ++++ redo/button_unix.go | 63 +++++ redo/button_windows.go | 77 ++++++ redo/checkbox_darwin.go | 27 ++ redo/checkbox_unix.go | 48 ++++ redo/checkbox_windows.go | 59 +++++ .../{basicctrls_darwin.go => label_darwin.go} | 95 ------- redo/label_unix.go | 71 ++++++ redo/label_windows.go | 68 +++++ redo/objc_darwin.h | 2 +- ...containerctrls_darwin.go => tab_darwin.go} | 0 .../{containerctrls_darwin.m => tab_darwin.m} | 0 redo/{containerctrls_unix.go => tab_unix.go} | 0 ...containerctrls_windows.c => tab_windows.c} | 0 ...ntainerctrls_windows.go => tab_windows.go} | 0 redo/textfield_darwin.go | 38 +++ redo/textfield_unix.go | 47 ++++ redo/textfield_windows.go | 50 ++++ 20 files changed, 601 insertions(+), 514 deletions(-) delete mode 100644 redo/basicctrls_unix.go delete mode 100644 redo/basicctrls_windows.go create mode 100644 redo/button_darwin.go create mode 100644 redo/button_unix.go create mode 100644 redo/button_windows.go create mode 100644 redo/checkbox_darwin.go create mode 100644 redo/checkbox_unix.go create mode 100644 redo/checkbox_windows.go rename redo/{basicctrls_darwin.go => label_darwin.go} (50%) create mode 100644 redo/label_unix.go create mode 100644 redo/label_windows.go rename redo/{containerctrls_darwin.go => tab_darwin.go} (100%) rename redo/{containerctrls_darwin.m => tab_darwin.m} (100%) rename redo/{containerctrls_unix.go => tab_unix.go} (100%) rename redo/{containerctrls_windows.c => tab_windows.c} (100%) rename redo/{containerctrls_windows.go => tab_windows.go} (100%) create mode 100644 redo/textfield_darwin.go create mode 100644 redo/textfield_unix.go create mode 100644 redo/textfield_windows.go 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 similarity index 50% rename from redo/basicctrls_darwin.go rename to 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 similarity index 100% rename from redo/containerctrls_darwin.go rename to redo/tab_darwin.go diff --git a/redo/containerctrls_darwin.m b/redo/tab_darwin.m similarity index 100% rename from redo/containerctrls_darwin.m rename to redo/tab_darwin.m diff --git a/redo/containerctrls_unix.go b/redo/tab_unix.go similarity index 100% rename from redo/containerctrls_unix.go rename to redo/tab_unix.go diff --git a/redo/containerctrls_windows.c b/redo/tab_windows.c similarity index 100% rename from redo/containerctrls_windows.c rename to redo/tab_windows.c diff --git a/redo/containerctrls_windows.go b/redo/tab_windows.go similarity index 100% rename from redo/containerctrls_windows.go rename to 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) +}