Skip to content

Commit

Permalink
reactive layout; addresses #179
Browse files Browse the repository at this point in the history
  • Loading branch information
wagoodman committed Dec 28, 2019
1 parent 65f40c2 commit 8818b99
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 466 deletions.
2 changes: 1 addition & 1 deletion runtime/ui/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (c *Controller) onLayerChange(selection viewmodel.LayerSelection) error {
return err
}

if c.views.Layer.CompareMode == view.CompareAll {
if c.views.Layer.CompareMode() == viewmodel.CompareAllLayers {
c.views.Tree.SetTitle("Aggregated Layer Contents")
} else {
c.views.Tree.SetTitle("Current Layer Contents")
Expand Down
19 changes: 17 additions & 2 deletions runtime/ui/format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,32 @@ func init() {
CompareBottom = color.New(color.BgGreen).SprintFunc()
}

func RenderNoHeader(width int, selected bool) string {
if selected {
return strings.Repeat(selectedFillStr, width)
}
return strings.Repeat(fillStr, width)
}

func RenderHeader(title string, width int, selected bool) string {
if selected {
body := Header(fmt.Sprintf("%s%s ", selectStr, title))
bodyLen := len(vtclean.Clean(body, false))
return fmt.Sprintf("%s%s%s%s\n", selectedLeftBracketStr, body, selectedRightBracketStr, strings.Repeat(selectedFillStr, width-bodyLen-2))
repeatCount := width - bodyLen - 2
if repeatCount < 0 {
repeatCount = 0
}
return fmt.Sprintf("%s%s%s%s\n", selectedLeftBracketStr, body, selectedRightBracketStr, strings.Repeat(selectedFillStr, repeatCount))
//return fmt.Sprintf("%s%s%s%s\n", Selected(selectedLeftBracketStr), body, Selected(selectedRightBracketStr), Selected(strings.Repeat(selectedFillStr, width-bodyLen-2)))
//return fmt.Sprintf("%s%s%s%s\n", Selected(selectedLeftBracketStr), body, Selected(selectedRightBracketStr), strings.Repeat(selectedFillStr, width-bodyLen-2))
}
body := Header(fmt.Sprintf(" %s ", title))
bodyLen := len(vtclean.Clean(body, false))
return fmt.Sprintf("%s%s%s%s\n", leftBracketStr, body, rightBracketStr, strings.Repeat(fillStr, width-bodyLen-2))
repeatCount := width - bodyLen - 2
if repeatCount < 0 {
repeatCount = 0
}
return fmt.Sprintf("%s%s%s%s\n", leftBracketStr, body, rightBracketStr, strings.Repeat(fillStr, repeatCount))
}

func RenderHelpKey(control, title string, selected bool) string {
Expand Down
57 changes: 45 additions & 12 deletions runtime/ui/layout/compound/layer_details_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (
)

type LayerDetailsCompoundLayout struct {
layer *view.Layer
details *view.Details
layer *view.Layer
details *view.Details
constrainRealEstate bool
}

func NewLayerDetailsCompoundLayout(layer *view.Layer, details *view.Details) *LayerDetailsCompoundLayout {
Expand Down Expand Up @@ -48,7 +49,7 @@ func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, max
// header + border
layerHeaderHeight := 2

layersHeight := len(cl.layer.Layers) + layerHeaderHeight + 1 // layers + header + base image layer row
layersHeight := cl.layer.LayerCount() + layerHeaderHeight + 1 // layers + header + base image layer row
maxLayerHeight := int(0.75 * float64(maxY))
if layersHeight > maxLayerHeight {
layersHeight = maxLayerHeight
Expand Down Expand Up @@ -80,24 +81,56 @@ func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, max
// header + border
detailsHeaderHeight := 2

// note: maxY needs to account for the (invisible) border, thus a +1
header, headerErr = g.SetView(cl.details.Name()+"header", minX, detailsMinY, maxX, detailsMinY+detailsHeaderHeight+1)
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
}
}

// we are going to overlap the view over the (invisible) border (so minY will be one less than expected)
// additionally, maxY will be bumped by one to include the border
main, viewErr = g.SetView(cl.details.Name(), minX, detailsMinY+detailsHeaderHeight, maxX, maxY+1)
} else {

if utils.IsNewView(viewErr, headerErr) {
err := cl.details.Setup(main, header)
if err != nil {
return err
// note: maxY needs to account for the (invisible) border, thus a +1
header, headerErr = g.SetView(cl.details.Name()+"header", minX, detailsMinY, maxX, detailsMinY+detailsHeaderHeight+1)

// we are going to overlap the view over the (invisible) border (so minY will be one less than expected)
// additionally, maxY will be bumped by one to include the border
main, viewErr = g.SetView(cl.details.Name(), minX, detailsMinY+detailsHeaderHeight, maxX, maxY+1)

if utils.IsNewView(viewErr, headerErr) {
err := cl.details.Setup(main, header)
if err != nil {
return err
}
}

}

return nil
}

func (cl *LayerDetailsCompoundLayout) RequestedSize(available int) *int {
// "available" is the entire screen real estate, so we can guess when its a bit too small and take action.
// This isn't perfect, but it gets the job done for now without complicated layout constraint solvers
if available < 90 {
cl.layer.ConstrainLayout()
cl.constrainRealEstate = true
size := 8
return &size
}
cl.layer.ExpandLayout()
cl.constrainRealEstate = false
return nil
}

Expand Down
9 changes: 9 additions & 0 deletions runtime/ui/layout/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"github.com/sirupsen/logrus"
)

type Constraint func(int) int

type Manager struct {
lastX, lastY int
lastHeaderArea, lastFooterArea, lastColumnArea Area
Expand Down Expand Up @@ -113,6 +115,13 @@ func (lm *Manager) planAndLayoutColumns(g *gocui.Gui, area Area) (Area, error) {
}
}

// at least one column must have a variable width, force the last column to be variable if there are no
// variable columns
if variableColumns == 0 {
variableColumns = 1
widths[len(widths)-1] = -1
}

defaultWidth := availableWidth / variableColumns

// second pass: layout columns left to right (based off predetermined widths)
Expand Down
30 changes: 15 additions & 15 deletions runtime/ui/view/filetree.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ import (
"regexp"
)

const (
CompareLayer CompareType = iota
CompareAll
)

type CompareType int

type ViewOptionChangeListener func() error

// FileTree holds the UI objects and data models for populating the right pane. Specifically the pane that
Expand Down Expand Up @@ -77,10 +70,6 @@ func (v *FileTree) Name() string {
return v.name
}

func (v *FileTree) areAttributesVisible() bool {
return v.vm.ShowAttributes
}

// Setup initializes the UI concerns within the context of a global [gocui] view object.
func (v *FileTree) Setup(view *gocui.View, header *gocui.View) error {
logrus.Tracef("view.Setup() %s", v.Name())
Expand Down Expand Up @@ -377,7 +366,7 @@ func (v *FileTree) Render() error {
if v.vm.ShowAttributes {
headerStr += fmt.Sprintf(filetree.AttributeFormat+" %s", "P", "ermission", "UID:GID", "Size", "Filetree")
}
_, _ = fmt.Fprintln(v.header, headerStr, false)
_, _ = fmt.Fprintln(v.header, headerStr)

// update the contents
v.view.Clear()
Expand All @@ -404,9 +393,19 @@ func (v *FileTree) KeyHelp() string {
func (v *FileTree) 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, v.Name())
attributeRowSize := 0
if v.areAttributesVisible() {

// make the layout responsive to the available realestate. Make more room for the main content by hiding auxillary
// content when there is not enough room
if maxX-minX < 60 {
v.vm.ConstrainLayout()
} else {
v.vm.ExpandLayout()
}

if v.vm.ShowAttributes {
attributeRowSize = 1
}

// header + attribute header
headerSize := 1 + attributeRowSize
// note: maxY needs to account for the (invisible) border, thus a +1
Expand All @@ -425,6 +424,7 @@ func (v *FileTree) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
}

func (v *FileTree) RequestedSize(available int) *int {
var requestedWidth = int(float64(available) * (1.0 - v.requestedWidthRatio))
return &requestedWidth
//var requestedWidth = int(float64(available) * (1.0 - v.requestedWidthRatio))
//return &requestedWidth
return nil
}
Loading

0 comments on commit 8818b99

Please sign in to comment.