Skip to content

Commit

Permalink
Enable the TextStyle to be passed in as part of the TextGridStyle
Browse files Browse the repository at this point in the history
Fix TextGrid tests
And underline to text style
Add underline support to TextGrid widget
  • Loading branch information
mgazza committed Jun 12, 2024
1 parent 389162b commit 123747e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 15 deletions.
3 changes: 3 additions & 0 deletions text.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ type TextStyle struct {
Symbol bool // Use the system symbol font.
// Since: 2.1
TabWidth int // Width of tabs in spaces
// Since: 2.5
// Currently only supported by the TextGrid widget.
Underline bool // Should text be underlined.
}

// MeasureText uses the current driver to calculate the size of text when rendered.
Expand Down
77 changes: 64 additions & 13 deletions widget/textgrid.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@ type TextGridRow struct {

// TextGridStyle defines a style that can be applied to a TextGrid cell.
type TextGridStyle interface {
Style() fyne.TextStyle
TextColor() color.Color
BackgroundColor() color.Color
}

// CustomTextGridStyle is a utility type for those not wanting to define their own style types.
type CustomTextGridStyle struct {
// Since: 2.5
TextStyle fyne.TextStyle
FGColor, BGColor color.Color
}

Expand All @@ -62,6 +65,11 @@ func (c *CustomTextGridStyle) BackgroundColor() color.Color {
return c.BGColor
}

// Style is the text style a cell should use.
func (c *CustomTextGridStyle) Style() fyne.TextStyle {
return c.TextStyle
}

// TextGrid is a monospaced grid of characters.
// This is designed to be used by a text editor, code preview or terminal emulator.
type TextGrid struct {
Expand Down Expand Up @@ -350,12 +358,15 @@ func (t *textGridRenderer) appendTextCell(str rune) {
text.TextStyle.Monospace = true

bg := canvas.NewRectangle(color.Transparent)
t.objects = append(t.objects, bg, text)

ul := canvas.NewLine(color.Transparent)

t.objects = append(t.objects, bg, text, ul)
}

func (t *textGridRenderer) refreshCell(row, col int) {
pos := row*t.cols + col
if pos*2+1 >= len(t.objects) {
if pos*3+1 >= len(t.objects) {
return
}

Expand All @@ -367,26 +378,59 @@ func (t *textGridRenderer) setCellRune(str rune, pos int, style, rowStyle TextGr
if str == 0 {
str = ' '
}
rect := t.objects[pos*3].(*canvas.Rectangle)
text := t.objects[pos*3+1].(*canvas.Text)
underline := t.objects[pos*3+2].(*canvas.Line)

th := t.text.Theme()
v := fyne.CurrentApp().Settings().ThemeVariant()

text := t.objects[pos*2+1].(*canvas.Text)
text.TextSize = th.Size(theme.SizeNameText)
fg := th.Color(theme.ColorNameForeground, v)
text.TextSize = th.Size(theme.SizeNameText)
textStyle := fyne.TextStyle{}
var underlineStrokeWidth float32 = 1
var underlineStrokeColor color.Color = color.Transparent

if style != nil && style.TextColor() != nil {
fg = style.TextColor()
} else if rowStyle != nil && rowStyle.TextColor() != nil {
fg = rowStyle.TextColor()
}

if style != nil {
if style.Style().Bold {
underlineStrokeWidth = 2
textStyle = fyne.TextStyle{
Bold: true,
}
}
if style.Style().Underline {
underlineStrokeColor = fg
}
} else if rowStyle != nil {
if rowStyle.Style().Bold {
underlineStrokeWidth = 2
textStyle = fyne.TextStyle{
Bold: true,
}
}
if rowStyle.Style().Underline {
underlineStrokeColor = fg
}
}

newStr := string(str)
if text.Text != newStr || text.Color != fg {
if text.Text != newStr || text.Color != fg || textStyle != text.TextStyle {
text.Text = newStr
text.Color = fg
text.TextStyle = textStyle
t.refresh(text)
}

rect := t.objects[pos*2].(*canvas.Rectangle)
if underlineStrokeWidth != underline.StrokeWidth || underlineStrokeColor != underline.StrokeColor {
underline.StrokeWidth, underline.StrokeColor = underlineStrokeWidth, underlineStrokeColor
t.refresh(underline)
}

bg := color.Color(color.Transparent)
if style != nil && style.BackgroundColor() != nil {
bg = style.BackgroundColor()
Expand All @@ -401,10 +445,10 @@ func (t *textGridRenderer) setCellRune(str rune, pos int, style, rowStyle TextGr

func (t *textGridRenderer) addCellsIfRequired() {
cellCount := t.cols * t.rows
if len(t.objects) == cellCount*2 {
if len(t.objects) == cellCount*3 {
return
}
for i := len(t.objects); i < cellCount*2; i += 2 {
for i := len(t.objects); i < cellCount*3; i += 3 {
t.appendTextCell(' ')
}
}
Expand Down Expand Up @@ -468,7 +512,7 @@ func (t *textGridRenderer) refreshGrid() {

line++
}
for ; x < len(t.objects)/2; x++ {
for ; x < len(t.objects)/3; x++ {
t.setCellRune(' ', x, TextGridStyleDefault, nil) // trailing cells and blank lines
}
}
Expand Down Expand Up @@ -513,10 +557,17 @@ func (t *textGridRenderer) Layout(size fyne.Size) {
cellPos := fyne.NewPos(0, 0)
for y := 0; y < t.rows; y++ {
for x := 0; x < t.cols; x++ {
t.objects[i*2+1].Move(cellPos)
// rect
t.objects[i*3].Resize(t.cellSize)
t.objects[i*3].Move(cellPos)

// text
t.objects[i*3+1].Move(cellPos)

// underline
t.objects[i*3+2].Move(cellPos.Add(fyne.Position{X: 0, Y: t.cellSize.Height}))
t.objects[i*3+2].Resize(fyne.Size{Width: t.cellSize.Width})

t.objects[i*2].Resize(t.cellSize)
t.objects[i*2].Move(cellPos)
cellPos.X += t.cellSize.Width
i++
}
Expand Down
4 changes: 2 additions & 2 deletions widget/textgrid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestTextGrid_CreateRendererRows(t *testing.T) {
rend := test.WidgetRenderer(grid).(*textGridRenderer)
rend.Refresh()

assert.Equal(t, 12, len(rend.objects))
assert.Equal(t, 18, len(rend.objects))
}

func TestTextGrid_Row(t *testing.T) {
Expand Down Expand Up @@ -266,6 +266,6 @@ func assertGridStyle(t *testing.T, g *TextGrid, expected string, expectedStyles
}

func rendererCell(r *textGridRenderer, row, col int) (*canvas.Rectangle, *canvas.Text) {
i := (row*r.cols + col) * 2
i := (row*r.cols + col) * 3
return r.objects[i].(*canvas.Rectangle), r.objects[i+1].(*canvas.Text)
}

0 comments on commit 123747e

Please sign in to comment.