Started dropping the whole request/response system because it fell apart... time to make a ui.Do(func(){ ... })

This commit is contained in:
Pietro Gagliardi 2014-07-19 09:44:32 -04:00
parent 47c0f573a9
commit 48c5055eb9
8 changed files with 202 additions and 460 deletions

View File

@ -16,24 +16,15 @@ type Control interface {
type Button interface { type Button interface {
Control Control
// OnClicked creates a Request to set the event handler for when the Button is clicked. // OnClicked sets the event handler for when the Button is clicked.
OnClicked(func(d Doer)) *Request OnClicked(func())
// Text and SetText creates a Request that get and set the Button's label text. // Text and SetText get and set the Button's label text.
Text() *Request Text() string
SetText(text string) *Request SetText(text string)
} }
// NewButton creates a Request to create a new Button with the given label text. // NewButton creates a new Button with the given label text.
func NewButton(text string) *Request { func NewButton(text string) {
return newButton(text) return newButton(text)
} }
// GetNewButton is like NewButton but sends the Request along the given Doer and returns the resultant Button.
// Example:
// b := ui.GetNewButton(ui.Do, "OK")
func GetNewButton(c Doer, text string) Button {
req := newButton(text)
c <- req
return (<-req.resp).(Button)
}

View File

@ -50,32 +50,19 @@ type button struct {
clicked *event clicked *event
} }
func newButton(text string) *Request { func newButton(text string) *button {
c := make(chan interface{}) ctext := C.CString(text)
return &Request{ defer C.free(unsafe.Pointer(ctext))
op: func() { b := &button{
ctext := C.CString(text) widgetbase: newWidget(C.newButton(ctext)),
defer C.free(unsafe.Pointer(ctext)) clicked: newEvent(),
b := &button{
widgetbase: newWidget(C.newButton(ctext)),
clicked: newEvent(),
}
C.buttonSetDelegate(b.id, unsafe.Pointer(b))
c <- b
},
resp: c,
} }
C.buttonSetDelegate(b.id, unsafe.Pointer(b))
return b
} }
func (b *button) OnClicked(e func(c Doer)) *Request { func (b *button) OnClicked(e func()) {
c := make(chan interface{}) b.clicked.set(e)
return &Request{
op: func() {
b.clicked.set(e)
c <- struct{}{}
},
resp: c,
}
} }
//export buttonClicked //export buttonClicked
@ -85,25 +72,12 @@ func buttonClicked(xb unsafe.Pointer) {
println("button clicked") println("button clicked")
} }
func (b *button) Text() *Request { func (b *button) Text() string {
c := make(chan interface{}) return C.GoString(C.buttonText(b.id))
return &Request{
op: func() {
c <- C.GoString(C.buttonText(b.id))
},
resp: c,
}
} }
func (b *button) SetText(text string) *Request { func (b *button) SetText(text string) {
c := make(chan interface{}) ctext := C.CString(text)
return &Request{ defer C.free(unsafe.Pointer(ctext))
op: func() { C.buttonSetText(b.id, ctext)
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
C.buttonSetText(b.id, ctext)
c <- struct{}{}
},
resp: c,
}
} }

View File

