diff --git a/ui/app/internal/input/router.go b/ui/app/internal/input/router.go index a70cdfa6..a663a66b 100644 --- a/ui/app/internal/input/router.go +++ b/ui/app/internal/input/router.go @@ -37,8 +37,8 @@ type handlerEvents struct { updated bool } -func (q *Router) Next(k ui.Key) (ui.Event, bool) { - return q.handlers.Next(k) +func (q *Router) Events(k ui.Key) []ui.Event { + return q.handlers.Events(k) } func (q *Router) Frame(ops *ui.Ops) { @@ -124,14 +124,12 @@ func (h *handlerEvents) Updated() bool { return u } -func (h *handlerEvents) Next(k ui.Key) (ui.Event, bool) { - events := h.handlers[k] - if len(events) == 0 { - return nil, false +func (h *handlerEvents) Events(k ui.Key) []ui.Event { + if events, ok := h.handlers[k]; ok { + h.handlers[k] = h.handlers[k][:0] + return events } - e := events[0] - h.handlers[k] = events[1:] - return e, true + return nil } func (h *handlerEvents) Clear() { diff --git a/ui/app/window.go b/ui/app/window.go index 3f90a7d8..d08b3874 100644 --- a/ui/app/window.go +++ b/ui/app/window.go @@ -323,8 +323,8 @@ func (w *Window) run(opts *windowOptions) { } } -func (q *Queue) Next(k ui.Key) (ui.Event, bool) { - return q.q.Next(k) +func (q *Queue) Events(k ui.Key) []ui.Event { + return q.q.Events(k) } // WithTitle returns an option that sets the window title. diff --git a/ui/doc.go b/ui/doc.go index f46d9681..533282b5 100644 --- a/ui/doc.go +++ b/ui/doc.go @@ -89,7 +89,7 @@ For example: var queue ui.Queue = ... - for e, ok := queue.Next(h); ok; e, ok = queue.Next(h) { + for _, e := range queue.Events(h) { switch e.(type) { ... } diff --git a/ui/gesture/gesture.go b/ui/gesture/gesture.go index 5e58638c..78064628 100644 --- a/ui/gesture/gesture.go +++ b/ui/gesture/gesture.go @@ -105,8 +105,9 @@ func (c *Click) State() ClickState { } // Next returns the next click event, if any. -func (c *Click) Next(q ui.Queue) (ClickEvent, bool) { - for evt, ok := q.Next(c); ok; evt, ok = q.Next(c) { +func (c *Click) Events(q ui.Queue) []ClickEvent { + var events []ClickEvent + for _, evt := range q.Events(c) { e, ok := evt.(pointer.Event) if !ok { continue @@ -116,7 +117,7 @@ func (c *Click) Next(q ui.Queue) (ClickEvent, bool) { wasPressed := c.state == StatePressed c.state = StateNormal if wasPressed { - return ClickEvent{Type: TypeClick, Position: e.Position, Source: e.Source}, true + events = append(events, ClickEvent{Type: TypeClick, Position: e.Position, Source: e.Source}) } case pointer.Cancel: c.state = StateNormal @@ -125,7 +126,7 @@ func (c *Click) Next(q ui.Queue) (ClickEvent, bool) { break } c.state = StatePressed - return ClickEvent{Type: TypePress, Position: e.Position, Source: e.Source}, true + events = append(events, ClickEvent{Type: TypePress, Position: e.Position, Source: e.Source}) case pointer.Move: if c.state == StatePressed && !e.Hit { c.state = StateNormal @@ -134,7 +135,7 @@ func (c *Click) Next(q ui.Queue) (ClickEvent, bool) { } } } - return ClickEvent{}, false + return events } // Add the handler to the operation list to receive scroll events. @@ -159,7 +160,7 @@ func (s *Scroll) Scroll(cfg ui.Config, q ui.Queue, axis Axis) int { return 0 } total := 0 - for evt, ok := q.Next(s); ok; evt, ok = q.Next(s) { + for _, evt := range q.Events(s) { e, ok := evt.(pointer.Event) if !ok { continue diff --git a/ui/input.go b/ui/input.go index 9b85a6f7..57be0ef1 100644 --- a/ui/input.go +++ b/ui/input.go @@ -5,9 +5,9 @@ package ui // Queue maps an event handler key to the events // available to the handler. type Queue interface { - // Next returns the next available event, or - // false if none are available. - Next(k Key) (Event, bool) + // Events returns the available events for a + // Key. + Events(k Key) []Event } // Key is the stable identifier for an event handler. diff --git a/ui/text/editor.go b/ui/text/editor.go index bb417887..cb68d9c9 100644 --- a/ui/text/editor.go +++ b/ui/text/editor.go @@ -62,6 +62,9 @@ type Editor struct { scrollOff image.Point clicker gesture.Click + + // events is the list of events not yet processed. + events []ui.Event } type EditorEvent interface { @@ -71,7 +74,7 @@ type EditorEvent interface { // A ChangeEvent is generated for every user change to the text. type ChangeEvent struct{} -// A SubmitEvent is generated when and Editor's Submit is set +// A SubmitEvent is generated when Submit is set // and a carriage return key is pressed. type SubmitEvent struct{} @@ -80,8 +83,8 @@ const ( maxBlinkDuration = 10 * time.Second ) -// Next returns the next available editor event, or false if none are available. -func (e *Editor) Next(gtx *layout.Context) (EditorEvent, bool) { +// Event returns the next available editor event, or false if none are available. +func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) { // Crude configuration change detection. if scale := gtx.Px(ui.Sp(100)); scale != e.oldScale { e.invalidate() @@ -106,7 +109,7 @@ func (e *Editor) Next(gtx *layout.Context) (EditorEvent, bool) { e.scrollOff.Y += sdist soff = e.scrollOff.Y } - for evt, ok := e.clicker.Next(gtx.Queue); ok; evt, ok = e.clicker.Next(gtx.Queue) { + for _, evt := range e.clicker.Events(gtx.Queue) { switch { case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse, evt.Type == gesture.TypeClick && evt.Source == pointer.Touch: @@ -124,7 +127,15 @@ func (e *Editor) Next(gtx *layout.Context) (EditorEvent, bool) { if (sdist > 0 && soff >= smax) || (sdist < 0 && soff <= smin) { e.scroller.Stop() } - for ke, ok := gtx.Queue.Next(e); ok; ke, ok = gtx.Queue.Next(e) { + e.events = append(e.events, gtx.Queue.Events(e)...) + return e.editorEvent(gtx) +} + +func (e *Editor) editorEvent(gtx *layout.Context) (EditorEvent, bool) { + for len(e.events) > 0 { + ke := e.events[0] + copy(e.events, e.events[1:]) + e.events = e.events[:len(e.events)-1] e.blinkStart = gtx.Now() switch ke := ke.(type) { case key.FocusEvent: @@ -133,7 +144,7 @@ func (e *Editor) Next(gtx *layout.Context) (EditorEvent, bool) { if !e.focused { break } - if e.Submit && (ke.Name == key.NameReturn || ke.Name == key.NameEnter) { + if e.Submit && ke.Name == key.NameReturn || ke.Name == key.NameEnter { if !ke.Modifiers.Contain(key.ModShift) { return SubmitEvent{}, true } @@ -166,7 +177,7 @@ func (e *Editor) Focus() { func (e *Editor) Layout(gtx *layout.Context) { cs := gtx.Constraints - for _, ok := e.Next(gtx); ok; _, ok = e.Next(gtx) { + for _, ok := e.Event(gtx); ok; _, ok = e.Event(gtx) { } twoDp := gtx.Px(ui.Dp(2)) e.padLeft, e.padRight = twoDp, twoDp