summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-03 09:18:35 -0400
committerPietro Gagliardi <[email protected]>2014-08-03 09:18:35 -0400
commit1aea308645585f2fbc6c8b170381c811d562cc99 (patch)
tree1db721a972133a1ed0d9808eafabfbed66f6892f
parent585f5f5b62da3170d4398b39670d16811013d078 (diff)
Set up the Control restructure and migrated the Windows implementation over. Lots of repetition, but hopefully more correct and maintainable!
-rw-r--r--redo/button_windows.go38
-rw-r--r--redo/checkbox_windows.go56
-rw-r--r--redo/control.go62
-rw-r--r--redo/control_windows.go44
-rw-r--r--redo/label_windows.go32
-rw-r--r--redo/tab_windows.go62
-rw-r--r--redo/table_windows.go45
-rw-r--r--redo/textfield_windows.go27
8 files changed, 229 insertions, 137 deletions
diff --git a/redo/button_windows.go b/redo/button_windows.go
index aa7a60a..5deb53d 100644
--- a/redo/button_windows.go
+++ b/redo/button_windows.go
@@ -16,9 +16,9 @@ type button struct {
var buttonclass = toUTF16("BUTTON")
-func startNewButton(text string, style C.DWORD) *button {
+func newButton(text string) *button {
c := newControl(buttonclass,
- style | C.WS_TABSTOP,
+ C.BS_PUSHBUTTON | C.WS_TABSTOP,
0)
c.setText(text)
C.controlSetControlFont(c.hwnd)
@@ -26,13 +26,7 @@ func startNewButton(text string, style C.DWORD) *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
}
@@ -55,13 +49,29 @@ func buttonClicked(data unsafe.Pointer) {
println("button clicked")
}
+func (b *button) setParent(p *controlParent) {
+ basesetParent(b.controlbase, p)
+}
+
+func (b *button) containerShow() {
+ basecontainerShow(b.controlbase)
+}
+
+func (b *button) containerHide() {
+ basecontainerHide(b.controlbase)
+}
+
+func (b *button) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(b, x, y, width, height, d)
+}
+
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...
+func (b *button) preferredSize(d *sizing) (width, height int) {
+ // comctl32.dll version 6 thankfully provides a method to grab this...
var size C.SIZE
size.cx = 0 // explicitly ask for ideal size
@@ -75,3 +85,11 @@ println("message failed; falling back")
xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
return xmargins + int(b.textlen), fromdlgunitsY(buttonHeight, d)
}
+
+func (b *button) commitResize(a *allocation, d *sizing) {
+ basecommitResize(b.controlbase, a, d)
+}
+
+func (b *button) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
diff --git a/redo/checkbox_windows.go b/redo/checkbox_windows.go
index 633f8e7..2dcf519 100644
--- a/redo/checkbox_windows.go
+++ b/redo/checkbox_windows.go
@@ -10,20 +10,38 @@ import (
import "C"
type checkbox struct {
- *button
+ *controlbase
+ toggled *event
}
func newCheckbox(text string) *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)
+ cc := newControl(buttonclass,
+ C.BS_CHECKBOX | C.WS_TABSTOP,
+ 0)
+ cc.setText(text)
+ C.controlSetControlFont(cc.hwnd)
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),
+ controlbase: cc,
+ toggled: newEvent(),
}
- c.fpreferredSize = c.checkboxpreferredSize
C.setCheckboxSubclass(c.hwnd, unsafe.Pointer(c))
return c
}
+func (c *checkbox) OnToggled(e func()) {
+ c.toggled.set(e)
+}
+
+func (c *checkbox) Text() string {
+ return c.text()
+}
+
+func (c *checkbox) SetText(text string) {
+ c.setText(text)
+}
+
func (c *checkbox) Checked() bool {
if C.checkboxChecked(c.hwnd) == C.FALSE {
return false
@@ -42,10 +60,26 @@ func (c *checkbox) SetChecked(checked bool) {
//export checkboxToggled
func checkboxToggled(data unsafe.Pointer) {
c := (*checkbox)(data)
- c.clicked.fire()
+ c.toggled.fire()
println("checkbox toggled")
}
+func (c *checkbox) setParent(p *controlParent) {
+ basesetParent(c.controlbase, p)
+}
+
+func (c *checkbox) containerShow() {
+ basecontainerShow(c.controlbase)
+}
+
+func (c *checkbox) containerHide() {
+ basecontainerHide(c.controlbase)
+}
+
+func (c *checkbox) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(c, x, y, width, height, d)
+}
+
const (
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
checkboxHeight = 10
@@ -53,7 +87,15 @@ const (
checkboxXFromLeftOfBoxToLeftOfLabel = 12
)
-func (c *checkbox) checkboxpreferredSize(d *sizing) (width, height int) {
+func (c *checkbox) preferredSize(d *sizing) (width, height int) {
return fromdlgunitsX(checkboxXFromLeftOfBoxToLeftOfLabel, d) + int(c.textlen),
fromdlgunitsY(checkboxHeight, d)
}
+
+func (c *checkbox) commitResize(a *allocation, d *sizing) {
+ basecommitResize(c.controlbase, a, d)
+}
+
+func (c *checkbox) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
diff --git a/redo/control.go b/redo/control.go
index 0b88533..953e241 100644
--- a/redo/control.go
+++ b/redo/control.go
@@ -13,57 +13,13 @@ type Control interface {
controlSizing
}
-// All Controls on the backend (that is, everything except Stack and Grid) embed this structure, which provides the Control interface methods.
-// If a Control needs to override one of these functions, it assigns to the function variables.
-type controldefs struct {
- fsetParent func(p *controlParent)
- fcontainerShow func()
- fcontainerHide func()
- fallocate func(x int, y int, width int, height int, d *sizing) []*allocation
- fpreferredSize func(*sizing) (int, int)
- fcommitResize func(*allocation, *sizing)
- fgetAuxResizeInfo func(*sizing)
-}
-
-// There's no newcontroldefs() function; all defaults are set by controlbase.
-
-func (w *controldefs) setParent(p *controlParent) {
- w.fsetParent(p)
-}
-
-func (w *controldefs) containerShow() {
- w.fcontainerShow()
-}
-
-func (w *controldefs) containerHide() {
- w.fcontainerHide()
-}
-
-func (w *controldefs) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
- return w.fallocate(x, y, width, height, d)
-}
-
-func (w *controldefs) preferredSize(d *sizing) (int, int) {
- return w.fpreferredSize(d)
-}
-
-func (w *controldefs) commitResize(c *allocation, d *sizing) {
- w.fcommitResize(c, d)
-}
-
-func (w *controldefs) getAuxResizeInfo(d *sizing) {
- w.fgetAuxResizeInfo(d)
-}
-
-// and this is the same across all platforms
-func baseallocate(c *controlbase) func(x int, y int, width int, height int, d *sizing) []*allocation {
- return func(x int, y int, width int, height int, d *sizing) []*allocation {
- return []*allocation{&allocation{
- x: x,
- y: y,
- width: width,
- height: height,
- this: c,
- }}
- }
+// this is the same across all platforms
+func baseallocate(c Control, x int, y int, width int, height int, d *sizing) []*allocation {
+ return []*allocation{&allocation{
+ x: x,
+ y: y,
+ width: width,
+ height: height,
+ this: c,
+ }}
}
diff --git a/redo/control_windows.go b/redo/control_windows.go
index b2af110..fd0ccaa 100644
--- a/redo/control_windows.go
+++ b/redo/control_windows.go
@@ -6,7 +6,6 @@ package ui
import "C"
type controlbase struct {
- *controldefs
hwnd C.HWND
parent C.HWND // for Tab and Group
textlen C.LONG
@@ -18,29 +17,34 @@ type controlParent struct {
func newControl(class C.LPWSTR, style C.DWORD, extstyle C.DWORD) *controlbase {
c := new(controlbase)
+ // TODO rename to newWidget
c.hwnd = C.newWidget(class, style, extstyle)
- c.controldefs = new(controldefs)
- c.fsetParent = func(p *controlParent) {
- C.controlSetParent(c.hwnd, p.hwnd)
- c.parent = p.hwnd
- }
- c.fcontainerShow = func() {
- C.ShowWindow(c.hwnd, C.SW_SHOW)
- }
- c.fcontainerHide = func() {
- C.ShowWindow(c.hwnd, C.SW_HIDE)
- }
- c.fallocate = baseallocate(c)
- // don't specify c.fpreferredSize; it is custom on ALL controls
- c.fcommitResize = func(a *allocation, d *sizing) {
- C.moveWindow(c.hwnd, C.int(a.x), C.int(a.y), C.int(a.width), C.int(a.height))
- }
- c.fgetAuxResizeInfo = func(d *sizing) {
- // do nothing
- }
return c
}
+func basesetParent(c *controlbase, p *controlParent) {
+ C.controlSetParent(c.hwnd, p.hwnd)
+ c.parent = p.hwnd
+}
+
+func basecontainerShow(c *controlbase) {
+ C.ShowWindow(c.hwnd, C.SW_SHOW)
+}
+
+func basecontainerHide(c *controlbase) {
+ C.ShowWindow(c.hwnd, C.SW_HIDE)
+}
+
+// don't specify basepreferredSize; it is custom on ALL controls
+
+func basecommitResize(c *controlbase, a *allocation, d *sizing) {
+ C.moveWindow(c.hwnd, C.int(a.x), C.int(a.y), C.int(a.width), C.int(a.height))
+}
+
+func basegetAuxResizeInfo(d *sizing) {
+ // do nothing
+}
+
// these are provided for convenience
func (c *controlbase) text() string {
diff --git a/redo/label_windows.go b/redo/label_windows.go
index e6b3e7f..516a14c 100644
--- a/redo/label_windows.go
+++ b/redo/label_windows.go
@@ -7,8 +7,7 @@ import "C"
type label struct {
*controlbase
- standalone bool
- supercommitResize func(c *allocation, d *sizing)
+ standalone bool
}
var labelclass = toUTF16("STATIC")
@@ -25,9 +24,6 @@ func finishNewLabel(text string, standalone bool) *label {
controlbase: c,
standalone: standalone,
}
- l.fpreferredSize = l.labelpreferredSize
- l.supercommitResize = l.fcommitResize
- l.fcommitResize = l.labelcommitResize
return l
}
@@ -47,6 +43,22 @@ func (l *label) SetText(text string) {
l.setText(text)
}
+func (l *label) setParent(p *controlParent) {
+ basesetParent(l.controlbase, p)
+}
+
+func (l *label) containerShow() {
+ basecontainerShow(l.controlbase)
+}
+
+func (l *label) containerHide() {
+ basecontainerHide(l.controlbase)
+}
+
+func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(l, x, y, width, height, d)
+}
+
const (
// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
labelHeight = 8
@@ -54,15 +66,19 @@ const (
// TODO the label is offset slightly by default...
)
-func (l *label) labelpreferredSize(d *sizing) (width, height int) {
+func (l *label) preferredSize(d *sizing) (width, height int) {
return int(l.textlen), fromdlgunitsY(labelHeight, d)
}
-func (l *label) labelcommitResize(c *allocation, d *sizing) {
+func (l *label) commitResize(c *allocation, d *sizing) {
if !l.standalone {
yoff := fromdlgunitsY(labelYOffset, d)
c.y += yoff
c.height -= yoff
}
- l.supercommitResize(c, d)
+ basecommitResize(l.controlbase, c, d)
+}
+
+func (l *label) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
}
diff --git a/redo/tab_windows.go b/redo/tab_windows.go
index e9d116b..032da7e 100644
--- a/redo/tab_windows.go
+++ b/redo/tab_windows.go
@@ -19,9 +19,7 @@ TODO
type tab struct {
*controlbase
- tabs []*sizer
- supersetParent func(p *controlParent)
- superallocate func(x int, y int, width int, height int, d *sizing) []*allocation
+ tabs []*sizer
}
func newTab() Tab {
@@ -31,23 +29,11 @@ func newTab() Tab {
t := &tab{
controlbase: c,
}
- t.supersetParent = t.fsetParent
- t.fsetParent = t.tabsetParent
- t.fpreferredSize = t.tabpreferredSize
- t.superallocate = t.fallocate
- t.fallocate = t.taballocate
C.controlSetControlFont(t.hwnd)
C.setTabSubclass(t.hwnd, unsafe.Pointer(t))
return t
}
-func (t *tab) tabsetParent(p *controlParent) {
- t.supersetParent(p)
- for _, c := range t.tabs {
- c.child.setParent(p)
- }
-}
-
func (t *tab) Append(name string, control Control) {
s := new(sizer)
t.tabs = append(t.tabs, s)
@@ -74,7 +60,28 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
t.tabs[int(new)].child.containerShow()
}
-func (t *tab) tabpreferredSize(d *sizing) (width, height int) {
+func (t *tab) setParent(p *controlParent) {
+ basesetParent(t.controlbase, p)
+ for _, c := range t.tabs {
+ c.child.setParent(p)
+ }
+}
+
+// TODO actually write this
+func (t *tab) containerShow() {
+ basecontainerShow(t.controlbase)
+}
+
+// TODO actually write this
+func (t *tab) containerHide() {
+ basecontainerHide(t.controlbase)
+}
+
+func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
+func (t *tab) preferredSize(d *sizing) (width, height int) {
// TODO only consider the size of the current tab?
for _, s := range t.tabs {
w, h := s.child.preferredSize(d)
@@ -89,22 +96,25 @@ func (t *tab) tabpreferredSize(d *sizing) (width, height int) {
}
// a tab control contains other controls; size appropriately
-// TODO change this to commitResize()
-func (t *tab) taballocate(x int, y int, width int, height int, d *sizing) []*allocation {
+func (t *tab) commitResize(c *allocation, d *sizing) {
var r C.RECT
// figure out what the rect for each child is...
- r.left = C.LONG(x) // load structure with the window's rect
- r.top = C.LONG(y)
- r.right = C.LONG(x + width)
- r.bottom = C.LONG(y + height)
+ r.left = C.LONG(c.x) // load structure with the window's rect
+ r.top = C.LONG(c.y)
+ r.right = C.LONG(c.x + c.width)
+ r.bottom = C.LONG(c.y + c.height)
C.tabGetContentRect(t.hwnd, &r)
- // and allocate
- // don't allocate to just the current tab; allocate to all tabs!
+ // and resize tabs
+ // don't resize just the current tab; resize all tabs!
for _, s := range t.tabs {
// because each widget is actually a child of the Window, the origin is the one we calculated above
s.resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top))
}
- // and now allocate the tab control itself
- return t.superallocate(x, y, width, height, d)
+ // and now resize the tab control itself
+ basecommitResize(t.controlbase, c, d)
+}
+
+func (t *tab) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
}
diff --git a/redo/table_windows.go b/redo/table_windows.go
index 7dfbc56..633486e 100644
--- a/redo/table_windows.go
+++ b/redo/table_windows.go
@@ -30,7 +30,6 @@ func finishNewTable(b *tablebase, ty reflect.Type) Table {
for i := 0; i < ty.NumField(); i++ {
C.tableAppendColumn(t.hwnd, C.int(i), toUTF16(ty.Field(i).Name))
}
- t.fpreferredSize = t.tablepreferredSize
return t
}
@@ -43,16 +42,6 @@ func (t *table) Unlock() {
C.tableUpdate(t.hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
}
-const (
- // from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now... (TODO see if I can reliably get item width/height from text size)
- tableWidth = 183
- tableHeight = 50
-)
-
-func (t *table) tablepreferredSize(d *sizing) (width, height int) {
- return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
-}
-
//export tableGetCellText
func tableGetCellText(data unsafe.Pointer, row C.int, col C.int, str *C.LPWSTR) {
t := (*table)(data)
@@ -63,3 +52,37 @@ func tableGetCellText(data unsafe.Pointer, row C.int, col C.int, str *C.LPWSTR)
s := fmt.Sprintf("%v", datum)
*str = toUTF16(s)
}
+
+func (t *table) setParent(p *controlParent) {
+ basesetParent(t.controlbase, p)
+}
+
+func (t *table) containerShow() {
+ basecontainerShow(t.controlbase)
+}
+
+func (t *table) containerHide() {
+ basecontainerHide(t.controlbase)
+}
+
+func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
+const (
+ // from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now... (TODO see if I can reliably get item width/height from text size)
+ tableWidth = 183
+ tableHeight = 50
+)
+
+func (t *table) preferredSize(d *sizing) (width, height int) {
+ return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
+}
+
+func (t *table) commitResize(a *allocation, d *sizing) {
+ basecommitResize(t.controlbase, a, d)
+}
+
+func (t *table) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}
diff --git a/redo/textfield_windows.go b/redo/textfield_windows.go
index d325a18..a2add7a 100644
--- a/redo/textfield_windows.go
+++ b/redo/textfield_windows.go
@@ -19,7 +19,6 @@ func startNewTextField(style C.DWORD) *textField {
t := &textField{
controlbase: c,
}
- t.fpreferredSize = t.textfieldpreferredSize
return t
}
@@ -39,12 +38,36 @@ func (t *textField) SetText(text string) {
t.setText(text)
}
+func (t *textField) setParent(p *controlParent) {
+ basesetParent(t.controlbase, p)
+}
+
+func (t *textField) containerShow() {
+ basecontainerShow(t.controlbase)
+}
+
+func (t *textField) containerHide() {
+ basecontainerHide(t.controlbase)
+}
+
+func (t *textField) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
+ return baseallocate(t, x, y, width, height, d)
+}
+
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) {
+func (t *textField) preferredSize(d *sizing) (width, height int) {
return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
}
+
+func (t *textField) commitResize(a *allocation, d *sizing) {
+ basecommitResize(t.controlbase, a, d)
+}
+
+func (t *textField) getAuxResizeInfo(d *sizing) {
+ basegetAuxResizeInfo(d)
+}