Switching browser screen to buffer data then display

This commit is contained in:
Brian Buller 2019-10-16 17:41:29 -05:00
parent 930ee1799e
commit 72d7cc8280
4 changed files with 133 additions and 74 deletions

View File

@ -12,7 +12,7 @@ import (
) )
var ProgramName = "boltbrowser" var ProgramName = "boltbrowser"
var VersionNum = 1.2 var VersionNum = 2.0
var databaseFiles []string var databaseFiles []string
var db *bolt.DB var db *bolt.DB

View File

@ -19,9 +19,7 @@ const (
) )
func defaultScreensForData(db *BoltDB) []Screen { func defaultScreensForData(db *BoltDB) []Screen {
var viewPort ViewPort browserScreen := BrowserScreen{db: db, rightViewPort: ViewPort{}, leftViewPort: ViewPort{}}
browserScreen := BrowserScreen{db: db, viewPort: viewPort}
aboutScreen := AboutScreen(0) aboutScreen := AboutScreen(0)
screens := [...]Screen{ screens := [...]Screen{
&browserScreen, &browserScreen,
@ -41,3 +39,9 @@ func layoutAndDrawScreen(screen Screen, style Style) {
screen.drawScreen(style) screen.drawScreen(style)
termbox.Flush() termbox.Flush()
} }
type Line struct {
Text string
Fg termbox.Attribute
Bg termbox.Attribute
}

View File

@ -20,16 +20,9 @@ AboutScreen is just a basic 'int' type that we can extend to make this screen
*/ */
type AboutScreen int type AboutScreen int
func drawCommandsAtPoint(commands []Command, x int, y int, style Style) { func drawCommandAtPoint(cmd Command, xPos int, yPos int, style Style) {
xPos, yPos := x, y termboxUtil.DrawStringAtPoint(fmt.Sprintf("%6s", cmd.key), xPos, yPos, style.defaultFg, style.defaultBg)
for index, cmd := range commands { termboxUtil.DrawStringAtPoint(cmd.description, xPos+8, yPos, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%6s", cmd.key), xPos, yPos, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint(cmd.description, xPos+8, yPos, style.defaultFg, style.defaultBg)
yPos++
if index > 2 && index%2 == 1 {
yPos++
}
}
} }
func (screen *AboutScreen) handleKeyEvent(event termbox.Event) int { func (screen *AboutScreen) handleKeyEvent(event termbox.Event) int {
@ -96,36 +89,58 @@ func (screen *AboutScreen) drawScreen(style Style) {
yPos++ yPos++
versionString := fmt.Sprintf("Version: %0.1f", VersionNum) versionString := fmt.Sprintf("Version: %0.1f", VersionNum)
termboxUtil.DrawStringAtPoint(versionString, (width-len(versionString))/2, yPos, style.defaultFg, style.defaultBg) termboxUtil.DrawStringAtPoint(versionString, (width-len(versionString))/2, yPos, style.defaultFg, style.defaultBg)
yPos++
commands1 := [...]Command{ commands1 := []Command{
{"h,←", "close parent"}, {"h,←", "close parent"},
{"j,↓", "down"}, {"j,↓", "down"},
{"k,↑", "up"}, {"k,↑", "up"},
{"l,→", "open item"}, {"l,→", "open item"},
{"J", "scroll right pane down"},
{"K", "scroll right pane up"},
{"", ""},
{"g", "goto top"}, {"g", "goto top"},
{"G", "goto bottom"}, {"G", "goto bottom"},
{"", ""},
{"ctrl+f", "jump down"}, {"ctrl+f", "jump down"},
{"ctrl+b", "jump up"}, {"ctrl+b", "jump up"},
} }
commands2 := [...]Command{ commands2 := []Command{
{"p,P", "create pair/at parent"}, {"p,P", "create pair/at parent"},
{"b,B", "create bucket/at parent"}, {"b,B", "create bucket/at parent"},
{"e", "edit value of pair"}, {"e", "edit value of pair"},
{"r", "rename pair/bucket"}, {"r", "rename pair/bucket"},
{"", ""},
{"", ""},
{"D", "delete item"}, {"D", "delete item"},
{"x,X", "export as string/json to file"}, {"x,X", "export as string/json to file"},
{"", ""},
{"?", "this screen"}, {"?", "this screen"},
{"q", "quit program"}, {"q", "quit program"},
} }
xPos = startX // + 20 var maxCmd1 int
for k := range commands1 {
tst := len(commands1[k].key) + 1 + len(commands1[k].description)
if tst > maxCmd1 {
maxCmd1 = tst
}
}
var maxCmd2 int
for k := range commands2 {
tst := len(commands2[k].key) + 1 + len(commands2[k].description)
if tst > maxCmd2 {
maxCmd2 = tst
}
}
xPos = (width / 2) - ((maxCmd1 + maxCmd2) / 2)
yPos++ yPos++
drawCommandsAtPoint(commands1[:], xPos, yPos+1, style) for k := range commands1 {
drawCommandsAtPoint(commands2[:], xPos+20, yPos+1, style) drawCommandAtPoint(commands1[k], xPos, yPos+1+k, style)
}
for k := range commands2 {
drawCommandAtPoint(commands2[k], xPos+40, yPos+1+k, style)
}
exitTxt := "Press any key to return to browser" exitTxt := "Press any key to return to browser"
termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, style.titleFg, style.titleBg) termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, style.titleFg, style.titleBg)
} }

View File

@ -17,6 +17,7 @@ type ViewPort struct {
bytesPerRow int bytesPerRow int
numberOfRows int numberOfRows int
firstRow int firstRow int
scrollRow int
} }
/* /*
@ -24,7 +25,8 @@ BrowserScreen holds all that's going on :D
*/ */
type BrowserScreen struct { type BrowserScreen struct {
db *BoltDB db *BoltDB
viewPort ViewPort leftViewPort ViewPort
rightViewPort ViewPort
queuedCommand string queuedCommand string
currentPath []string currentPath []string
currentType int currentType int
@ -37,6 +39,9 @@ type BrowserScreen struct {
rightPaneHeight int rightPaneHeight int
rightPaneCursor int rightPaneCursor int
leftPaneBuffer []Line
rightPaneBuffer []Line
} }
/* /*
@ -480,10 +485,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 {
screen.rightViewPort.scrollRow--
return true
}
return false return false
} }
func (screen *BrowserScreen) moveRightPaneDown() bool { func (screen *BrowserScreen) moveRightPaneDown() bool {
return false screen.rightViewPort.scrollRow++
return true
} }
func (screen *BrowserScreen) performLayout() {} func (screen *BrowserScreen) performLayout() {}
@ -528,41 +538,35 @@ func (screen *BrowserScreen) drawFooter(style Style) {
_, height := termbox.Size() _, height := termbox.Size()
termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, style.defaultFg, style.defaultBg) termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, style.defaultFg, style.defaultBg)
} }
func (screen *BrowserScreen) buildLeftPane(style Style) {
screen.leftPaneBuffer = nil
if len(screen.currentPath) == 0 {
screen.currentPath = screen.db.getNextVisiblePath(nil)
}
curPathSpot := 0
visPaths, err := screen.db.buildVisiblePathSlice()
if err == nil {
for idx, pth := range visPaths {
screen.leftPaneBuffer
}
}
}
func (screen *BrowserScreen) drawLeftPane(style Style) { func (screen *BrowserScreen) drawLeftPane(style 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.viewPort.numberOfRows = h - 2 screen.leftViewPort.bytesPerRow = w
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 y := 2
screen.viewPort.firstRow = y screen.leftViewPort.firstRow = y
if len(screen.currentPath) == 0 {
screen.currentPath = screen.db.getNextVisiblePath(nil)
}
// So we know how much of the tree _wants_ to be visible
// we only have screen.viewPort.numberOfRows of space though
curPathSpot := 0
visPaths, err := screen.db.buildVisiblePathSlice()
if err == nil {
for idx, pth := range visPaths {
isCurPath := true
for i := range pth {
if len(screen.currentPath) > i && pth[i] != screen.currentPath[i] {
isCurPath = false
break
}
}
if isCurPath {
curPathSpot = idx
}
}
}
treeOffset := 0 treeOffset := 0
maxCursor := screen.viewPort.numberOfRows * 2 / 3 maxCursor := screen.leftViewPort.numberOfRows * 2 / 3
if curPathSpot > maxCursor { if curPathSpot > maxCursor {
treeOffset = curPathSpot - maxCursor treeOffset = curPathSpot - maxCursor
} }
@ -573,39 +577,71 @@ func (screen *BrowserScreen) drawLeftPane(style Style) {
y += bktH y += bktH
} }
} }
func (screen *BrowserScreen) buildRightPane(style Style) {
screen.rightPaneBuffer = nil
b, p, err := screen.db.getGenericFromPath(screen.currentPath)
if err == nil {
if b != nil {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(b.GetPath()), " → ")), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Buckets: %d", len(b.buckets)), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Pairs: %d", len(b.pairs)), style.defaultFg, style.defaultBg})
} else if p != nil {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → ")), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Key: %s", stringify([]byte(p.key))), style.defaultFg, style.defaultBg})
value := strings.Split(string(formatValue([]byte(p.val))), "\n")
if len(value) == 1 {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Value: %s", value[0]), style.defaultFg, style.defaultBg})
} else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{"Value:", style.defaultFg, style.defaultBg})
for _, v := range value {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{v, style.defaultFg, style.defaultBg})
}
}
}
} else {
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg})
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
Line{err.Error(), termbox.ColorRed, termbox.ColorBlack})
}
}
func (screen *BrowserScreen) drawRightPane(style Style) { func (screen *BrowserScreen) drawRightPane(style 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.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.viewPort.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.viewPort.firstRow, w, h, style.defaultFg, style.defaultBg) termboxUtil.FillWithChar(' ', (w/2)+1, screen.rightViewPort.firstRow, w, h, style.defaultFg, style.defaultBg)
b, p, err := screen.db.getGenericFromPath(screen.currentPath)
startX := (w / 2) + 2 startX := (w / 2) + 2
startY := 2 startY := 2
if err == nil { maxScroll := len(screen.rightPaneBuffer)-screen.rightViewPort.numberOfRows
if b != nil { if maxScroll < 0 {
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(b.GetPath()), " → ")) maxScroll = 0
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg) }
bucketString := fmt.Sprintf("Buckets: %d", len(b.buckets)) if screen.rightViewPort.scrollRow > maxScroll {
startY += screen.drawMultilineText(bucketString, 9, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg) screen.rightViewPort.scrollRow = maxScroll
pairsString := fmt.Sprintf("Pairs: %d", len(b.pairs)) }
startY += screen.drawMultilineText(pairsString, 7, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg) if len(screen.rightPaneBuffer) > 0 {
} else if p != nil { for k, v := range screen.rightPaneBuffer[screen.rightViewPort.scrollRow:] {
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → ")) termboxUtil.DrawStringAtPoint(v.Text, startX, (startY + k - 1), v.Fg, v.Bg)
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg) }
keyString := fmt.Sprintf("Key: %s", stringify([]byte(p.key))) }
startY += screen.drawMultilineText(keyString, 5, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
valString := fmt.Sprintf("Value: %s", formatValue([]byte(p.val)))
startY += screen.drawMultilineText(valString, 7, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
}
} else {
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(screen.currentPath), " → "))
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
startY += screen.drawMultilineText(err.Error(), 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
}
} }
} }
@ -631,6 +667,10 @@ func formatValueJSON(val []byte) ([]byte, error) {
return out, nil return out, nil
} }
func (screen *BrowserScreen) bucketToStrings(bkt *BoltBucket, style Style) []string {
}
/* drawBucket /* drawBucket
* @bkt *BoltBucket - The bucket to draw * @bkt *BoltBucket - The bucket to draw
* @style Style - The style to use * @style Style - The style to use