From 72a1ec681cb04c2617b66e246fab19e3862a7cf1 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 28 Jun 2022 10:53:07 +0100 Subject: [PATCH 1/3] Fix crashing when minsize is below wrap width Fixes #3003, #2961 --- CHANGELOG.md | 4 ++++ widget/entry_test.go | 16 +++++++++++++++- widget/richtext.go | 31 ++++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6bbe9f504..93e112eeca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This file lists the main changes with each version of the Fyne toolkit. More detailed release notes can be found on the [releases page](https://github.com/fyne-io/fyne/releases). +### 2.2.3 - Ongoing + +* Wrappable RichText in a Split container causes crash (#3003, #2961) + ## 2.2.2 - 28 June 2022 ### Fixed diff --git a/widget/entry_test.go b/widget/entry_test.go index bbe4cf4ecd..0b1c986677 100644 --- a/widget/entry_test.go +++ b/widget/entry_test.go @@ -533,7 +533,6 @@ func TestEntry_OnKeyDown_Backspace(t *testing.T) { assert.Equal(t, 1, entry.CursorColumn) entry = widget.NewMultiLineEntry() - entry.Wrapping = fyne.TextWrapWord entry.SetText("Line\n2b\n") down := &fyne.KeyEvent{Name: fyne.KeyDown} entry.TypedKey(down) @@ -545,6 +544,21 @@ func TestEntry_OnKeyDown_Backspace(t *testing.T) { assert.Equal(t, "Line\nb\n", entry.Text) assert.Equal(t, 1, entry.CursorRow) assert.Equal(t, 0, entry.CursorColumn) + + entry.CursorRow = 0 + entry.CursorColumn = 0 + entry.Wrapping = fyne.TextWrapWord + entry.SetText("Line 2b") + entry.Resize(fyne.NewSize(50, 50)) + entry.TypedKey(down) + entry.TypedKey(right) + assert.Equal(t, 1, entry.CursorRow) + assert.Equal(t, 1, entry.CursorColumn) + + entry.TypedKey(backspace) + assert.Equal(t, "Line b", entry.Text) + assert.Equal(t, 1, entry.CursorRow) + assert.Equal(t, 0, entry.CursorColumn) } func TestEntry_OnKeyDown_BackspaceBeyondText(t *testing.T) { diff --git a/widget/richtext.go b/widget/richtext.go index 1ff9e1261d..097d203651 100644 --- a/widget/richtext.go +++ b/widget/richtext.go @@ -756,7 +756,7 @@ func findSpaceIndex(text []rune, fallback int) int { // lineBounds returns a slice containing the boundary metadata of each line with the given wrapping applied. func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float32, measurer func([]rune) float32) []rowBoundary { lines := splitLines(seg) - if maxWidth <= 0 || wrap == fyne.TextWrapOff { + if wrap == fyne.TextWrapOff { return lines } @@ -791,13 +791,21 @@ func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float high = l.end measureWidth = maxWidth } else { - high = binarySearch(checker, low, high) + newHigh := binarySearch(checker, low, high) + if newHigh <= low { + bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low+1}) + reuse++ + low++ + } else { + high = newHigh + } } } case fyne.TextWrapWord: for low < high { sub := text[low:high] - if measurer(sub) <= measureWidth { + subWidth := measurer(sub) + if subWidth <= measureWidth { bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, high}) reuse++ low = high @@ -810,8 +818,21 @@ func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float oldHigh := high last := low + len(sub) - 1 fallback := binarySearch(checker, low, last) - low - high = low + findSpaceIndex(sub, fallback) - if high == fallback && measurer(sub) <= maxWidth { // add a newline as there is more space on next + + if fallback < 1 { // even a character won't fit + sub = text[low:low+1] + bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low+1}) + low++ + high = low+1 + reuse++ + + if high > l.end { + return bounds + } + } else { + high = low + findSpaceIndex(sub, fallback) + } + if high == fallback && subWidth <= maxWidth { // add a newline as there is more space on next bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low}) reuse++ high = oldHigh From d84c9431d7c0ddb8de470ef54ed9200533f2c934 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 28 Jun 2022 17:25:34 +0100 Subject: [PATCH 2/3] Fix format --- widget/richtext.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/widget/richtext.go b/widget/richtext.go index 097d203651..adc319b895 100644 --- a/widget/richtext.go +++ b/widget/richtext.go @@ -793,7 +793,7 @@ func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float } else { newHigh := binarySearch(checker, low, high) if newHigh <= low { - bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low+1}) + bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low + 1}) reuse++ low++ } else { @@ -820,10 +820,10 @@ func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float fallback := binarySearch(checker, low, last) - low if fallback < 1 { // even a character won't fit - sub = text[low:low+1] - bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low+1}) + sub = text[low : low+1] + bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low + 1}) low++ - high = low+1 + high = low + 1 reuse++ if high > l.end { From d65feb85c5a14148ed03e784e9e3bf2be2be9836 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 30 Jun 2022 22:34:51 +0100 Subject: [PATCH 3/3] Remove unneeded set --- widget/richtext.go | 1 - 1 file changed, 1 deletion(-) diff --git a/widget/richtext.go b/widget/richtext.go index adc319b895..47ea3cb9bb 100644 --- a/widget/richtext.go +++ b/widget/richtext.go @@ -820,7 +820,6 @@ func lineBounds(seg *TextSegment, wrap fyne.TextWrap, firstWidth, maxWidth float fallback := binarySearch(checker, low, last) - low if fallback < 1 { // even a character won't fit - sub = text[low : low+1] bounds = append(bounds, rowBoundary{[]RichTextSegment{seg}, reuse, low, low + 1}) low++ high = low + 1