Use a buffer system for building the panes

This commit is contained in:
Brian Buller 2019-10-17 10:49:08 -05:00
parent 72d7cc8280
commit e6f872fbf6
1 changed files with 78 additions and 178 deletions

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/br0xen/termbox-util" termboxUtil "github.com/br0xen/termbox-util"
"github.com/nsf/termbox-go" "github.com/nsf/termbox-go"
) )
@ -17,7 +17,7 @@ type ViewPort struct {
bytesPerRow int bytesPerRow int
numberOfRows int numberOfRows int
firstRow int firstRow int
scrollRow int scrollRow int
} }
/* /*
@ -25,8 +25,8 @@ BrowserScreen holds all that's going on :D
*/ */
type BrowserScreen struct { type BrowserScreen struct {
db *BoltDB db *BoltDB
leftViewPort ViewPort leftViewPort ViewPort
rightViewPort ViewPort rightViewPort ViewPort
queuedCommand string queuedCommand string
currentPath []string currentPath []string
currentType int currentType int
@ -37,9 +37,6 @@ type BrowserScreen struct {
messageTimeout time.Duration messageTimeout time.Duration
messageTime time.Time messageTime time.Time
rightPaneHeight int
rightPaneCursor int
leftPaneBuffer []Line leftPaneBuffer []Line
rightPaneBuffer []Line rightPaneBuffer []Line
} }
@ -485,15 +482,15 @@ func (screen *BrowserScreen) moveCursorDown() bool {
return false return false
} }
func (screen *BrowserScreen) moveRightPaneUp() bool { func (screen *BrowserScreen) moveRightPaneUp() bool {
if screen.rightViewPort.scrollRow > 0 { if screen.rightViewPort.scrollRow > 0 {
screen.rightViewPort.scrollRow-- screen.rightViewPort.scrollRow--
return true return true
} }
return false return false
} }
func (screen *BrowserScreen) moveRightPaneDown() bool { func (screen *BrowserScreen) moveRightPaneDown() bool {
screen.rightViewPort.scrollRow++ screen.rightViewPort.scrollRow++
return true return true
} }
func (screen *BrowserScreen) performLayout() {} func (screen *BrowserScreen) performLayout() {}
@ -540,42 +537,44 @@ func (screen *BrowserScreen) drawFooter(style Style) {
} }
func (screen *BrowserScreen) buildLeftPane(style Style) { func (screen *BrowserScreen) buildLeftPane(style Style) {
screen.leftPaneBuffer = nil screen.leftPaneBuffer = nil
if len(screen.currentPath) == 0 { if len(screen.currentPath) == 0 {
screen.currentPath = screen.db.getNextVisiblePath(nil) screen.currentPath = screen.db.getNextVisiblePath(nil)
} }
curPathSpot := 0 for i := range screen.db.buckets {
visPaths, err := screen.db.buildVisiblePathSlice() screen.leftPaneBuffer = append(screen.leftPaneBuffer, screen.bucketToLines(&screen.db.buckets[i], style)...)
if err == nil { }
for idx, pth := range visPaths { // Find the cursor in the leftPane
screen.leftPaneBuffer for k, v := range screen.leftPaneBuffer {
if v.Fg == style.cursorFg {
screen.leftViewPort.scrollRow = k
break
} }
} }
} }
func (screen *BrowserScreen) drawLeftPane(style Style) { func (screen *BrowserScreen) drawLeftPane(style Style) {
screen.buildLeftPane(style) screen.buildLeftPane(style)
w, h := termbox.Size() w, h := termbox.Size()
if w > 80 { if w > 80 {
w = w / 2 w = w / 2
} }
screen.leftViewPort.bytesPerRow = w screen.leftViewPort.bytesPerRow = w
screen.leftViewPort.numberOfRows = h - 2 screen.leftViewPort.numberOfRows = h - 2
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg) termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
y := 2 startX, startY := 0, 3
screen.leftViewPort.firstRow = y screen.leftViewPort.firstRow = startY
treeOffset := 0
maxCursor := screen.leftViewPort.numberOfRows * 2 / 3
treeOffset := 0 if screen.leftViewPort.scrollRow > maxCursor {
maxCursor := screen.leftViewPort.numberOfRows * 2 / 3 treeOffset = screen.leftViewPort.scrollRow - maxCursor
if curPathSpot > maxCursor { }
treeOffset = curPathSpot - maxCursor if len(screen.leftPaneBuffer) > 0 {
} for k, v := range screen.leftPaneBuffer[treeOffset:] {
termboxUtil.DrawStringAtPoint(v.Text, startX, (startY + k - 1), v.Fg, v.Bg)
for i := range screen.db.buckets { }
// The drawBucket function returns how many lines it took up }
bktH := screen.drawBucket(&screen.db.buckets[i], style, (y - treeOffset))
y += bktH
}
} }
func (screen *BrowserScreen) buildRightPane(style Style) { func (screen *BrowserScreen) buildRightPane(style Style) {
@ -595,18 +594,18 @@ func (screen *BrowserScreen) buildRightPane(style Style) {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Key: %s", stringify([]byte(p.key))), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Key: %s", stringify([]byte(p.key))), style.defaultFg, style.defaultBg})
value := strings.Split(string(formatValue([]byte(p.val))), "\n") value := strings.Split(string(formatValue([]byte(p.val))), "\n")
if len(value) == 1 { if len(value) == 1 {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Value: %s", value[0]), style.defaultFg, style.defaultBg}) Line{fmt.Sprintf("Value: %s", value[0]), style.defaultFg, style.defaultBg})
} else { } else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{"Value:", style.defaultFg, style.defaultBg}) Line{"Value:", style.defaultFg, style.defaultBg})
for _, v := range value { for _, v := range value {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{v, style.defaultFg, style.defaultBg}) Line{v, style.defaultFg, style.defaultBg})
} }
} }
} }
} else { } else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer, screen.rightPaneBuffer = append(screen.rightPaneBuffer,
@ -620,28 +619,28 @@ func (screen *BrowserScreen) drawRightPane(style Style) {
screen.buildRightPane(style) screen.buildRightPane(style)
w, h := termbox.Size() w, h := termbox.Size()
if w > 80 { if w > 80 {
screen.rightViewPort.bytesPerRow = w / 2 screen.rightViewPort.bytesPerRow = w / 2
screen.rightViewPort.numberOfRows = h - 2 screen.rightViewPort.numberOfRows = h - 2
// Screen is wide enough, split it // Screen is wide enough, split it
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg) termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
termboxUtil.FillWithChar('|', (w / 2), screen.rightViewPort.firstRow-1, (w / 2), h, style.defaultFg, style.defaultBg) termboxUtil.FillWithChar('|', (w / 2), screen.rightViewPort.firstRow-1, (w / 2), h, style.defaultFg, style.defaultBg)
// Clear the right pane // Clear the right pane
termboxUtil.FillWithChar(' ', (w/2)+1, screen.rightViewPort.firstRow, w, h, style.defaultFg, style.defaultBg) termboxUtil.FillWithChar(' ', (w/2)+1, screen.rightViewPort.firstRow+2, w, h, style.defaultFg, style.defaultBg)
startX := (w / 2) + 2 startX := (w / 2) + 2
startY := 2 startY := 3
maxScroll := len(screen.rightPaneBuffer)-screen.rightViewPort.numberOfRows maxScroll := len(screen.rightPaneBuffer) - screen.rightViewPort.numberOfRows
if maxScroll < 0 { if maxScroll < 0 {
maxScroll = 0 maxScroll = 0
} }
if screen.rightViewPort.scrollRow > maxScroll { if screen.rightViewPort.scrollRow > maxScroll {
screen.rightViewPort.scrollRow = maxScroll screen.rightViewPort.scrollRow = maxScroll
} }
if len(screen.rightPaneBuffer) > 0 { if len(screen.rightPaneBuffer) > 0 {
for k, v := range screen.rightPaneBuffer[screen.rightViewPort.scrollRow:] { for k, v := range screen.rightPaneBuffer[screen.rightViewPort.scrollRow:] {
termboxUtil.DrawStringAtPoint(v.Text, startX, (startY + k - 1), v.Fg, v.Bg) termboxUtil.DrawStringAtPoint(v.Text, startX, (startY + k - 1), v.Fg, v.Bg)
} }
} }
} }
} }
@ -667,105 +666,31 @@ func formatValueJSON(val []byte) ([]byte, error) {
return out, nil return out, nil
} }
func (screen *BrowserScreen) bucketToStrings(bkt *BoltBucket, style Style) []string { func (screen *BrowserScreen) bucketToLines(bkt *BoltBucket, style Style) []Line {
var ret []Line
} bfg, bbg := style.defaultFg, style.defaultBg
/* drawBucket
* @bkt *BoltBucket - The bucket to draw
* @style Style - The style to use
* @w int - The Width of the lines
* @y int - The Y position to start drawing
* return - The number of lines used
*/
func (screen *BrowserScreen) drawBucket(bkt *BoltBucket, style Style, y int) int {
w, _ := termbox.Size()
if w > 80 {
w = w / 2
}
usedLines := 0
bucketFg := style.defaultFg
bucketBg := style.defaultBg
if comparePaths(screen.currentPath, bkt.GetPath()) { if comparePaths(screen.currentPath, bkt.GetPath()) {
bucketFg = style.cursorFg bfg, bbg = style.cursorFg, style.cursorBg
bucketBg = style.cursorBg
} }
bktPrefix := strings.Repeat(" ", len(bkt.GetPath())*2)
prefixSpaces := strings.Repeat(" ", len(bkt.GetPath())*2)
bktString := prefixSpaces
prefixSpaces = prefixSpaces + " "
padAmt := (len(bkt.GetPath())*2 + 2)
if bkt.expanded { if bkt.expanded {
bktString = bktString + "- " + stringify([]byte(bkt.name)) ret = append(ret, Line{bktPrefix + "- " + stringify([]byte(bkt.name)), bfg, bbg})
if len(bktString)+padAmt > w {
bktString = bktString[:w-padAmt-3] + "..."
}
usedLines = screen.drawMultilineText(bktString, (len(bkt.GetPath())*2 + 2), 0, y, (w - 1), bucketFg, bucketBg)
for i := range bkt.buckets { for i := range bkt.buckets {
usedLines += screen.drawBucket(&bkt.buckets[i], style, y+usedLines) ret = append(ret, screen.bucketToLines(&bkt.buckets[i], style)...)
} }
for i := range bkt.pairs { for _, bp := range bkt.pairs {
usedLines += screen.drawPair(&bkt.pairs[i], style, y+usedLines) pfg, pbg := style.defaultFg, style.defaultBg
if comparePaths(screen.currentPath, bp.GetPath()) {
pfg, pbg = style.cursorFg, style.cursorBg
}
prPrefix := strings.Repeat(" ", len(bp.GetPath())*2)
pairString := fmt.Sprintf("%s%s: %s", prPrefix, stringify([]byte(bp.key)), stringify([]byte(bp.val)))
ret = append(ret, Line{pairString, pfg, pbg})
} }
} else { } else {
bktString = bktString + "+ " + stringify([]byte(bkt.name)) ret = append(ret, Line{bktPrefix + "+ " + stringify([]byte(bkt.name)), bfg, bbg})
if len(bktString)+padAmt > w {
bktString = bktString[:w-padAmt-3] + "..."
}
usedLines = screen.drawMultilineText(bktString, (len(bkt.GetPath())*2 + 2), 0, y, (w - 1), bucketFg, bucketBg)
} }
return usedLines return ret
}
func (screen *BrowserScreen) drawPair(bp *BoltPair, style Style, y int) int {
w, _ := termbox.Size()
if w > 80 {
w = w / 2
}
usedLines := 0
bucketFg := style.defaultFg
bucketBg := style.defaultBg
if comparePaths(screen.currentPath, bp.GetPath()) {
bucketFg = style.cursorFg
bucketBg = style.cursorBg
}
prefixSpaces := strings.Repeat(" ", len(bp.GetPath())*2)
pairString := prefixSpaces
pairString = fmt.Sprintf("%s%s: %s", pairString, stringify([]byte(bp.key)), stringify([]byte(bp.val)))
if len(pairString) > w {
}
prefixSpaces = prefixSpaces + " "
if len(pairString) > w {
// The long pair strings are causing a problem, for now, truncate
pairString = pairString[:w-3] + "..."
}
/* TODO: Re-enable this when I figure out the display issue
// Long pair string, wrap it
// We're going to try to wrap it at the :, if we can
if len(bp.GetPath())*2+len(bp.key)+1 > w {
// We can't... So just wrap it
usedLines = screen.drawMultilineText(pairString, (len(bp.GetPath()) * 2), 0, y, (w - 1), style.defaultFg, style.defaultBg)
} else {
// That's convenient, wrap at the :
pairString := strings.Repeat(" ", len(bp.GetPath())*2)
pairString = fmt.Sprintf("%s%s:", pairString, bp.key)
termboxUtil.DrawStringAtPoint(pairString, 0, y, bucketFg, bucketBg)
usedLines++
pairString = strings.Repeat(" ", len(bp.GetPath())*2+2) + bp.val
usedLines += screen.drawMultilineText(pairString, (len(bp.GetPath())*2)+2, 0, y+1, (w - 1), bucketFg, bucketBg)
}
} else {
*/
if w-len(pairString) > 0 {
pairString = fmt.Sprintf("%s%s", pairString, strings.Repeat(" ", (w-len(pairString))))
}
termboxUtil.DrawStringAtPoint(pairString, 0, y, bucketFg, bucketBg)
usedLines = 1
// }
return usedLines
} }
func (screen *BrowserScreen) startDeleteItem() bool { func (screen *BrowserScreen) startDeleteItem() bool {
@ -963,31 +888,6 @@ func (screen *BrowserScreen) startExportJSON() bool {
return false return false
} }
// Print text on multiple lines, if needed
// msg - What to print
// indentPadding - number of spaces to pad lines after the first
// startX - Starting x
// startY - Starting y
// maxWidth - Maximum width
// fg, bg - Colors
// Returns the number of lines used
func (screen *BrowserScreen) drawMultilineText(msg string, indentPadding, startX, startY, maxWidth int, fg, bg termbox.Attribute) int {
var numLines int
spacePadding := strings.Repeat(" ", indentPadding)
// First we need to split 'msg' into the lines it should have (split on '\n')
msgs := strings.Split(msg, "\n")
for _, msg = range msgs {
for len(msg) > maxWidth {
termboxUtil.DrawStringAtPoint(msg[:maxWidth-1], startX, (startY + numLines), fg, bg)
msg = spacePadding + msg[maxWidth-1:]
numLines++
}
termboxUtil.DrawStringAtPoint(msg, startX, (startY + numLines), fg, bg)
numLines++
}
return numLines
}
func (screen *BrowserScreen) setMessage(msg string) { func (screen *BrowserScreen) setMessage(msg string) {
screen.message = msg screen.message = msg
screen.messageTime = time.Now() screen.messageTime = time.Now()