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) +}