Fixed the build. New API works on Windows! Also removed TODO on dialogs in Windows since I can't reproduce the weird behavior anymore; I guess the new code fixes it.

This commit is contained in:
Pietro Gagliardi 2014-06-28 16:37:55 -04:00
parent 02d6a03ba3
commit affc65a5a4
13 changed files with 63 additions and 54 deletions

View File

@ -14,7 +14,6 @@ func NewButton(text string) (b *Button) {
return &Button{
sysData: mksysdata(c_button),
initText: text,
Clicked: newEvent(),
}
}

View File

@ -12,11 +12,7 @@ const (
// sentinel (not nil so programmer errors don't go undetected)
// this window is invalid and cannot be used directly
// notice the support it uses
var dialogWindow = &Window{
sysData: &sysData{
winhandler: dh,
}
}
var dialogWindow = new(Window)
// MsgBox displays an informational message box to the user with just an OK button.
// primaryText should be a short string describing the message, and will be displayed with additional emphasis on platforms that support it.

View File

@ -11,11 +11,11 @@ var (
_messageBox = user32.NewProc("MessageBoxW")
)
var dialogResponse = map[uintptr]Response{
var dialogResponses = map[uintptr]Response{
_IDOK: OK,
}
func _msgBox(parent *Window, primarytext string, secondarytext string, uType uint32) (result int) {
func _msgBox(parent *Window, primarytext string, secondarytext string, uType uint32) Response {
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa511267.aspx says "Use task dialogs whenever appropriate to achieve a consistent look and layout. Task dialogs require Windows Vista® or later, so they aren't suitable for earlier versions of Windows. If you must use a message box, separate the main instruction from the supplemental instruction with two line breaks."
text := primarytext
if secondarytext != "" {

15
init.go
View File

@ -18,7 +18,7 @@ import (
// If you must, and if the toolkit also has environment variable equivalents to these flags (for instance, GTK+), use those instead.
func Go() error {
runtime.LockOSThread()
if err := uiinit(main); err != nil {
if err := uiinit(); err != nil {
return err
}
Ready <- struct{}{}
@ -37,9 +37,18 @@ var Ready = make(chan struct{})
var Stop = make(chan struct{})
// This function is a simple helper functionn that basically pushes the effect of a function call for later. This allows the selected safe Window methods to be safe.
// It's also currently used by the various dialog box functions on Windows to allow them to return instantly, rather than wait for the dialog box to finish (which both GTK+ and Mac OS X let you do). I consider this a race condition bug. TODO (also TODO document the /intended/ behavior)
// TODO make sure this acts sanely if called from uitask itself
func touitask(f func()) {
done := make(chan struct{})
defer close(done)
go func() { // to avoid locking uitask itself
uitask <- f
done2 := make(chan struct{}) // make the chain uitask <- f <- uitask to avoid deadlocks
defer close(done2)
uitask <- func() {
f()
done2 <- struct{}{}
}
done <- <-done2
}()
<-done
}

View File

@ -391,6 +391,7 @@ func (s *sysData) setWindowSize(width int, height int) error {
if err != nil {
panic(fmt.Errorf("error actually resizing window: %v", err))
}
return nil
}
func (s *sysData) delete(index int) {

View File

@ -74,7 +74,7 @@ func (a *keyboardArea) Key(e KeyEvent) (repaint bool) {
}
type kbhandler struct{}
func (kbhandler) Handle(e Event, d interface{}) {
func (kbhandler) Event(e Event, d interface{}) {
if e == Closing {
*(d.(*bool)) = true
}

View File

@ -47,10 +47,11 @@ func gridWindow() *Window {
g.SetStretchy(1, 1)
w.SetSpaced(*spacingTest)
w.Open(g)
go func() {for {select {
case <-b12.Clicked:
c21.SetChecked(!c21.Checked())
}}}()
//TODO
// go func() {for {select {
// case <-b12.Clicked:
// c21.SetChecked(!c21.Checked())
// }}}()
return w
}
@ -236,7 +237,7 @@ func areaTest() {
a: a,
timedisp: timedisp,
widthbox: widthbox,
heightbox: heighbox,
heightbox: heightbox,
resize: resize,
modaltest: modaltest,
repainttest: repainttest,
@ -252,7 +253,7 @@ func areaTest() {
}
type areatestwinhandler struct {
areahandler *areahandler
areahandler *areaHandler
a *Area
timedisp *Label
widthbox *LineEdit
@ -264,18 +265,19 @@ type areatestwinhandler struct {
func (a *areatestwinhandler) Event(e Event, d interface{}) {
switch e {
case Closing:
*(data.(*bool)) = true
*(d.(*bool)) = true
Stop <- struct{}{}
case Clicked:
switch d {
case a.resize:
width, err := strconv.Atoi(a.widthbox.Text())
if err != nil { println(err); continue }
if err != nil { println(err); return }
height, err := strconv.Atoi(a.heightbox.Text())
if err != nil { println(err); continue }
if err != nil { println(err); return }
a.a.SetSize(width, height)
case modaltest:
case a.modaltest:
MsgBox("Modal Test", "")
case repainttest:
case a.repainttest:
a.areahandler.mutate()
a.a.RepaintAll()
}
@ -378,7 +380,7 @@ func runMainTest() {
handler.resetl = func() {
handler.l.SetText("This is a label")
}
handler.b3 := NewButton("List Info")
handler.b3 = NewButton("List Info")
s3 := NewHorizontalStack(handler.l, handler.b3)
s3.SetStretchy(0)
// s3.SetStretchy(1)
@ -390,15 +392,15 @@ func runMainTest() {
handler.invalidButton = NewButton("Run Invalid Test")
sincdec := NewHorizontalStack(handler.incButton, handler.decButton, handler.indetButton, handler.invalidButton)
handler.password = NewPasswordEdit()
s0 := NewVerticalStack(handler.s2, handler.c, handler.cb1, handler.cb2, handler.e, handler.s3, handler.pbar, handler.sincdec, Space(), handler.password)
s0 := NewVerticalStack(s2, handler.c, handler.cb1, handler.cb2, handler.e, s3, handler.pbar, sincdec, Space(), handler.password)
s0.SetStretchy(8)
handler.lb1 = NewMultiSelListbox("Select One", "Or More", "To Continue")
handler.lb2 = NewListbox("Select", "Only", "One", "Please")
handler.i = 0
handler.doAdjustments = func() {
handler.cb1.Append("append")
handler.cb2.InsertBefore(fmt.Sprintf("before %d", i), 1)
handler.lb1.InsertBefore(fmt.Sprintf("%d", i), 2)
handler.cb2.InsertBefore(fmt.Sprintf("before %d", handler.i), 1)
handler.lb1.InsertBefore(fmt.Sprintf("%d", handler.i), 2)
handler.lb2.Append("Please")
handler.i++
}
@ -414,8 +416,8 @@ func runMainTest() {
if *invalidBefore {
invalidTest(handler.cb1, handler.lb1, s, NewGrid(1, Space()))
}
w.SetSpaced(*spacingTest)
w.Open(s)
handler.w.SetSpaced(*spacingTest)
handler.w.Open(s)
if *gridtest {
gridWindow()
}
@ -481,7 +483,7 @@ func (handler *testwinhandler) Event(e Event, d interface{}) {
switch e {
case Closing:
println("window closed event received")
*(d.(*bool)) = true
Stop <- struct{}{}
case Clicked:
switch d {
case handler.b:
@ -555,7 +557,7 @@ type dialoghandler struct {
}
// == TODO ==
func (handler *dialoghandler) Event(e Event, d Data) {
func (handler *dialoghandler) Event(e Event, d interface{}) {
if e == Clicked {
switch d {
case handler.bMsgBox:

View File

@ -41,7 +41,7 @@ func spaceTest() {
a2 := NewArea(w, h, ah)
a3 := NewArea(w, h, ah)
a4 := NewArea(w, h, ah)
win := NewWindow("Stack", 250, 250, nullwindowhandler{})
win := NewWindow("Stack", 250, 250, nullwinhandler{})
win.SetSpaced(true)
win.Open(f(a1, a2))
win = NewWindow("Grid", 250, 250, nullwinhandler{})

View File

@ -3,6 +3,12 @@ ALL:
- gtk+: currently requires labels to be filling for this to work: grids don't do this by default, for instance
- won't cause any issues, just an inconvenience that should be addressed
- make sure tab stop behavior for Areas makes sense, or provide a handler function
- the following seems weird and will not allow clean removal of the last window; think of something better?
```
case ui.Closing:
*(d.(*bool)) = true
ui.Stop <- struct{}{}
```
MAC OS X:
- NSComboBox scans the entered text to see if it matches one of the items and returns the index of that item if it does; find out how to suppress this so that it returns -1 unless the item was chosen from the list (like the other platforms)
@ -13,9 +19,6 @@ MAC OS X:
- probably use fittingSize instead of sizeToFit
WINDOWS:
- there seems to be a caching issue: with the test program and `-dialog`, click one of the dialog buttons, then quickly tap one of the buttons in the main window. The dialog will pop up twice, and after both are closed the program aborts with a send on closed channel
- appears to be a bug in my dialog code
- appears to have *always* been a bug in dialog code...
- windows: windows key handling is just wrong; figure out how to avoid (especially since Windows intercepts that key by default)
- control sizing is a MAJOR pain
- http://stackoverflow.com/questions/24130548/is-there-a-proper-way-to-get-the-preferred-size-of-windows-controls-there-are-s

View File

@ -4,7 +4,6 @@ package ui
import (
"fmt"
"runtime"
"syscall"
"unsafe"
)
@ -46,13 +45,15 @@ var (
_postMessage = user32.NewProc("PostMessageW")
)
var msghwnd _HWND
func uiinit() error {
err := doWindowsInit()
if err != nil {
return fmt.Errorf("error doing general Windows initialization: %v", err)
}
hwnd, err := makeMessageHandler()
msghwnd, err = makeMessageHandler()
if err != nil {
return fmt.Errorf("error making invisible window for handling events: %v", err)
}
@ -68,7 +69,7 @@ func ui() {
select {
case m := <-uitask:
r1, _, err := _postMessage.Call(
uintptr(hwnd),
uintptr(msghwnd),
msgRequested,
uintptr(0),
uintptr(unsafe.Pointer(&m)))
@ -77,10 +78,10 @@ func ui() {
}
case <-Stop:
r1, _, err := _postMessage.Call(
uintptr(hwnd),
msgQuit,
uintptr(0),
uintptr(0))
uintptr(msghwnd),
msgQuit,
uintptr(0),
uintptr(0))
if r1 == 0 { // failure
panic("error sending quit message to message loop: " + err.Error())
}

View File

@ -88,20 +88,15 @@ func (w *Window) SetSpaced(spaced bool) {
// Open creates the Window with Create and then shows the Window with Show. As with Create, you cannot call Open more than once per window.
func (w *Window) Open(control Control) {
done := make(chan struct{})
defer close(done)
touitask(func() {
w.Create(control)
w.Show()
done <- struct{}{}
})
<-done
w.create(control, true)
}
// Create creates the Window, setting its control to the given control. It does not show the window. This can only be called once per window, and finalizes all initialization of the control.
func (w *Window) Create(control Control) {
done := make(chan struct{})
defer close(done)
w.create(control, false)
}
func (w *Window) create(control Control, show bool) {
touitask(func() {
if w.created {
panic("window already open")
@ -128,9 +123,10 @@ func (w *Window) Create(control Control) {
}
w.sysData.setText(w.initTitle)
w.created = true
done <- struct{}{}
if show {
w.Show()
}
})
<-done
}
// Show shows the window.

View File

@ -35,6 +35,7 @@ const _FALSE = 0
const _GWLP_USERDATA = -21
const _GWL_STYLE = -16
const _ICC_PROGRESS_CLASS = 32
const _IDOK = 1
const _LBS_EXTENDEDSEL = 2048
const _LBS_NOINTEGRALHEIGHT = 256
const _LBS_NOTIFY = 1

View File

@ -35,6 +35,7 @@ const _FALSE = 0
const _GWLP_USERDATA = -21
const _GWL_STYLE = -16
const _ICC_PROGRESS_CLASS = 32
const _IDOK = 1
const _LBS_EXTENDEDSEL = 2048
const _LBS_NOINTEGRALHEIGHT = 256
const _LBS_NOTIFY = 1