1
0
mirror of https://github.com/rivo/tview.git synced 2025-04-28 13:48:53 +08:00

The inner area of a Box does not clamp to screen borders anymore. Consequently added some drawing optimization to primitives. Resolves #405

This commit is contained in:
Oliver 2020-02-19 18:31:32 +01:00
parent fe30520195
commit ba670d23ba
6 changed files with 85 additions and 98 deletions

23
box.go
View File

@ -314,29 +314,6 @@ func (b *Box) Draw(screen tcell.Screen) {
b.innerX = -1 b.innerX = -1
b.innerX, b.innerY, b.innerWidth, b.innerHeight = b.GetInnerRect() b.innerX, b.innerY, b.innerWidth, b.innerHeight = b.GetInnerRect()
} }
// Clamp inner rect to screen.
width, height := screen.Size()
if b.innerX < 0 {
b.innerWidth += b.innerX
b.innerX = 0
}
if b.innerX+b.innerWidth >= width {
b.innerWidth = width - b.innerX
}
if b.innerY+b.innerHeight >= height {
b.innerHeight = height - b.innerY
}
if b.innerY < 0 {
b.innerHeight += b.innerY
b.innerY = 0
}
if b.innerWidth < 0 {
b.innerWidth = 0
}
if b.innerHeight < 0 {
b.innerHeight = 0
}
} }
// Focus is called when this primitive receives focus. // Focus is called when this primitive receives focus.

View File

@ -394,6 +394,10 @@ func (l *List) Draw(screen tcell.Screen) {
// Determine the dimensions. // Determine the dimensions.
x, y, width, height := l.GetInnerRect() x, y, width, height := l.GetInnerRect()
bottomLimit := y + height bottomLimit := y + height
_, totalHeight := screen.Size()
if bottomLimit > totalHeight {
bottomLimit = totalHeight
}
// Do we show any shortcuts? // Do we show any shortcuts?
var showShortcuts bool var showShortcuts bool

View File

@ -563,6 +563,7 @@ func (t *Table) Draw(screen tcell.Screen) {
t.Box.Draw(screen) t.Box.Draw(screen)
// What's our available screen space? // What's our available screen space?
_, totalHeight := screen.Size()
x, y, width, height := t.GetInnerRect() x, y, width, height := t.GetInnerRect()
if t.borders { if t.borders {
t.visibleRows = height / 2 t.visibleRows = height / 2
@ -800,7 +801,7 @@ ColumnLoop:
} }
drawBorder(columnX, rowY, ch) drawBorder(columnX, rowY, ch)
rowY++ rowY++
if rowY >= height { if rowY >= height || y+rowY >= totalHeight {
break // No space for the text anymore. break // No space for the text anymore.
} }
drawBorder(columnX, rowY, Borders.Vertical) drawBorder(columnX, rowY, Borders.Vertical)

View File

@ -752,6 +752,7 @@ func (t *TextView) Draw(screen tcell.Screen) {
t.Lock() t.Lock()
defer t.Unlock() defer t.Unlock()
t.Box.Draw(screen) t.Box.Draw(screen)
totalWidth, totalHeight := screen.Size()
// Get the available size. // Get the available size.
x, y, width, height := t.GetInnerRect() x, y, width, height := t.GetInnerRect()
@ -838,7 +839,7 @@ func (t *TextView) Draw(screen tcell.Screen) {
defaultStyle := tcell.StyleDefault.Foreground(t.textColor) defaultStyle := tcell.StyleDefault.Foreground(t.textColor)
for line := t.lineOffset; line < len(t.index); line++ { for line := t.lineOffset; line < len(t.index); line++ {
// Are we done? // Are we done?
if line-t.lineOffset >= height { if line-t.lineOffset >= height || y+line-t.lineOffset >= totalHeight {
break break
} }
@ -868,82 +869,84 @@ func (t *TextView) Draw(screen tcell.Screen) {
} }
// Print the line. // Print the line.
var colorPos, regionPos, escapePos, tagOffset, skipped int if y+line-t.lineOffset >= 0 {
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool { var colorPos, regionPos, escapePos, tagOffset, skipped int
// Process tags. iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
for { // Process tags.
if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] { for {
// Get the color. if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos]) // Get the color.
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0] foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos])
colorPos++ tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
} else if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] { colorPos++
// Get the region. } else if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] {
regionID = regions[regionPos][1] // Get the region.
tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0] regionID = regions[regionPos][1]
regionPos++ tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0]
} else { regionPos++
break
}
}
// Skip the second-to-last character of an escape tag.
if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
tagOffset++
escapePos++
}
// Mix the existing style with the new style.
_, _, existingStyle, _ := screen.GetContent(x+posX, y+line-t.lineOffset)
_, background, _ := existingStyle.Decompose()
style := overlayStyle(background, defaultStyle, foregroundColor, backgroundColor, attributes)
// Do we highlight this character?
var highlighted bool
if len(regionID) > 0 {
if _, ok := t.highlights[regionID]; ok {
highlighted = true
}
}
if highlighted {
fg, bg, _ := style.Decompose()
if bg == tcell.ColorDefault {
r, g, b := fg.RGB()
c := colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255}
_, _, li := c.Hcl()
if li < .5 {
bg = tcell.ColorWhite
} else { } else {
bg = tcell.ColorBlack break
} }
} }
style = style.Background(fg).Foreground(bg)
}
// Skip to the right. // Skip the second-to-last character of an escape tag.
if !t.wrap && skipped < skip { if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
skipped += screenWidth tagOffset++
return false escapePos++
}
// Stop at the right border.
if posX+screenWidth > width {
return true
}
// Draw the character.
for offset := screenWidth - 1; offset >= 0; offset-- {
if offset == 0 {
screen.SetContent(x+posX+offset, y+line-t.lineOffset, main, comb, style)
} else {
screen.SetContent(x+posX+offset, y+line-t.lineOffset, ' ', nil, style)
} }
}
// Advance. // Mix the existing style with the new style.
posX += screenWidth _, _, existingStyle, _ := screen.GetContent(x+posX, y+line-t.lineOffset)
return false _, background, _ := existingStyle.Decompose()
}) style := overlayStyle(background, defaultStyle, foregroundColor, backgroundColor, attributes)
// Do we highlight this character?
var highlighted bool
if len(regionID) > 0 {
if _, ok := t.highlights[regionID]; ok {
highlighted = true
}
}
if highlighted {
fg, bg, _ := style.Decompose()
if bg == tcell.ColorDefault {
r, g, b := fg.RGB()
c := colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255}
_, _, li := c.Hcl()
if li < .5 {
bg = tcell.ColorWhite
} else {
bg = tcell.ColorBlack
}
}
style = style.Background(fg).Foreground(bg)
}
// Skip to the right.
if !t.wrap && skipped < skip {
skipped += screenWidth
return false
}
// Stop at the right border.
if posX+screenWidth > width || x+posX >= totalWidth {
return true
}
// Draw the character.
for offset := screenWidth - 1; offset >= 0; offset-- {
if offset == 0 {
screen.SetContent(x+posX+offset, y+line-t.lineOffset, main, comb, style)
} else {
screen.SetContent(x+posX+offset, y+line-t.lineOffset, ' ', nil, style)
}
}
// Advance.
posX += screenWidth
return false
})
}
} }
// If this view is not scrollable, we'll purge the buffer of lines that have // If this view is not scrollable, we'll purge the buffer of lines that have

View File

@ -575,6 +575,7 @@ func (t *TreeView) Draw(screen tcell.Screen) {
if t.root == nil { if t.root == nil {
return return
} }
_, totalHeight := screen.Size()
t.process() t.process()
@ -609,7 +610,7 @@ func (t *TreeView) Draw(screen tcell.Screen) {
lineStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.graphicsColor) lineStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.graphicsColor)
for index, node := range t.nodes { for index, node := range t.nodes {
// Skip invisible parts. // Skip invisible parts.
if posY >= y+height+1 { if posY >= y+height+1 || posY >= totalHeight {
break break
} }
if index < t.offsetY { if index < t.offsetY {

View File

@ -247,7 +247,8 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
// printWithStyle works like Print() but it takes a style instead of just a // printWithStyle works like Print() but it takes a style instead of just a
// foreground color. // foreground color.
func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int, style tcell.Style) (int, int) { func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int, style tcell.Style) (int, int) {
if maxWidth <= 0 || len(text) == 0 { totalWidth, totalHeight := screen.Size()
if maxWidth <= 0 || len(text) == 0 || y < 0 || y >= totalHeight {
return 0, 0 return 0, 0
} }
@ -365,7 +366,7 @@ func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int,
) )
iterateString(strippedText, func(main rune, comb []rune, textPos, length, screenPos, screenWidth int) bool { iterateString(strippedText, func(main rune, comb []rune, textPos, length, screenPos, screenWidth int) bool {
// Only continue if there is still space. // Only continue if there is still space.
if drawnWidth+screenWidth > maxWidth { if drawnWidth+screenWidth > maxWidth || x+drawnWidth >= totalWidth {
return true return true
} }