Skip to content

Commit

Permalink
Add scrolling to layers pane
Browse files Browse the repository at this point in the history
  • Loading branch information
moaimullet authored and mark2185 committed Sep 27, 2023
1 parent a885fa6 commit 8406531
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 73 deletions.
106 changes: 34 additions & 72 deletions runtime/ui/view/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,12 @@ func (v *Layer) Setup(body *gocui.View, header *gocui.View) error {
}
v.helpKeys = helpKeys

return v.Render()
_, height := v.body.Size()
v.vm.Setup(0, height)
_ = v.Update()
_ = v.Render()

return nil
}

// height obtains the height of the current pane (taking into account the lost space due to the header).
Expand All @@ -161,62 +166,48 @@ func (v *Layer) IsVisible() bool {

// PageDown moves to next page putting the cursor on top
func (v *Layer) PageDown() error {
step := int(v.height()) + 1
targetLayerIndex := v.vm.LayerIndex + step

if targetLayerIndex > len(v.vm.Layers) {
step -= targetLayerIndex - (len(v.vm.Layers) - 1)
}

if step > 0 {
// err := CursorStep(v.gui, v.body, step)
err := error(nil)
if err == nil {
return v.SetCursor(v.vm.LayerIndex + step)
if v.vm.PageDown() {
err := v.notifyLayerChangeListeners()
if err != nil {
return err
}
return v.Render()
}
return nil
}

// PageUp moves to previous page putting the cursor on top
func (v *Layer) PageUp() error {
step := int(v.height()) + 1
targetLayerIndex := v.vm.LayerIndex - step

if targetLayerIndex < 0 {
step += targetLayerIndex
}

if step > 0 {
// err := CursorStep(v.gui, v.body, -step)
err := error(nil)
if err == nil {
return v.SetCursor(v.vm.LayerIndex - step)
if v.vm.PageUp() {
err := v.notifyLayerChangeListeners()
if err != nil {
return err
}
return v.Render()
}
return nil
}

// CursorDown moves the cursor down in the layer pane (selecting a higher layer).
func (v *Layer) CursorDown() error {
if v.vm.LayerIndex < len(v.vm.Layers)-1 {
// err := CursorDown(v.gui, v.body)
err := error(nil)
if err == nil {
return v.SetCursor(v.vm.LayerIndex + 1)
if v.vm.CursorDown() {
err := v.notifyLayerChangeListeners()
if err != nil {
return err
}
return v.Render()
}
return nil
}

// CursorUp moves the cursor up in the layer pane (selecting a lower layer).
func (v *Layer) CursorUp() error {
if v.vm.LayerIndex > 0 {
// err := CursorUp(v.gui, v.body)
err := error(nil)
if err == nil {
return v.SetCursor(v.vm.LayerIndex - 1)
if v.vm.CursorUp() {
err := v.notifyLayerChangeListeners()
if err != nil {
return err
}
return v.Render()
}
return nil
}
Expand All @@ -243,21 +234,6 @@ func (v *Layer) setCompareMode(compareMode viewmodel.LayerCompareMode) error {
return v.notifyLayerChangeListeners()
}

// renderCompareBar returns the formatted string for the given layer.
func (v *Layer) renderCompareBar(layerIdx int) string {
bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop := v.vm.GetCompareIndexes()
result := " "

if layerIdx >= bottomTreeStart && layerIdx <= bottomTreeStop {
result = format.CompareBottom(" ")
}
if layerIdx >= topTreeStart && layerIdx <= topTreeStop {
result = format.CompareTop(" ")
}

return result
}

func (v *Layer) ConstrainLayout() {
if !v.constrainedRealEstate {
logrus.Debugf("constraining layer layout")
Expand Down Expand Up @@ -293,7 +269,7 @@ func (v *Layer) Render() error {
logrus.Tracef("view.Render() %s", v.Name())

// indicate when selected
title := "Layers"
title := fmt.Sprintf("Layers (%d / %d)", v.vm.LayerIndex+1, len(v.vm.Layers))
isSelected := v.gui.CurrentView() == v.body

v.gui.Update(func(g *gocui.Gui) error {
Expand All @@ -319,28 +295,14 @@ func (v *Layer) Render() error {

// update contents
v.body.Clear()
for idx, layer := range v.vm.Layers {
var layerStr string
if v.constrainedRealEstate {
layerStr = fmt.Sprintf("%-4d", layer.Index)
} else {
layerStr = layer.String()
}

compareBar := v.renderCompareBar(idx)

if idx == v.vm.LayerIndex {
_, err = fmt.Fprintln(v.body, compareBar+" "+format.Selected(layerStr))
} else {
_, err = fmt.Fprintln(v.body, compareBar+" "+layerStr)
}

if err != nil {
logrus.Debug("unable to write to buffer: ", err)
return err
}
v.vm.Update(v.constrainedRealEstate)
err = v.vm.Render()
if err != nil {
return err
}
return nil
_, err = fmt.Fprint(v.body, v.vm.Buffer.String())

return err
})
return nil
}
Expand Down
170 changes: 169 additions & 1 deletion runtime/ui/viewmodel/layer_set_state.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,187 @@
package viewmodel

import "github.com/wagoodman/dive/dive/image"
import (
"bytes"
"fmt"

"github.com/sirupsen/logrus"

"github.com/wagoodman/dive/dive/image"
"github.com/wagoodman/dive/runtime/ui/format"
)

type LayerSetState struct {
LayerIndex int
Layers []*image.Layer
CompareMode LayerCompareMode
CompareStartIndex int

constrainedRealEstate bool
viewStartIndex int
viewHeight int

Buffer bytes.Buffer
}

func NewLayerSetState(layers []*image.Layer, compareMode LayerCompareMode) *LayerSetState {
return &LayerSetState{
Layers: layers,
CompareMode: compareMode,
LayerIndex: 0,
viewStartIndex: 0,
}
}

// Setup initializes the UI concerns within the context of a global [gocui] view object.
func (vm *LayerSetState) Setup(lowerBound, height int) {
vm.viewStartIndex = lowerBound
vm.viewHeight = height
}

// height returns the current height and considers the header
func (vm *LayerSetState) height() int {
return vm.viewHeight - 1
}

// IsVisible indicates if the layer view pane is currently initialized
func (vm *LayerSetState) IsVisible() bool {
return vm != nil
}

// ResetCursor moves the cursor back to the top of the buffer and translates to the top of the buffer.
func (vm *LayerSetState) ResetCursor() {
vm.LayerIndex = 0
vm.viewStartIndex = 0
}


// PageUp moves to previous page putting the cursor on top
func (vm *LayerSetState) PageUp() bool {
prevPageEndIndex := vm.viewStartIndex
prevPageStartIndex := vm.viewStartIndex - vm.viewHeight + 1

if prevPageStartIndex < 0 {
prevPageStartIndex = 0
vm.LayerIndex = 0
prevPageEndIndex = vm.viewHeight
if prevPageEndIndex >= len(vm.Layers) {
return false
}
}

vm.viewStartIndex = prevPageStartIndex

if vm.LayerIndex >= prevPageEndIndex {
vm.LayerIndex = prevPageEndIndex
}
return true
}

// PageDown moves to next page putting the cursor on top
func (vm *LayerSetState) PageDown() bool {
nextPageStartIndex := vm.viewStartIndex + vm.viewHeight - 1
nextPageEndIndex := nextPageStartIndex + vm.viewHeight

if nextPageEndIndex > len(vm.Layers) {
nextPageEndIndex = len(vm.Layers) - 1
vm.LayerIndex = nextPageEndIndex
nextPageStartIndex = nextPageEndIndex - vm.viewHeight + 1
if (nextPageStartIndex < 0) {
return false
}
}

vm.viewStartIndex = nextPageStartIndex

if vm.LayerIndex < nextPageStartIndex {
vm.LayerIndex = nextPageStartIndex
}

return true
}

// doCursorUp performs the internal view's adjustments on cursor up. Note: this is independent of the gocui buffer.
func (vm *LayerSetState) CursorUp() bool {
if vm.LayerIndex <= 0 {
return false
}
vm.LayerIndex--
if vm.LayerIndex < vm.viewStartIndex {
vm.viewStartIndex--
}
return true
}

// doCursorDown performs the internal view's adjustments on cursor down. Note: this is independent of the gocui buffer.
func (vm *LayerSetState) CursorDown() bool {
if vm.LayerIndex >= len(vm.Layers) - 1 {
return false
}
vm.LayerIndex++
if vm.LayerIndex >= vm.viewStartIndex + vm.viewHeight {
vm.viewStartIndex++
}
return true
}

// renderCompareBar returns the formatted string for the given layer.
func (vm *LayerSetState) renderCompareBar(layerIdx int) string {
bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop := vm.GetCompareIndexes()
result := " "

if layerIdx >= bottomTreeStart && layerIdx <= bottomTreeStop {
result = format.CompareBottom(" ")
}
if layerIdx >= topTreeStart && layerIdx <= topTreeStop {
result = format.CompareTop(" ")
}

return result
}

// Update refreshes the state objects for future rendering
func (vm *LayerSetState) Update(isConstrainedRealEstate bool) error {
vm.constrainedRealEstate = isConstrainedRealEstate
return nil
}

// Render flushes the state objects to the screen. The layers pane reports:
// 1. the layers of the image surrounding the currently selected layer
// 2. the current selected layer
func (vm *LayerSetState) Render() error {
logrus.Tracef("viewmodel.LayerSetState.Render() %s", vm.Layers[vm.LayerIndex].Id)

// write contents of pane
vm.Buffer.Reset()
for idx, layer := range vm.Layers {
if idx < vm.viewStartIndex {
continue
}
if idx > vm.viewStartIndex + vm.viewHeight {
break
}
var layerStr string
if vm.constrainedRealEstate {
layerStr = fmt.Sprintf("%-4d", layer.Index)
} else {
layerStr = layer.String()
}

compareBar := vm.renderCompareBar(idx)

err := error(nil)
if idx == vm.LayerIndex {
_, err = fmt.Fprintln(&vm.Buffer, compareBar+" "+format.Selected(layerStr))
} else {
_, err = fmt.Fprintln(&vm.Buffer, compareBar+" "+layerStr)
}

if err != nil {
logrus.Debug("unable to write to buffer: ", err)
return err
}
}
return nil
}

// getCompareIndexes determines the layer boundaries to use for comparison (based on the current compare mode)
Expand Down

0 comments on commit 8406531

Please sign in to comment.