Migrated window.go and sysdata.go to the new API. Controls will need to be migrated as well.

This commit is contained in:
Pietro Gagliardi 2014-06-28 01:22:40 -04:00
parent ea6200a432
commit d13e398e90
2 changed files with 28 additions and 53 deletions

View File

@ -2,21 +2,15 @@
package ui package ui
const eventbufsiz = 100 // suggested by skelterjohn
// newEvent returns a new channel suitable for listening for events.
func newEvent() chan struct{} {
return make(chan struct{}, eventbufsiz)
}
// The sysData type contains all system data. It provides the system-specific underlying implementation. It is guaranteed to have the following by embedding: // The sysData type contains all system data. It provides the system-specific underlying implementation. It is guaranteed to have the following by embedding:
type cSysData struct { type cSysData struct {
ctype int ctype int
event chan struct{}
allocate func(x int, y int, width int, height int, d *sysSizeData) []*allocation allocate func(x int, y int, width int, height int, d *sysSizeData) []*allocation
spaced bool spaced bool
alternate bool // editable for Combobox, multi-select for listbox, password for lineedit alternate bool // editable for Combobox, multi-select for listbox, password for lineedit
handler AreaHandler // for Areas handler AreaHandler // for Areas; TODO rename to areahandler
winhandler WindowHandler // for Windows
event func() // provided by each widget
} }
// this interface is used to make sure all sysDatas are synced // this interface is used to make sure all sysDatas are synced
@ -44,19 +38,6 @@ var _xSysData interface {
setChecked(bool) setChecked(bool)
} = &sysData{} // this line will error if there's an inconsistency } = &sysData{} // this line will error if there's an inconsistency
// signal sends the event signal. This raise is done asynchronously to avoid deadlocking the UI task.
// Thanks skelterjohn for this techinque: if we can't queue any more events, drop them
func (s *cSysData) signal() {
if s.event != nil {
go func() {
select {
case s.event <- struct{}{}:
default:
}
}()
}
}
const ( const (
c_window = iota c_window = iota
c_button c_button

View File

@ -4,17 +4,10 @@ package ui
import ( import (
"fmt" "fmt"
"sync"
) )
// Window represents an on-screen window. // Window represents an on-screen window.
type Window struct { type Window struct {
// Closing gets a message when the user clicks the window's close button.
// You cannot change it once the Window has been created.
// If you do not respond to this signal, nothing will happen; regardless of whether you handle the signal or not, the window will not be closed.
Closing chan struct{}
lock sync.Mutex
created bool created bool
sysData *sysData sysData *sysData
initTitle string initTitle string
@ -22,24 +15,44 @@ type Window struct {
initHeight int initHeight int
shownOnce bool shownOnce bool
spaced bool spaced bool
handler WindowHandler
} }
// WindowHandler represents an event handler for a Window and all its child Controls.
//
// When an event on a Window or one of its child Controls comes in, the respect Window's handler's Event() method is called. The method call occurs on the main thread, and thus any call to any package ui method can be performed.
//
// Each Event() call takes two parameters: the event ID and a data argument. For most events, the data argument is a pointer to the Control that triggered the event.
//
// For Closing, the data argument is [TODO].
//
// For any event >= CustomEvent, the data argument is the argument passed to the Window's SendEvent() method.
type WindowHandler interface {
Event(e Event, data interface{})
}
// Event represents an event; see WindowHandler for details.
// All event values >= CustomEvent are available for program use.
type Event int
const (
Closing Event = iota // Window close
Clicked // Button click
CustomEvent = 5000 // very high number; higher than the package would ever need, anyway
)
// NewWindow allocates a new Window with the given title and size. The window is not created until a call to Create() or Open(). // NewWindow allocates a new Window with the given title and size. The window is not created until a call to Create() or Open().
func NewWindow(title string, width int, height int) *Window { func NewWindow(title string, width int, height int, handler WindowHandler) *Window {
return &Window{ return &Window{
sysData: mksysdata(c_window), sysData: mksysdata(c_window),
initTitle: title, initTitle: title,
initWidth: width, initWidth: width,
initHeight: height, initHeight: height,
Closing: newEvent(), handler: handler,
} }
} }
// SetTitle sets the window's title. // SetTitle sets the window's title.
func (w *Window) SetTitle(title string) { func (w *Window) SetTitle(title string) {
w.lock.Lock()
defer w.lock.Unlock()
if w.created { if w.created {
w.sysData.setText(title) w.sysData.setText(title)
return return
@ -49,9 +62,6 @@ func (w *Window) SetTitle(title string) {
// SetSize sets the window's size. // SetSize sets the window's size.
func (w *Window) SetSize(width int, height int) (err error) { func (w *Window) SetSize(width int, height int) (err error) {
w.lock.Lock()
defer w.lock.Unlock()
if w.created { if w.created {
err := w.sysData.setWindowSize(width, height) err := w.sysData.setWindowSize(width, height)
if err != nil { if err != nil {
@ -70,9 +80,6 @@ func (w *Window) SetSize(width int, height int) (err error) {
// This property is visible recursively throughout the widget hierarchy of the Window. // This property is visible recursively throughout the widget hierarchy of the Window.
// This property cannot be set after the Window has been created. // This property cannot be set after the Window has been created.
func (w *Window) SetSpaced(spaced bool) { func (w *Window) SetSpaced(spaced bool) {
w.lock.Lock()
defer w.lock.Unlock()
if w.created { if w.created {
panic(fmt.Errorf("Window.SetSpaced() called after window created")) panic(fmt.Errorf("Window.SetSpaced() called after window created"))
} }
@ -87,14 +94,10 @@ func (w *Window) Open(control Control) {
// 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. // 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) { func (w *Window) Create(control Control) {
w.lock.Lock()
defer w.lock.Unlock()
if w.created { if w.created {
panic("window already open") panic("window already open")
} }
w.sysData.spaced = w.spaced w.sysData.spaced = w.spaced
w.sysData.event = w.Closing
err := w.sysData.make(nil) err := w.sysData.make(nil)
if err != nil { if err != nil {
panic(fmt.Errorf("error opening window: %v", err)) panic(fmt.Errorf("error opening window: %v", err))
@ -116,9 +119,6 @@ func (w *Window) Create(control Control) {
// Show shows the window. // Show shows the window.
func (w *Window) Show() { func (w *Window) Show() {
w.lock.Lock()
defer w.lock.Unlock()
if !w.shownOnce { if !w.shownOnce {
w.shownOnce = true w.shownOnce = true
err := w.sysData.firstShow() err := w.sysData.firstShow()
@ -132,9 +132,6 @@ func (w *Window) Show() {
// Hide hides the window. // Hide hides the window.
func (w *Window) Hide() { func (w *Window) Hide() {
w.lock.Lock()
defer w.lock.Unlock()
w.sysData.hide() w.sysData.hide()
} }
@ -142,9 +139,6 @@ func (w *Window) Hide() {
// The concept of "screen" in the case of a multi-monitor setup is implementation-defined. // The concept of "screen" in the case of a multi-monitor setup is implementation-defined.
// It presently panics if the Window has not been created. // It presently panics if the Window has not been created.
func (w *Window) Center() { func (w *Window) Center() {
w.lock.Lock()
defer w.lock.Unlock()
if !w.created { if !w.created {
panic("attempt to center Window before it has been created") panic("attempt to center Window before it has been created")
} }