From 56b89c607969010c0dd956ec48d7ace378f97373 Mon Sep 17 00:00:00 2001 From: "Luke I. Wilson" Date: Wed, 7 Apr 2021 13:56:32 -0500 Subject: [PATCH] PanelContainer: Implement cycling selection --- main.go | 8 ++++++-- ui/panel.go | 35 +++++++++++++++++++++++++---------- ui/panelcontainer.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index f5f855c..09c2701 100644 --- a/main.go +++ b/main.go @@ -295,8 +295,12 @@ func main() { panelMenu := ui.NewMenu("Panel", 0, &theme) - panelMenu.AddItems([]ui.Item{&ui.ItemEntry{Name: "Focus Up", QuickChar: -1, Shortcut: "Alt+Up", Callback: func() { - + panelMenu.AddItems([]ui.Item{&ui.ItemEntry{Name: "Focus Next", Shortcut: "Alt+.", Callback: func() { + panelContainer.SelectNext() + }}, &ui.ItemEntry{Name: "Focus Prev", Shortcut: "Alt+,", Callback: func() { + panelContainer.SelectPrev() + }}, &ui.ItemEntry{Name: "Focus Up", QuickChar: -1, Shortcut: "Alt+Up", Callback: func() { + }}, &ui.ItemEntry{Name: "Focus Down", QuickChar: -1, Shortcut: "Alt+Down", Callback: func() { }}, &ui.ItemEntry{Name: "Focus Left", QuickChar: -1, Shortcut: "Alt+Left", Callback: func() { diff --git a/ui/panel.go b/ui/panel.go index 00a139e..d056a30 100755 --- a/ui/panel.go +++ b/ui/panel.go @@ -69,27 +69,42 @@ func (p *Panel) UpdateSplits() { } // Same as EachLeaf, but returns true if any call to `f` returned true. -func (p *Panel) eachLeaf(f func(*Component) bool) bool { +func (p *Panel) eachLeaf(rightMost bool, f func(*Panel) bool) bool { switch p.Kind { + case PanelKindEmpty: + fallthrough case PanelKindSingle: - return f(&p.Left) + return f(p) + case PanelKindSplitVert: fallthrough case PanelKindSplitHor: - if p.Left.(*Panel).eachLeaf(f) { - return true + if rightMost { + if p.Right.(*Panel).eachLeaf(rightMost, f) { + return true + } + return p.Left.(*Panel).eachLeaf(rightMost, f) + } else { + if p.Left.(*Panel).eachLeaf(rightMost, f) { + return true + } + return p.Right.(*Panel).eachLeaf(rightMost, f) } - return p.Right.(*Panel).eachLeaf(f) + default: return false } } -// EachLeaf visits the entire tree in left-most order, and calls function `f` -// at each individual Component (never for Panels). If the function `f` returns -// true, then visiting stops. -func (p *Panel) EachLeaf(f func(*Component) bool) { - p.eachLeaf(f) +// EachLeaf visits the entire tree, and calls function `f` at each leaf Panel. +// If the function `f` returns true, then visiting stops. if `rtl` is true, +// the tree is traversed in right-most order. The default is to traverse +// in left-most order. +// +// The caller of this function can safely assert that Panel's Kind is always +// either `PanelKindSingle` or `PanelKindEmpty`. +func (p *Panel) EachLeaf(rightMost bool, f func(*Panel) bool) { + p.eachLeaf(rightMost, f) } // IsLeaf returns whether the Panel is a leaf or not. A leaf is a panel with diff --git a/ui/panelcontainer.go b/ui/panelcontainer.go index e433a1c..e0a1cd4 100755 --- a/ui/panelcontainer.go +++ b/ui/panelcontainer.go @@ -266,6 +266,36 @@ func (c *PanelContainer) UnfloatSelected(kind SplitKind) bool { return c.SetFloatingFocused(true) } +func (c *PanelContainer) selectNext(rightMost bool) { + var nextIsIt bool + c.root.EachLeaf(rightMost, func(p *Panel) bool { + if nextIsIt { + c.selected = &p + nextIsIt = false + return true + } else if p == *c.selected { + nextIsIt = true + } + return false + }) + + // This boolean must be false if we found the next leaf. + // Therefore, if it is true, c.selected was the last leaf + // of the tree. We need to wrap around to the first leaf. + if nextIsIt { + // This gets the first leaf in left-most or right-most order + c.root.EachLeaf(rightMost, func(p *Panel) bool { c.selected = &p; return true }) + } +} + +func (c *PanelContainer) SelectNext() { + c.selectNext(false) +} + +func (c *PanelContainer) SelectPrev() { + c.selectNext(true) +} + func (c *PanelContainer) Draw(s tcell.Screen) { c.root.Draw(s) for i := len(c.floating)-1; i >= 0; i-- {