summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--newctrl/button_windows.go73
-rw-r--r--newctrl/control.go29
-rw-r--r--newctrl/control_windows.go61
-rw-r--r--newctrl/window_windows.go101
-rw-r--r--newctrl/zz_test.go36
5 files changed, 300 insertions, 0 deletions
diff --git a/newctrl/button_windows.go b/newctrl/button_windows.go
new file mode 100644
index 0000000..d7cfff8
--- /dev/null
+++ b/newctrl/button_windows.go
@@ -0,0 +1,73 @@
+// 15 july 2014
+
+package ui
+
+import (
+ "unsafe"
+)
+
+// #include "winapi_windows.h"
+import "C"
+
+type button struct {
+ *controlSingleHWNDWithText
+ clicked *event
+}
+
+var buttonclass = toUTF16("BUTTON")
+
+func newButton(text string) *button {
+ hwnd := C.newControl(buttonclass,
+ C.BS_PUSHBUTTON|C.WS_TABSTOP,
+ 0)
+ b := &button{
+ controlSingleHWNDWithText: newControlSingleHWNDWithText(hwnd),
+ clicked: newEvent(),
+ }
+ b.fpreferredSize = b.preferredSize
+ b.SetText(text)
+ C.controlSetControlFont(b.hwnd)
+ C.setButtonSubclass(b.hwnd, unsafe.Pointer(b))
+ return b
+}
+
+func (b *button) OnClicked(e func()) {
+ b.clicked.set(e)
+}
+
+func (b *button) Text() string {
+ return b.text()
+}
+
+func (b *button) SetText(text string) {
+ b.setText(text)
+}
+
+//export buttonClicked
+func buttonClicked(data unsafe.Pointer) {
+ b := (*button)(data)
+ b.clicked.fire()
+}
+
+const (
+ // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
+ buttonHeight = 14
+)
+
+func (b *button) preferredSize(d *sizing) (width, height int) {
+return 0,0/*TODO/*
+ // comctl32.dll version 6 thankfully provides a method to grab this...
+ var size C.SIZE
+
+ size.cx = 0 // explicitly ask for ideal size
+ size.cy = 0
+ if C.SendMessageW(b.hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE {
+ return int(size.cx), int(size.cy)
+ }
+ // that failed, fall back
+ println("message failed; falling back")
+ // don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such)
+ xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE))
+ return xmargins + int(b.textlen), fromdlgunitsY(buttonHeight, d)
+*/
+}
diff --git a/newctrl/control.go b/newctrl/control.go
new file mode 100644
index 0000000..028b195
--- /dev/null
+++ b/newctrl/control.go
@@ -0,0 +1,29 @@
+// 30 july 2014
+
+package ui
+
+// Control represents a control.
+type Control interface {
+ setParent(p *controlParent) // controlParent defined per-platform
+// nChildren() int // TODO
+ preferredSize(d *sizing) (width, height int)
+ resize(x int, y int, width int, height int, d *sizing)
+}
+
+type controlbase struct {
+ fsetParent func(p *controlParent)
+ fpreferredSize func(d *sizing) (width, height int)
+ fresize func(x int, y int, width int, height int, d *sizing)
+}
+
+func (c *controlbase) setParent(p *controlParent) {
+ c.fsetParent(p)
+}
+
+func (c *controlbase) preferredSize(d *sizing) (width, height int) {
+ return c.fpreferredSize(d)
+}
+
+func (c *controlbase) resize(x int, y int, width int, height int, d *sizing) {
+ c.fresize(x, y, width, height, d)
+}
diff --git a/newctrl/control_windows.go b/newctrl/control_windows.go
new file mode 100644
index 0000000..106727b
--- /dev/null
+++ b/newctrl/control_windows.go
@@ -0,0 +1,61 @@
+// 30 july 2014
+
+package ui
+
+// #include "winapi_windows.h"
+import "C"
+
+type controlParent struct {
+ hwnd C.HWND
+}
+type sizing struct {
+ // TODO
+}
+
+// don't specify preferredSize in any of these; they're per-control
+
+type controlSingleHWND struct {
+ *controlbase
+ hwnd C.HWND
+}
+
+func newControlSingleHWND(hwnd C.HWND) *controlSingleHWND {
+ c := new(controlSingleHWND)
+ c.controlbase = &controlbase{
+ fsetParent: c.setParent,
+ fresize: c.resize,
+ }
+ c.hwnd = hwnd
+ return c
+}
+
+func (c *controlSingleHWND) setParent(p *controlParent) {
+ C.controlSetParent(c.hwnd, p.hwnd)
+}
+
+func (c *controlSingleHWND) resize(x int, y int, width int, height int, d *sizing) {
+ C.moveWindow(c.hwnd, C.int(x), C.int(y), C.int(width), C.int(height))
+}
+
+// these are provided for convenience
+
+type controlSingleHWNDWithText struct {
+ *controlSingleHWND
+ textlen C.LONG
+}
+
+func newControlSingleHWNDWithText(h C.HWND) *controlSingleHWNDWithText {
+ return &controlSingleHWNDWithText{
+ controlSingleHWND: newControlSingleHWND(h),
+ }
+}
+
+func (c *controlSingleHWNDWithText) text() string {
+ return getWindowText(c.hwnd)
+}
+
+func (c *controlSingleHWNDWithText) setText(text string) {
+ t := toUTF16(text)
+ C.setWindowText(c.hwnd, t)
+ c.textlen = C.controlTextLength(c.hwnd, t)
+}
diff --git a/newctrl/window_windows.go b/newctrl/window_windows.go
new file mode 100644
index 0000000..4dc5454
--- /dev/null
+++ b/newctrl/window_windows.go
@@ -0,0 +1,101 @@
+// 12 july 2014
+
+package ui
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// #include "winapi_windows.h"
+import "C"
+
+type window struct {
+ hwnd C.HWND
+ shownbefore bool
+
+ closing *event
+
+ child Control
+}
+
+func makeWindowWindowClass() error {
+ var errmsg *C.char
+
+ err := C.makeWindowWindowClass(&errmsg)
+ if err != 0 || errmsg != nil {
+ return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
+ }
+ return nil
+}
+
+func newWindow(title string, width int, height int, control Control) *window {
+ w := &window{
+ // hwnd set in WM_CREATE handler
+ closing: newEvent(),
+ child: control,
+ }
+ hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
+ if hwnd != w.hwnd {
+ panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in Window (%p) differ", hwnd, w.hwnd))
+ }
+ hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE|C.ETDT_USETABTEXTURE)
+ if hresult != C.S_OK {
+ panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
+ }
+ w.child.setParent(&controlParent{w.hwnd})
+ return w
+}
+
+func (w *window) Title() string {
+ return getWindowText(w.hwnd)
+}
+
+func (w *window) SetTitle(title string) {
+ C.setWindowText(w.hwnd, toUTF16(title))
+}
+
+func (w *window) Show() {
+ if !w.shownbefore {
+ C.ShowWindow(w.hwnd, C.nCmdShow)
+ C.updateWindow(w.hwnd)
+ w.shownbefore = true
+ } else {
+ C.ShowWindow(w.hwnd, C.SW_SHOW)
+ }
+}
+
+func (w *window) Hide() {
+ C.ShowWindow(w.hwnd, C.SW_HIDE)
+}
+
+func (w *window) Close() {
+ C.windowClose(w.hwnd)
+}
+
+func (w *window) OnClosing(e func() bool) {
+ w.closing.setbool(e)
+}
+
+//export storeWindowHWND
+func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
+ w := (*window)(data)
+ w.hwnd = hwnd
+}
+
+//export windowResize
+func windowResize(data unsafe.Pointer, r *C.RECT) {
+ w := (*window)(data)
+ TODO := &sizing{}
+ w.child.resize(int(r.left), int (r.top), int(r.right - r.left), int(r.bottom - r.top), TODO)
+}
+
+//export windowClosing
+func windowClosing(data unsafe.Pointer) {
+ w := (*window)(data)
+ close := w.closing.fire()
+ if close {
+ C.windowClose(w.hwnd)
+ }
+}
diff --git a/newctrl/zz_test.go b/newctrl/zz_test.go
new file mode 100644
index 0000000..a1537fd
--- /dev/null
+++ b/newctrl/zz_test.go
@@ -0,0 +1,36 @@
+// 14 october 2014
+
+package ui
+
+import "flag"
+import "testing"
+
+var twindow *window
+
+func maketw(done chan struct{}) {
+ button := newButton("Greet")
+ twindow = newWindow("Hello", 200, 100, button)
+ twindow.OnClosing(func() bool {
+ Stop()
+ return true
+ })
+ twindow.Show()
+}
+
+// because Cocoa hates being run off the main thread, even if it's run exclusively off the main thread
+func init() {
+ flag.Parse()
+ go func() {
+ done := make(chan struct{})
+ Do(func() { maketw(done) })
+ <-done
+ }()
+ err := Go()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func TestDummy(t *testing.T) {
+ // do nothing
+}