Laid down the framework for control events on Windows. The only problem left is that we need to use functions from comctl32.dll, so it's time to bring that blob of code back.
This commit is contained in:
parent
1a712d4064
commit
19f7b2946a
|
@ -46,3 +46,13 @@ func storelpParam(hwnd uintptr, lParam t_LPARAM) {
|
|||
cs = (*s_CREATESTRUCTW)(unsafe.Pointer(uintptr(lParam)))
|
||||
f_SetWindowLongPtrW(hwnd, c_GWLP_USERDATA, cs.lpCreateParams)
|
||||
}
|
||||
|
||||
func (w t_WPARAM) HIWORD() uint16 {
|
||||
u := uintptr(w) & 0xFFFF0000
|
||||
return uint16(u >> 16)
|
||||
}
|
||||
|
||||
func (w t_WPARAM) LOWORD() uint16 {
|
||||
u := uintptr(w) & 0x0000FFFF
|
||||
return uint16(u)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package ui
|
|||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type widgetbase struct {
|
||||
|
@ -73,8 +74,20 @@ func (w *widgetbase) settext(text string, results ...t_LRESULT) *Request {
|
|||
}
|
||||
}
|
||||
|
||||
// all controls that have events receive the events themselves through subclasses
|
||||
// to do this, all windows (including the message-only window; see http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q104069) forward WM_COMMAND to each control with this function
|
||||
func forwardCommand(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
|
||||
control := uintptr(lParam)
|
||||
// don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
|
||||
if control != hNULL && f_IsChild(msgwin, control) == 0 {
|
||||
return f_SendMessageW(control, msgCOMMAND, wParam, lParam)
|
||||
}
|
||||
return f_DefWindowProcW(hwnd, uMsg, wParam, lParam)
|
||||
}
|
||||
|
||||
type button struct {
|
||||
*widgetbase
|
||||
clicked *event
|
||||
}
|
||||
|
||||
var buttonclass = syscall.StringToUTF16Ptr("BUTTON")
|
||||
|
@ -89,6 +102,7 @@ func newButton(text string) *Request {
|
|||
setWindowText(w.hwnd, text, []t_LRESULT{c_FALSE})
|
||||
c <- &button{
|
||||
widgetbase: w,
|
||||
clicked: newEvent(),
|
||||
}
|
||||
},
|
||||
resp: c,
|
||||
|
@ -96,8 +110,14 @@ func newButton(text string) *Request {
|
|||
}
|
||||
|
||||
func (b *button) OnClicked(e func(c Doer)) *Request {
|
||||
// TODO
|
||||
return nil
|
||||
c := make(chan interface{})
|
||||
return &Request{
|
||||
op: func() {
|
||||
b.clicked.set(e)
|
||||
c <- struct{}{}
|
||||
},
|
||||
resp: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *button) Text() *Request {
|
||||
|
@ -107,3 +127,24 @@ func (b *button) Text() *Request {
|
|||
func (b *button) SetText(text string) *Request {
|
||||
return b.settext(text)
|
||||
}
|
||||
|
||||
var buttonsubprocptr = syscall.NewCallback(buttonSubProc)
|
||||
|
||||
func buttonSubProc(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM, id t_UINT_PTR, data t_DWORD_PTR) t_LRESULT {
|
||||
b := (*button)(unsafe.Pointer(uintptr(data)))
|
||||
switch uMsg {
|
||||
case msgCOMMAND:
|
||||
if wParam.HIWORD() == c_BN_CLICKED {
|
||||
b.clicked.fire()
|
||||
println("button clicked")
|
||||
return 0
|
||||
}
|
||||
// TODO return
|
||||
case c_WM_NCDESTROY:
|
||||
// TODO remove
|
||||
// TODO return
|
||||
default:
|
||||
// TODO return
|
||||
}
|
||||
panic(fmt.Errorf("Button message %d does not return a value (bug in buttonSubProc())", uMsg))
|
||||
}
|
||||
|
|
|
@ -38,3 +38,4 @@ package ui
|
|||
// wfunc user32 GetDC uintptr uintptr
|
||||
// wfunc gdi32 SelectObject uintptr uintptr uintptr
|
||||
// wfunc user32 ReleaseDC uintptr uintptr uintptr
|
||||
// wfunc user32 IsChild uintptr uintptr uintptr,noerr
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
// global messages unique to everything
|
||||
const (
|
||||
msgRequest = c_WM_APP + 1 + iota // + 1 just to be safe
|
||||
msgCOMMAND // WM_COMMAND proxy; see forwardCommand() in controls_windows.go
|
||||
)
|
||||
|
||||
var msgwin uintptr
|
||||
|
@ -91,6 +92,8 @@ func makemsgwin() error {
|
|||
|
||||
func msgwinproc(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
|
||||
switch uMsg {
|
||||
case c_WM_COMMAND:
|
||||
return forwardCommand(hwnd, uMsg, wParam, lParam)
|
||||
case msgRequest:
|
||||
req := (*Request)(unsafe.Pointer(uintptr(lParam)))
|
||||
perform(req)
|
||||
|
|
|
@ -160,6 +160,7 @@ func (w *window) OnClosing(e func(Doer) bool) *Request {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO msg -> uMsg
|
||||
func windowWndProc(hwnd uintptr, msg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
|
||||
w := (*window)(unsafe.Pointer(f_GetWindowLongPtrW(hwnd, c_GWLP_USERDATA)))
|
||||
if w == nil {
|
||||
|
@ -173,6 +174,8 @@ func windowWndProc(hwnd uintptr, msg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t
|
|||
return f_DefWindowProcW(hwnd, msg, wParam, lParam)
|
||||
}
|
||||
switch msg {
|
||||
case c_WM_COMMAND:
|
||||
return forwardCommand(hwnd, msg, wParam, lParam)
|
||||
case c_WM_SIZE:
|
||||
var r s_RECT
|
||||
|
||||
|
|
|
@ -276,6 +276,8 @@ func main() {
|
|||
fmt.Fprintf(buf, "type t_WPARAM %s\n", winName(reflect.TypeOf(C.WPARAM(0))))
|
||||
fmt.Fprintf(buf, "type t_LPARAM %s\n", winName(reflect.TypeOf(C.LPARAM(0))))
|
||||
fmt.Fprintf(buf, "type t_LRESULT %s\n", winName(reflect.TypeOf(C.LRESULT(0))))
|
||||
fmt.Fprintf(buf, "type t_UINT_PTR %s\n", winName(reflect.TypeOf(C.UINT_PTR(0))))
|
||||
fmt.Fprintf(buf, "type t_DWORD_PTR %s\n", winName(reflect.TypeOf(C.DWORD_PTR(0))))
|
||||
// and one for GetMessageW()
|
||||
fmt.Fprintf(buf, "type t_BOOL %s\n", winName(reflect.TypeOf(C.BOOL(0))))
|
||||
|
||||
|
|
Loading…
Reference in New Issue