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.
This commit is contained in:
parent
1f6bcde3d9
commit
d018953d7e
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue