From ba670d23ba6e4ab785c2c9f0c284afdd954fa048 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 19 Feb 2020 18:31:32 +0100 Subject: [PATCH] The inner area of a Box does not clamp to screen borders anymore. Consequently added some drawing optimization to primitives. Resolves #405 --- box.go | 23 --------- list.go | 4 ++ table.go | 3 +- textview.go | 145 +++++++++++++++++++++++++++------------------------- treeview.go | 3 +- util.go | 5 +- 6 files changed, 85 insertions(+), 98 deletions(-) diff --git a/box.go b/box.go index cc0e160..04d01ce 100644 --- a/box.go +++ b/box.go @@ -314,29 +314,6 @@ func (b *Box) Draw(screen tcell.Screen) { b.innerX = -1 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. diff --git a/list.go b/list.go index bc55f5a..a8cab97 100644 --- a/list.go +++ b/list.go @@ -394,6 +394,10 @@ func (l *List) Draw(screen tcell.Screen) { // Determine the dimensions. x, y, width, height := l.GetInnerRect() bottomLimit := y + height + _, totalHeight := screen.Size() + if bottomLimit > totalHeight { + bottomLimit = totalHeight + } // Do we show any shortcuts? var showShortcuts bool diff --git a/table.go b/table.go index 9d0db29..04fe448 100644 --- a/table.go +++ b/table.go @@ -563,6 +563,7 @@ func (t *Table) Draw(screen tcell.Screen) { t.Box.Draw(screen) // What's our available screen space? + _, totalHeight := screen.Size() x, y, width, height := t.GetInnerRect() if t.borders { t.visibleRows = height / 2 @@ -800,7 +801,7 @@ ColumnLoop: } drawBorder(columnX, rowY, ch) rowY++ - if rowY >= height { + if rowY >= height || y+rowY >= totalHeight { break // No space for the text anymore. } drawBorder(columnX, rowY, Borders.Vertical) diff --git a/textview.go b/textview.go index ddc4252..38876b9 100644 --- a/textview.go +++ b/textview.go @@ -752,6 +752,7 @@ func (t *TextView) Draw(screen tcell.Screen) { t.Lock() defer t.Unlock() t.Box.Draw(screen) + totalWidth, totalHeight := screen.Size() // Get the available size. x, y, width, height := t.GetInnerRect() @@ -838,7 +839,7 @@ func (t *TextView) Draw(screen tcell.Screen) { defaultStyle := tcell.StyleDefault.Foreground(t.textColor) for line := t.lineOffset; line < len(t.index); line++ { // Are we done? - if line-t.lineOffset >= height { + if line-t.lineOffset >= height || y+line-t.lineOffset >= totalHeight { break } @@ -868,82 +869,84 @@ func (t *TextView) Draw(screen tcell.Screen) { } // Print the line. - var colorPos, regionPos, escapePos, tagOffset, skipped int - iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool { - // Process tags. - for { - if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] { - // Get the color. - foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos]) - tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0] - colorPos++ - } else if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] { - // Get the region. - regionID = regions[regionPos][1] - tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0] - regionPos++ - } else { - 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 + if y+line-t.lineOffset >= 0 { + var colorPos, regionPos, escapePos, tagOffset, skipped int + iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool { + // Process tags. + for { + if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] { + // Get the color. + foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos]) + tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0] + colorPos++ + } else if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] { + // Get the region. + regionID = regions[regionPos][1] + tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0] + regionPos++ } else { - bg = tcell.ColorBlack + break } } - 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 { - 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) + // Skip the second-to-last character of an escape tag. + if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 { + tagOffset++ + escapePos++ } - } - // Advance. - posX += screenWidth - return false - }) + // 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 { + 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 diff --git a/treeview.go b/treeview.go index 2d95763..2a8c16c 100644 --- a/treeview.go +++ b/treeview.go @@ -575,6 +575,7 @@ func (t *TreeView) Draw(screen tcell.Screen) { if t.root == nil { return } + _, totalHeight := screen.Size() t.process() @@ -609,7 +610,7 @@ func (t *TreeView) Draw(screen tcell.Screen) { lineStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.graphicsColor) for index, node := range t.nodes { // Skip invisible parts. - if posY >= y+height+1 { + if posY >= y+height+1 || posY >= totalHeight { break } if index < t.offsetY { diff --git a/util.go b/util.go index 975f087..bdb9e3b 100644 --- a/util.go +++ b/util.go @@ -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 // foreground color. 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 } @@ -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 { // Only continue if there is still space. - if drawnWidth+screenWidth > maxWidth { + if drawnWidth+screenWidth > maxWidth || x+drawnWidth >= totalWidth { return true }