summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordwillist <dthornton@vmware.com>2021-01-17 02:18:11 -0500
committerdwillist <dthornton@vmware.com>2021-01-17 02:18:11 -0500
commit90cc80430ee6e215dfad48cf0718414835e1791f (patch)
tree6eb180a67b91c6c982fc491d1b204085564b3fc6
parentd2e5ac1e5ab9bca20acc5ac0b30336e5be4c3010 (diff)
add keybinding menu
- update displayed keybindings as focus changes - highlight toggleable keys Signed-off-by: dwillist <dthornton@vmware.com>
-rw-r--r--=11
-rw-r--r--runtime/ui/app.go48
-rw-r--r--runtime/ui/components/cnb_layer_details_view.go5
-rw-r--r--runtime/ui/components/dive_application.go56
-rw-r--r--runtime/ui/components/filetree_primative.go30
-rw-r--r--runtime/ui/components/filter_primative.go4
-rw-r--r--runtime/ui/components/image_details_view.go4
-rw-r--r--runtime/ui/components/key_config.go8
-rw-r--r--runtime/ui/components/keybinding_primitive.go89
-rw-r--r--runtime/ui/components/layer_details_view.go5
-rw-r--r--runtime/ui/components/layers_primative.go12
-rw-r--r--runtime/ui/components/visible_grid.go40
-rw-r--r--runtime/ui/components/wrapper_primative.go7
-rw-r--r--runtime/ui/format/format.go2
14 files changed, 287 insertions, 34 deletions
diff --git a/= b/=
new file mode 100644
index 0000000..cccc50b
--- /dev/null
+++ b/=
@@ -0,0 +1,11 @@
+package componenets
+
+import "github.com/rivo/tview"
+
+type Keybinded interface {
+ GetKeyBindings() []KeyBinding
+}
+
+type KeyMenuPrimitive struct {
+ *tview.TextView
+}
diff --git a/runtime/ui/app.go b/runtime/ui/app.go
index dfe8063..a7d013a 100644
--- a/runtime/ui/app.go
+++ b/runtime/ui/app.go
@@ -17,21 +17,22 @@ const debug = false
// type global
var (
- once sync.Once
- appSingleton *diveApp
+ once sync.Once
+ uiSingleton *UI
)
-type diveApp struct {
- app *tview.Application
+type UI struct {
+ app *components.DiveApplication
layers tview.Primitive
fileTree tview.Primitive
filterView tview.Primitive
}
-func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetree.Comparer, isCNB bool) (*diveApp, error) {
+func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetree.Comparer, isCNB bool) (*UI, error) {
var err error
once.Do(func() {
config := components.NewKeyConfig()
+ diveApplication := components.NewDiveApplication(app)
// ensure the background color is inherited from the terminal emulator
//tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
@@ -41,6 +42,8 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
filterViewModel := viewmodels.NewFilterViewModel(nil)
var layerModel viewmodels.LayersModel
var layerDetailsBox *components.Wrapper
+
+ // TODO extract the CNB specific logic here for now...
if isCNB {
cnbLayerViewModel := viewmodels.NewCNBLayersViewModel(analysis.Layers, analysis.BOMMapping)
cnbLayerDetailsView := components.NewCNBLayerDetailsView(cnbLayerViewModel).Setup()
@@ -75,6 +78,8 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
fileTreeView = fileTreeView.Setup(config)
fileTreeBox := components.NewWrapper("Current Layer Contents", "subtitle!", fileTreeView).Setup()
+ keyMenuView := components.NewKeyMenuView()
+
// Implementation notes: should we factor out this setup??
// Probably yes, but difficult to make this both easy to setup & mutable
leftVisibleGrid := components.NewVisibleFlex()
@@ -82,6 +87,11 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
rightVisibleGrid := components.NewVisibleFlex()
rightVisibleGrid.SetDirection(tview.FlexRow)
totalVisibleGrid := components.NewVisibleFlex()
+ gridWithFooter := tview.NewGrid().
+ SetRows(0, 1).
+ SetColumns(0).
+ AddItem(totalVisibleGrid, 0, 0, 1, 1, 0, 0, true).
+ AddItem(keyMenuView, 1, 0, 1, 1, 0, 0, false)
leftVisibleGrid.AddItem(layersBox, 0, 3, true).
AddItem(layerDetailsBox, 0, 1, false).
@@ -96,12 +106,14 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
totalVisibleGrid.AddItem(leftVisibleGrid, 0, 1, true).
AddItem(rightVisibleGrid, 0, 1, false)
- appSingleton = &diveApp{
- app: app,
+ uiSingleton = &UI{
+ app: diveApplication,
fileTree: fileTreeBox,
layers: layersBox,
}
+ keyMenuView.AddBoundViews(diveApplication)
+
quitBinding, err := config.GetKeyBinding("keybinding.quit")
if err != nil {
// TODO handle this as an error
@@ -118,6 +130,8 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
// TODO handle this as an error
panic(err)
}
+ diveApplication.AddBindings(quitBinding, filterBinding, switchBinding)
+ diveApplication.AddBoundViews(fileTreeBox, layersBox, filterView)
switchFocus := func(event *tcell.EventKey) *tcell.EventKey {
var result *tcell.EventKey = nil
@@ -125,17 +139,17 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
case quitBinding.Match(event):
app.Stop()
case switchBinding.Match(event):
- if appSingleton.app.GetFocus() == appSingleton.layers {
- appSingleton.app.SetFocus(appSingleton.fileTree)
+ if diveApplication.GetFocus() == uiSingleton.layers {
+ diveApplication.SetFocus(uiSingleton.fileTree)
} else {
- appSingleton.app.SetFocus(appSingleton.layers)
+ diveApplication.SetFocus(uiSingleton.layers)
}
case filterBinding.Match(event):
if filterView.HasFocus() {
filterView.Blur()
- appSingleton.app.SetFocus(fileTreeBox)
+ diveApplication.SetFocus(fileTreeBox)
} else {
- appSingleton.app.SetFocus(filterView)
+ diveApplication.SetFocus(filterView)
}
default:
@@ -144,13 +158,13 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
return result
}
- totalVisibleGrid.SetInputCapture(switchFocus)
+ diveApplication.SetInputCapture(switchFocus)
- app.SetRoot(totalVisibleGrid, true)
- app.SetFocus(totalVisibleGrid)
+ diveApplication.SetRoot(gridWithFooter, true)
+ diveApplication.SetFocus(gridWithFooter)
})
- return appSingleton, err
+ return uiSingleton, err
}
// Run is the UI entrypoint.
@@ -174,7 +188,7 @@ func Run(analysis *image.AnalysisResult, treeStack filetree.Comparer, isCNB bool
return err
}
- if err = appSingleton.app.Run(); err != nil {
+ if err = uiSingleton.app.Run(); err != nil {
zap.S().Info("app error: ", err.Error())
return err
}
diff --git a/runtime/ui/components/cnb_layer_details_view.go b/runtime/ui/components/cnb_layer_details_view.go
index 1840bd1..4987a23 100644
--- a/runtime/ui/components/cnb_layer_details_view.go
+++ b/runtime/ui/components/cnb_layer_details_view.go
@@ -43,6 +43,11 @@ func (lv *CNBLayerDetailsView) Draw(screen tcell.Screen) {
lv.TextView.Draw(screen)
}
+
+func (lv *CNBLayerDetailsView) GetKeyBindings() []KeyBindingDisplay {
+ return []KeyBindingDisplay {}
+}
+
func layerCNBDetailsText(layer *image.Layer, bom lifecycle.BOMEntry) string {
lines := []string{}
if layer.Names != nil && len(layer.Names) > 0 {
diff --git a/runtime/ui/components/dive_application.go b/runtime/ui/components/dive_application.go
new file mode 100644
index 0000000..e3dcacc
--- /dev/null
+++ b/runtime/ui/components/dive_application.go
@@ -0,0 +1,56 @@
+package components
+
+import (
+ "github.com/rivo/tview"
+ "github.com/sirupsen/logrus"
+)
+
+type DiveApplication struct {
+ *tview.Application
+
+ boundList []BoundView
+
+ // todo remove this
+ bindings []KeyBinding
+}
+
+func NewDiveApplication(app *tview.Application) *DiveApplication {
+ return &DiveApplication{
+ Application: app,
+ boundList: []BoundView{},
+ }
+}
+
+func (d *DiveApplication) GetKeyBindings() []KeyBindingDisplay {
+ result := []KeyBindingDisplay{}
+ for i := 0; i < len(d.bindings); i++ {
+ binding := d.bindings[i]
+ logrus.Debug("adding keybinding with name %s", binding.Display)
+ result = append(result, KeyBindingDisplay{KeyBinding: &binding, Selected: false})
+ }
+
+ for _, bound := range d.boundList {
+ if bound.HasFocus() {
+ result = append(result, bound.GetKeyBindings()...)
+ }
+ }
+
+ return result
+}
+
+func (d *DiveApplication) AddBindings(bindings ...KeyBinding) *DiveApplication {
+ d.bindings = append(d.bindings, bindings...)
+
+ return d
+}
+
+func (d *DiveApplication) AddBoundViews(views ...BoundView) *DiveApplication {
+ d.boundList = append(d.boundList, views...)
+
+ return d
+}
+
+// Application always has focus
+func (d *DiveApplication) HasFocus() bool {
+ return true
+}
diff --git a/runtime/ui/components/filetree_primative.go b/runtime/ui/components/filetree_primative.go
index 4f7b3cb..479c872 100644
--- a/runtime/ui/components/filetree_primative.go
+++ b/runtime/ui/components/filetree_primative.go
@@ -37,7 +37,7 @@ type TreeView struct {
inputHandler func(event *tcell.EventKey, setFocus func(p tview.Primitive))
- keyBindings map[string]KeyBinding
+ bindingArray []KeyBindingDisplay
showAttributes bool
}
@@ -75,8 +75,20 @@ func (t *TreeView) Setup(config KeyBindingConfig) *TreeView {
"keybinding.page-down": func() bool { return t.pageDown() },
}
- bindingArray := []KeyBinding{}
+ bindingUpdateSettings := map[string]bool{
+ "keybinding.toggle-collapse-dir": false,
+ "keybinding.toggle-collapse-all-dir": false,
+ "keybinding.toggle-filetree-attributes": true,
+ "keybinding.toggle-added-files": true,
+ "keybinding.toggle-removed-files": true,
+ "keybinding.toggle-modified-files": true,
+ "keybinding.toggle-unmodified-files": true,
+ "keybinding.page-up": false,
+ "keybinding.page-down": false,
+ }
+
actionArray := []keyAction{}
+ updateArray := []bool{}
for keybinding, action := range bindingSettings {
binding, err := config.GetKeyBinding(keybinding)
@@ -85,8 +97,9 @@ func (t *TreeView) Setup(config KeyBindingConfig) *TreeView {
// TODO handle this error
//return nil
}
- bindingArray = append(bindingArray, binding)
+ t.bindingArray = append(t.bindingArray, KeyBindingDisplay{KeyBinding: &binding, Selected: false})
actionArray = append(actionArray, action)
+ updateArray = append(updateArray, bindingUpdateSettings[keybinding])
}
t.inputHandler = func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
@@ -101,9 +114,12 @@ func (t *TreeView) Setup(config KeyBindingConfig) *TreeView {
t.keyLeft()
}
- for idx, binding := range bindingArray {
+ for idx, binding := range t.bindingArray {
if binding.Match(event) {
actionArray[idx]()
+ if updateArray[idx] {
+ t.bindingArray[idx].Selected = !t.bindingArray[idx].Selected
+ }
}
}
}
@@ -124,6 +140,12 @@ func (t *TreeView) getInputWrapper() inputFn {
return t.InputHandler
}
+// Keybinding list
+
+func (t *TreeView) GetKeyBindings() []KeyBindingDisplay {
+ return t.bindingArray
+}
+
// Implementation note:
// what do we want here??? a binding object?? yes
func (t *TreeView) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
diff --git a/runtime/ui/components/filter_primative.go b/runtime/ui/components/filter_primative.go
index 596a4b0..21daba6 100644
--- a/runtime/ui/components/filter_primative.go
+++ b/runtime/ui/components/filter_primative.go
@@ -68,3 +68,7 @@ func (fv *FilterView) Empty() bool {
func (fv *FilterView) Visible() bool {
return !fv.Empty() || fv.HasFocus()
}
+
+func (fv *FilterView) GetKeyBindings() []KeyBindingDisplay {
+ return []KeyBindingDisplay{}
+}
diff --git a/runtime/ui/components/image_details_view.go b/runtime/ui/components/image_details_view.go
index 6d88d1c..9457991 100644
--- a/runtime/ui/components/image_details_view.go
+++ b/runtime/ui/components/image_details_view.go
@@ -68,3 +68,7 @@ func (lv *ImageDetails) imageDetailsText() string {
return fmt.Sprintf("%s\n%s\n%s\n%s", imageSizeStr, wastedSpaceStr, effStr, inefficiencyReport)
}
+
+func (lv *ImageDetails) GetKeyBindings() []KeyBindingDisplay {
+ return []KeyBindingDisplay{}
+}
diff --git a/runtime/ui/components/key_config.go b/runtime/ui/components/key_config.go
index 187c719..4b41cb3 100644
--- a/runtime/ui/components/key_config.go
+++ b/runtime/ui/components/key_config.go
@@ -16,6 +16,11 @@ type KeyBinding struct{
Display string
}
+type KeyBindingDisplay struct {
+ *KeyBinding
+ Selected bool
+}
+
type keyAction func() bool
@@ -58,7 +63,4 @@ func (k *KeyConfig) GetKeyBinding(key string) (result KeyBinding, err error) {
return KeyBinding{}, err
}
return result, err
- //if config == "" {
- // return "", NewMissingConfigErr(lookupName)
- //}
}
diff --git a/runtime/ui/components/keybinding_primitive.go b/runtime/ui/components/keybinding_primitive.go
new file mode 100644
index 0000000..5394d6b
--- /dev/null
+++ b/runtime/ui/components/keybinding_primitive.go
@@ -0,0 +1,89 @@
+package components
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/rivo/tview"
+ "github.com/sirupsen/logrus"
+ "github.com/wagoodman/dive/runtime/ui/format"
+)
+
+type BoundView interface {
+ HasFocus() bool
+ GetKeyBindings() []KeyBindingDisplay
+}
+
+type KeyMenuView struct {
+ *tview.TextView
+ boundList []BoundView
+}
+
+func NewKeyMenuView() *KeyMenuView {
+ return &KeyMenuView{
+ TextView: tview.NewTextView(),
+ boundList: []BoundView{},
+ }
+}
+
+func (t *KeyMenuView) AddBoundViews(b ...BoundView) *KeyMenuView {
+ t.boundList = append(t.boundList, b...)
+ return t
+}
+
+func (t *KeyMenuView) RemoveViews(b ...BoundView) *KeyMenuView {
+ newBoundList := []BoundView{}
+ boundSet := map[BoundView]interface{}{}
+ for _, v := range b {
+ boundSet[v] = true
+ }
+
+ for _, bound := range t.boundList {
+ if _, ok := boundSet[bound]; !ok {
+ newBoundList = append(newBoundList, bound)
+ }
+ }
+
+ t.boundList = newBoundList
+ return t
+}
+
+func (t *KeyMenuView) GetKeyBindings() []KeyBindingDisplay {
+ logrus.Debug("Getting binding keys from keybinding primitive")
+ result := []KeyBindingDisplay{}
+ for _, view := range t.boundList {
+ if view.HasFocus() {
+ result = append(result, view.GetKeyBindings()...)
+ }
+ }
+
+ return result
+}
+
+func (t *KeyMenuView) Draw(screen tcell.Screen) {
+ t.Box.Draw(screen)
+ x, y, width, _ := t.Box.GetInnerRect()
+ // TODO: add logic to highlight selected options
+
+ line := []string{}
+ for _, keyBinding := range t.GetKeyBindings() {
+ formatter := format.StatusControlNormal
+ if keyBinding.Selected {
+ formatter = format.StatusControlSelected
+ }
+ line = append(line, formatter(fmt.Sprintf("%s (%s)", keyBinding.Display, keyBinding.Name())))
+ }
+
+ format.PrintLine(screen, strings.Join(line, format.StatusControlNormal(" ▏")), x, y, width, tview.AlignLeft, tcell.StyleDefault)
+
+}
+
+// for wrappers
+func (t *KeyMenuView) getBox() *tview.Box {
+ return t.Box
+}
+
+func (t *KeyMenuView) getDraw() drawFn {
+ return t.Draw
+}
diff --git a/runtime/ui/components/layer_details_view.go b/runtime/ui/components/layer_details_view.go
index a38f811..7b41b2c 100644
--- a/runtime/ui/components/layer_details_view.go
+++ b/runtime/ui/components/layer_details_view.go
@@ -50,6 +50,10 @@ func (lv *LayerDetailsView) Draw(screen tcell.Screen) {
lv.TextView.Draw(screen)
}
+func (lv *LayerDetailsView) GetKeyBindings() []KeyBindingDisplay {
+ return []KeyBindingDisplay{}
+}
+
func layerDetailsText(layer *image.Layer) string {
lines := []string{}
if layer.Names != nil && len(layer.Names) > 0 {
@@ -67,3 +71,4 @@ func layerDetailsText(layer *image.Layer) string {
func boldString(s string) string {
return fmt.Sprintf("[::b]%s[::-]", s)
}
+
diff --git a/runtime/ui/components/layers_primative.go b/runtime/ui/components/layers_primative.go
index cb9b5b5..81ef1d7 100644
--- a/runtime/ui/components/layers_primative.go
+++ b/runtime/ui/components/layers_primative.go
@@ -24,6 +24,9 @@ type LayerList struct {
cmpIndex int
changed LayerListHandler
inputHandler func(event *tcell.EventKey, setFocus func(p tview.Primitive))
+
+ bindingArray []KeyBindingDisplay
+
LayersViewModel
}
@@ -58,7 +61,6 @@ func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList {
},
}
- bindingArray := []KeyBinding{}
actionArray := []keyAction{}
for keybinding, action := range bindingSettings {
@@ -68,7 +70,7 @@ func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList {
// TODO handle this error
//return nil
}
- bindingArray = append(bindingArray, binding)
+ ll.bindingArray = append(ll.bindingArray, KeyBindingDisplay{KeyBinding: &binding, Selected: false})
actionArray = append(actionArray, action)
}
@@ -88,7 +90,7 @@ func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList {
}
}
- for idx, binding := range bindingArray {
+ for idx, binding := range ll.bindingArray {
if binding.Match(event) {
actionArray[idx]()
}
@@ -97,6 +99,10 @@ func (ll *LayerList) Setup(config KeyBindingConfig) *LayerList {
return ll
}
+func (ll *LayerList) GetKeyBindings() []KeyBindingDisplay {
+ return ll.bindingArray
+}
+
func (ll *LayerList) getBox() *tview.Box {
return ll.Box
}
diff --git a/runtime/ui/components/visible_grid.go b/runtime/ui/components/visible_grid.go
index f0db4bc..7fdbe1c 100644
--- a/runtime/ui/components/visible_grid.go
+++ b/runtime/ui/components/visible_grid.go
@@ -7,8 +7,13 @@ import (
"github.com/rivo/tview"
)
+type GridPrimitive interface {
+ VisiblePrimitive
+ GetKeyBindings() []KeyBindingDisplay
+}
+
type flexItem struct {
- Item VisiblePrimitive // The item to be positioned. May be nil for an empty item.
+ Item GridPrimitive // The item to be positioned. May be nil for an empty item.
FixedSize int // The item's fixed size which may not be changed, 0 if it has no fixed size.
Proportion int // The item's proportion
Focus bool // Whether or not this item attracts the layout's focus.
@@ -26,6 +31,10 @@ type VisibleFlex struct {
direction int
visible VisibleFunc
+
+ bindingArray []KeyBinding
+
+ inputHandler func(event *tcell.EventKey, setFocus func(p tview.Primitive))
}
func NewVisibleFlex() *VisibleFlex {
@@ -36,7 +45,24 @@ func NewVisibleFlex() *VisibleFlex {
}
}
-func (f *VisibleFlex) SetVisibility(visibleFunc VisibleFunc) VisiblePrimitive {
+func (f *VisibleFlex) GetKeyBindings() []KeyBindingDisplay {
+ result := []KeyBindingDisplay{}
+
+ for _, binding := range f.bindingArray {
+ result = append(result, KeyBindingDisplay{KeyBinding: &binding, Selected: false})
+ }
+
+ for _, item := range f.items {
+ if item.Item.HasFocus() {
+ result = append(result, item.Item.GetKeyBindings()...)
+ }
+ }
+
+ return result
+}
+
+
+func (f *VisibleFlex) SetVisibility(visibleFunc VisibleFunc) GridPrimitive {
f.visible = visibleFunc
return f
}
@@ -46,7 +72,7 @@ func (f *VisibleFlex) SetDirection(direction int) *VisibleFlex {
return f
}
-func (f *VisibleFlex) AddItem(item VisiblePrimitive, fixedSize, proportion int, focus bool) *VisibleFlex {
+func (f *VisibleFlex) AddItem(item GridPrimitive, fixedSize, proportion int, focus bool) *VisibleFlex {
f.items = append(f.items, &flexItem{Item: item, FixedSize: fixedSize, Proportion: proportion, Focus: focus})
f.consume = append(f.consume, []int{})
return f
@@ -54,7 +80,7 @@ func (f *VisibleFlex) AddItem(item VisiblePrimitive, fixedSize, proportion int,
// RemoveItem removes all items for the given primitive from the container,
// keeping the order of the remaining items intact.
-func (f *VisibleFlex) RemoveItem(p VisiblePrimitive) *VisibleFlex {
+func (f *VisibleFlex) RemoveItem(p GridPrimitive) *VisibleFlex {
for index := len(f.items) - 1; index >= 0; index-- {
if f.items[index].Item == p {
f.items = append(f.items[:index], f.items[index+1:]...)
@@ -82,7 +108,7 @@ func (f *VisibleFlex) ResizeItem(p tview.Primitive, fixedSize, proportion int) *
// TODO: update the API here this is pretty rough
// Method provided to give configuration that would otherwise not be possible when primitives are repeated
-func (f *VisibleFlex) SetConsumersByIndex(p VisiblePrimitive, consumeIndicies []int) *VisibleFlex {
+func (f *VisibleFlex) SetConsumersByIndex(p GridPrimitive, consumeIndicies []int) *VisibleFlex {
for i, item := range f.items {
if item.Item == p {
f.consume[i] = consumeIndicies
@@ -95,8 +121,8 @@ func (f *VisibleFlex) SetConsumersByIndex(p VisiblePrimitive, consumeIndicies []
// Implementation notes:
// we want a list of indicies []int{} where each visible primitive corresponds to the first matching primitive
// in our list of items
-func (f *VisibleFlex) SetConsumers(p VisiblePrimitive, consumes ...VisiblePrimitive) *VisibleFlex {
- indexMap := map[VisiblePrimitive]int{}
+func (f *VisibleFlex) SetConsumers(p GridPrimitive, consumes ...GridPrimitive) *VisibleFlex {
+ indexMap := map[GridPrimitive]int{}
for _, item := range f.items {
_, ok := indexMap[item.Item]
if !ok {
diff --git a/runtime/ui/components/wrapper_primative.go b/runtime/ui/components/wrapper_primative.go
index ce9e375..83f080f 100644
--- a/runtime/ui/components/wrapper_primative.go
+++ b/runtime/ui/components/wrapper_primative.go
@@ -14,6 +14,7 @@ type wrapable interface {
getBox() *tview.Box
getDraw() drawFn
getInputWrapper() inputFn
+ GetKeyBindings() []KeyBindingDisplay
}
type Wrapper struct {
@@ -26,6 +27,7 @@ type Wrapper struct {
title string
subtitle string
visible VisibleFunc
+ getKeyBindings func() []KeyBindingDisplay
}
type drawFn func(screen tcell.Screen)
@@ -42,6 +44,7 @@ func NewWrapper(title, subtitle string, inner wrapable) *Wrapper {
subtitleTextView: tview.NewTextView().SetText(subtitle),
inner: inner,
visible: Always(true),
+ getKeyBindings: inner.GetKeyBindings,
}
w.setTitle(w.inner.getBox().HasFocus())
return w
@@ -129,3 +132,7 @@ func (b *Wrapper) SetVisibility(visibleFunc VisibleFunc) *Wrapper {
b.visible = visibleFunc
return b
}
+
+func (b *Wrapper) GetKeyBindings() []KeyBindingDisplay {
+ return b.getKeyBindings()
+}
diff --git a/runtime/ui/format/format.go b/runtime/ui/format/format.go
index 8a07c66..690c0e5 100644
--- a/runtime/ui/format/format.go
+++ b/runtime/ui/format/format.go
@@ -79,6 +79,8 @@ var (
// Styles these are needed to completely color a line
SelectedStyle tcell.Style = tcell.Style{}.Bold(true).Reverse(true)
+ MenuStyle tcell.Style = tcell.Style{}.Reverse(true)
+ SelectedMenuStyle tcell.Style = tcell.Style{}.Background(tcell.ColorDarkBlue).Foreground(tcell.ColorWhite).Bold(true)
)
func PrintLine(screen tcell.Screen, text string, x, y, maxWidth, align int, style tcell.Style) (int, int) {