mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
text: replace Editor.Event with Editor.Event and add Text to SubmitEvent
THe single-stepping Event was done so that SubmitEvents didn't have to copy the text out if it wasn't needed. This is a dubious optimization, because SubmitEvents are only generated when Editor.Submit is true, in which case it is highly likely the user wants the text. Furthermore, I expect Editors with Submit enabled to be relatively short, in the order of a message field in a chat program. Finally, Editor will need support for undo at some point. Supporting undo means we can support a lightweight SubmitEvent that points to an older Editor state. All in all (1) we gain a simpler Events method, and (2) we can allow the user to call it before or after Editor.Layout. Before this change any the events were gone after Layout was called. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+32
-20
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/gesture"
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
@@ -32,6 +31,7 @@ type Editor struct {
|
||||
// If not enabled, carriage returns are inserted as newlines in the text.
|
||||
Submit bool
|
||||
|
||||
eventKey int
|
||||
scale int
|
||||
font Font
|
||||
blinkStart time.Time
|
||||
@@ -58,7 +58,7 @@ type Editor struct {
|
||||
clicker gesture.Click
|
||||
|
||||
// events is the list of events not yet processed.
|
||||
events []event.Event
|
||||
events []EditorEvent
|
||||
}
|
||||
|
||||
type EditorEvent interface {
|
||||
@@ -70,7 +70,9 @@ type ChangeEvent struct{}
|
||||
|
||||
// A SubmitEvent is generated when Submit is set
|
||||
// and a carriage return key is pressed.
|
||||
type SubmitEvent struct{}
|
||||
type SubmitEvent struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
type line struct {
|
||||
offset f32.Point
|
||||
@@ -82,8 +84,20 @@ const (
|
||||
maxBlinkDuration = 10 * time.Second
|
||||
)
|
||||
|
||||
// Event returns the next available editor event, or false if none are available.
|
||||
func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) {
|
||||
// Events returns available editor events.
|
||||
func (e *Editor) Events(gtx *layout.Context) []EditorEvent {
|
||||
e.processEvents(gtx)
|
||||
events := e.events
|
||||
e.events = nil
|
||||
return events
|
||||
}
|
||||
|
||||
func (e *Editor) processEvents(gtx *layout.Context) {
|
||||
e.processPointer(gtx)
|
||||
e.processKey(gtx)
|
||||
}
|
||||
|
||||
func (e *Editor) processPointer(gtx *layout.Context) {
|
||||
sbounds := e.scrollBounds()
|
||||
var smin, smax int
|
||||
var axis gesture.Axis
|
||||
@@ -103,7 +117,7 @@ func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) {
|
||||
e.scrollRel(0, sdist)
|
||||
soff = e.scrollOff.Y
|
||||
}
|
||||
for _, evt := range e.clicker.Events(gtx.Queue) {
|
||||
for _, evt := range e.clicker.Events(gtx) {
|
||||
switch {
|
||||
case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse,
|
||||
evt.Type == gesture.TypeClick && evt.Source == pointer.Touch:
|
||||
@@ -121,15 +135,10 @@ func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) {
|
||||
if (sdist > 0 && soff >= smax) || (sdist < 0 && soff <= smin) {
|
||||
e.scroller.Stop()
|
||||
}
|
||||
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]
|
||||
func (e *Editor) processKey(gtx *layout.Context) {
|
||||
for _, ke := range gtx.Events(&e.eventKey) {
|
||||
e.blinkStart = gtx.Now()
|
||||
switch ke := ke.(type) {
|
||||
case key.FocusEvent:
|
||||
@@ -140,7 +149,9 @@ func (e *Editor) editorEvent(gtx *layout.Context) (EditorEvent, bool) {
|
||||
}
|
||||
if e.Submit && ke.Name == key.NameReturn || ke.Name == key.NameEnter {
|
||||
if !ke.Modifiers.Contain(key.ModShift) {
|
||||
return SubmitEvent{}, true
|
||||
e.events = append(e.events, SubmitEvent{
|
||||
Text: e.Text(),
|
||||
})
|
||||
}
|
||||
}
|
||||
if e.command(ke) {
|
||||
@@ -153,10 +164,9 @@ func (e *Editor) editorEvent(gtx *layout.Context) (EditorEvent, bool) {
|
||||
e.append(ke.Text)
|
||||
}
|
||||
if e.rr.Changed() {
|
||||
return ChangeEvent{}, true
|
||||
e.events = append(e.events, ChangeEvent{})
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Focus requests the input focus for the Editor.
|
||||
@@ -164,18 +174,20 @@ func (e *Editor) Focus() {
|
||||
e.requestFocus = true
|
||||
}
|
||||
|
||||
// Layout flushes any remaining events and lays out the editor.
|
||||
// Layout lays out the editor.
|
||||
func (e *Editor) Layout(gtx *layout.Context, sh *Shaper, font Font) {
|
||||
if e.font != font {
|
||||
e.invalidate()
|
||||
e.font = font
|
||||
}
|
||||
e.processEvents(gtx)
|
||||
e.layout(gtx, sh)
|
||||
if !e.clicker.Active() {
|
||||
e.events = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) layout(gtx *layout.Context, sh *Shaper) {
|
||||
for _, ok := e.Event(gtx); ok; _, ok = e.Event(gtx) {
|
||||
}
|
||||
// Crude configuration change detection.
|
||||
if scale := gtx.Px(unit.Sp(100)); scale != e.scale {
|
||||
e.invalidate()
|
||||
@@ -230,7 +242,7 @@ func (e *Editor) layout(gtx *layout.Context, sh *Shaper) {
|
||||
e.shapes = append(e.shapes, line{off, path})
|
||||
}
|
||||
|
||||
key.InputOp{Key: e, Focus: e.requestFocus}.Add(gtx.Ops)
|
||||
key.InputOp{Key: &e.eventKey, Focus: e.requestFocus}.Add(gtx.Ops)
|
||||
e.requestFocus = false
|
||||
pointerPadding := gtx.Px(unit.Dp(4))
|
||||
r := image.Rectangle{Max: e.viewSize}
|
||||
|
||||
Reference in New Issue
Block a user