Hide the editor caret while another input has focus
The caret was drawn unconditionally, so it kept showing in the main edit window while key focus sat in the find bar's search input — reading as if the editor still had focus. drawWrappedText now takes the field's focus state and draws the caret only when the field is focused (editorElem.Focused follows FocusedElementID, which is find_bar while the find bar is open); the caret returns when focus comes back on close. e2e: the editor TextField reports unfocused while the find bar is open and focused again after close.
This commit is contained in:
parent
cfaf4927ac
commit
1cbb367b1f
|
|
@ -113,6 +113,10 @@ func TestRealFile_FindBarAndNavigation(t *testing.T) {
|
|||
if got := reg.(ui.Region); got.Y != ui.Dp(32)+editor.FindBarHeight {
|
||||
t.Fatalf("editor region top %d, want %d (find bar must not cover text)", int(got.Y), int(ui.Dp(32)+editor.FindBarHeight))
|
||||
}
|
||||
// The editor field reports UNFOCUSED while the find bar is open (the
|
||||
// renderer hides its caret for unfocused fields; main hands key focus to
|
||||
// the search input).
|
||||
waitForEditorField(t, h, func(tf ui.TextField) bool { return !tf.Focused })
|
||||
|
||||
// Type the query through the same channel main uses.
|
||||
h.Logic().FindQueryChan() <- "NEEDLE" // case-insensitive
|
||||
|
|
@ -190,6 +194,8 @@ func TestRealFile_FindBarAndNavigation(t *testing.T) {
|
|||
if focus.(string) != "editor_text" {
|
||||
t.Fatalf("focus %q, want editor_text after close", focus)
|
||||
}
|
||||
// And the editor field reports focused again (caret returns).
|
||||
waitForEditorField(t, h, func(tf ui.TextField) bool { return tf.Focused })
|
||||
}
|
||||
|
||||
func TestRealFile_FindMatchesSurviveEdits(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ func (tf TextField) Draw(gtx layout.Context, r *Renderer) {
|
|||
r.lastSelCaret = -1
|
||||
r.lastIMEShowSeq = 0
|
||||
}
|
||||
r.drawWrappedText(gtx, tf.Value, tf.region, tf.WordWrap, tf.WrapWidth, tf.ScrollOffset, tf.CursorPosition, tf.SelectionStart, tf.SelectionEnd, tf.CaretDrag, tf.MatchRanges, tf.CurrentMatch)
|
||||
r.drawWrappedText(gtx, tf.Value, tf.region, tf.WordWrap, tf.WrapWidth, tf.ScrollOffset, tf.CursorPosition, tf.SelectionStart, tf.SelectionEnd, tf.CaretDrag, tf.MatchRanges, tf.CurrentMatch, tf.Focused)
|
||||
}
|
||||
|
||||
// runeCount returns the number of UTF-8 runes in s[:bytePos] (bytePos is a
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@ func (r *Renderer) drawRangeHighlight(gtx layout.Context, layout *GlyphLayout, s
|
|||
}
|
||||
}
|
||||
|
||||
func (r *Renderer) drawWrappedText(gtx layout.Context, str string, reg Region, wordWrap bool, wrapWidth Dp, scrollOffset Dp, cursorPos, selStart, selEnd int, caretDrag bool, matchRanges [][2]int, currentMatch int) {
|
||||
func (r *Renderer) drawWrappedText(gtx layout.Context, str string, reg Region, wordWrap bool, wrapWidth Dp, scrollOffset Dp, cursorPos, selStart, selEnd int, caretDrag bool, matchRanges [][2]int, currentMatch int, focused bool) {
|
||||
if str == "" {
|
||||
return
|
||||
}
|
||||
|
|
@ -920,14 +920,18 @@ func (r *Renderer) drawWrappedText(gtx layout.Context, str string, reg Region, w
|
|||
return CaretPoint(layout, str, byteOff, ascent, lineH)
|
||||
}
|
||||
|
||||
// Draw the caret only when the cursor's byte is inside the shaped window
|
||||
// (window-relative: [0, len(str)]). The window covers the viewport
|
||||
// exactly, so an out-of-range cursor is off-screen and its caret must not
|
||||
// be drawn; the caller used to clamp it to 0, which made the caret jump
|
||||
// onto the top (or, past the end, the bottom) visible line whenever the
|
||||
// user scrolled past it. The boundary values are on-screen: 0 is the
|
||||
// window's first byte and len(str) is the window's last insertion point.
|
||||
if cursorPos >= 0 && cursorPos <= len(str) {
|
||||
// Draw the caret only when (a) the field holds key focus and (b) the
|
||||
// cursor's byte is inside the shaped window (window-relative:
|
||||
// [0, len(str)]). (a): while another input is focused — the find bar's
|
||||
// search input is the case that motivated this — a live caret in the
|
||||
// editor reads as if the editor still had focus; the caret returns when
|
||||
// focus comes back. (b): the window covers the viewport exactly, so an
|
||||
// out-of-range cursor is off-screen and its caret must not be drawn; the
|
||||
// caller used to clamp it to 0, which made the caret jump onto the top
|
||||
// (or, past the end, the bottom) visible line whenever the user scrolled
|
||||
// past it. The boundary values are on-screen: 0 is the window's first
|
||||
// byte and len(str) is the window's last insertion point.
|
||||
if focused && cursorPos >= 0 && cursorPos <= len(str) {
|
||||
// Determine cursor position from `layout` and `cursorPos`
|
||||
cursorX, cursorY := caretPoint(cursorPos)
|
||||
cursorX = reg.X + cursorX
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user