@ -53,38 +53,25 @@ type button struct {
clicked *event clicked *event
} }
func newButton(text string) *Request { func newButton(text string) *button {
c := make(chan interface{}) ctext := togstr(text)
return &Request{ defer freegstr(ctext)
op: func() { widget := C.gtk_button_new_with_label(ctext)
ctext := togstr(text) b := &button{
defer freegstr(ctext) widgetbase: newWidget(widget),
widget := C.gtk_button_new_with_label(ctext) button: (*C.GtkButton)(unsafe.Pointer(widget)),
b := &button{ clicked: newEvent(),
widgetbase: newWidget(widget),
button: (*C.GtkButton)(unsafe.Pointer(widget)),
clicked: newEvent(),
}
g_signal_connect(
C.gpointer(unsafe.Pointer(b.button)),
"clicked",
C.GCallback(C.buttonClicked),
C.gpointer(unsafe.Pointer(b)))
c <- b
},
resp: c,
} }
g_signal_connect(
C.gpointer(unsafe.Pointer(b.button)),
"clicked",
C.GCallback(C.buttonClicked),
C.gpointer(unsafe.Pointer(b)))
return b
} }
func (b *button) OnClicked(e func(c Doer)) *Request { func (b *button) OnClicked(e func()) {
c := make(chan interface{}) b.clicked.set(e)
return &Request{
op: func() {
b.clicked.set(e)
c <- struct{}{}
},
resp: c,
}
} }
//export buttonClicked //export buttonClicked
@ -94,25 +81,12 @@ func buttonClicked(bwid *C.GtkButton, data C.gpointer) {
println("button clicked") println("button clicked")
} }
func (b *button) Text() *Request { func (b *button) Text() string {
c := make(chan interface{}) return fromgstr(C.gtk_button_get_label(b.button))
return &Request{
op: func() {
c <- fromgstr(C.gtk_button_get_label(b.button))
},
resp: c,
}
} }
func (b *button) SetText(text string) *Request { func (b *button) SetText(text string) {
c := make(chan interface{}) ctext := togstr(text)
return &Request{ defer freegstr(ctext)
op: func() { C.gtk_button_set_label(b.button, ctext)
ctext := togstr(text)
defer freegstr(ctext)
C.gtk_button_set_label(b.button, ctext)
c <- struct{}{}
},
resp: c,
}
} }

View File

