diff --git a/lib/pager_stack.go b/lib/pager_stack.go index eb605f5..f8d4381 100644 --- a/lib/pager_stack.go +++ b/lib/pager_stack.go @@ -1,5 +1,10 @@ package rat +import ( + "math" +) + +// PagerStack is a stack of Pagers type PagerStack interface { Widget Show(int) @@ -17,9 +22,11 @@ type pagerStack struct { lastEl *pagerStackElement size int numToShow int + widthToBreak int eventHandlers HandlerRegistry box Box validLayout bool + splitFunction func(n, totalSize int) []section } type pagerStackElement struct { @@ -28,11 +35,14 @@ type pagerStackElement struct { creatingKeys string } +// NewPagerStack creates a new instance of PagerStack func NewPagerStack() PagerStack { - ps := &pagerStack{} - - ps.numToShow = 3 - ps.eventHandlers = NewHandlerRegistry() + ps := &pagerStack{ + numToShow: 3, + widthToBreak: 100, + eventHandlers: NewHandlerRegistry(), + splitFunction: goldenSizes, + } return ps } @@ -109,15 +119,14 @@ func (ps *pagerStack) visiblePagers() []Pager { } func (ps *pagerStack) splitHorizontal() bool { - return ps.box.Width() > 180 + return ps.box.Width() > ps.widthToBreak } func (ps *pagerStack) layout() { pagers := ps.visiblePagers() n := len(pagers) - offset := 0 - var totalSize, size int + var totalSize int if ps.splitHorizontal() { totalSize = ps.box.Width() @@ -125,19 +134,20 @@ func (ps *pagerStack) layout() { totalSize = ps.box.Height() } - remaining := totalSize + sections := ps.splitFunction(n, totalSize) for i, p := range pagers { - size = (remaining - (n - i - 1)) / (n - i) + bs := sections[i] if ps.splitHorizontal() { - p.SetBox(NewBox(offset, 0, size, ps.box.Height())) + p.SetBox(NewBox( + bs.offset, 0, + bs.size, ps.box.Height())) } else { - p.SetBox(NewBox(0, offset, ps.box.Width(), size)) + p.SetBox(NewBox( + 0, bs.offset, + ps.box.Width(), bs.size)) } - - offset = offset + size + 1 - remaining = totalSize - offset } } @@ -197,9 +207,8 @@ func (ps *pagerStack) parentPager() Pager { if ps.size > 1 { return ps.lastEl.previous.pager - } else { - return ps.lastEl.pager } + return ps.lastEl.pager } func (ps *pagerStack) ParentCursorUp() { @@ -215,3 +224,42 @@ func (ps *pagerStack) ParentCursorDown() { ps.parentPager().HandleEvent(KeySequenceFromString(ps.lastEl.creatingKeys)) } } + +type section struct { + offset int + size int +} + +// evenSizes is a function that splits the panes in even sizes +// this was the default behaviour of rat and +// maybe desirable as a setting +func evenSizes(n, totalSize int) []section { + boxes := make([]section, n) + remaining := totalSize + var size, offset int + + for i := 0; i < n; i++ { + size = (remaining - (n - i - 1)) / (n - i) + boxes[i] = section{offset, size} + offset = offset + size + 1 + remaining = totalSize - offset + } + return boxes +} + +func golden(n, totalSize, offset int) []section { + if n <= 1 { + return []section{section{offset, totalSize}} + } + // Split total size + big := int(math.Floor(float64(totalSize) / math.Phi)) + small := totalSize - big - 1 + + return append(golden(n-1, small, offset), section{offset + small + 1, big}) +} + +// goldenSizes splits panes using the golden ratio +// of Phi making the active pane bigger +func goldenSizes(n, totalSize int) []section { + return golden(n, totalSize, 0) +} diff --git a/lib/pager_stack_test.go b/lib/pager_stack_test.go new file mode 100644 index 0000000..a1e3d32 --- /dev/null +++ b/lib/pager_stack_test.go @@ -0,0 +1,44 @@ +package rat + +import ( + "reflect" + "testing" +) + +func TestEvenSizes(t *testing.T) { + tests := []struct { + n int + totalSize int + expected []section + }{ + {1, 120, []section{section{0, 120}}}, + {2, 120, []section{section{0, 59}, section{60, 60}}}, + {3, 120, []section{section{0, 39}, section{40, 39}, section{80, 40}}}, + } + + for _, tt := range tests { + sections := evenSizes(tt.n, tt.totalSize) + if !reflect.DeepEqual(sections, tt.expected) { + t.Errorf("evenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, sections) + } + } +} + +func TestGoldenSizes(t *testing.T) { + tests := []struct { + n int + totalSize int + expected []section + }{ + {1, 120, []section{section{0, 120}}}, + {2, 120, []section{section{0, 45}, section{46, 74}}}, + {3, 120, []section{section{0, 17}, section{18, 27}, section{46, 74}}}, + } + + for _, tt := range tests { + sections := goldenSizes(tt.n, tt.totalSize) + if !reflect.DeepEqual(sections, tt.expected) { + t.Errorf("goldenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, sections) + } + } +}