mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-11 13:53:25 +02:00
move box layout stuff into its own package
This commit is contained in:
parent
8430b04492
commit
1e12a60b34
@ -1,19 +1,20 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/boxlayout"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) mainSectionChildren() []*box {
|
||||
func (gui *Gui) mainSectionChildren() []*boxlayout.Box {
|
||||
currentViewName := gui.currentViewName()
|
||||
|
||||
// if we're not in split mode we can just show the one main panel. Likewise if
|
||||
// the main panel is focused and we're in full-screen mode
|
||||
if !gui.State.SplitMainPanel || (gui.State.ScreenMode == SCREEN_FULL && currentViewName == "main") {
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
{
|
||||
viewName: "main",
|
||||
weight: 1,
|
||||
ViewName: "main",
|
||||
Weight: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -25,14 +26,14 @@ func (gui *Gui) mainSectionChildren() []*box {
|
||||
main, secondary = secondary, main
|
||||
}
|
||||
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
{
|
||||
viewName: main,
|
||||
weight: 1,
|
||||
ViewName: main,
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
viewName: secondary,
|
||||
weight: 1,
|
||||
ViewName: secondary,
|
||||
Weight: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -65,41 +66,41 @@ func (gui *Gui) getMidSectionWeights() (int, int) {
|
||||
return sideSectionWeight, mainSectionWeight
|
||||
}
|
||||
|
||||
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*box {
|
||||
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
||||
if gui.State.Searching.isSearching {
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
{
|
||||
viewName: "searchPrefix",
|
||||
size: len(SEARCH_PREFIX),
|
||||
ViewName: "searchPrefix",
|
||||
Size: len(SEARCH_PREFIX),
|
||||
},
|
||||
{
|
||||
viewName: "search",
|
||||
weight: 1,
|
||||
ViewName: "search",
|
||||
Weight: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
result := []*box{}
|
||||
result := []*boxlayout.Box{}
|
||||
|
||||
if len(appStatus) > 0 {
|
||||
result = append(result,
|
||||
&box{
|
||||
viewName: "appStatus",
|
||||
size: len(appStatus) + len(INFO_SECTION_PADDING),
|
||||
&boxlayout.Box{
|
||||
ViewName: "appStatus",
|
||||
Size: len(appStatus) + len(INFO_SECTION_PADDING),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
result = append(result,
|
||||
[]*box{
|
||||
[]*boxlayout.Box{
|
||||
{
|
||||
viewName: "options",
|
||||
weight: 1,
|
||||
ViewName: "options",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
viewName: "information",
|
||||
ViewName: "information",
|
||||
// unlike appStatus, informationStr has various colors so we need to decolorise before taking the length
|
||||
size: len(INFO_SECTION_PADDING) + len(utils.Decolorise(informationStr)),
|
||||
Size: len(INFO_SECTION_PADDING) + len(utils.Decolorise(informationStr)),
|
||||
},
|
||||
}...,
|
||||
)
|
||||
@ -107,82 +108,82 @@ func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) getViewDimensions(informationStr string, appStatus string) map[string]dimensions {
|
||||
func (gui *Gui) getViewDimensions(informationStr string, appStatus string) map[string]boxlayout.Dimensions {
|
||||
width, height := gui.g.Size()
|
||||
|
||||
sideSectionWeight, mainSectionWeight := gui.getMidSectionWeights()
|
||||
|
||||
sidePanelsDirection := COLUMN
|
||||
sidePanelsDirection := boxlayout.COLUMN
|
||||
portraitMode := width <= 84 && height > 45
|
||||
if portraitMode {
|
||||
sidePanelsDirection = ROW
|
||||
sidePanelsDirection = boxlayout.ROW
|
||||
}
|
||||
|
||||
root := &box{
|
||||
direction: ROW,
|
||||
children: []*box{
|
||||
root := &boxlayout.Box{
|
||||
Direction: boxlayout.ROW,
|
||||
Children: []*boxlayout.Box{
|
||||
{
|
||||
direction: sidePanelsDirection,
|
||||
weight: 1,
|
||||
children: []*box{
|
||||
Direction: sidePanelsDirection,
|
||||
Weight: 1,
|
||||
Children: []*boxlayout.Box{
|
||||
{
|
||||
direction: ROW,
|
||||
weight: sideSectionWeight,
|
||||
conditionalChildren: gui.sidePanelChildren,
|
||||
Direction: boxlayout.ROW,
|
||||
Weight: sideSectionWeight,
|
||||
ConditionalChildren: gui.sidePanelChildren,
|
||||
},
|
||||
{
|
||||
conditionalDirection: func(width int, height int) int {
|
||||
ConditionalDirection: func(width int, height int) int {
|
||||
mainPanelSplitMode := gui.Config.GetUserConfig().GetString("gui.mainPanelSplitMode")
|
||||
|
||||
switch mainPanelSplitMode {
|
||||
case "vertical":
|
||||
return ROW
|
||||
return boxlayout.ROW
|
||||
case "horizontal":
|
||||
return COLUMN
|
||||
return boxlayout.COLUMN
|
||||
default:
|
||||
if width < 160 && height > 30 { // 2 80 character width panels
|
||||
return ROW
|
||||
return boxlayout.ROW
|
||||
} else {
|
||||
return COLUMN
|
||||
return boxlayout.COLUMN
|
||||
}
|
||||
}
|
||||
},
|
||||
direction: COLUMN,
|
||||
weight: mainSectionWeight,
|
||||
children: gui.mainSectionChildren(),
|
||||
Direction: boxlayout.COLUMN,
|
||||
Weight: mainSectionWeight,
|
||||
Children: gui.mainSectionChildren(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
direction: COLUMN,
|
||||
size: 1,
|
||||
children: gui.infoSectionChildren(informationStr, appStatus),
|
||||
Direction: boxlayout.COLUMN,
|
||||
Size: 1,
|
||||
Children: gui.infoSectionChildren(informationStr, appStatus),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return gui.arrangeViews(root, 0, 0, width, height)
|
||||
return boxlayout.ArrangeViews(root, 0, 0, width, height)
|
||||
}
|
||||
|
||||
func (gui *Gui) sidePanelChildren(width int, height int) []*box {
|
||||
func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box {
|
||||
currentCyclableViewName := gui.currentCyclableViewName()
|
||||
|
||||
if gui.State.ScreenMode == SCREEN_FULL || gui.State.ScreenMode == SCREEN_HALF {
|
||||
fullHeightBox := func(viewName string) *box {
|
||||
fullHeightBox := func(viewName string) *boxlayout.Box {
|
||||
if viewName == currentCyclableViewName {
|
||||
return &box{
|
||||
viewName: viewName,
|
||||
weight: 1,
|
||||
return &boxlayout.Box{
|
||||
ViewName: viewName,
|
||||
Weight: 1,
|
||||
}
|
||||
} else {
|
||||
return &box{
|
||||
viewName: viewName,
|
||||
size: 0,
|
||||
return &boxlayout.Box{
|
||||
ViewName: viewName,
|
||||
Size: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
fullHeightBox("status"),
|
||||
fullHeightBox("files"),
|
||||
fullHeightBox("branches"),
|
||||
@ -191,26 +192,26 @@ func (gui *Gui) sidePanelChildren(width int, height int) []*box {
|
||||
}
|
||||
} else if height >= 28 {
|
||||
accordianMode := gui.Config.GetUserConfig().GetBool("gui.expandFocusedSidePanel")
|
||||
accordianBox := func(defaultBox *box) *box {
|
||||
if accordianMode && defaultBox.viewName == currentCyclableViewName {
|
||||
return &box{
|
||||
viewName: defaultBox.viewName,
|
||||
weight: 2,
|
||||
accordianBox := func(defaultBox *boxlayout.Box) *boxlayout.Box {
|
||||
if accordianMode && defaultBox.ViewName == currentCyclableViewName {
|
||||
return &boxlayout.Box{
|
||||
ViewName: defaultBox.ViewName,
|
||||
Weight: 2,
|
||||
}
|
||||
}
|
||||
|
||||
return defaultBox
|
||||
}
|
||||
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
{
|
||||
viewName: "status",
|
||||
size: 3,
|
||||
ViewName: "status",
|
||||
Size: 3,
|
||||
},
|
||||
accordianBox(&box{viewName: "files", weight: 1}),
|
||||
accordianBox(&box{viewName: "branches", weight: 1}),
|
||||
accordianBox(&box{viewName: "commits", weight: 1}),
|
||||
accordianBox(&box{viewName: "stash", size: 3}),
|
||||
accordianBox(&boxlayout.Box{ViewName: "files", Weight: 1}),
|
||||
accordianBox(&boxlayout.Box{ViewName: "branches", Weight: 1}),
|
||||
accordianBox(&boxlayout.Box{ViewName: "commits", Weight: 1}),
|
||||
accordianBox(&boxlayout.Box{ViewName: "stash", Size: 3}),
|
||||
}
|
||||
} else {
|
||||
squashedHeight := 1
|
||||
@ -218,21 +219,21 @@ func (gui *Gui) sidePanelChildren(width int, height int) []*box {
|
||||
squashedHeight = 3
|
||||
}
|
||||
|
||||
squashedSidePanelBox := func(viewName string) *box {
|
||||
squashedSidePanelBox := func(viewName string) *boxlayout.Box {
|
||||
if viewName == currentCyclableViewName {
|
||||
return &box{
|
||||
viewName: viewName,
|
||||
weight: 1,
|
||||
return &boxlayout.Box{
|
||||
ViewName: viewName,
|
||||
Weight: 1,
|
||||
}
|
||||
} else {
|
||||
return &box{
|
||||
viewName: viewName,
|
||||
size: squashedHeight,
|
||||
return &boxlayout.Box{
|
||||
ViewName: viewName,
|
||||
Size: squashedHeight,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []*box{
|
||||
return []*boxlayout.Box{
|
||||
squashedSidePanelBox("status"),
|
||||
squashedSidePanelBox("files"),
|
||||
squashedSidePanelBox("branches"),
|
||||
|
@ -1,12 +1,12 @@
|
||||
package gui
|
||||
package boxlayout
|
||||
|
||||
import "math"
|
||||
|
||||
type dimensions struct {
|
||||
x0 int
|
||||
x1 int
|
||||
y0 int
|
||||
y1 int
|
||||
type Dimensions struct {
|
||||
X0 int
|
||||
X1 int
|
||||
Y0 int
|
||||
Y1 int
|
||||
}
|
||||
|
||||
const (
|
||||
@ -24,56 +24,56 @@ const (
|
||||
// boxes, one with weight 1 and the other with weight 2, the first one gets 33%
|
||||
// of the available space and the second one gets the remaining 66%
|
||||
|
||||
type box struct {
|
||||
// direction decides how the children boxes are laid out. ROW means the children will each form a row i.e. that they will be stacked on top of eachother.
|
||||
direction int // ROW or COLUMN
|
||||
type Box struct {
|
||||
// Direction decides how the children boxes are laid out. ROW means the children will each form a row i.e. that they will be stacked on top of eachother.
|
||||
Direction int // ROW or COLUMN
|
||||
|
||||
// function which takes the width and height assigned to the box and decides which orientation it will have
|
||||
conditionalDirection func(width int, height int) int
|
||||
ConditionalDirection func(width int, height int) int
|
||||
|
||||
children []*box
|
||||
Children []*Box
|
||||
|
||||
// function which takes the width and height assigned to the box and decides the layout of the children.
|
||||
conditionalChildren func(width int, height int) []*box
|
||||
ConditionalChildren func(width int, height int) []*Box
|
||||
|
||||
// viewName refers to the name of the view this box represents, if there is one
|
||||
viewName string
|
||||
// ViewName refers to the name of the view this box represents, if there is one
|
||||
ViewName string
|
||||
|
||||
// static size. If parent box's direction is ROW this refers to height, otherwise width
|
||||
size int
|
||||
// static Size. If parent box's direction is ROW this refers to height, otherwise width
|
||||
Size int
|
||||
|
||||
// dynamic size. Once all statically sized children have been considered, weight decides how much of the remaining space will be taken up by the box
|
||||
// TODO: consider making there be one int and a type enum so we can't have size and weight simultaneously defined
|
||||
weight int
|
||||
// dynamic size. Once all statically sized children have been considered, Weight decides how much of the remaining space will be taken up by the box
|
||||
// TODO: consider making there be one int and a type enum so we can't have size and Weight simultaneously defined
|
||||
Weight int
|
||||
}
|
||||
|
||||
func (b *box) isStatic() bool {
|
||||
return b.size > 0
|
||||
func (b *Box) isStatic() bool {
|
||||
return b.Size > 0
|
||||
}
|
||||
|
||||
func (b *box) getDirection(width int, height int) int {
|
||||
if b.conditionalDirection != nil {
|
||||
return b.conditionalDirection(width, height)
|
||||
func (b *Box) getDirection(width int, height int) int {
|
||||
if b.ConditionalDirection != nil {
|
||||
return b.ConditionalDirection(width, height)
|
||||
}
|
||||
return b.direction
|
||||
return b.Direction
|
||||
}
|
||||
|
||||
func (b *box) getChildren(width int, height int) []*box {
|
||||
if b.conditionalChildren != nil {
|
||||
return b.conditionalChildren(width, height)
|
||||
func (b *Box) getChildren(width int, height int) []*Box {
|
||||
if b.ConditionalChildren != nil {
|
||||
return b.ConditionalChildren(width, height)
|
||||
}
|
||||
return b.children
|
||||
return b.Children
|
||||
}
|
||||
|
||||
func (gui *Gui) arrangeViews(root *box, x0, y0, width, height int) map[string]dimensions {
|
||||
func ArrangeViews(root *Box, x0, y0, width, height int) map[string]Dimensions {
|
||||
children := root.getChildren(width, height)
|
||||
if len(children) == 0 {
|
||||
// leaf node
|
||||
if root.viewName != "" {
|
||||
dimensionsForView := dimensions{x0: x0, y0: y0, x1: x0 + width - 1, y1: y0 + height - 1}
|
||||
return map[string]dimensions{root.viewName: dimensionsForView}
|
||||
if root.ViewName != "" {
|
||||
dimensionsForView := Dimensions{X0: x0, Y0: y0, X1: x0 + width - 1, Y1: y0 + height - 1}
|
||||
return map[string]Dimensions{root.ViewName: dimensionsForView}
|
||||
}
|
||||
return map[string]dimensions{}
|
||||
return map[string]Dimensions{}
|
||||
}
|
||||
|
||||
direction := root.getDirection(width, height)
|
||||
@ -90,8 +90,8 @@ func (gui *Gui) arrangeViews(root *box, x0, y0, width, height int) map[string]di
|
||||
totalWeight := 0
|
||||
for _, child := range children {
|
||||
// assuming either size or weight are non-zero
|
||||
reservedSize += child.size
|
||||
totalWeight += child.weight
|
||||
reservedSize += child.Size
|
||||
totalWeight += child.Weight
|
||||
}
|
||||
|
||||
remainingSize := availableSize - reservedSize
|
||||
@ -106,37 +106,37 @@ func (gui *Gui) arrangeViews(root *box, x0, y0, width, height int) map[string]di
|
||||
extraSize = remainingSize % totalWeight
|
||||
}
|
||||
|
||||
result := map[string]dimensions{}
|
||||
result := map[string]Dimensions{}
|
||||
offset := 0
|
||||
for _, child := range children {
|
||||
var boxSize int
|
||||
if child.isStatic() {
|
||||
boxSize = child.size
|
||||
boxSize = child.Size
|
||||
} else {
|
||||
// TODO: consider more evenly distributing the remainder
|
||||
boxSize = unitSize * child.weight
|
||||
boxExtraSize := int(math.Min(float64(extraSize), float64(child.weight)))
|
||||
boxSize = unitSize * child.Weight
|
||||
boxExtraSize := int(math.Min(float64(extraSize), float64(child.Weight)))
|
||||
boxSize += boxExtraSize
|
||||
extraSize -= boxExtraSize
|
||||
}
|
||||
|
||||
var resultForChild map[string]dimensions
|
||||
var resultForChild map[string]Dimensions
|
||||
if direction == COLUMN {
|
||||
resultForChild = gui.arrangeViews(child, x0+offset, y0, boxSize, height)
|
||||
resultForChild = ArrangeViews(child, x0+offset, y0, boxSize, height)
|
||||
} else {
|
||||
resultForChild = gui.arrangeViews(child, x0, y0+offset, width, boxSize)
|
||||
resultForChild = ArrangeViews(child, x0, y0+offset, width, boxSize)
|
||||
}
|
||||
|
||||
result = gui.mergeDimensionMaps(result, resultForChild)
|
||||
result = mergeDimensionMaps(result, resultForChild)
|
||||
offset += boxSize
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) mergeDimensionMaps(a map[string]dimensions, b map[string]dimensions) map[string]dimensions {
|
||||
result := map[string]dimensions{}
|
||||
for _, dimensionMap := range []map[string]dimensions{a, b} {
|
||||
func mergeDimensionMaps(a map[string]Dimensions, b map[string]Dimensions) map[string]Dimensions {
|
||||
result := map[string]Dimensions{}
|
||||
for _, dimensionMap := range []map[string]Dimensions{a, b} {
|
||||
for k, v := range dimensionMap {
|
||||
result[k] = v
|
||||
}
|
@ -123,7 +123,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
prevMainView, err := gui.g.View("main")
|
||||
if err == nil {
|
||||
_, prevMainHeight := prevMainView.Size()
|
||||
newMainHeight := viewDimensions["main"].y1 - viewDimensions["main"].y0 - 1
|
||||
newMainHeight := viewDimensions["main"].Y1 - viewDimensions["main"].Y0 - 1
|
||||
heightDiff := newMainHeight - prevMainHeight
|
||||
if heightDiff > 0 {
|
||||
if manager, ok := gui.viewBufferManagerMap["main"]; ok {
|
||||
@ -143,10 +143,10 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
}
|
||||
return g.SetView(
|
||||
viewName,
|
||||
dimensionsObj.x0-frameOffset,
|
||||
dimensionsObj.y0-frameOffset,
|
||||
dimensionsObj.x1+frameOffset,
|
||||
dimensionsObj.y1+frameOffset,
|
||||
dimensionsObj.X0-frameOffset,
|
||||
dimensionsObj.Y0-frameOffset,
|
||||
dimensionsObj.X1+frameOffset,
|
||||
dimensionsObj.Y1+frameOffset,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user