Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bold and Underline to TextGrid widget #4244

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
mgazza marked this conversation as resolved.
Show resolved Hide resolved
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)
mgazza marked this conversation as resolved.
Show resolved Hide resolved

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)
}