200 lines
4.3 KiB
Go
200 lines
4.3 KiB
Go
// 12 july 2014
|
|
|
|
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type window struct {
|
|
hwnd uintptr
|
|
shownbefore bool
|
|
|
|
child Control
|
|
|
|
closing *event
|
|
|
|
spaced bool
|
|
}
|
|
|
|
const windowclassname = "gouiwindow"
|
|
var windowclassptr = syscall.StringToUTF16Ptr(windowclassname)
|
|
|
|
func makeWindowWindowClass() error {
|
|
var wc s_WNDCLASSW
|
|
|
|
wc.lpfnWndProc = syscall.NewCallback(windowWndProc)
|
|
wc.hInstance = hInstance
|
|
wc.hIcon = hDefaultIcon
|
|
wc.hCursor = hArrowCursor
|
|
wc.hbrBackground = c_COLOR_BTNFACE + 1
|
|
wc.lpszClassName = windowclassptr
|
|
res, err := f_RegisterClassW(&wc)
|
|
if res == 0 {
|
|
return fmt.Errorf("error registering Window window class: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func newWindow(title string, width int, height int) *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
w := &window{
|
|
// hwnd set in WM_CREATE handler
|
|
closing: newEvent(),
|
|
}
|
|
hwnd, err := f_CreateWindowExW(
|
|
0,
|
|
windowclassptr,
|
|
syscall.StringToUTF16Ptr(title),
|
|
c_WS_OVERLAPPEDWINDOW,
|
|
c_CW_USEDEFAULT, c_CW_USEDEFAULT,
|
|
uintptr(width), uintptr(height),
|
|
hNULL, hNULL, hInstance, unsafe.Pointer(w))
|
|
if hwnd == hNULL {
|
|
panic(fmt.Errorf("Window creation failed: %v", err))
|
|
} else if hwnd != w.hwnd {
|
|
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in window (%p) differ", hwnd, w.hwnd))
|
|
}
|
|
c <- w
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) SetControl(control Control) *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
if w.child != nil { // unparent existing control
|
|
w.child.unparent()
|
|
}
|
|
control.unparent()
|
|
control.parent(w)
|
|
w.child = control
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) Title() *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
c <- getWindowText(w.hwnd)
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) SetTitle(title string) *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
setWindowText(w.hwnd, title, []t_LRESULT{c_FALSE})
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) Show() *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
if !w.shownbefore {
|
|
// TODO get rid of need for cast
|
|
f_ShowWindow(w.hwnd, uintptr(nCmdShow))
|
|
updateWindow(w.hwnd, "Window.Show()")
|
|
w.shownbefore = true
|
|
} else {
|
|
f_ShowWindow(w.hwnd, c_SW_SHOW)
|
|
}
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) Hide() *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
f_ShowWindow(w.hwnd, c_SW_HIDE)
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func doclose(w *window) {
|
|
res, err := f_DestroyWindow(w.hwnd)
|
|
if res == 0 {
|
|
panic(fmt.Errorf("error destroying window: %v", err))
|
|
}
|
|
}
|
|
|
|
func (w *window) Close() *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
doclose(w)
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
func (w *window) OnClosing(e func(Doer) bool) *Request {
|
|
c := make(chan interface{})
|
|
return &Request{
|
|
op: func() {
|
|
w.closing.setbool(e)
|
|
c <- struct{}{}
|
|
},
|
|
resp: c,
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
// the lpParam is available during WM_NCCREATE and WM_CREATE
|
|
if msg == c_WM_NCCREATE {
|
|
storelpParam(hwnd, lParam)
|
|
w := (*window)(unsafe.Pointer(f_GetWindowLongPtrW(hwnd, c_GWLP_USERDATA)))
|
|
w.hwnd = hwnd
|
|
}
|
|
// act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
|
|
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
|
|
|
|
res, err := f_GetClientRect(w.hwnd, &r)
|
|
if res == 0 {
|
|
panic(fmt.Errorf("error getting client rect for Window in WM_SIZE: %v", err))
|
|
}
|
|
w.doresize(int(r.right - r.left), int(r.bottom - r.top))
|
|
fmt.Printf("new size %d x %d\n", r.right - r.left, r.bottom - r.top)
|
|
return 0
|
|
case c_WM_CLOSE:
|
|
close := w.closing.fire()
|
|
if close {
|
|
doclose(w)
|
|
}
|
|
return 0
|
|
default:
|
|
return f_DefWindowProcW(hwnd, msg, wParam, lParam)
|
|
}
|
|
panic(fmt.Errorf("Window message %d does not return a value (bug in windowWndProc())", msg))
|
|
}
|