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:
parent
02d6a03ba3
commit
affc65a5a4
|
@ -14,7 +14,6 @@ func NewButton(text string) (b *Button) {
|
|||
return &Button{
|
||||
sysData: mksysdata(c_button),
|
||||
initText: text,
|
||||
Clicked: newEvent(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
15
init.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
40
test/main.go
40
test/main.go
|
@ -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:
|
||||
|
|
|
@ -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{})
|
||||
|
|
9
todo.md
9
todo.md
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
20
window.go
20
window.go
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue