2020-05-17 13:32:17 +02:00
|
|
|
package gui
|
|
|
|
|
2020-05-18 14:21:36 +02:00
|
|
|
import (
|
2020-08-15 00:28:02 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/boxlayout"
|
2020-05-18 14:21:36 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
|
|
)
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
func (gui *Gui) mainSectionChildren() []*boxlayout.Box {
|
2020-05-18 14:00:07 +02:00
|
|
|
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
|
2020-08-18 00:26:40 +02:00
|
|
|
if !gui.isMainPanelSplit() || (gui.State.ScreenMode == SCREEN_FULL && currentViewName == "main") {
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-18 14:00:07 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "main",
|
|
|
|
Weight: 1,
|
2020-05-18 14:00:07 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2020-05-17 13:32:17 +02:00
|
|
|
|
|
|
|
main := "main"
|
|
|
|
secondary := "secondary"
|
2020-05-18 14:00:07 +02:00
|
|
|
if gui.secondaryViewFocused() {
|
|
|
|
// when you think you've focused the secondary view, we've actually just swapped them around in the layout
|
2020-05-17 13:32:17 +02:00
|
|
|
main, secondary = secondary, main
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-17 13:32:17 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: main,
|
|
|
|
Weight: 1,
|
2020-05-17 13:32:17 +02:00
|
|
|
},
|
2020-05-18 14:00:07 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: secondary,
|
|
|
|
Weight: 1,
|
2020-05-18 14:00:07 +02:00
|
|
|
},
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
2020-05-18 14:00:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (gui *Gui) getMidSectionWeights() (int, int) {
|
|
|
|
currentViewName := gui.currentViewName()
|
2020-05-17 13:32:17 +02:00
|
|
|
|
2020-05-17 13:44:59 +02:00
|
|
|
// we originally specified this as a ratio i.e. .20 would correspond to a weight of 1 against 4
|
|
|
|
sidePanelWidthRatio := gui.Config.GetUserConfig().GetFloat64("gui.sidePanelWidth")
|
|
|
|
// we could make this better by creating ratios like 2:3 rather than always 1:something
|
|
|
|
mainSectionWeight := int(1/sidePanelWidthRatio) - 1
|
|
|
|
sideSectionWeight := 1
|
|
|
|
|
2020-08-18 00:26:40 +02:00
|
|
|
if gui.isMainPanelSplit() {
|
2020-05-17 13:44:59 +02:00
|
|
|
mainSectionWeight = 5 // need to shrink side panel to make way for main panels if side-by-side
|
|
|
|
}
|
2020-05-18 14:00:07 +02:00
|
|
|
|
2020-05-17 13:44:59 +02:00
|
|
|
if currentViewName == "main" {
|
|
|
|
if gui.State.ScreenMode == SCREEN_HALF || gui.State.ScreenMode == SCREEN_FULL {
|
|
|
|
sideSectionWeight = 0
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if gui.State.ScreenMode == SCREEN_HALF {
|
|
|
|
mainSectionWeight = 1
|
|
|
|
} else if gui.State.ScreenMode == SCREEN_FULL {
|
|
|
|
mainSectionWeight = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-18 14:00:07 +02:00
|
|
|
return sideSectionWeight, mainSectionWeight
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
2020-05-18 14:21:36 +02:00
|
|
|
if gui.State.Searching.isSearching {
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-18 14:21:36 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "searchPrefix",
|
|
|
|
Size: len(SEARCH_PREFIX),
|
2020-05-18 14:21:36 +02:00
|
|
|
},
|
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "search",
|
|
|
|
Weight: 1,
|
2020-05-18 14:21:36 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
result := []*boxlayout.Box{}
|
2020-05-18 14:21:36 +02:00
|
|
|
|
|
|
|
if len(appStatus) > 0 {
|
|
|
|
result = append(result,
|
2020-08-15 00:28:02 +02:00
|
|
|
&boxlayout.Box{
|
|
|
|
ViewName: "appStatus",
|
|
|
|
Size: len(appStatus) + len(INFO_SECTION_PADDING),
|
2020-05-18 14:21:36 +02:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
result = append(result,
|
2020-08-15 00:28:02 +02:00
|
|
|
[]*boxlayout.Box{
|
2020-05-18 14:21:36 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "options",
|
|
|
|
Weight: 1,
|
2020-05-18 14:21:36 +02:00
|
|
|
},
|
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "information",
|
2020-05-18 14:21:36 +02:00
|
|
|
// unlike appStatus, informationStr has various colors so we need to decolorise before taking the length
|
2020-08-15 00:28:02 +02:00
|
|
|
Size: len(INFO_SECTION_PADDING) + len(utils.Decolorise(informationStr)),
|
2020-05-18 14:21:36 +02:00
|
|
|
},
|
|
|
|
}...,
|
|
|
|
)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
func (gui *Gui) getViewDimensions(informationStr string, appStatus string) map[string]boxlayout.Dimensions {
|
2020-05-18 14:00:07 +02:00
|
|
|
width, height := gui.g.Size()
|
|
|
|
|
|
|
|
sideSectionWeight, mainSectionWeight := gui.getMidSectionWeights()
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
sidePanelsDirection := boxlayout.COLUMN
|
2020-05-18 14:40:29 +02:00
|
|
|
portraitMode := width <= 84 && height > 45
|
2020-05-17 13:44:59 +02:00
|
|
|
if portraitMode {
|
2020-08-15 00:28:02 +02:00
|
|
|
sidePanelsDirection = boxlayout.ROW
|
2020-05-17 13:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
root := &boxlayout.Box{
|
|
|
|
Direction: boxlayout.ROW,
|
|
|
|
Children: []*boxlayout.Box{
|
2020-05-17 13:44:59 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
Direction: sidePanelsDirection,
|
|
|
|
Weight: 1,
|
|
|
|
Children: []*boxlayout.Box{
|
2020-05-17 13:44:59 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
Direction: boxlayout.ROW,
|
|
|
|
Weight: sideSectionWeight,
|
|
|
|
ConditionalChildren: gui.sidePanelChildren,
|
2020-05-17 13:44:59 +02:00
|
|
|
},
|
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ConditionalDirection: func(width int, height int) int {
|
2020-08-12 14:18:03 +02:00
|
|
|
mainPanelSplitMode := gui.Config.GetUserConfig().GetString("gui.mainPanelSplitMode")
|
|
|
|
|
|
|
|
switch mainPanelSplitMode {
|
|
|
|
case "vertical":
|
2020-08-15 00:28:02 +02:00
|
|
|
return boxlayout.ROW
|
2020-08-12 14:18:03 +02:00
|
|
|
case "horizontal":
|
2020-08-15 00:28:02 +02:00
|
|
|
return boxlayout.COLUMN
|
2020-08-12 14:18:03 +02:00
|
|
|
default:
|
|
|
|
if width < 160 && height > 30 { // 2 80 character width panels
|
2020-08-15 00:28:02 +02:00
|
|
|
return boxlayout.ROW
|
2020-08-12 14:18:03 +02:00
|
|
|
} else {
|
2020-08-15 00:28:02 +02:00
|
|
|
return boxlayout.COLUMN
|
2020-08-12 14:18:03 +02:00
|
|
|
}
|
2020-05-17 13:44:59 +02:00
|
|
|
}
|
|
|
|
},
|
2020-08-15 00:28:02 +02:00
|
|
|
Direction: boxlayout.COLUMN,
|
|
|
|
Weight: mainSectionWeight,
|
|
|
|
Children: gui.mainSectionChildren(),
|
2020-05-17 13:44:59 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
Direction: boxlayout.COLUMN,
|
|
|
|
Size: 1,
|
|
|
|
Children: gui.infoSectionChildren(informationStr, appStatus),
|
2020-05-17 13:44:59 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
return boxlayout.ArrangeViews(root, 0, 0, width, height)
|
2020-05-17 13:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box {
|
2020-05-17 13:32:17 +02:00
|
|
|
currentCyclableViewName := gui.currentCyclableViewName()
|
|
|
|
|
|
|
|
if gui.State.ScreenMode == SCREEN_FULL || gui.State.ScreenMode == SCREEN_HALF {
|
2020-08-15 00:28:02 +02:00
|
|
|
fullHeightBox := func(viewName string) *boxlayout.Box {
|
2020-05-17 13:32:17 +02:00
|
|
|
if viewName == currentCyclableViewName {
|
2020-08-15 00:28:02 +02:00
|
|
|
return &boxlayout.Box{
|
|
|
|
ViewName: viewName,
|
|
|
|
Weight: 1,
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-08-15 00:28:02 +02:00
|
|
|
return &boxlayout.Box{
|
|
|
|
ViewName: viewName,
|
|
|
|
Size: 0,
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-17 13:32:17 +02:00
|
|
|
fullHeightBox("status"),
|
|
|
|
fullHeightBox("files"),
|
|
|
|
fullHeightBox("branches"),
|
|
|
|
fullHeightBox("commits"),
|
|
|
|
fullHeightBox("stash"),
|
|
|
|
}
|
2020-05-17 13:44:59 +02:00
|
|
|
} else if height >= 28 {
|
2020-08-12 14:06:37 +02:00
|
|
|
accordianMode := gui.Config.GetUserConfig().GetBool("gui.expandFocusedSidePanel")
|
2020-08-15 00:28:02 +02:00
|
|
|
accordianBox := func(defaultBox *boxlayout.Box) *boxlayout.Box {
|
|
|
|
if accordianMode && defaultBox.ViewName == currentCyclableViewName {
|
|
|
|
return &boxlayout.Box{
|
|
|
|
ViewName: defaultBox.ViewName,
|
|
|
|
Weight: 2,
|
2020-08-12 14:06:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultBox
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-17 13:32:17 +02:00
|
|
|
{
|
2020-08-15 00:28:02 +02:00
|
|
|
ViewName: "status",
|
|
|
|
Size: 3,
|
2020-05-17 13:32:17 +02:00
|
|
|
},
|
2020-08-15 00:28:02 +02:00
|
|
|
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}),
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
squashedHeight := 1
|
|
|
|
if height >= 21 {
|
|
|
|
squashedHeight = 3
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
squashedSidePanelBox := func(viewName string) *boxlayout.Box {
|
2020-05-17 13:32:17 +02:00
|
|
|
if viewName == currentCyclableViewName {
|
2020-08-15 00:28:02 +02:00
|
|
|
return &boxlayout.Box{
|
|
|
|
ViewName: viewName,
|
|
|
|
Weight: 1,
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-08-15 00:28:02 +02:00
|
|
|
return &boxlayout.Box{
|
|
|
|
ViewName: viewName,
|
|
|
|
Size: squashedHeight,
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-15 00:28:02 +02:00
|
|
|
return []*boxlayout.Box{
|
2020-05-17 13:32:17 +02:00
|
|
|
squashedSidePanelBox("status"),
|
|
|
|
squashedSidePanelBox("files"),
|
|
|
|
squashedSidePanelBox("branches"),
|
|
|
|
squashedSidePanelBox("commits"),
|
|
|
|
squashedSidePanelBox("stash"),
|
|
|
|
}
|
|
|
|
}
|
2020-05-17 13:44:59 +02:00
|
|
|
}
|
2020-05-17 13:32:17 +02:00
|
|
|
|
2020-05-17 13:44:59 +02:00
|
|
|
func (gui *Gui) currentCyclableViewName() string {
|
2020-08-16 05:58:29 +02:00
|
|
|
// there is always a cyclable context in the context stack. We'll look from top to bottom
|
|
|
|
for idx := range gui.State.ContextStack {
|
|
|
|
reversedIdx := len(gui.State.ContextStack) - 1 - idx
|
|
|
|
context := gui.State.ContextStack[reversedIdx]
|
|
|
|
|
|
|
|
if context.GetKind() == SIDE_CONTEXT {
|
|
|
|
viewName := context.GetViewName()
|
|
|
|
|
|
|
|
// unfortunate result of the fact that these are separate views, have to map explicitly
|
|
|
|
if viewName == "commitFiles" {
|
|
|
|
return "commits"
|
2020-05-17 13:44:59 +02:00
|
|
|
}
|
2020-05-17 13:32:17 +02:00
|
|
|
|
2020-08-16 05:58:29 +02:00
|
|
|
return viewName
|
|
|
|
}
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 05:58:29 +02:00
|
|
|
return "files" // default
|
2020-05-17 13:32:17 +02:00
|
|
|
}
|