mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +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/f32"
|
||||||
"gioui.org/gesture"
|
"gioui.org/gesture"
|
||||||
"gioui.org/io/event"
|
|
||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
"gioui.org/io/pointer"
|
"gioui.org/io/pointer"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
@@ -32,6 +31,7 @@ type Editor struct {
|
|||||||
// If not enabled, carriage returns are inserted as newlines in the text.
|
// If not enabled, carriage returns are inserted as newlines in the text.
|
||||||
Submit bool
|
Submit bool
|
||||||
|
|
||||||
|
eventKey int
|
||||||
scale int
|
scale int
|
||||||
font Font
|
font Font
|
||||||
blinkStart time.Time
|
blinkStart time.Time
|
||||||
@@ -58,7 +58,7 @@ type Editor struct {
|
|||||||
clicker gesture.Click
|
clicker gesture.Click
|
||||||
|
|
||||||
// events is the list of events not yet processed.
|
// events is the list of events not yet processed.
|
||||||
events []event.Event
|
events []EditorEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditorEvent interface {
|
type EditorEvent interface {
|
||||||
@@ -70,7 +70,9 @@ type ChangeEvent struct{}
|
|||||||
|
|
||||||
// A SubmitEvent is generated when Submit is set
|
// A SubmitEvent is generated when Submit is set
|
||||||
// and a carriage return key is pressed.
|
// and a carriage return key is pressed.
|
||||||
type SubmitEvent struct{}
|
type SubmitEvent struct {
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
type line struct {
|
type line struct {
|
||||||
offset f32.Point
|
offset f32.Point
|
||||||
@@ -82,8 +84,20 @@ const (
|
|||||||
maxBlinkDuration = 10 * time.Second
|
maxBlinkDuration = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event returns the next available editor event, or false if none are available.
|
// Events returns available editor events.
|
||||||
func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) {
|
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()
|
sbounds := e.scrollBounds()
|
||||||
var smin, smax int
|
var smin, smax int
|
||||||
var axis gesture.Axis
|
var axis gesture.Axis
|
||||||
@@ -103,7 +117,7 @@ func (e *Editor) Event(gtx *layout.Context) (EditorEvent, bool) {
|
|||||||
e.scrollRel(0, sdist)
|
e.scrollRel(0, sdist)
|
||||||
soff = e.scrollOff.Y
|
soff = e.scrollOff.Y
|
||||||
}
|
}
|
||||||
for _, evt := range e.clicker.Events(gtx.Queue) {
|
for _, evt := range e.clicker.Events(gtx) {
|
||||||
switch {
|
switch {
|
||||||
case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse,
|
case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse,
|
||||||
evt.Type == gesture.TypeClick && evt.Source == pointer.Touch:
|
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) {
|
if (sdist > 0 && soff >= smax) || (sdist < 0 && soff <= smin) {
|
||||||
e.scroller.Stop()
|
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) {
|
func (e *Editor) processKey(gtx *layout.Context) {
|
||||||
for len(e.events) > 0 {
|
for _, ke := range gtx.Events(&e.eventKey) {
|
||||||
ke := e.events[0]
|
|
||||||
copy(e.events, e.events[1:])
|
|
||||||
e.events = e.events[:len(e.events)-1]
|
|
||||||
e.blinkStart = gtx.Now()
|
e.blinkStart = gtx.Now()
|
||||||
switch ke := ke.(type) {
|
switch ke := ke.(type) {
|
||||||
case key.FocusEvent:
|
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 e.Submit && ke.Name == key.NameReturn || ke.Name == key.NameEnter {
|
||||||
if !ke.Modifiers.Contain(key.ModShift) {
|
if !ke.Modifiers.Contain(key.ModShift) {
|
||||||
return SubmitEvent{}, true
|
e.events = append(e.events, SubmitEvent{
|
||||||
|
Text: e.Text(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if e.command(ke) {
|
if e.command(ke) {
|
||||||
@@ -153,10 +164,9 @@ func (e *Editor) editorEvent(gtx *layout.Context) (EditorEvent, bool) {
|
|||||||
e.append(ke.Text)
|
e.append(ke.Text)
|
||||||
}
|
}
|
||||||
if e.rr.Changed() {
|
if e.rr.Changed() {
|
||||||
return ChangeEvent{}, true
|
e.events = append(e.events, ChangeEvent{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus requests the input focus for the Editor.
|
// Focus requests the input focus for the Editor.
|
||||||
@@ -164,18 +174,20 @@ func (e *Editor) Focus() {
|
|||||||
e.requestFocus = true
|
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) {
|
func (e *Editor) Layout(gtx *layout.Context, sh *Shaper, font Font) {
|
||||||
if e.font != font {
|
if e.font != font {
|
||||||
e.invalidate()
|
e.invalidate()
|
||||||
e.font = font
|
e.font = font
|
||||||
}
|
}
|
||||||
|
e.processEvents(gtx)
|
||||||
e.layout(gtx, sh)
|
e.layout(gtx, sh)
|
||||||
|
if !e.clicker.Active() {
|
||||||
|
e.events = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Editor) layout(gtx *layout.Context, sh *Shaper) {
|
func (e *Editor) layout(gtx *layout.Context, sh *Shaper) {
|
||||||
for _, ok := e.Event(gtx); ok; _, ok = e.Event(gtx) {
|
|
||||||
}
|
|
||||||
// Crude configuration change detection.
|
// Crude configuration change detection.
|
||||||
if scale := gtx.Px(unit.Sp(100)); scale != e.scale {
|
if scale := gtx.Px(unit.Sp(100)); scale != e.scale {
|
||||||
e.invalidate()
|
e.invalidate()
|
||||||
@@ -230,7 +242,7 @@ func (e *Editor) layout(gtx *layout.Context, sh *Shaper) {
|
|||||||
e.shapes = append(e.shapes, line{off, path})
|
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
|
e.requestFocus = false
|
||||||
pointerPadding := gtx.Px(unit.Dp(4))
|
pointerPadding := gtx.Px(unit.Dp(4))
|
||||||
r := image.Rectangle{Max: e.viewSize}
|
r := image.Rectangle{Max: e.viewSize}
|
||||||
|
|||||||
Reference in New Issue
Block a user