From 45d7f10e19b1ad354dd9cdcef050c1cd3127e8b5 Mon Sep 17 00:00:00 2001 From: Santiago Date: Mon, 11 Mar 2019 20:44:52 +0100 Subject: [PATCH 1/2] Use golden ratio to divide panels --- lib/pager_stack.go | 78 ++++++++++++++++++++++++++++++++--------- lib/pager_stack_test.go | 44 +++++++++++++++++++++++ 2 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 lib/pager_stack_test.go diff --git a/lib/pager_stack.go b/lib/pager_stack.go index eb605f5..1bcd6bc 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) @@ -20,6 +25,7 @@ type pagerStack struct { eventHandlers HandlerRegistry box Box validLayout bool + splitFunction func(n, totalSize int) []boxSize } type pagerStackElement struct { @@ -28,11 +34,13 @@ 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, + eventHandlers: NewHandlerRegistry(), + splitFunction: goldenSizes, + } return ps } @@ -109,15 +117,14 @@ func (ps *pagerStack) visiblePagers() []Pager { } func (ps *pagerStack) splitHorizontal() bool { - return ps.box.Width() > 180 + return ps.box.Width() > 100 } 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 +132,20 @@ func (ps *pagerStack) layout() { totalSize = ps.box.Height() } - remaining := totalSize + boxSizes := ps.splitFunction(n, totalSize) for i, p := range pagers { - size = (remaining - (n - i - 1)) / (n - i) + bs := boxSizes[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 +205,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 +222,42 @@ func (ps *pagerStack) ParentCursorDown() { ps.parentPager().HandleEvent(KeySequenceFromString(ps.lastEl.creatingKeys)) } } + +type boxSize 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) []boxSize { + boxes := make([]boxSize, n) + remaining := totalSize + var size, offset int + + for i := 0; i < n; i++ { + size = (remaining - (n - i - 1)) / (n - i) + boxes[i] = boxSize{offset, size} + offset = offset + size + 1 + remaining = totalSize - offset + } + return boxes +} + +func golden(n, totalSize, offset int) []boxSize { + if n <= 1 { + return []boxSize{boxSize{offset, totalSize}} + } + // Split total size + big := int(math.Floor(float64(totalSize) / math.Phi)) + small := totalSize - big - 1 + + return append(golden(n-1, small, offset), boxSize{offset + small + 1, big}) +} + +// goldenSizes splits panes using the golden ratio +// of Phi making the active pane bigger +func goldenSizes(n, totalSize int) []boxSize { + 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..93f7234 --- /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 []boxSize + }{ + {1, 120, []boxSize{boxSize{0, 120}}}, + {2, 120, []boxSize{boxSize{0, 59}, boxSize{60, 60}}}, + {3, 120, []boxSize{boxSize{0, 39}, boxSize{40, 39}, boxSize{80, 40}}}, + } + + for _, tt := range tests { + boxes := evenSizes(tt.n, tt.totalSize) + if !reflect.DeepEqual(boxes, tt.expected) { + t.Errorf("evenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, boxes) + } + } +} + +func TestGoldenSizes(t *testing.T) { + tests := []struct { + n int + totalSize int + expected []boxSize + }{ + {1, 120, []boxSize{boxSize{0, 120}}}, + {2, 120, []boxSize{boxSize{0, 45}, boxSize{46, 74}}}, + {3, 120, []boxSize{boxSize{0, 17}, boxSize{18, 27}, boxSize{46, 74}}}, + } + + for _, tt := range tests { + boxes := goldenSizes(tt.n, tt.totalSize) + if !reflect.DeepEqual(boxes, tt.expected) { + t.Errorf("goldenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, boxes) + } + } +} From 9f962a8ce43235a36cf65e3dbb43dc48a8cc83e8 Mon Sep 17 00:00:00 2001 From: Santiago Date: Mon, 11 Mar 2019 20:55:56 +0100 Subject: [PATCH 2/2] Renamed boxSize to section --- lib/pager_stack.go | 26 ++++++++++++++------------ lib/pager_stack_test.go | 28 ++++++++++++++-------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/pager_stack.go b/lib/pager_stack.go index 1bcd6bc..f8d4381 100644 --- a/lib/pager_stack.go +++ b/lib/pager_stack.go @@ -22,10 +22,11 @@ type pagerStack struct { lastEl *pagerStackElement size int numToShow int + widthToBreak int eventHandlers HandlerRegistry box Box validLayout bool - splitFunction func(n, totalSize int) []boxSize + splitFunction func(n, totalSize int) []section } type pagerStackElement struct { @@ -38,6 +39,7 @@ type pagerStackElement struct { func NewPagerStack() PagerStack { ps := &pagerStack{ numToShow: 3, + widthToBreak: 100, eventHandlers: NewHandlerRegistry(), splitFunction: goldenSizes, } @@ -117,7 +119,7 @@ func (ps *pagerStack) visiblePagers() []Pager { } func (ps *pagerStack) splitHorizontal() bool { - return ps.box.Width() > 100 + return ps.box.Width() > ps.widthToBreak } func (ps *pagerStack) layout() { @@ -132,10 +134,10 @@ func (ps *pagerStack) layout() { totalSize = ps.box.Height() } - boxSizes := ps.splitFunction(n, totalSize) + sections := ps.splitFunction(n, totalSize) for i, p := range pagers { - bs := boxSizes[i] + bs := sections[i] if ps.splitHorizontal() { p.SetBox(NewBox( @@ -223,7 +225,7 @@ func (ps *pagerStack) ParentCursorDown() { } } -type boxSize struct { +type section struct { offset int size int } @@ -231,33 +233,33 @@ type boxSize struct { // 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) []boxSize { - boxes := make([]boxSize, n) +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] = boxSize{offset, size} + boxes[i] = section{offset, size} offset = offset + size + 1 remaining = totalSize - offset } return boxes } -func golden(n, totalSize, offset int) []boxSize { +func golden(n, totalSize, offset int) []section { if n <= 1 { - return []boxSize{boxSize{offset, totalSize}} + 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), boxSize{offset + small + 1, big}) + 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) []boxSize { +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 index 93f7234..a1e3d32 100644 --- a/lib/pager_stack_test.go +++ b/lib/pager_stack_test.go @@ -9,17 +9,17 @@ func TestEvenSizes(t *testing.T) { tests := []struct { n int totalSize int - expected []boxSize + expected []section }{ - {1, 120, []boxSize{boxSize{0, 120}}}, - {2, 120, []boxSize{boxSize{0, 59}, boxSize{60, 60}}}, - {3, 120, []boxSize{boxSize{0, 39}, boxSize{40, 39}, boxSize{80, 40}}}, + {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 { - boxes := evenSizes(tt.n, tt.totalSize) - if !reflect.DeepEqual(boxes, tt.expected) { - t.Errorf("evenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, boxes) + 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) } } } @@ -28,17 +28,17 @@ func TestGoldenSizes(t *testing.T) { tests := []struct { n int totalSize int - expected []boxSize + expected []section }{ - {1, 120, []boxSize{boxSize{0, 120}}}, - {2, 120, []boxSize{boxSize{0, 45}, boxSize{46, 74}}}, - {3, 120, []boxSize{boxSize{0, 17}, boxSize{18, 27}, boxSize{46, 74}}}, + {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 { - boxes := goldenSizes(tt.n, tt.totalSize) - if !reflect.DeepEqual(boxes, tt.expected) { - t.Errorf("goldenSizes(%d, %d): expected %v, got %v", tt.n, tt.totalSize, tt.expected, boxes) + 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) } } }