Set up a new, cleaner model for deriving Control's methods and applied it to the Windows backend.
This commit is contained in:
parent
5a51263adc
commit
210102fe95
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue