Skip to content

Commit

Permalink
Merge pull request #399 from mark2185/feature/gui-layout-rework
Browse files Browse the repository at this point in the history
GUI rework
  • Loading branch information
wagoodman authored Jul 6, 2023
2 parents abbac15 + 2aad87c commit 8bf4341
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 315 deletions.
4 changes: 3 additions & 1 deletion dive/image/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package image

import (
"fmt"
"strings"

"github.com/dustin/go-humanize"
"github.com/wagoodman/dive/dive/filetree"
)
Expand Down Expand Up @@ -39,5 +41,5 @@ func (l *Layer) String() string {
}
return fmt.Sprintf(LayerFormat,
humanize.Bytes(l.Size),
l.Command)
strings.Split(l.Command, "\n")[0])
}
10 changes: 9 additions & 1 deletion runtime/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func newApp(gui *gocui.Gui, imageName string, analysis *image.AnalysisResult, ca
lm := layout.NewManager()
lm.Add(controller.views.Status, layout.LocationFooter)
lm.Add(controller.views.Filter, layout.LocationFooter)
lm.Add(compound.NewLayerDetailsCompoundLayout(controller.views.Layer, controller.views.Details), layout.LocationColumn)
lm.Add(compound.NewLayerDetailsCompoundLayout(controller.views.Layer, controller.views.LayerDetails, controller.views.ImageDetails), layout.LocationColumn)
lm.Add(controller.views.Tree, layout.LocationColumn)

// todo: access this more programmatically
Expand Down Expand Up @@ -76,6 +76,14 @@ func newApp(gui *gocui.Gui, imageName string, analysis *image.AnalysisResult, ca
OnAction: controller.ToggleView,
Display: "Switch view",
},
{
Key: gocui.KeyArrowRight,
OnAction: controller.NextPane,
},
{
Key: gocui.KeyArrowLeft,
OnAction: controller.PrevPane,
},
{
ConfigKeys: []string{"keybinding.filter-files"},
OnAction: controller.ToggleFilterView,
Expand Down
50 changes: 49 additions & 1 deletion runtime/ui/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *Controller) onFilterEdit(filter string) error {

func (c *Controller) onLayerChange(selection viewmodel.LayerSelection) error {
// update the details
c.views.Details.SetCurrentLayer(selection.Layer)
c.views.LayerDetails.CurrentLayer = selection.Layer

// update the filetree
err := c.views.Tree.SetTree(selection.BottomTreeStart, selection.BottomTreeStop, selection.TopTreeStart, selection.TopTreeStop)
Expand Down Expand Up @@ -141,6 +141,54 @@ func (c *Controller) Render() error {
return nil
}

func (c *Controller) NextPane() (err error) {
v := c.gui.CurrentView()
if v == nil {
panic("Current view is nil")
}
if v.Name() == c.views.Layer.Name() {
_, err = c.gui.SetCurrentView(c.views.LayerDetails.Name())
c.views.Status.SetCurrentView(c.views.LayerDetails)
} else if v.Name() == c.views.LayerDetails.Name() {
_, err = c.gui.SetCurrentView(c.views.ImageDetails.Name())
c.views.Status.SetCurrentView(c.views.ImageDetails)
} else if v.Name() == c.views.ImageDetails.Name() {
_, err = c.gui.SetCurrentView(c.views.Layer.Name())
c.views.Status.SetCurrentView(c.views.Layer)
}

if err != nil {
logrus.Error("unable to toggle view: ", err)
return err
}

return c.UpdateAndRender()
}

func (c *Controller) PrevPane() (err error) {
v := c.gui.CurrentView()
if v == nil {
panic("Current view is nil")
}
if v.Name() == c.views.Layer.Name() {
_, err = c.gui.SetCurrentView(c.views.ImageDetails.Name())
c.views.Status.SetCurrentView(c.views.ImageDetails)
} else if v.Name() == c.views.LayerDetails.Name() {
_, err = c.gui.SetCurrentView(c.views.Layer.Name())
c.views.Status.SetCurrentView(c.views.Layer)
} else if v.Name() == c.views.ImageDetails.Name() {
_, err = c.gui.SetCurrentView(c.views.LayerDetails.Name())
c.views.Status.SetCurrentView(c.views.LayerDetails)
}

if err != nil {
logrus.Error("unable to toggle view: ", err)
return err
}

return c.UpdateAndRender()
}

// ToggleView switches between the file view and the layer view and re-renders the screen.
func (c *Controller) ToggleView() (err error) {
v := c.gui.CurrentView()
Expand Down
102 changes: 41 additions & 61 deletions runtime/ui/layout/compound/layer_details_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import (

type LayerDetailsCompoundLayout struct {
layer *view.Layer
details *view.Details
layerDetails *view.LayerDetails
imageDetails *view.ImageDetails
constrainRealEstate bool
}

func NewLayerDetailsCompoundLayout(layer *view.Layer, details *view.Details) *LayerDetailsCompoundLayout {
func NewLayerDetailsCompoundLayout(layer *view.Layer, layerDetails *view.LayerDetails, imageDetails *view.ImageDetails) *LayerDetailsCompoundLayout {
return &LayerDetailsCompoundLayout{
layer: layer,
details: details,
layer: layer,
layerDetails: layerDetails,
imageDetails: imageDetails,
}
}

Expand All @@ -32,87 +34,65 @@ func (cl *LayerDetailsCompoundLayout) OnLayoutChange() error {
return err
}

err = cl.details.OnLayoutChange()
err = cl.layerDetails.OnLayoutChange()
if err != nil {
logrus.Error("unable to setup details controller onLayoutChange", err)
logrus.Error("unable to setup layer details controller onLayoutChange", err)
return err
}

err = cl.imageDetails.OnLayoutChange()
if err != nil {
logrus.Error("unable to setup image details controller onLayoutChange", err)
return err
}
return nil
}

func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
logrus.Tracef("view.Layout(minX: %d, minY: %d, maxX: %d, maxY: %d) %s", minX, minY, maxX, maxY, cl.Name())

////////////////////////////////////////////////////////////////////////////////////
// Layers View

func (cl *LayerDetailsCompoundLayout) layoutRow(g *gocui.Gui, minX, minY, maxX, maxY int, viewName string, setup func(*gocui.View, *gocui.View) error) error {
logrus.Tracef("layoutRow(g, minX: %d, minY: %d, maxX: %d, maxY: %d, viewName: %s, <setup func>)", minX, minY, maxX, maxY, viewName)
// header + border
layerHeaderHeight := 2

layersHeight := cl.layer.LayerCount() + layerHeaderHeight + 1 // layers + header + base image layer row
maxLayerHeight := int(0.75 * float64(maxY))
if layersHeight > maxLayerHeight {
layersHeight = maxLayerHeight
}
headerHeight := 2

// TODO: investigate overlap
// note: maxY needs to account for the (invisible) border, thus a +1
header, headerErr := g.SetView(cl.layer.Name()+"header", minX, minY, maxX, minY+layerHeaderHeight+1, 0)
headerView, headerErr := g.SetView(viewName+"Header", minX, minY, maxX, minY+headerHeight+1, 0)

// we are going to overlap the view over the (invisible) border (so minY will be one less than expected)
main, viewErr := g.SetView(cl.layer.Name(), minX, minY+layerHeaderHeight, maxX, minY+layerHeaderHeight+layersHeight, 0)
bodyView, bodyErr := g.SetView(viewName, minX, minY+headerHeight, maxX, maxY, 0)

if utils.IsNewView(viewErr, headerErr) {
err := cl.layer.Setup(main, header)
if utils.IsNewView(bodyErr, headerErr) {
err := setup(bodyView, headerView)
if err != nil {
logrus.Error("unable to setup layer layout", err)
return err
}

if _, err = g.SetCurrentView(cl.layer.Name()); err != nil {
logrus.Error("unable to set view to layer", err)
logrus.Debug("unable to setup row layout for ", viewName, err)
return err
}
}
return nil
}

////////////////////////////////////////////////////////////////////////////////////
// Details
detailsMinY := minY + layersHeight

// header + border
detailsHeaderHeight := 2

v, _ := g.View(cl.details.Name())
if v != nil {
// the view exists already!

// don't show the details pane when there isn't enough room on the screen
if cl.constrainRealEstate {
// take note: deleting a view will invoke layout again, so ensure this call is protected from an infinite loop
err := g.DeleteView(cl.details.Name())
if err != nil {
return err
}
// take note: deleting a view will invoke layout again, so ensure this call is protected from an infinite loop
err = g.DeleteView(cl.details.Name() + "header")
if err != nil {
return err
}

return nil
}
func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
logrus.Tracef("LayerDetailsCompountLayout.Layout(minX: %d, minY: %d, maxX: %d, maxY: %d) %s", minX, minY, maxX, maxY, cl.Name())

layouts := []view.IView{
cl.layer,
cl.layerDetails,
cl.imageDetails,
}

header, headerErr = g.SetView(cl.details.Name()+"header", minX, detailsMinY, maxX, detailsMinY+detailsHeaderHeight, 0)
main, viewErr = g.SetView(cl.details.Name(), minX, detailsMinY+detailsHeaderHeight, maxX, maxY, 0)

if utils.IsNewView(viewErr, headerErr) {
err := cl.details.Setup(main, header)
if err != nil {
rowHeight := maxY / 3
for i := 0; i < 3; i++ {
if err := cl.layoutRow(g, minX, i*rowHeight, maxX, (i+1)*rowHeight, layouts[i].Name(), layouts[i].Setup); err != nil {
logrus.Debug("Laying out layers view errored!")
return err
}
}

if g.CurrentView() == nil {
if _, err := g.SetCurrentView(cl.layer.Name()); err != nil {
logrus.Error("unable to set view to layer", err)
return err
}
}
return nil
}

Expand Down
Loading

0 comments on commit 8bf4341

Please sign in to comment.