@ -31,25 +31,12 @@ func (w *widgetbase) parent(win *window) {
// don't embed these as exported; let each Control decide if it should // don't embed these as exported; let each Control decide if it should
func (w *widgetbase) text() *Request { func (w *widgetbase) text() string {
c := make(chan interface{}) return getWindowText(w.hwnd)
return &Request{
op: func() {
c <- getWindowText(w.hwnd)
},
resp: c,
}
} }
func (w *widgetbase) settext(text string) *Request { func (w *widgetbase) settext(text string) {
c := make(chan interface{}) C.setWindowText(w.hwnd, toUTF16(text))
return &Request{
op: func() {
C.setWindowText(w.hwnd, toUTF16(text))
c <- struct{}{}
},
resp: c,
}
} }
type button struct { type button struct {
@ -59,42 +46,30 @@ type button struct {
var buttonclass = toUTF16("BUTTON") var buttonclass = toUTF16("BUTTON")
func newButton(text string) *Request { func newButton(text string) *button {
c := make(chan interface{}) op: func() {
return &Request{ w := newWidget(buttonclass,
op: func() { C.BS_PUSHBUTTON | C.WS_TABSTOP,
w := newWidget(buttonclass, 0)
C.BS_PUSHBUTTON | C.WS_TABSTOP, C.setWindowText(w.hwnd, toUTF16(text))
0) C.controlSetControlFont(w.hwnd)
C.setWindowText(w.hwnd, toUTF16(text)) b := &button{
C.controlSetControlFont(w.hwnd) widgetbase: w,
b := &button{ clicked: newEvent(),
widgetbase: w,
clicked: newEvent(),
}
C.setButtonSubclass(w.hwnd, unsafe.Pointer(b))
c <- b
},
resp: c,
} }
C.setButtonSubclass(w.hwnd, unsafe.Pointer(b))
return b
} }
func (b *button) OnClicked(e func(c Doer)) *Request { func (b *button) OnClicked(e func()) {
c := make(chan interface{}) b.clicked.set(e)
return &Request{
op: func() {
b.clicked.set(e)
c <- struct{}{}
},
resp: c,
}
} }
func (b *button) Text() *Request { func (b *button) Text() string {
return b.text() return b.text()
} }
func (b *button) SetText(text string) *Request { func (b *button) SetText(text string) {
return b.settext(text) return b.settext(text)
} }

View File

@ -6,41 +6,32 @@ package ui
// Windows in package ui can only contain one control; the Stack and Grid layout Controls allow you to pack multiple Controls in a Window. // Windows in package ui can only contain one control; the Stack and Grid layout Controls allow you to pack multiple Controls in a Window.
// Note that a Window is not itself a Control. // Note that a Window is not itself a Control.
type Window interface { type Window interface {
// SetControl creates a Request to the Window's child Control. // SetControl sets the Window's child Control.
SetControl(c Control) *Request SetControl(c Control)
// Title and SetTitle create Requests to get and set the Window's title, respectively. // Title and SetTitle get and set the Window's title, respectively.
Title() *Request Title() string
SetTitle(title string) *Request SetTitle(title string)
// Show and Hide create Requests to bring the Window on-screen and off-screen, respectively. // Show and Hide bring the Window on-screen and off-screen, respectively.
Show() *Request Show()
Hide() *Request Hide()
// Close creates a Request to close the Window. // Close closes the Window.
// Any Controls within the Window are destroyed, and the Window itself is also destroyed. // Any Controls within the Window are destroyed, and the Window itself is also destroyed.
// Attempting to use a Window after it has been closed results in undefined behavior. // Attempting to use a Window after it has been closed results in undefined behavior.
// Close unconditionally closes the Window; it neither raises OnClosing nor checks for a return from OnClosing. // Close unconditionally closes the Window; it neither raises OnClosing nor checks for a return from OnClosing.
// TODO make sure the above happens on GTK+ and Mac OS X; it does on Windows // TODO make sure the above happens on GTK+ and Mac OS X; it does on Windows
Close() *Request Close()
// OnClosing creates a Request to register an event handler that is triggered when the user clicks the Window's close button. // OnClosing registers an event handler that is triggered when the user clicks the Window's close button.
// On systems where whole applications own windows, OnClosing is also triggered when the user asks to close the application. // On systems where whole applications own windows, OnClosing is also triggered when the user asks to close the application.
// If this handler returns true, the Window is closed as defined by Close above. // If this handler returns true, the Window is closed as defined by Close above.
// If this handler returns false, the Window is not closed. // If this handler returns false, the Window is not closed.
OnClosing(func(c Doer) bool) *Request OnClosing(func() bool)
} }
// NewWindow returns a Request to create a new Window with the given title text and size. // NewWindow creates a new Window with the given title text and size.
func NewWindow(title string, width int, height int) *Request { func NewWindow(title string, width int, height int) Window {
return newWindow(title, width, height) return newWindow(title, width, height)
} }
// GetNewWindow is like NewWindow but sends the Request along the given Doer and returns the resultant Window.
// Example:
// w := ui.GetNewWindow(ui.Do, "Main Window")
func GetNewWindow(c Doer, title string, width int, height int) Window {
req := newWindow(title, width, height)
c <- req
return (<-req.resp).(Window)
}

View File

@ -20,106 +20,52 @@ type window struct {
spaced bool spaced bool
} }
func newWindow(title string, width int, height int) *Request { func newWindow(title string, width int, height int) *window {
c := make(chan interface{}) id := C.newWindow(C.intptr_t(width), C.intptr_t(height))
return &Request{ ctitle := C.CString(title)
op: func() { defer C.free(unsafe.Pointer(ctitle))
id := C.newWindow(C.intptr_t(width), C.intptr_t(height)) C.windowSetTitle(id, ctitle)
ctitle := C.CString(title) w := &window{
defer C.free(unsafe.Pointer(ctitle)) id: id,
C.windowSetTitle(id, ctitle) closing: newEvent(),
w := &window{
id: id,
closing: newEvent(),
}
C.windowSetDelegate(id, unsafe.Pointer(w))
c <- w
},
resp: c,
} }
C.windowSetDelegate(id, unsafe.Pointer(w))
return w
} }
func (w *window) SetControl(control Control) *Request { func (w *window) SetControl(control Control) {
c := make(chan interface{}) if w.child != nil { // unparent existing control
return &Request{ w.child.unparent()
op: func() {
if w.child != nil { // unparent existing control
w.child.unparent()
}
control.unparent()
control.parent(w)
w.child = control
c <- struct{}{}
},
resp: c,
} }
control.unparent()
control.parent(w)
w.child = control
} }
func (w *window) Title() *Request { func (w *window) Title() string {
c := make(chan interface{}) return C.GoString(C.windowTitle(w.id))
return &Request{
op: func() {
c <- C.GoString(C.windowTitle(w.id))
},
resp: c,
}
} }
func (w *window) SetTitle(title string) *Request { func (w *window) SetTitle(title string) {
c := make(chan interface{}) ctitle := C.CString(title)
return &Request{ defer C.free(unsafe.Pointer(ctitle))
op: func() { C.windowSetTitle(w.id, ctitle)
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
C.windowSetTitle(w.id, ctitle)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Show() *Request { func (w *window) Show() {
c := make(chan interface{}) C.windowShow(w.id)
return &Request{
op: func() {
C.windowShow(w.id)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Hide() *Request { func (w *window) Hide() {
c := make(chan interface{}) C.windowHide(w.id)
return &Request{
op: func() {
C.windowHide(w.id)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Close() *Request { func (w *window) Close() {
c := make(chan interface{}) C.windowClose(w.id)
return &Request{
op: func() {
C.windowClose(w.id)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) OnClosing(e func(c Doer) bool) *Request { func (w *window) OnClosing(e func() bool) {
c := make(chan interface{}) w.closing.setbool(e)
return &Request{
op: func() {
w.closing.setbool(e)
c <- struct{}{}
},
resp: c,
}
} }
//export windowClosing //export windowClosing

View File

@ -30,128 +30,73 @@ type window struct {
spaced bool spaced bool
} }
func newWindow(title string, width int, height int) *Request { func newWindow(title string, width int, height int) *window {
c := make(chan interface{}) widget := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL)
return &Request{ ctitle := togstr(title)
op: func() { defer freegstr(ctitle)
widget := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL) layoutw := C.gtk_layout_new(nil, nil)
ctitle := togstr(title) w := &window{
defer freegstr(ctitle) widget: widget,
layoutw := C.gtk_layout_new(nil, nil) container: (*C.GtkContainer)(unsafe.Pointer(widget)),
w := &window{ bin: (*C.GtkBin)(unsafe.Pointer(widget)),
widget: widget, window: (*C.GtkWindow)(unsafe.Pointer(widget)),
container: (*C.GtkContainer)(unsafe.Pointer(widget)), layoutc: (*C.GtkContainer)(unsafe.Pointer(layoutw)),
bin: (*C.GtkBin)(unsafe.Pointer(widget)), layout: (*C.GtkLayout)(unsafe.Pointer(layoutw)),
window: (*C.GtkWindow)(unsafe.Pointer(widget)), closing: newEvent(),
layoutc: (*C.GtkContainer)(unsafe.Pointer(layoutw)),
layout: (*C.GtkLayout)(unsafe.Pointer(layoutw)),
closing: newEvent(),
}
C.gtk_window_set_title(w.window, ctitle)
g_signal_connect(
C.gpointer(unsafe.Pointer(w.window)),
"delete-event",
C.GCallback(C.windowClosing),
C.gpointer(unsafe.Pointer(w)))
// we connect to the layout's size-allocate, not to the window's configure-event
// this allows us to handle client-side decoration-based configurations (such as GTK+ on Wayland) properly
// also see commitResize() in sizing_unix.go for additional notes
// thanks to many people in irc.gimp.net/#gtk+ for help (including tristan for suggesting g_signal_connect_after())
g_signal_connect_after(
C.gpointer(unsafe.Pointer(layoutw)),
"size-allocate",
C.GCallback(C.windowResizing),
C.gpointer(unsafe.Pointer(w)))
// TODO size
C.gtk_container_add(w.container, layoutw)
c <- w
},
resp: c,
} }
C.gtk_window_set_title(w.window, ctitle)
g_signal_connect(
C.gpointer(unsafe.Pointer(w.window)),
"delete-event",
C.GCallback(C.windowClosing),
C.gpointer(unsafe.Pointer(w)))
// we connect to the layout's size-allocate, not to the window's configure-event
// this allows us to handle client-side decoration-based configurations (such as GTK+ on Wayland) properly
// also see commitResize() in sizing_unix.go for additional notes
// thanks to many people in irc.gimp.net/#gtk+ for help (including tristan for suggesting g_signal_connect_after())
g_signal_connect_after(
C.gpointer(unsafe.Pointer(layoutw)),
"size-allocate",
C.GCallback(C.windowResizing),
C.gpointer(unsafe.Pointer(w)))
// TODO size
C.gtk_container_add(w.container, layoutw)
return w
} }
func (w *window) SetControl(control Control) *Request { func (w *window) SetControl(control Control) {
c := make(chan interface{}) if w.child != nil { // unparent existing control
return &Request{ w.child.unparent()
op: func() {
if w.child != nil { // unparent existing control
w.child.unparent()
}
control.unparent()
control.parent(w)
w.child = control
c <- struct{}{}
},
resp: c,
} }
control.unparent()
control.parent(w)
w.child = control
} }
func (w *window) Title() *Request { func (w *window) Title() string {
c := make(chan interface{}) return fromgstr(C.gtk_window_get_title(w.window))
return &Request{
op: func() {
c <- fromgstr(C.gtk_window_get_title(w.window))
},
resp: c,
}
} }
func (w *window) SetTitle(title string) *Request { func (w *window) SetTitle(title string) {
c := make(chan interface{}) ctitle := togstr(title)
return &Request{ defer freegstr(ctitle)
op: func() { C.gtk_window_set_title(w.window, ctitle)
ctitle := togstr(title)
defer freegstr(ctitle)
C.gtk_window_set_title(w.window, ctitle)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Show() {
func (w *window) Show() *Request { C.gtk_widget_show_all(w.widget)
c := make(chan interface{})
return &Request{
op: func() {
C.gtk_widget_show_all(w.widget)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Hide() *Request { func (w *window) Hide() {
c := make(chan interface{}) C.gtk_widget_hide(w.widget)
return &Request{
op: func() {
C.gtk_widget_hide(w.widget)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) Close() *Request { func (w *window) Close() {
c := make(chan interface{}) C.gtk_widget_destroy(w.widget)
return &Request{
op: func() {
C.gtk_widget_destroy(w.widget)
c <- struct{}{}
},
resp: c,
}
} }
func (w *window) OnClosing(e func(c Doer) bool) *Request { func (w *window) OnClosing(e func() bool) {
c := make(chan interface{}) w.closing.setbool(e)
return &Request{
op: func() {
w.closing.setbool(e)
c <- struct{}{}
},
resp: c,
}
} }
//export windowClosing //export windowClosing

View File

@ -35,109 +35,55 @@ func makeWindowWindowClass() error {
return nil return nil
} }
func newWindow(title string, width int, height int) *Request { func newWindow(title string, width int, height int) *window {
c := make(chan interface{}) w := &window{
return &Request{ // hwnd set in WM_CREATE handler
op: func() { closing: newEvent(),
w := &window{ }
// hwnd set in WM_CREATE handler hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
closing: newEvent(), if hwnd != w.hwnd {
} panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in window (%p) differ", hwnd, w.hwnd))
hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w)) }
if hwnd != w.hwnd { return w
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in window (%p) differ", hwnd, w.hwnd)) }
}
c <- w func (w *window) SetControl(control Control) {
}, if w.child != nil { // unparent existing control
resp: c, w.child.unparent()
}
control.unparent()
control.parent(w)
w.child = control
}
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) SetControl(control Control) *Request { func (w *window) Hide() {
c := make(chan interface{}) C.ShowWindow(w.hwnd, C.SW_HIDE)
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 { func (w *window) Close() {
c := make(chan interface{}) C.windowClose(w.hwnd)
return &Request{
op: func() {
c <- getWindowText(w.hwnd)
},
resp: c,
}
} }
func (w *window) SetTitle(title string) *Request { func (w *window) OnClosing(e func() bool) {
c := make(chan interface{}) w.closing.setbool(e)
return &Request{
op: func() {
C.setWindowText(w.hwnd, toUTF16(title))
c <- struct{}{}
},
resp: c,
}
}
func (w *window) Show() *Request {
c := make(chan interface{})
return &Request{
op: func() {
if !w.shownbefore {
C.ShowWindow(w.hwnd, C.nCmdShow)
C.updateWindow(w.hwnd)
w.shownbefore = true
} else {
C.ShowWindow(w.hwnd, C.SW_SHOW)
}
c <- struct{}{}
},
resp: c,
}
}
func (w *window) Hide() *Request {
c := make(chan interface{})
return &Request{
op: func() {
C.ShowWindow(w.hwnd, C.SW_HIDE)
c <- struct{}{}
},
resp: c,
}
}
func (w *window) Close() *Request {
c := make(chan interface{})
return &Request{
op: func() {
C.windowClose(w.hwnd)
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,
}
} }
//export storeWindowHWND //export storeWindowHWND