1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-12 11:15:00 +02:00
lazygit/pkg/gui/arrangement.go

330 lines
7.9 KiB
Go
Raw Normal View History

2020-05-17 13:32:17 +02:00
package gui
import (
"github.com/jesseduffield/lazygit/pkg/gui/boxlayout"
"github.com/jesseduffield/lazygit/pkg/utils"
)
2021-04-11 13:52:04 +02:00
const INFO_SECTION_PADDING = " "
func (gui *Gui) mainSectionChildren() []*boxlayout.Box {
2020-08-21 11:53:45 +02:00
currentWindow := gui.currentWindow()
2020-05-18 14:00:07 +02:00
// 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-21 11:53:45 +02:00
if !gui.isMainPanelSplit() || (gui.State.ScreenMode == SCREEN_FULL && currentWindow == "main") {
return []*boxlayout.Box{
2020-05-18 14:00:07 +02:00
{
2020-08-21 11:53:45 +02:00
Window: "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
}
return []*boxlayout.Box{
2020-05-17 13:32:17 +02:00
{
2020-08-21 11:53:45 +02:00
Window: main,
Weight: 1,
2020-05-17 13:32:17 +02:00
},
2020-05-18 14:00:07 +02:00
{
2020-08-21 11:53:45 +02:00
Window: 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) {
2020-08-21 11:53:45 +02:00
currentWindow := gui.currentWindow()
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
2020-10-03 06:54:55 +02:00
sidePanelWidthRatio := gui.Config.GetUserConfig().Gui.SidePanelWidth
2020-05-17 13:44:59 +02:00
// we could make this better by creating ratios like 2:3 rather than always 1:something
mainSectionWeight := int(1/sidePanelWidthRatio) - 1
sideSectionWeight := 1
if gui.splitMainPanelSideBySide() {
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-08-21 11:53:45 +02:00
if currentWindow == "main" {
2020-05-17 13:44:59 +02:00
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
}
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
if gui.State.Searching.isSearching {
return []*boxlayout.Box{
{
2020-08-21 11:53:45 +02:00
Window: "searchPrefix",
Size: len(SEARCH_PREFIX),
},
{
2020-08-21 11:53:45 +02:00
Window: "search",
Weight: 1,
},
}
}
result := []*boxlayout.Box{}
if len(appStatus) > 0 {
result = append(result,
&boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: "appStatus",
Size: len(appStatus) + len(INFO_SECTION_PADDING),
},
)
}
result = append(result,
[]*boxlayout.Box{
{
2020-08-21 11:53:45 +02:00
Window: "options",
Weight: 1,
},
{
2020-08-21 11:53:45 +02:00
Window: "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)),
},
}...,
)
return result
}
func (gui *Gui) splitMainPanelSideBySide() bool {
if !gui.isMainPanelSplit() {
return false
}
mainPanelSplitMode := gui.Config.GetUserConfig().Gui.MainPanelSplitMode
width, height := gui.g.Size()
switch mainPanelSplitMode {
case "vertical":
return false
case "horizontal":
return true
default:
if width < 200 && height > 30 { // 2 80 character width panels + 40 width for side panel
return false
} else {
return true
}
}
}
2021-04-19 10:04:00 +02:00
func (gui *Gui) getExtrasWindowSize(screenHeight int) int {
if !gui.ShowExtrasWindow {
return 0
}
var baseSize int
if gui.currentStaticContext().GetKey() == COMMAND_LOG_CONTEXT_KEY {
baseSize = 1000 // my way of saying 'fill the available space'
} else if screenHeight < 40 {
baseSize = 1
} else {
baseSize = gui.Config.GetUserConfig().Gui.CommandLogSize
}
frameSize := 2
return baseSize + frameSize
}
2020-08-21 11:53:45 +02:00
func (gui *Gui) getWindowDimensions(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()
sidePanelsDirection := boxlayout.COLUMN
portraitMode := width <= 84 && height > 45
2020-05-17 13:44:59 +02:00
if portraitMode {
sidePanelsDirection = boxlayout.ROW
2020-05-17 13:44:59 +02:00
}
mainPanelsDirection := boxlayout.ROW
if gui.splitMainPanelSideBySide() {
mainPanelsDirection = boxlayout.COLUMN
}
2021-04-19 10:04:00 +02:00
extrasWindowSize := gui.getExtrasWindowSize(height)
2021-04-10 05:08:51 +02:00
root := &boxlayout.Box{
Direction: boxlayout.ROW,
Children: []*boxlayout.Box{
2020-05-17 13:44:59 +02:00
{
Direction: sidePanelsDirection,
Weight: 1,
Children: []*boxlayout.Box{
2020-05-17 13:44:59 +02:00
{
Direction: boxlayout.ROW,
Weight: sideSectionWeight,
ConditionalChildren: gui.sidePanelChildren,
2020-05-17 13:44:59 +02:00
},
{
2021-04-10 05:08:51 +02:00
Direction: boxlayout.ROW,
Weight: mainSectionWeight,
2021-04-10 05:08:51 +02:00
Children: []*boxlayout.Box{
{
Direction: mainPanelsDirection,
Children: gui.mainSectionChildren(),
Weight: 1,
},
{
2021-04-11 03:43:07 +02:00
Window: "extras",
Size: extrasWindowSize,
2021-04-10 05:08:51 +02:00
},
},
2020-05-17 13:44:59 +02:00
},
},
},
{
Direction: boxlayout.COLUMN,
Size: 1,
Children: gui.infoSectionChildren(informationStr, appStatus),
2020-05-17 13:44:59 +02:00
},
},
}
2020-08-21 11:53:45 +02:00
return boxlayout.ArrangeWindows(root, 0, 0, width, height)
2020-05-17 13:44:59 +02:00
}
2020-08-23 07:01:02 +02:00
// The stash window by default only contains one line so that it's not hogging
// too much space, but if you access it it should take up some space. This is
// the default behaviour when accordian mode is NOT in effect. If it is in effect
// then when it's accessed it will have weight 2, not 1.
func (gui *Gui) getDefaultStashWindowBox() *boxlayout.Box {
gui.State.ContextManager.RLock()
defer gui.State.ContextManager.RUnlock()
2020-08-23 07:01:02 +02:00
box := &boxlayout.Box{Window: "stash"}
stashWindowAccessed := false
for _, context := range gui.State.ContextManager.ContextStack {
2020-08-23 07:01:02 +02:00
if context.GetWindowName() == "stash" {
stashWindowAccessed = true
}
}
// if the stash window is anywhere in our stack we should enlargen it
if stashWindowAccessed {
box.Weight = 1
} else {
box.Size = 3
}
return box
}
func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box {
2020-08-21 11:53:45 +02:00
currentWindow := gui.currentSideWindowName()
2020-05-17 13:32:17 +02:00
if gui.State.ScreenMode == SCREEN_FULL || gui.State.ScreenMode == SCREEN_HALF {
2020-08-21 11:53:45 +02:00
fullHeightBox := func(window string) *boxlayout.Box {
if window == currentWindow {
return &boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: window,
Weight: 1,
2020-05-17 13:32:17 +02:00
}
} else {
return &boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: window,
Size: 0,
2020-05-17 13:32:17 +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-10-03 06:54:55 +02:00
accordianMode := gui.Config.GetUserConfig().Gui.ExpandFocusedSidePanel
accordianBox := func(defaultBox *boxlayout.Box) *boxlayout.Box {
2020-08-21 11:53:45 +02:00
if accordianMode && defaultBox.Window == currentWindow {
return &boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: defaultBox.Window,
Weight: 2,
}
}
return defaultBox
}
return []*boxlayout.Box{
2020-05-17 13:32:17 +02:00
{
2020-08-21 11:53:45 +02:00
Window: "status",
Size: 3,
2020-05-17 13:32:17 +02:00
},
2020-08-21 11:53:45 +02:00
accordianBox(&boxlayout.Box{Window: "files", Weight: 1}),
accordianBox(&boxlayout.Box{Window: "branches", Weight: 1}),
accordianBox(&boxlayout.Box{Window: "commits", Weight: 1}),
2020-08-23 07:01:02 +02:00
accordianBox(gui.getDefaultStashWindowBox()),
2020-05-17 13:32:17 +02:00
}
} else {
squashedHeight := 1
if height >= 21 {
squashedHeight = 3
}
2020-08-21 11:53:45 +02:00
squashedSidePanelBox := func(window string) *boxlayout.Box {
if window == currentWindow {
return &boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: window,
Weight: 1,
2020-05-17 13:32:17 +02:00
}
} else {
return &boxlayout.Box{
2020-08-21 11:53:45 +02:00
Window: window,
Size: squashedHeight,
2020-05-17 13:32:17 +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-08-21 11:53:45 +02:00
func (gui *Gui) currentSideWindowName() string {
// there is always one and only one cyclable context in the context stack. We'll look from top to bottom
gui.State.ContextManager.RLock()
defer gui.State.ContextManager.RUnlock()
for idx := range gui.State.ContextManager.ContextStack {
reversedIdx := len(gui.State.ContextManager.ContextStack) - 1 - idx
context := gui.State.ContextManager.ContextStack[reversedIdx]
2020-08-16 05:58:29 +02:00
if context.GetKind() == SIDE_CONTEXT {
2020-08-21 11:53:45 +02:00
return context.GetWindowName()
2020-08-16 05:58:29 +02:00
}
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
}