From 3fde0c00619a30343a2133237a050da8d5e7627c Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Fri, 10 Nov 2023 14:59:06 -0500 Subject: [PATCH] widget: [API] split text widget Update from Layout This commit introduces Update(gtx) functions for both Selectable and Editor, allowing their state to be updated explicitly prior to layout. This completes the transition that allows all Gio widgets to have their state updated ahead-of-time, ensuring that there is zero frame lag between an input event and the widget response to that event. Signed-off-by: Chris Waldon --- widget/editor.go | 21 ++++++++++++--------- widget/selectable.go | 10 ++++++++-- widget/text.go | 10 ++-------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/widget/editor.go b/widget/editor.go index d723f0ea..e87e8c3e 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -517,15 +517,10 @@ func (e *Editor) initBuffer() { e.text.WrapPolicy = e.WrapPolicy } -// Layout lays out the editor using the provided textMaterial as the paint material -// for the text glyphs+caret and the selectMaterial as the paint material for the -// selection rectangle. -func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, textMaterial, selectMaterial op.CallOp) layout.Dimensions { +// Update the state of the editor in response to input events. +func (e *Editor) Update(gtx layout.Context) { e.initBuffer() - e.text.Update(gtx, lt, font, size, e.processEvents) - - dims := e.layout(gtx, textMaterial, selectMaterial) - + e.processEvents(gtx) if e.focused { // Notify IME of selection if it changed. newSel := e.ime.selection @@ -551,8 +546,16 @@ func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, siz e.updateSnippet(gtx, e.ime.start, e.ime.end) } +} - return dims +// Layout lays out the editor using the provided textMaterial as the paint material +// for the text glyphs+caret and the selectMaterial as the paint material for the +// selection rectangle. +func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, textMaterial, selectMaterial op.CallOp) layout.Dimensions { + e.Update(gtx) + + e.text.Layout(gtx, lt, font, size) + return e.layout(gtx, textMaterial, selectMaterial) } // updateSnippet adds a key.SnippetOp if the snippet content or position diff --git a/widget/selectable.go b/widget/selectable.go index d3084746..186a2ac8 100644 --- a/widget/selectable.go +++ b/widget/selectable.go @@ -182,18 +182,24 @@ func (l *Selectable) Truncated() bool { return l.text.Truncated() } +// Update the state of the selectable in response to input events. +func (l *Selectable) Update(gtx layout.Context) { + l.initialize() + l.handleEvents(gtx) +} + // Layout clips to the dimensions of the selectable, updates the shaped text, configures input handling, and paints // the text and selection rectangles. The provided textMaterial and selectionMaterial ops are used to set the // paint material for the text and selection rectangles, respectively. func (l *Selectable) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, textMaterial, selectionMaterial op.CallOp) layout.Dimensions { - l.initialize() + l.Update(gtx) l.text.LineHeight = l.LineHeight l.text.LineHeightScale = l.LineHeightScale l.text.Alignment = l.Alignment l.text.MaxLines = l.MaxLines l.text.Truncator = l.Truncator l.text.WrapPolicy = l.WrapPolicy - l.text.Update(gtx, lt, font, size, l.handleEvents) + l.text.Layout(gtx, lt, font, size) dims := l.text.Dimensions() defer clip.Rect(image.Rectangle{Max: dims.Size}).Push(gtx.Ops).Pop() pointer.CursorText.Add(gtx.Ops) diff --git a/widget/text.go b/widget/text.go index fca325c7..52cfb1e2 100644 --- a/widget/text.go +++ b/widget/text.go @@ -228,10 +228,8 @@ func (e *textView) calculateViewSize(gtx layout.Context) image.Point { return gtx.Constraints.Constrain(base) } -// Update the text, reshaping it as necessary. If not nil, eventHandling will be invoked after reshaping the text to -// allow parent widgets to adapt to any changes in text content or positioning. If eventHandling modifies the contents -// of the textView, it is guaranteed to be reshaped (and ready for painting) before Update returns. -func (e *textView) Update(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp, eventHandling func(gtx layout.Context)) { +// Layout the text, reshaping it as necessary. +func (e *textView) Layout(gtx layout.Context, lt *text.Shaper, font font.Font, size unit.Sp) { if e.params.Locale != gtx.Locale { e.params.Locale = gtx.Locale e.invalidate() @@ -289,10 +287,6 @@ func (e *textView) Update(gtx layout.Context, lt *text.Shaper, font font.Font, s } e.makeValid() - if eventHandling != nil { - eventHandling(gtx) - e.makeValid() - } if viewSize := e.calculateViewSize(gtx); viewSize != e.viewSize { e.viewSize = viewSize