Set up a new, cleaner model for deriving Control's methods and applied it to the Windows backend.

This commit is contained in:
Pietro Gagliardi 2014-07-30 02:06:01 -04:00
parent 5a51263adc
commit 210102fe95
6 changed files with 166 additions and 105 deletions

View File

@ -9,61 +9,21 @@ import (
// #include "winapi_windows.h"
import "C"
type widgetbase struct {
hwnd C.HWND
parent C.HWND
}
func newWidget(class C.LPCWSTR, style C.DWORD, extstyle C.DWORD) *widgetbase {
return &widgetbase{
hwnd: C.newWidget(class, style, extstyle),
}
}
// these few methods are embedded by all the various Controls since they all will do the same thing
type controlParent struct {
hwnd C.HWND
}
func (w *widgetbase) setParent(win *controlParent) {
C.controlSetParent(w.hwnd, win.hwnd)
w.parent = win.hwnd
}
func (w *widgetbase) containerShow() {
C.ShowWindow(w.hwnd, C.SW_SHOW)
}
func (w *widgetbase) containerHide() {
C.ShowWindow(w.hwnd, C.SW_HIDE)
}
// don't embed these as exported; let each Control decide if it should
func (w *widgetbase) text() string {
return getWindowText(w.hwnd)
}
func (w *widgetbase) settext(text string) {
C.setWindowText(w.hwnd, toUTF16(text))
}
type button struct {
*widgetbase
*controlbase
clicked *event
}
var buttonclass = toUTF16("BUTTON")
func startNewButton(text string, style C.DWORD) *button {
w := newWidget(buttonclass,
c := newControl(buttonclass,
style | C.WS_TABSTOP,
0)
C.setWindowText(w.hwnd, toUTF16(text))
C.controlSetControlFont(w.hwnd)
C.setWindowText(c.hwnd, toUTF16(text))
C.controlSetControlFont(c.hwnd)
b := &button{
widgetbase: w,
controlbase: c,
clicked: newEvent(),
}
return b
@ -84,7 +44,7 @@ func (b *button) Text() string {
}
func (b *button) SetText(text string) {
b.settext(text)
b.setText(text)
}
//export buttonClicked
@ -94,6 +54,8 @@ func buttonClicked(data unsafe.Pointer) {
println("button clicked")
}
// TODO button preferredSize
type checkbox struct {
*button
}
@ -131,18 +93,18 @@ func checkboxToggled(data unsafe.Pointer) {
}
type textField struct {
*widgetbase
*controlbase
}
var editclass = toUTF16("EDIT")
func startNewTextField(style C.DWORD) *textField {
w := newWidget(editclass,
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(w.hwnd)
C.controlSetControlFont(c.hwnd)
return &textField{
widgetbase: w,
controlbase: c,
}
}
@ -159,28 +121,31 @@ func (t *textField) Text() string {
}
func (t *textField) SetText(text string) {
t.settext(text)
t.setText(text)
}
type label struct {
*widgetbase
standalone bool
*controlbase
standalone bool
supercommitResize func(c *allocation, d *sizing)
}
var labelclass = toUTF16("STATIC")
func finishNewLabel(text string, standalone bool) *label {
w := newWidget(labelclass,
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.setWindowText(w.hwnd, toUTF16(text))
C.controlSetControlFont(w.hwnd)
C.setWindowText(c.hwnd, toUTF16(text))
C.controlSetControlFont(c.hwnd)
l := &label{
widgetbase: w,
controlbase: c,
standalone: standalone,
}
l.supercommitResize = l.fcommitResize
l.fcommitResize = l.labelcommitResize
return l
}
@ -197,7 +162,20 @@ func (l *label) Text() string {
}
func (l *label) SetText(text string) {
l.settext(text)
l.setText(text)
}
// TODO label commitResize
func (l *label) labelcommitResize(c *allocation, d *sizing) {
// TODO
/*
yoff := stdDlgSizes[s.ctype].yoff
if s.standalone {
yoff = stdDlgSizes[s.ctype].yoffalt
}
if yoff != 0 {
yoff = int(C.MulDiv(C.int(yoff), C.int(d.baseY), 8))
}
c.y += yoff
*/
l.supercommitResize(c, d)
}

View File

@ -18,24 +18,30 @@ TODO
*/
type tab struct {
*widgetbase
tabs []*container
*controlbase
tabs []*container
supersetParent func(p *controlParent)
superallocate func(x int, y int, width int, height int, d *sizing) []*allocation
}
func newTab() Tab {
w := newWidget(C.xWC_TABCONTROL,
c := newControl(C.xWC_TABCONTROL,
C.TCS_TOOLTIPS | C.WS_TABSTOP,
0)
t := &tab{
widgetbase: w,
controlbase: c,
}
C.controlSetControlFont(w.hwnd)
C.setTabSubclass(w.hwnd, unsafe.Pointer(t))
t.supersetParent = t.fsetParent
t.fsetParent = t.tabsetParent
t.superallocate = t.fallocate
t.fallocate = t.taballocate
C.controlSetControlFont(t.hwnd)
C.setTabSubclass(t.hwnd, unsafe.Pointer(t))
return t
}
func (t *tab) setParent(p *controlParent) {
t.widgetbase.setParent(p)
func (t *tab) tabsetParent(p *controlParent) {
t.supersetParent(p)
for _, c := range t.tabs {
c.child.setParent(p)
}
@ -68,7 +74,7 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
}
// a tab control contains other controls; size appropriately
func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
func (t *tab) taballocate(x int, y int, width int, height int, d *sizing) []*allocation {
var r C.RECT
// figure out what the rect for each child is...
@ -84,5 +90,5 @@ func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*alloca
c.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.widgetbase.allocate(x, y, width, height, d)
return t.superallocate(x, y, width, height, d)
}

45
redo/control.go Normal file
View File

@ -0,0 +1,45 @@
// 30 july 2014
package ui
// All Controls 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)
}

63
redo/control_windows.go Normal file
View File

@ -0,0 +1,63 @@
// 30 july 2014
package ui
// #include "winapi_windows.h"
import "C"
type controlbase struct {
*controldefs
hwnd C.HWND
parent C.HWND // for Tab and Group
}
type controlParent struct {
hwnd C.HWND
}
func newControl(class C.LPCWSTR, style C.DWORD, extstyle C.DWORD) *controlbase {
c := new(controlbase)
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 = func(x int, y int, width int, height int, d *sizing) []*allocation {
// TODO split into its own function
return []*allocation{&allocation{
x: x,
y: y,
width: width,
height: height,
this: c,
}}
}
c.fpreferredSize = func(d *sizing) (int, int) {
// TODO
return 75, 23
}
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
}
// these are provided for convenience
func (c *controlbase) text() string {
return getWindowText(c.hwnd)
}
func (c *controlbase) setText(text string) {
C.setWindowText(c.hwnd, toUTF16(text))
}

View File

@ -41,37 +41,6 @@ func (c *container) translateAllocationCoords(allocations []*allocation, winwidt
// no translation needed on windows
}
// TODO move this to sizing.go
// TODO when doing so, account for margins
func (w *widgetbase) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
return []*allocation{&allocation{
x: x,
y: y,
width: width,
height: height,
this: w,
}}
}
func (w *widgetbase) commitResize(c *allocation, d *sizing) {
// TODO
/*
yoff := stdDlgSizes[s.ctype].yoff
if s.alternate {
yoff = stdDlgSizes[s.ctype].yoffalt
}
if yoff != 0 {
yoff = int(C.MulDiv(C.int(yoff), C.int(d.baseY), 8))
}
c.y += yoff
*/
C.moveWindow(w.hwnd, C.int(c.x), C.int(c.y), C.int(c.width), C.int(c.height))
}
func (w *widgetbase) getAuxResizeInfo(d *sizing) {
// do nothing
}
// For Windows, Microsoft just hands you a list of preferred control sizes as part of the MSDN documentation and tells you to roll with it.
// These sizes are given in "dialog units", which are independent of the font in use.
// We need to convert these into standard pixels, which requires we get the device context of the OS window.
@ -143,7 +112,7 @@ var stdDlgSizes = [nctypes]dlgunits{
}
*/
func (w *widgetbase) preferredSize(d *sizing) (width int, height int) {
//func (w *widgetbase) preferredSize(d *sizing) (width int, height int) {
// TODO
/*
// the preferred size of an Area is its size
@ -174,8 +143,8 @@ func (w *widgetbase) preferredSize(d *sizing) (width int, height int) {
width = int(C.MulDiv(C.int(width), C.int(d.baseX), 4)) // equivalent to right of rect
height = int(C.MulDiv(C.int(height), C.int(d.baseY), 8)) // equivalent to bottom of rect
*/
return width, height
}
// return width, height
//}
// note on MulDiv():
// div will not be 0 in the usages above

View File

@ -12,13 +12,13 @@ import (
import "C"
type table struct {
*widgetbase
*controlbase
*tablebase
}
func finishNewTable(b *tablebase, ty reflect.Type) Table {
t := &table{
widgetbase: newWidget(C.xWC_LISTVIEW,
controlbase: newControl(C.xWC_LISTVIEW,
C.LVS_REPORT | C.LVS_OWNERDATA | C.LVS_NOSORTHEADER | C.LVS_SHOWSELALWAYS | C.WS_HSCROLL | C.WS_VSCROLL,
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)
tablebase: b,