Much Work

- Definable KeyMaps
- Change 'Tabbable' to just use 'Focusable'
This commit is contained in:
2025-09-04 11:09:34 -05:00
parent c1db729bb3
commit f571b13a31
26 changed files with 881 additions and 615 deletions

View File

@@ -49,12 +49,17 @@ func NewRuneMap(m map[rune]func(*tcell.EventKey) bool) KeyMap {
} }
} }
func (m KeyMap) Merge(km KeyMap) {
for k, v := range km.Keys {
m.Keys[k] = v
}
for r, v := range km.Runes {
m.Runes[r] = v
}
}
func (m KeyMap) Add(k tcell.Key, do func(*tcell.EventKey) bool) { m.Keys[k] = do } func (m KeyMap) Add(k tcell.Key, do func(*tcell.EventKey) bool) { m.Keys[k] = do }
func (m KeyMap) Remove(k tcell.Key) { func (m KeyMap) Remove(k tcell.Key) { delete(m.Keys, k) }
if _, ok := m.Keys[k]; ok {
delete(m.Keys, k)
}
}
func (m KeyMap) AddAll(all map[tcell.Key]func(*tcell.EventKey) bool) { func (m KeyMap) AddAll(all map[tcell.Key]func(*tcell.EventKey) bool) {
for k, v := range all { for k, v := range all {
@@ -62,11 +67,7 @@ func (m KeyMap) AddAll(all map[tcell.Key]func(*tcell.EventKey) bool) {
} }
} }
func (m KeyMap) AddRune(k rune, do func(*tcell.EventKey) bool) { m.Runes[k] = do } func (m KeyMap) AddRune(k rune, do func(*tcell.EventKey) bool) { m.Runes[k] = do }
func (m KeyMap) RemoveRune(k rune) { func (m KeyMap) RemoveRune(k rune) { delete(m.Runes, k) }
if _, ok := m.Runes[k]; ok {
delete(m.Runes, k)
}
}
func (m KeyMap) AddRunes(all map[rune]func(*tcell.EventKey) bool) { func (m KeyMap) AddRunes(all map[rune]func(*tcell.EventKey) bool) {
for k, v := range all { for k, v := range all {

View File

@@ -45,6 +45,7 @@ const (
const ( const (
LFAlignTopLeft = LayoutFlag(LFAlignHLeft | LFAlignVTop) LFAlignTopLeft = LayoutFlag(LFAlignHLeft | LFAlignVTop)
LFAlignCenter = LayoutFlag(LFAlignHCenter | LFAlignVCenter)
) )
func (f LayoutFlag) Add(fl LayoutFlag) { f |= fl } func (f LayoutFlag) Add(fl LayoutFlag) { f |= fl }

View File

@@ -40,7 +40,9 @@ type AbsoluteLayout struct {
active bool active bool
visible bool visible bool
tabbable bool focusable bool
keyMap KeyMap
cursor int cursor int
disableTab bool disableTab bool
@@ -76,20 +78,30 @@ func (w *AbsoluteLayout) Init(id string, s tcell.Style) {
w.style = s w.style = s
w.visible = true w.visible = true
w.defAnchor = AnchorTL w.defAnchor = AnchorTL
w.keyMap = BlankKeyMap()
w.wCoords = make(map[Widget]Coord) w.wCoords = make(map[Widget]Coord)
w.wAnchor = make(map[Widget]AbsoluteAnchor) w.wAnchor = make(map[Widget]AbsoluteAnchor)
w.wManualSizes = make(map[Widget]Coord) w.wManualSizes = make(map[Widget]Coord)
w.tabbable = true w.focusable = true
} }
func (w *AbsoluteLayout) Id() string { return w.id } func (w *AbsoluteLayout) Id() string { return w.id }
func (w *AbsoluteLayout) HandleResize(ev *tcell.EventResize) { func (w *AbsoluteLayout) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW())
// w.h = wh.Min(w.h, w.WantH())
w.updateWidgetLayouts() w.updateWidgetLayouts()
} }
func (w *AbsoluteLayout) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *AbsoluteLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *AbsoluteLayout) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *AbsoluteLayout) HandleKey(ev *tcell.EventKey) bool { func (w *AbsoluteLayout) HandleKey(ev *tcell.EventKey) bool {
if !w.disableTab && ev.Key() == tcell.KeyTab { if !w.disableTab && ev.Key() == tcell.KeyTab {
fndP := -1 fndP := -1
@@ -101,7 +113,7 @@ func (w *AbsoluteLayout) HandleKey(ev *tcell.EventKey) bool {
continue continue
} }
} else { } else {
if w.widgets[i].Focusable() && w.widgets[i].Tabbable() { if w.widgets[i].Focusable() {
w.widgets[i].SetActive(true) w.widgets[i].SetActive(true)
return true return true
} }
@@ -112,7 +124,7 @@ func (w *AbsoluteLayout) HandleKey(ev *tcell.EventKey) bool {
return false return false
} }
for i := 0; i < fndP; i++ { for i := 0; i < fndP; i++ {
if w.widgets[i].Focusable() && w.widgets[i].Tabbable() { if w.widgets[i].Focusable() {
w.widgets[i].SetActive(true) w.widgets[i].SetActive(true)
return true return true
} }
@@ -147,9 +159,8 @@ func (w *AbsoluteLayout) Active() bool { return w.active }
func (w *AbsoluteLayout) SetActive(a bool) { w.active = a } func (w *AbsoluteLayout) SetActive(a bool) { w.active = a }
func (w *AbsoluteLayout) Visible() bool { return w.visible } func (w *AbsoluteLayout) Visible() bool { return w.visible }
func (w *AbsoluteLayout) SetVisible(a bool) { w.visible = a } func (w *AbsoluteLayout) SetVisible(a bool) { w.visible = a }
func (w *AbsoluteLayout) Focusable() bool { return true } func (w *AbsoluteLayout) Focusable() bool { return w.focusable }
func (w *AbsoluteLayout) SetTabbable(b bool) { w.tabbable = b } func (w *AbsoluteLayout) SetFocusable(b bool) { w.focusable = b }
func (w *AbsoluteLayout) Tabbable() bool { return w.tabbable }
func (w *AbsoluteLayout) SetX(x int) { w.x = x } func (w *AbsoluteLayout) SetX(x int) { w.x = x }
func (w *AbsoluteLayout) SetY(y int) { w.y = y } func (w *AbsoluteLayout) SetY(y int) { w.y = y }
func (w *AbsoluteLayout) GetX() int { return w.x } func (w *AbsoluteLayout) GetX() int { return w.x }

View File

@@ -36,7 +36,7 @@ type Alert struct {
w, h int w, h int
active bool active bool
visible bool visible bool
tabbable bool focusable bool
layout *LinearLayout layout *LinearLayout
title string title string
@@ -60,14 +60,17 @@ func (w *Alert) Init(id string, style tcell.Style) {
w.id = id w.id = id
w.style = style w.style = style
w.layout = NewLinearLayout(fmt.Sprintf("%s-layout", id), tcell.StyleDefault) w.layout = NewLinearLayout(fmt.Sprintf("%s-layout", id), style)
// w.layout.SetStacked(true)
w.message = NewText(fmt.Sprintf("%s-text", id), style) w.message = NewText(fmt.Sprintf("%s-text", id), style)
w.layout.Add(w.message) w.layout.Add(w.message)
w.layout.AddFlag(w.message, LFAlignCenter)
w.btnLayout = NewLinearLayout("alertbtn-layout", tcell.StyleDefault) w.btnLayout = NewLinearLayout("alertbtn-layout", style)
w.btnLayout.SetOrientation(LinLayH) w.btnLayout.SetOrientation(LinLayH)
w.layout.Add(w.btnLayout) w.layout.Add(w.btnLayout)
w.layout.AddFlag(w.btnLayout, LFAlignCenter)
w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style) w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style)
w.btnCancel.SetLabel("Cancel") w.btnCancel.SetLabel("Cancel")
@@ -86,22 +89,27 @@ func (w *Alert) Init(id string, style tcell.Style) {
tcell.KeyUp: w.SelectNext, tcell.KeyUp: w.SelectNext,
tcell.KeyEnter: w.Do, tcell.KeyEnter: w.Do,
}) })
w.tabbable = true w.focusable = true
} }
func (w *Alert) Id() string { return w.id } func (w *Alert) Id() string { return w.id }
func (w *Alert) HandleResize(ev *tcell.EventResize) { func (w *Alert) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
if w.w > w.MinW() {
w.w = w.MinW()
}
if w.h > w.MinH() {
w.h = w.MinH()
}
// Trim space for the borders and pass on the size to the layout // Trim space for the borders and pass on the size to the layout
w.layout.SetPos(Coord{X: 1, Y: 1}) w.layout.SetPos(Coord{X: 1, Y: 1})
w.layout.HandleResize(tcell.NewEventResize(w.w-2, w.h-2)) w.layout.HandleResize(tcell.NewEventResize(w.w-2, w.h-2))
} }
func (w *Alert) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Alert) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Alert) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Alert) HandleKey(ev *tcell.EventKey) bool { func (w *Alert) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -134,9 +142,8 @@ func (w *Alert) SetH(y int) { w.h = y }
func (w *Alert) GetW() int { return w.w } func (w *Alert) GetW() int { return w.w }
func (w *Alert) GetH() int { return w.y } func (w *Alert) GetH() int { return w.y }
func (w *Alert) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Alert) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Alert) Focusable() bool { return true } func (w *Alert) Focusable() bool { return w.focusable }
func (w *Alert) SetTabbable(b bool) { w.tabbable = b } func (w *Alert) SetFocusable(b bool) { w.focusable = b }
func (w *Alert) Tabbable() bool { return w.tabbable }
func (w *Alert) WantW() int { func (w *Alert) WantW() int {
return 4 + wh.Max(w.message.WantW(), (w.btnOk.WantW()+w.btnCancel.WantW())) return 4 + wh.Max(w.message.WantW(), (w.btnOk.WantW()+w.btnCancel.WantW()))
} }
@@ -145,31 +152,41 @@ func (w *Alert) WantH() int {
return 4 + w.btnOk.WantH() + w.message.WantH() return 4 + w.btnOk.WantH() + w.message.WantH()
} }
// Borders + Buttons
func (w *Alert) MinW() int { func (w *Alert) MinW() int {
return 5 + wh.Max(w.message.MinW(), (w.btnOk.MinW()+w.btnCancel.MinW())) return 4 + wh.Max(w.message.MinW(), (w.btnOk.MinW()+w.btnCancel.MinW()))
} }
// Borders + Buttons + 2 lines for message
func (w *Alert) MinH() int { func (w *Alert) MinH() int {
return 5 + w.message.MinH() + w.btnOk.MinH() return 4 + w.message.MinH() + w.btnOk.MinH()
} }
func (w *Alert) SetTitle(ttl string) { w.title = ttl } func (w *Alert) SetTitle(ttl string) { w.title = ttl }
func (w *Alert) SetMessage(msg string) { w.message.SetText(msg) } func (w *Alert) SetMessage(msg string) { w.message.SetText(msg) }
func (w *Alert) SetOkPressed(b func() bool) { w.btnOk.SetOnPressed(b) } func (w *Alert) SetOkPressed(b func() bool) {
func (w *Alert) SetCancelPressed(b func() bool) { w.btnCancel.SetOnPressed(b) } w.btnOk.SetVisible(b != nil)
w.btnOk.SetFocusable(b != nil)
w.btnOk.SetOnPressed(b)
}
func (w *Alert) SetCancelPressed(b func() bool) {
w.btnCancel.SetVisible(b != nil)
w.btnCancel.SetFocusable(b != nil)
w.btnCancel.SetOnPressed(b)
}
func (w *Alert) SelectNext(ev *tcell.EventKey) bool { func (w *Alert) SelectNext(ev *tcell.EventKey) bool {
if w.btnOk.Active() { if w.btnOk.Active() && w.btnCancel.Visible() {
w.btnOk.SetActive(false) w.btnOk.SetActive(false)
w.btnCancel.SetActive(true) w.btnCancel.SetActive(true)
} else { return true
} else if w.btnCancel.Active() && w.btnOk.Visible() {
w.btnOk.SetActive(true) w.btnOk.SetActive(true)
w.btnCancel.SetActive(false) w.btnCancel.SetActive(false)
}
return true return true
} }
return false
}
func (w *Alert) Do(ev *tcell.EventKey) bool { func (w *Alert) Do(ev *tcell.EventKey) bool {
if w.btnOk.Active() { if w.btnOk.Active() {

View File

@@ -27,6 +27,7 @@ import "github.com/gdamore/tcell"
type BlankWidget struct { type BlankWidget struct {
id string id string
x, y int x, y int
keyMap KeyMap
} }
var _ Widget = (*BlankWidget)(nil) var _ Widget = (*BlankWidget)(nil)
@@ -36,9 +37,19 @@ func NewBlankWidget(id string) *BlankWidget {
return ret return ret
} }
func (w *BlankWidget) Init(id string, st tcell.Style) {} func (w *BlankWidget) Init(id string, st tcell.Style) { w.keyMap = BlankKeyMap() }
func (w *BlankWidget) Id() string { return w.id } func (w *BlankWidget) Id() string { return w.id }
func (w *BlankWidget) HandleResize(ev *tcell.EventResize) {} func (w *BlankWidget) HandleResize(ev *tcell.EventResize) {}
func (w *BlankWidget) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *BlankWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *BlankWidget) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *BlankWidget) HandleKey(ev *tcell.EventKey) bool { return false } func (w *BlankWidget) HandleKey(ev *tcell.EventKey) bool { return false }
func (w *BlankWidget) HandleTime(ev *tcell.EventTime) {} func (w *BlankWidget) HandleTime(ev *tcell.EventTime) {}
func (w *BlankWidget) Draw(screen tcell.Screen) {} func (w *BlankWidget) Draw(screen tcell.Screen) {}
@@ -48,8 +59,7 @@ func (w *BlankWidget) SetActive(a bool) {}
func (w *BlankWidget) Visible() bool { return true } func (w *BlankWidget) Visible() bool { return true }
func (w *BlankWidget) SetVisible(v bool) {} func (w *BlankWidget) SetVisible(v bool) {}
func (w *BlankWidget) Focusable() bool { return false } func (w *BlankWidget) Focusable() bool { return false }
func (w *BlankWidget) Tabbable() bool { return false } func (w *BlankWidget) SetFocusable(t bool) {}
func (w *BlankWidget) SetTabbable(t bool) {}
func (w *BlankWidget) SetX(x int) {} func (w *BlankWidget) SetX(x int) {}
func (w *BlankWidget) SetY(y int) {} func (w *BlankWidget) SetY(y int) {}
func (w *BlankWidget) GetX() int { return w.x } func (w *BlankWidget) GetX() int { return w.x }

View File

@@ -39,7 +39,7 @@ type BorderedWidget struct {
title string title string
active bool active bool
visible bool visible bool
tabbable bool focusable bool
logger func(string) logger func(string)
} }
@@ -57,7 +57,7 @@ func (w *BorderedWidget) Init(id string, s tcell.Style) {
w.style = s w.style = s
w.visible = true w.visible = true
w.border = wh.BRD_CSIMPLE w.border = wh.BRD_CSIMPLE
w.tabbable = true w.focusable = true
} }
func (w *BorderedWidget) Id() string { return w.id } func (w *BorderedWidget) Id() string { return w.id }
@@ -68,6 +68,9 @@ func (w *BorderedWidget) HandleResize(ev *tcell.EventResize) {
w.widget.HandleResize(tcell.NewEventResize(w.w-2, w.h-2)) w.widget.HandleResize(tcell.NewEventResize(w.w-2, w.h-2))
} }
func (w *BorderedWidget) SetKeyMap(km KeyMap) { w.widget.SetKeyMap(km) }
func (w *BorderedWidget) AddToKeyMap(km KeyMap) { w.widget.AddToKeyMap(km) }
func (w *BorderedWidget) RemoveFromKeyMap(km KeyMap) { w.widget.RemoveFromKeyMap(km) }
func (w *BorderedWidget) HandleKey(ev *tcell.EventKey) bool { return w.HandleKey(ev) } func (w *BorderedWidget) HandleKey(ev *tcell.EventKey) bool { return w.HandleKey(ev) }
func (w *BorderedWidget) HandleTime(ev *tcell.EventTime) { w.HandleTime(ev) } func (w *BorderedWidget) HandleTime(ev *tcell.EventTime) { w.HandleTime(ev) }
@@ -88,9 +91,8 @@ func (w *BorderedWidget) Active() bool { return w.active }
func (w *BorderedWidget) SetActive(a bool) { w.active = a } func (w *BorderedWidget) SetActive(a bool) { w.active = a }
func (w *BorderedWidget) Visible() bool { return w.visible } func (w *BorderedWidget) Visible() bool { return w.visible }
func (w *BorderedWidget) SetVisible(a bool) { w.visible = a } func (w *BorderedWidget) SetVisible(a bool) { w.visible = a }
func (w *BorderedWidget) Focusable() bool { return true } func (w *BorderedWidget) Focusable() bool { return w.focusable }
func (w *BorderedWidget) SetTabbable(b bool) { w.tabbable = b } func (w *BorderedWidget) SetFocusable(b bool) { w.focusable = b }
func (w *BorderedWidget) Tabbable() bool { return w.tabbable }
func (w *BorderedWidget) SetX(x int) { w.x = x } func (w *BorderedWidget) SetX(x int) { w.x = x }
func (w *BorderedWidget) SetY(y int) { w.y = y } func (w *BorderedWidget) SetY(y int) { w.y = y }
func (w *BorderedWidget) GetX() int { return w.x } func (w *BorderedWidget) GetX() int { return w.x }

View File

@@ -38,7 +38,8 @@ type Button struct {
active bool active bool
visible bool visible bool
tabbable bool focusable bool
keyMap KeyMap
onPressed func() bool onPressed func() bool
logger func(string, ...any) logger func(string, ...any)
@@ -56,24 +57,31 @@ func (w *Button) Init(id string, style tcell.Style) {
w.id = id w.id = id
w.style = style w.style = style
w.visible = true w.visible = true
w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{
tcell.KeyEnter: func(ev *tcell.EventKey) bool { return w.onPressed() },
})
w.onPressed = func() bool { return false } w.onPressed = func() bool { return false }
w.tabbable = true w.focusable = true
} }
func (w *Button) Id() string { return w.id } func (w *Button) Id() string { return w.id }
func (w *Button) HandleResize(ev *tcell.EventResize) { func (w *Button) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() }
w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW()) func (w *Button) SetKeyMap(km KeyMap) { w.keyMap = km }
// w.h = wh.Min(w.h, w.WantH()) func (w *Button) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Button) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
} }
func (w *Button) HandleKey(ev *tcell.EventKey) bool { func (w *Button) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
} }
if ev.Key() == tcell.KeyEnter { return w.keyMap.Handle(ev)
return w.onPressed()
}
return false
} }
func (w *Button) HandleTime(ev *tcell.EventTime) {} func (w *Button) HandleTime(ev *tcell.EventTime) {}
@@ -81,12 +89,7 @@ func (w *Button) Draw(screen tcell.Screen) {
if !w.visible { if !w.visible {
return return
} }
dStyle := w.style dStyle := w.style.Dim(!w.active)
if w.active {
dStyle = w.style.Bold(true)
} else {
dStyle = w.style.Dim(true)
}
switch w.h { switch w.h {
case 1: case 1:
lbl := w.label lbl := w.label
@@ -140,9 +143,8 @@ func (w *Button) GetH() int { return w.h }
func (w *Button) WantW() int { return 4 + len(w.label) } func (w *Button) WantW() int { return 4 + len(w.label) }
func (w *Button) WantH() int { return 3 } func (w *Button) WantH() int { return 3 }
func (w *Button) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Button) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Button) Focusable() bool { return true } func (w *Button) Focusable() bool { return w.focusable }
func (w *Button) SetTabbable(b bool) { w.tabbable = b } func (w *Button) SetFocusable(b bool) { w.focusable = b }
func (w *Button) Tabbable() bool { return w.tabbable }
func (w *Button) MinW() int { return len(w.label) + 2 } func (w *Button) MinW() int { return len(w.label) + 2 }
func (w *Button) MinH() int { return 1 } func (w *Button) MinH() int { return 1 }

View File

@@ -38,7 +38,7 @@ type Chat struct {
w, h int w, h int
active bool active bool
visible bool visible bool
tabbable bool focusable bool
title string title string
rawLog []string rawLog []string
@@ -66,14 +66,23 @@ func (w *Chat) Init(id string, s tcell.Style) {
w.id, w.style = id, s w.id, w.style = id, s
w.visible = true w.visible = true
w.initKeyMap() w.initKeyMap()
w.tabbable = true w.focusable = true
} }
func (w *Chat) Id() string { return w.id } func (w *Chat) Id() string { return w.id }
func (w *Chat) HandleResize(ev *tcell.EventResize) { func (w *Chat) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW()) }
// w.h = wh.Min(w.h, w.WantH())
func (w *Chat) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Chat) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Chat) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
} }
func (w *Chat) HandleKey(ev *tcell.EventKey) bool { func (w *Chat) HandleKey(ev *tcell.EventKey) bool {
@@ -161,9 +170,8 @@ func (w *Chat) Active() bool { return w.active }
func (w *Chat) SetActive(a bool) { w.active = a } func (w *Chat) SetActive(a bool) { w.active = a }
func (w *Chat) Visible() bool { return w.visible } func (w *Chat) Visible() bool { return w.visible }
func (w *Chat) SetVisible(a bool) { w.visible = a } func (w *Chat) SetVisible(a bool) { w.visible = a }
func (w *Chat) Focusable() bool { return true } func (w *Chat) Focusable() bool { return w.focusable }
func (w *Chat) SetTabbable(b bool) { w.tabbable = b } func (w *Chat) SetFocusable(b bool) { w.focusable = b }
func (w *Chat) Tabbable() bool { return w.tabbable }
func (w *Chat) SetX(x int) { w.x = x } func (w *Chat) SetX(x int) { w.x = x }
func (w *Chat) SetY(y int) { w.y = y } func (w *Chat) SetY(y int) { w.y = y }
func (w *Chat) GetX() int { return w.x } func (w *Chat) GetX() int { return w.x }

View File

@@ -40,11 +40,12 @@ type Checkbox struct {
style tcell.Style style tcell.Style
active bool active bool
visible bool visible bool
tabbable bool focusable bool
state int state int
x, y int x, y int
w, h int w, h int
keyMap KeyMap
stateRunes []rune stateRunes []rune
} }
@@ -61,29 +62,40 @@ func (w *Checkbox) Init(id string, style tcell.Style) {
w.style = style w.style = style
w.visible = true w.visible = true
w.stateRunes = []rune{'X', ' ', '-'} w.stateRunes = []rune{'X', ' ', '-'}
w.tabbable = true w.focusable = true
} w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{
func (w *Checkbox) Id() string { return w.id } tcell.KeyEnter: func(_ *tcell.EventKey) bool {
func (w *Checkbox) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW())
// w.h = wh.Min(w.h, w.WantH())
}
func (w *Checkbox) HandleKey(ev *tcell.EventKey) bool {
if !w.active {
return false
}
if ev.Key() == tcell.KeyEnter {
if w.state == CHECKBOX_ON { if w.state == CHECKBOX_ON {
w.state = CHECKBOX_OFF w.state = CHECKBOX_OFF
} else { } else {
w.state = CHECKBOX_ON w.state = CHECKBOX_ON
} }
return true return true
},
})
} }
func (w *Checkbox) Id() string { return w.id }
func (w *Checkbox) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size()
}
func (w *Checkbox) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Checkbox) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Checkbox) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Checkbox) HandleKey(ev *tcell.EventKey) bool {
if !w.active {
return false return false
} }
return w.keyMap.Handle(ev)
}
func (w *Checkbox) HandleTime(ev *tcell.EventTime) {} func (w *Checkbox) HandleTime(ev *tcell.EventTime) {}
func (w *Checkbox) Draw(screen tcell.Screen) { func (w *Checkbox) Draw(screen tcell.Screen) {
if !w.visible { if !w.visible {
@@ -115,9 +127,8 @@ func (w *Checkbox) WantW() int {
} }
func (w *Checkbox) WantH() int { return 1 } func (w *Checkbox) WantH() int { return 1 }
func (w *Checkbox) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Checkbox) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Checkbox) Focusable() bool { return true } func (w *Checkbox) Focusable() bool { return w.focusable }
func (w *Checkbox) SetTabbable(b bool) { w.tabbable = b } func (w *Checkbox) SetFocusable(b bool) { w.focusable = b }
func (w *Checkbox) Tabbable() bool { return w.tabbable }
func (w *Checkbox) MinW() int { func (w *Checkbox) MinW() int {
return len(fmt.Sprintf("[%s] %s", string(w.state), w.label)) return len(fmt.Sprintf("[%s] %s", string(w.state), w.label))
} }

View File

@@ -39,7 +39,7 @@ type Cli struct {
w, h int w, h int
active bool active bool
visible bool visible bool
tabbable bool focusable bool
title string title string
rawLog []string rawLog []string
@@ -71,7 +71,7 @@ func (w *Cli) Init(id string, s tcell.Style) {
w.id, w.style = id, s w.id, w.style = id, s
w.visible = true w.visible = true
w.initKeyMap() w.initKeyMap()
w.tabbable = true w.focusable = true
} }
func (w *Cli) Id() string { return w.id } func (w *Cli) Id() string { return w.id }
@@ -79,6 +79,17 @@ func (w *Cli) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
} }
func (w *Cli) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Cli) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Cli) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Cli) HandleKey(ev *tcell.EventKey) bool { func (w *Cli) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -172,8 +183,7 @@ func (w *Cli) SetActive(a bool) { w.active = a }
func (w *Cli) Visible() bool { return w.visible } func (w *Cli) Visible() bool { return w.visible }
func (w *Cli) SetVisible(a bool) { w.visible = a } func (w *Cli) SetVisible(a bool) { w.visible = a }
func (w *Cli) Focusable() bool { return true } func (w *Cli) Focusable() bool { return true }
func (w *Cli) SetTabbable(b bool) { w.tabbable = b } func (w *Cli) SetFocusable(b bool) { w.focusable = b }
func (w *Cli) Tabbable() bool { return w.tabbable }
func (w *Cli) SetX(x int) { w.x = x } func (w *Cli) SetX(x int) { w.x = x }
func (w *Cli) SetY(y int) { w.y = y } func (w *Cli) SetY(y int) { w.y = y }
func (w *Cli) GetX() int { return w.x } func (w *Cli) GetX() int { return w.x }

View File

@@ -40,9 +40,10 @@ type DebugWidget struct {
drawRulers bool drawRulers bool
active bool active bool
visible bool visible bool
tabbable bool focusable bool
mTL, mBR Coord // Margins (Top-Right & Bottom Left) mTL, mBR Coord // Margins (Top-Right & Bottom Left)
keyMap KeyMap
logger func(string, ...any) logger func(string, ...any)
} }
@@ -60,9 +61,10 @@ func (w *DebugWidget) Init(id string, s tcell.Style) {
w.id = id w.id = id
w.style = s w.style = s
w.visible = true w.visible = true
w.tabbable = true w.focusable = true
w.drawRulers = true w.drawRulers = true
w.setW, w.setH = -1, -1 w.setW, w.setH = -1, -1
w.keyMap = BlankKeyMap()
} }
func (w *DebugWidget) SetLogger(l func(string, ...any)) { w.logger = l } func (w *DebugWidget) SetLogger(l func(string, ...any)) { w.logger = l }
@@ -104,7 +106,23 @@ func (w *DebugWidget) HandleResize(ev *tcell.EventResize) {
w.widget.HandleResize(tcell.NewEventResize(w.w-w.mTL.X-w.mBR.X, w.h-w.mTL.Y-w.mBR.Y)) w.widget.HandleResize(tcell.NewEventResize(w.w-w.mTL.X-w.mBR.X, w.h-w.mTL.Y-w.mBR.Y))
} }
func (w *DebugWidget) HandleKey(ev *tcell.EventKey) bool { return w.widget.HandleKey(ev) } func (w *DebugWidget) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *DebugWidget) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *DebugWidget) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *DebugWidget) HandleKey(ev *tcell.EventKey) bool {
if ok := w.keyMap.Handle(ev); ok {
return true
}
return w.widget.HandleKey(ev)
}
func (w *DebugWidget) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) } func (w *DebugWidget) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) }
func (w *DebugWidget) Draw(screen tcell.Screen) { func (w *DebugWidget) Draw(screen tcell.Screen) {
@@ -162,9 +180,8 @@ func (w *DebugWidget) SetActive(a bool) {
} }
func (w *DebugWidget) Visible() bool { return w.visible } func (w *DebugWidget) Visible() bool { return w.visible }
func (w *DebugWidget) SetVisible(a bool) { w.visible = a } func (w *DebugWidget) SetVisible(a bool) { w.visible = a }
func (w *DebugWidget) Focusable() bool { return true } func (w *DebugWidget) Focusable() bool { return w.focusable }
func (w *DebugWidget) SetTabbable(b bool) { w.tabbable = b } func (w *DebugWidget) SetFocusable(b bool) { w.focusable = b }
func (w *DebugWidget) Tabbable() bool { return w.tabbable }
func (w *DebugWidget) SetX(x int) { w.x = x } func (w *DebugWidget) SetX(x int) { w.x = x }
func (w *DebugWidget) SetY(y int) { w.y = y } func (w *DebugWidget) SetY(y int) { w.y = y }
func (w *DebugWidget) GetX() int { return w.x } func (w *DebugWidget) GetX() int { return w.x }

View File

@@ -38,7 +38,7 @@ type Field struct {
cursor int cursor int
visible bool visible bool
active bool active bool
tabbable bool focusable bool
x, y int x, y int
w, h int w, h int
@@ -71,12 +71,23 @@ func (w *Field) Init(id string, style tcell.Style) {
tcell.KeyEnd: w.handleEnd, tcell.KeyEnd: w.handleEnd,
tcell.KeyCtrlU: w.clearValueBeforeCursor, tcell.KeyCtrlU: w.clearValueBeforeCursor,
}) })
w.tabbable = true w.focusable = true
} }
func (w *Field) Id() string { return w.id } func (w *Field) Id() string { return w.id }
func (w *Field) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() } func (w *Field) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() }
func (w *Field) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Field) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Field) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Field) HandleKey(ev *tcell.EventKey) bool { func (w *Field) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -159,9 +170,8 @@ func (w *Field) WantH() int {
return 1 return 1
} }
func (w *Field) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Field) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Field) Focusable() bool { return true } func (w *Field) Focusable() bool { return w.focusable }
func (w *Field) SetTabbable(b bool) { w.tabbable = b } func (w *Field) SetFocusable(b bool) { w.focusable = b }
func (w *Field) Tabbable() bool { return w.tabbable }
func (w *Field) MinW() int { return len(w.label) + wh.Max(15, len(w.value)) } func (w *Field) MinW() int { return len(w.label) + wh.Max(15, len(w.value)) }
func (w *Field) MinH() int { return 1 } func (w *Field) MinH() int { return 1 }

View File

@@ -37,7 +37,6 @@ type FilePicker struct {
active bool active bool
visible bool visible bool
focusable bool focusable bool
tabbable bool
x, y int x, y int
w, h int w, h int
@@ -50,6 +49,8 @@ type FilePicker struct {
fileList *List fileList *List
btnSelect, btnCancel *Button btnSelect, btnCancel *Button
keyMap KeyMap
} }
var _ Widget = (*FilePicker)(nil) var _ Widget = (*FilePicker)(nil)
@@ -72,7 +73,8 @@ func (w *FilePicker) Init(id string, style tcell.Style) {
w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style) w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style)
w.btnCancel.SetLabel("Cancel") w.btnCancel.SetLabel("Cancel")
w.layout.Add(w.btnCancel, nil, RelAncBL) w.layout.Add(w.btnCancel, nil, RelAncBL)
w.tabbable = true w.focusable = true
w.keyMap = BlankKeyMap()
} }
func (w *FilePicker) Id() string { return w.id } func (w *FilePicker) Id() string { return w.id }
func (w *FilePicker) HandleResize(ev *tcell.EventResize) { func (w *FilePicker) HandleResize(ev *tcell.EventResize) {
@@ -82,21 +84,29 @@ func (w *FilePicker) HandleResize(ev *tcell.EventResize) {
w.btnCancel.SetPos(Coord{X: w.x + 1, Y: w.y + w.h - 1}) w.btnCancel.SetPos(Coord{X: w.x + 1, Y: w.y + w.h - 1})
} }
func (w *FilePicker) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *FilePicker) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *FilePicker) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *FilePicker) HandleKey(ev *tcell.EventKey) bool { func (w *FilePicker) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
} }
return false return w.keyMap.Handle(ev)
} }
func (w *FilePicker) HandleTime(ev *tcell.EventTime) {} func (w *FilePicker) HandleTime(ev *tcell.EventTime) {}
func (w *FilePicker) Draw(screen tcell.Screen) { func (w *FilePicker) Draw(screen tcell.Screen) {
if !w.visible { if !w.visible {
return return
} }
ds := w.style ds := w.style.Dim(!w.active)
if !w.active {
ds = ds.Dim(true)
}
wh.TitledBorderFilled(w.x, w.y, w.x+w.w, w.y+w.h, w.title, wh.BRD_SIMPLE, ds, screen) wh.TitledBorderFilled(w.x, w.y, w.x+w.w, w.y+w.h, w.title, wh.BRD_SIMPLE, ds, screen)
// TODO: Draw the file picker // TODO: Draw the file picker
wh.DrawText(w.x+1, w.y+1, "TODO: Draw Filepicker", ds, screen) wh.DrawText(w.x+1, w.y+1, "TODO: Draw Filepicker", ds, screen)
@@ -120,8 +130,7 @@ func (w *FilePicker) GetW() int { return w.w }
func (w *FilePicker) GetH() int { return w.y } func (w *FilePicker) GetH() int { return w.y }
func (w *FilePicker) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *FilePicker) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *FilePicker) Focusable() bool { return w.focusable } func (w *FilePicker) Focusable() bool { return w.focusable }
func (w *FilePicker) SetTabbable(b bool) { w.tabbable = b } func (w *FilePicker) SetFocusable(b bool) { w.focusable = b }
func (w *FilePicker) Tabbable() bool { return w.tabbable }
func (w *FilePicker) WantW() int { func (w *FilePicker) WantW() int {
// borders + the greater of the buttons next to each other or the list width // borders + the greater of the buttons next to each other or the list width
return wh.Max((w.btnSelect.WantW()+w.btnCancel.WantW()), w.fileList.WantW()) + 2 return wh.Max((w.btnSelect.WantW()+w.btnCancel.WantW()), w.fileList.WantW()) + 2

View File

@@ -52,10 +52,12 @@ type LinearLayout struct {
active bool active bool
visible bool visible bool
tabbable bool focusable bool
disableTab bool disableTab bool
insetBorder bool insetBorder bool
keyMap KeyMap
logger func(string, ...any) logger func(string, ...any)
} }
@@ -78,10 +80,23 @@ func (w *LinearLayout) Init(id string, s tcell.Style) {
w.id = id w.id = id
w.style = s w.style = s
w.visible = true w.visible = true
w.tabbable = true w.focusable = true
w.defFlags = LayoutFlag(LFAlignHCenter | LFAlignVCenter) w.defFlags = LayoutFlag(LFAlignHCenter | LFAlignVCenter)
w.layoutFlags = make(map[Widget]LayoutFlag) w.layoutFlags = make(map[Widget]LayoutFlag)
w.layoutWeights = make(map[Widget]int) w.layoutWeights = make(map[Widget]int)
w.keyMap = BlankKeyMap()
w.keyMap.Add(tcell.KeyTab, func(ev *tcell.EventKey) bool {
active := w.findActive()
if active == nil && len(w.widgets) > 0 {
// No widget is active
if w.widgets[0].Focusable() {
w.widgets[0].SetActive(true)
return true
}
return false
}
return w.activateNext()
})
} }
func (w *LinearLayout) Id() string { return w.id } func (w *LinearLayout) Id() string { return w.id }
@@ -90,6 +105,17 @@ func (w *LinearLayout) HandleResize(ev *tcell.EventResize) {
w.updateWidgetLayouts() w.updateWidgetLayouts()
} }
func (w *LinearLayout) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *LinearLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *LinearLayout) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *LinearLayout) HandleKey(ev *tcell.EventKey) bool { func (w *LinearLayout) HandleKey(ev *tcell.EventKey) bool {
if !w.active || w.disableTab { if !w.active || w.disableTab {
return false return false
@@ -100,19 +126,7 @@ func (w *LinearLayout) HandleKey(ev *tcell.EventKey) bool {
return true return true
} }
} }
if ev.Key() == tcell.KeyTab { return w.keyMap.Handle(ev)
if active == nil && len(w.widgets) > 0 {
// No widget is active
if w.widgets[0].Tabbable() {
w.widgets[0].SetActive(true)
return true
}
return false
}
return w.activateNext()
}
return false
} }
func (w *LinearLayout) GetActive() Widget { return w.findActive() } func (w *LinearLayout) GetActive() Widget { return w.findActive() }
@@ -148,9 +162,8 @@ func (w *LinearLayout) SetActive(a bool) {
} }
func (w *LinearLayout) Visible() bool { return w.visible } func (w *LinearLayout) Visible() bool { return w.visible }
func (w *LinearLayout) SetVisible(a bool) { w.visible = a } func (w *LinearLayout) SetVisible(a bool) { w.visible = a }
func (w *LinearLayout) Focusable() bool { return true } func (w *LinearLayout) Focusable() bool { return w.focusable }
func (w *LinearLayout) SetTabbable(b bool) { w.tabbable = b } func (w *LinearLayout) SetFocusable(b bool) { w.focusable = b }
func (w *LinearLayout) Tabbable() bool { return w.tabbable }
func (w *LinearLayout) SetX(x int) { w.x = x } func (w *LinearLayout) SetX(x int) { w.x = x }
func (w *LinearLayout) SetY(y int) { w.y = y } func (w *LinearLayout) SetY(y int) { w.y = y }
func (w *LinearLayout) GetX() int { return w.x } func (w *LinearLayout) GetX() int { return w.x }
@@ -245,7 +258,7 @@ func (w *LinearLayout) findActiveOrFirst() Widget {
func (w *LinearLayout) activateNext() bool { func (w *LinearLayout) activateNext() bool {
var found bool var found bool
for i := range w.widgets { for i := range w.widgets {
if found && w.widgets[i].Tabbable() { if found && w.widgets[i].Focusable() {
w.widgets[i].SetActive(true) w.widgets[i].SetActive(true)
return true return true
} else if w.widgets[i].Active() { } else if w.widgets[i].Active() {
@@ -443,8 +456,10 @@ func (w *LinearLayout) updateLLVWidgetPos(wd Widget) {
if w.widgets[i] == wd { if w.widgets[i] == wd {
break break
} }
if w.widgets[i].Visible() {
c.Y = w.widgets[i].GetY() + w.widgets[i].GetH() c.Y = w.widgets[i].GetY() + w.widgets[i].GetH()
} }
}
// Do we have a layout flag for this widget? // Do we have a layout flag for this widget?
var ok bool var ok bool
@@ -484,8 +499,10 @@ func (w *LinearLayout) updateLLHWidgetPos(wd Widget) {
} }
break break
} }
if w.widgets[i].Visible() {
c.X = w.widgets[i].GetX() + w.widgets[i].GetW() c.X = w.widgets[i].GetX() + w.widgets[i].GetW()
} }
}
// Do we have a layout flag for this widget? // Do we have a layout flag for this widget?
var ok bool var ok bool

View File

@@ -33,7 +33,6 @@ type List struct {
active bool active bool
visible bool visible bool
focusable bool focusable bool
tabbable bool
x, y int x, y int
w, h int w, h int
@@ -86,13 +85,24 @@ func (w *List) Init(id string, style tcell.Style) {
return false return false
}) })
w.itemsStyle = make(map[int]tcell.Style) w.itemsStyle = make(map[int]tcell.Style)
w.tabbable = true w.focusable = true
} }
func (w *List) Id() string { return w.id } func (w *List) Id() string { return w.id }
func (w *List) HandleResize(ev *tcell.EventResize) { func (w *List) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
} }
func (w *List) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *List) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *List) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *List) HandleKey(ev *tcell.EventKey) bool { func (w *List) HandleKey(ev *tcell.EventKey) bool {
if !w.active || !w.focusable { if !w.active || !w.focusable {
return false return false
@@ -122,7 +132,7 @@ func (w *List) Draw(screen tcell.Screen) {
rev = true rev = true
} }
txt := w.list[i] txt := w.list[i]
if len(txt) > w.w-brdSz { if len(txt) > w.w-brdSz && w.w-brdSz >= 0 {
txt = txt[:(w.w - brdSz)] txt = txt[:(w.w - brdSz)]
} }
var ok bool var ok bool
@@ -151,8 +161,7 @@ func (w *List) GetW() int { return w.w }
func (w *List) GetH() int { return w.y } func (w *List) GetH() int { return w.y }
func (w *List) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *List) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *List) Focusable() bool { return w.focusable } func (w *List) Focusable() bool { return w.focusable }
func (w *List) SetTabbable(b bool) { w.tabbable = b } func (w *List) SetFocusable(b bool) { w.focusable = b }
func (w *List) Tabbable() bool { return w.tabbable }
func (w *List) WantW() int { func (w *List) WantW() int {
lng := wh.Longest(w.list) lng := wh.Longest(w.list)
if len(w.border) > 0 { if len(w.border) > 0 {
@@ -179,8 +188,6 @@ func (w *List) MinW() int {
func (w *List) MinH() int { return 4 } func (w *List) MinH() int { return 4 }
func (w *List) SetFocusable(f bool) { w.focusable = f }
func (w *List) SetCursorWrap(b bool) { w.cursorWrap = b } func (w *List) SetCursorWrap(b bool) { w.cursorWrap = b }
func (w *List) MoveUp(ev *tcell.EventKey) bool { func (w *List) MoveUp(ev *tcell.EventKey) bool {
if w.cursor > 0 { if w.cursor > 0 {

View File

@@ -34,7 +34,7 @@ type Menu struct {
style tcell.Style style tcell.Style
active bool active bool
visible bool visible bool
tabbable bool focusable bool
x, y int x, y int
w, h int w, h int
@@ -81,18 +81,25 @@ func (w *Menu) Init(id string, style tcell.Style) {
return false return false
}, },
}) })
w.tabbable = true w.focusable = true
} }
func (w *Menu) Id() string { return w.id } func (w *Menu) Id() string { return w.id }
func (w *Menu) HandleResize(ev *tcell.EventResize) { func (w *Menu) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW())
// w.h = wh.Min(w.h, w.WantH())
// TODO: Trickle-down HandleResize // TODO: Trickle-down HandleResize
} }
func (w *Menu) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Menu) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Menu) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Menu) HandleKey(ev *tcell.EventKey) bool { func (w *Menu) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -181,8 +188,7 @@ func (w *Menu) GetW() int { return w.w }
func (w *Menu) GetH() int { return w.y } func (w *Menu) GetH() int { return w.y }
func (w *Menu) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Menu) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Menu) Focusable() bool { return true } func (w *Menu) Focusable() bool { return true }
func (w *Menu) SetTabbable(b bool) { w.tabbable = b } func (w *Menu) SetFocusable(b bool) { w.focusable = b }
func (w *Menu) Tabbable() bool { return w.tabbable }
func (w *Menu) WantW() int { func (w *Menu) WantW() int {
var maxW int var maxW int
@@ -241,7 +247,6 @@ func (w *Menu) MinH() int {
} }
func (w *Menu) SetType(tp MenuType) { w.menuType = tp } func (w *Menu) SetType(tp MenuType) { w.menuType = tp }
func (w *Menu) SetLabel(lbl string) { w.label = lbl } func (w *Menu) SetLabel(lbl string) { w.label = lbl }
func (w *Menu) SetFocusable(f bool) {}
func (w *Menu) GetItems() []*MenuItem { return w.items } func (w *Menu) GetItems() []*MenuItem { return w.items }
func (w *Menu) GetItem(idx int) *MenuItem { func (w *Menu) GetItem(idx int) *MenuItem {

View File

@@ -32,7 +32,7 @@ type MenuItem struct {
style tcell.Style style tcell.Style
active bool active bool
visible bool visible bool
tabbable bool focusable bool
x, y int x, y int
w, h int w, h int
@@ -75,7 +75,7 @@ func (w *MenuItem) Init(id string, style tcell.Style) {
for i := range w.items { for i := range w.items {
w.items[i].SetActive(i == w.cursor) w.items[i].SetActive(i == w.cursor)
} }
w.tabbable = true w.focusable = true
} }
func (w *MenuItem) Id() string { return w.id } func (w *MenuItem) Id() string { return w.id }
func (w *MenuItem) HandleResize(ev *tcell.EventResize) { func (w *MenuItem) HandleResize(ev *tcell.EventResize) {
@@ -83,6 +83,17 @@ func (w *MenuItem) HandleResize(ev *tcell.EventResize) {
// TODO: Trickle-down HandleResize // TODO: Trickle-down HandleResize
} }
func (w *MenuItem) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *MenuItem) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *MenuItem) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *MenuItem) HandleKey(ev *tcell.EventKey) bool { func (w *MenuItem) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -158,9 +169,8 @@ func (w *MenuItem) WantH() int {
return ret return ret
} }
func (w *MenuItem) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *MenuItem) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *MenuItem) Focusable() bool { return !w.disabled } func (w *MenuItem) Focusable() bool { return w.focusable && !w.disabled }
func (w *MenuItem) SetTabbable(b bool) { w.tabbable = b } func (w *MenuItem) SetFocusable(b bool) { w.focusable = b }
func (w *MenuItem) Tabbable() bool { return w.tabbable }
// How much width this item wants // How much width this item wants
func (w *MenuItem) Expand(e bool) { func (w *MenuItem) Expand(e bool) {

View File

@@ -38,13 +38,15 @@ type Prompt struct {
w, h int w, h int
active bool active bool
visible bool visible bool
tabbable bool focusable bool
title string title string
message *Text message *Text
field *Field field *Field
btnOk, btnCancel *Button btnOk, btnCancel *Button
onOk func(string) bool onOk func(string) bool
keyMap KeyMap
} }
var _ Widget = (*Prompt)(nil) var _ Widget = (*Prompt)(nil)
@@ -64,7 +66,8 @@ func (w *Prompt) Init(id string, style tcell.Style) {
w.btnOk.SetLabel("Ok") w.btnOk.SetLabel("Ok")
w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style) w.btnCancel = NewButton(fmt.Sprintf("%s-cancel", id), style)
w.btnCancel.SetLabel("Cancel") w.btnCancel.SetLabel("Cancel")
w.tabbable = true w.focusable = true
w.keyMap = BlankKeyMap()
} }
func (w *Prompt) Id() string { return w.id } func (w *Prompt) Id() string { return w.id }
func (w *Prompt) HandleResize(ev *tcell.EventResize) { func (w *Prompt) HandleResize(ev *tcell.EventResize) {
@@ -80,11 +83,22 @@ func (w *Prompt) HandleResize(ev *tcell.EventResize) {
w.btnCancel.SetPos(Coord{X: w.x + 1, Y: w.y + w.h - 1}) w.btnCancel.SetPos(Coord{X: w.x + 1, Y: w.y + w.h - 1})
} }
func (w *Prompt) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Prompt) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Prompt) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Prompt) HandleKey(ev *tcell.EventKey) bool { func (w *Prompt) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
} }
return false return w.keyMap.Handle(ev)
} }
func (w *Prompt) HandleTime(ev *tcell.EventTime) {} func (w *Prompt) HandleTime(ev *tcell.EventTime) {}
func (w *Prompt) Draw(screen tcell.Screen) { func (w *Prompt) Draw(screen tcell.Screen) {
@@ -116,9 +130,8 @@ func (w *Prompt) SetH(y int) { w.h = y }
func (w *Prompt) GetW() int { return w.w } func (w *Prompt) GetW() int { return w.w }
func (w *Prompt) GetH() int { return w.y } func (w *Prompt) GetH() int { return w.y }
func (w *Prompt) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Prompt) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Prompt) Focusable() bool { return true } func (w *Prompt) Focusable() bool { return w.focusable }
func (w *Prompt) SetTabbable(b bool) { w.tabbable = b } func (w *Prompt) SetFocusable(b bool) { w.focusable = b }
func (w *Prompt) Tabbable() bool { return w.tabbable }
func (w *Prompt) WantW() int { func (w *Prompt) WantW() int {
return w.btnOk.WantW() + w.btnCancel.WantW() + 4 return w.btnOk.WantW() + w.btnCancel.WantW() + 4
} }

View File

@@ -28,15 +28,16 @@ import (
type RelativeLayout struct { type RelativeLayout struct {
id string id string
style tcell.Style style tcell.Style
x, y int
w, h int
widgetRelations map[Widget][]widgetRelation widgetRelations map[Widget][]widgetRelation
widgets []Widget widgets []Widget
active bool active bool
visible bool visible bool
tabbable bool focusable bool
x, y int keyMap KeyMap
w, h int
} }
var _ Widget = (*RelativeLayout)(nil) var _ Widget = (*RelativeLayout)(nil)
@@ -74,18 +75,26 @@ func (w *RelativeLayout) Init(id string, style tcell.Style) {
w.id = id w.id = id
w.style = style w.style = style
w.visible = true w.visible = true
w.tabbable = true w.focusable = true
w.keyMap = BlankKeyMap()
} }
func (w *RelativeLayout) Id() string { return w.id } func (w *RelativeLayout) Id() string { return w.id }
func (w *RelativeLayout) HandleResize(ev *tcell.EventResize) { func (w *RelativeLayout) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
// w.w = wh.Min(w.w, w.WantW())
// w.h = wh.Min(w.h, w.WantH())
// TODO: Trickle-down HandleResize // TODO: Trickle-down HandleResize
} }
func (w *RelativeLayout) HandleKey(ev *tcell.EventKey) bool { return false }
func (w *RelativeLayout) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *RelativeLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *RelativeLayout) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *RelativeLayout) HandleKey(ev *tcell.EventKey) bool { return w.keyMap.Handle(ev) }
func (w *RelativeLayout) HandleTime(ev *tcell.EventTime) {} func (w *RelativeLayout) HandleTime(ev *tcell.EventTime) {}
func (w *RelativeLayout) Draw(screen tcell.Screen) { func (w *RelativeLayout) Draw(screen tcell.Screen) {
if !w.visible { if !w.visible {
@@ -109,9 +118,8 @@ func (w *RelativeLayout) Active() bool { return w.active }
func (w *RelativeLayout) SetActive(a bool) { w.active = a } func (w *RelativeLayout) SetActive(a bool) { w.active = a }
func (w *RelativeLayout) Visible() bool { return w.visible } func (w *RelativeLayout) Visible() bool { return w.visible }
func (w *RelativeLayout) SetVisible(a bool) { w.visible = a } func (w *RelativeLayout) SetVisible(a bool) { w.visible = a }
func (w *RelativeLayout) Focusable() bool { return true } func (w *RelativeLayout) Focusable() bool { return w.focusable }
func (w *RelativeLayout) SetTabbable(b bool) { w.tabbable = b } func (w *RelativeLayout) SetFocusable(b bool) { w.focusable = b }
func (w *RelativeLayout) Tabbable() bool { return w.tabbable }
func (w *RelativeLayout) SetX(x int) { w.x = x } func (w *RelativeLayout) SetX(x int) { w.x = x }
func (w *RelativeLayout) SetY(y int) { w.y = y } func (w *RelativeLayout) SetY(y int) { w.y = y }
func (w *RelativeLayout) GetX() int { return w.x } func (w *RelativeLayout) GetX() int { return w.x }

View File

@@ -37,7 +37,7 @@ type Searcher struct {
w, h int w, h int
active bool active bool
visible bool visible bool
tabbable bool focusable bool
title string title string
search *Field search *Field
@@ -79,7 +79,7 @@ func (w *Searcher) Init(id string, style tcell.Style) {
tcell.KeyPgDn: w.handleKeyPgDn, tcell.KeyPgDn: w.handleKeyPgDn,
tcell.KeyEnter: w.handleKeyEnter, tcell.KeyEnter: w.handleKeyEnter,
}) })
w.tabbable = true w.focusable = true
} }
func (w *Searcher) Id() string { return w.id } func (w *Searcher) Id() string { return w.id }
@@ -94,6 +94,17 @@ func (w *Searcher) HandleResize(ev *tcell.EventResize) {
w.search.HandleResize(Coord{X: aW, Y: aH}.ResizeEvent()) w.search.HandleResize(Coord{X: aW, Y: aH}.ResizeEvent())
} }
func (w *Searcher) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Searcher) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Searcher) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *Searcher) HandleKey(ev *tcell.EventKey) bool { func (w *Searcher) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -252,9 +263,8 @@ func (w *Searcher) SetH(y int) { w.h = y }
func (w *Searcher) GetW() int { return w.w } func (w *Searcher) GetW() int { return w.w }
func (w *Searcher) GetH() int { return w.h } func (w *Searcher) GetH() int { return w.h }
func (w *Searcher) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Searcher) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Searcher) Focusable() bool { return true } func (w *Searcher) Focusable() bool { return w.focusable }
func (w *Searcher) SetTabbable(b bool) { w.tabbable = b } func (w *Searcher) SetFocusable(b bool) { w.focusable = b }
func (w *Searcher) Tabbable() bool { return w.tabbable }
func (w *Searcher) MinW() int { func (w *Searcher) MinW() int {
return 2 + w.search.MinW() return 2 + w.search.MinW()
} }

View File

@@ -38,6 +38,10 @@ func NewShrinkWrap(w Widget) *ShrinkWrap {
func (w *ShrinkWrap) Init(id string, st tcell.Style) { w.widget.Init(id, st) } func (w *ShrinkWrap) Init(id string, st tcell.Style) { w.widget.Init(id, st) }
func (w *ShrinkWrap) Id() string { return w.widget.Id() } func (w *ShrinkWrap) Id() string { return w.widget.Id() }
func (w *ShrinkWrap) HandleResize(ev *tcell.EventResize) { w.widget.HandleResize(ev) } func (w *ShrinkWrap) HandleResize(ev *tcell.EventResize) { w.widget.HandleResize(ev) }
func (w *ShrinkWrap) SetKeyMap(km KeyMap) { w.widget.SetKeyMap(km) }
func (w *ShrinkWrap) AddToKeyMap(km KeyMap) { w.widget.AddToKeyMap(km) }
func (w *ShrinkWrap) RemoveFromKeyMap(km KeyMap) { w.widget.RemoveFromKeyMap(km) }
func (w *ShrinkWrap) HandleKey(ev *tcell.EventKey) bool { return w.widget.HandleKey(ev) } func (w *ShrinkWrap) HandleKey(ev *tcell.EventKey) bool { return w.widget.HandleKey(ev) }
func (w *ShrinkWrap) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) } func (w *ShrinkWrap) HandleTime(ev *tcell.EventTime) { w.widget.HandleTime(ev) }
func (w *ShrinkWrap) Draw(screen tcell.Screen) { w.widget.Draw(screen) } func (w *ShrinkWrap) Draw(screen tcell.Screen) { w.widget.Draw(screen) }
@@ -47,8 +51,7 @@ func (w *ShrinkWrap) SetActive(a bool) { w.widget.SetActive(a) }
func (w *ShrinkWrap) Visible() bool { return w.widget.Visible() } func (w *ShrinkWrap) Visible() bool { return w.widget.Visible() }
func (w *ShrinkWrap) SetVisible(v bool) { w.widget.SetVisible(v) } func (w *ShrinkWrap) SetVisible(v bool) { w.widget.SetVisible(v) }
func (w *ShrinkWrap) Focusable() bool { return w.widget.Focusable() } func (w *ShrinkWrap) Focusable() bool { return w.widget.Focusable() }
func (w *ShrinkWrap) Tabbable() bool { return w.widget.Tabbable() } func (w *ShrinkWrap) SetFocusable(t bool) { w.widget.SetFocusable(t) }
func (w *ShrinkWrap) SetTabbable(t bool) { w.widget.SetTabbable(t) }
func (w *ShrinkWrap) SetX(x int) { w.widget.SetX(x) } func (w *ShrinkWrap) SetX(x int) { w.widget.SetX(x) }
func (w *ShrinkWrap) SetY(y int) { w.widget.SetY(y) } func (w *ShrinkWrap) SetY(y int) { w.widget.SetY(y) }
func (w *ShrinkWrap) GetX() int { return w.widget.GetX() } func (w *ShrinkWrap) GetX() int { return w.widget.GetX() }

View File

@@ -36,7 +36,6 @@ type Table struct {
active bool active bool
visible bool visible bool
focusable bool focusable bool
tabbable bool
header []string header []string
footer []string footer []string
@@ -52,6 +51,8 @@ type Table struct {
w, h int w, h int
columnWidths []int columnWidths []int
keyMap KeyMap
} }
var _ Widget = (*Table)(nil) var _ Widget = (*Table)(nil)
@@ -82,21 +83,30 @@ func (w *Table) Init(id string, style tcell.Style) {
w.style = style w.style = style
w.visible = true w.visible = true
w.border = wh.BRD_CSIMPLE w.border = wh.BRD_CSIMPLE
w.tabbable = true w.focusable = true
w.keyMap = BlankKeyMap()
} }
func (w *Table) Id() string { return w.id } func (w *Table) Id() string { return w.id }
func (w *Table) HandleResize(ev *tcell.EventResize) { func (w *Table) HandleResize(ev *tcell.EventResize) {
w.w, w.h = ev.Size() w.w, w.h = ev.Size()
}
// w.w = wh.Min(w.w, w.WantW()) func (w *Table) SetKeyMap(km KeyMap) { w.keyMap = km }
// w.h = wh.Min(w.h, w.WantH()) func (w *Table) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Table) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
} }
func (w *Table) HandleKey(ev *tcell.EventKey) bool { func (w *Table) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
} }
return false return w.keyMap.Handle(ev)
} }
func (w *Table) HandleTime(ev *tcell.EventTime) {} func (w *Table) HandleTime(ev *tcell.EventTime) {}
func (w *Table) Draw(screen tcell.Screen) { func (w *Table) Draw(screen tcell.Screen) {
@@ -254,11 +264,9 @@ func (w *Table) MinH() int {
func (w *Table) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Table) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Table) Focusable() bool { return w.focusable } func (w *Table) Focusable() bool { return w.focusable }
func (w *Table) SetTabbable(b bool) { w.tabbable = b } func (w *Table) SetFocusable(b bool) { w.focusable = b }
func (w *Table) Tabbable() bool { return w.tabbable }
func (w *Table) SetTitle(ttl string) { w.title = ttl } func (w *Table) SetTitle(ttl string) { w.title = ttl }
func (w *Table) SetFocusable(f bool) { w.focusable = f }
func (w *Table) SetBorder(b []rune) { w.border = b } func (w *Table) SetBorder(b []rune) { w.border = b }
func (w *Table) AddRow(row []string) { w.data = append(w.data, row) } func (w *Table) AddRow(row []string) { w.data = append(w.data, row) }

View File

@@ -38,7 +38,9 @@ type Text struct {
x, y int x, y int
w, h int w, h int
visible bool visible bool
tabbable bool active bool
focusable bool
keyMap KeyMap
} }
var _ Widget = (*Text)(nil) var _ Widget = (*Text)(nil)
@@ -53,11 +55,22 @@ func (w *Text) Init(id string, style tcell.Style) {
w.id = id w.id = id
w.style = style w.style = style
w.visible = true w.visible = true
w.tabbable = false w.focusable = false
w.keyMap = BlankKeyMap()
} }
func (w *Text) Id() string { return w.id } func (w *Text) Id() string { return w.id }
func (w *Text) HandleResize(ev *tcell.EventResize) { func (w *Text) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size() }
w.w, w.h = ev.Size()
func (w *Text) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *Text) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *Text) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
} }
func (w *Text) HandleKey(ev *tcell.EventKey) bool { return false } func (w *Text) HandleKey(ev *tcell.EventKey) bool { return false }
func (w *Text) HandleTime(ev *tcell.EventTime) {} func (w *Text) HandleTime(ev *tcell.EventTime) {}
@@ -72,8 +85,8 @@ func (w *Text) Draw(screen tcell.Screen) {
} }
} }
func (w *Text) Active() bool { return false } func (w *Text) Active() bool { return w.active }
func (w *Text) SetActive(a bool) {} func (w *Text) SetActive(a bool) { w.active = a }
func (w *Text) Visible() bool { return w.visible } func (w *Text) Visible() bool { return w.visible }
func (w *Text) SetVisible(a bool) { w.visible = a } func (w *Text) SetVisible(a bool) { w.visible = a }
func (w *Text) SetX(x int) { w.x = x } func (w *Text) SetX(x int) { w.x = x }
@@ -85,13 +98,12 @@ func (w *Text) SetPos(c Coord) { w.x, w.y = c.X, c.Y }
func (w *Text) SetW(x int) { w.w = x } func (w *Text) SetW(x int) { w.w = x }
func (w *Text) SetH(y int) { w.h = y } func (w *Text) SetH(y int) { w.h = y }
func (w *Text) GetW() int { return w.w } func (w *Text) GetW() int { return w.w }
func (w *Text) GetH() int { return w.y } func (w *Text) GetH() int { return w.h }
func (w *Text) WantW() int { return wh.Longest(w.message) } func (w *Text) WantW() int { return wh.Longest(w.message) }
func (w *Text) WantH() int { return len(w.message) } func (w *Text) WantH() int { return len(w.message) }
func (w *Text) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *Text) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *Text) Focusable() bool { return false } func (w *Text) Focusable() bool { return w.focusable }
func (w *Text) SetTabbable(b bool) { w.tabbable = b } func (w *Text) SetFocusable(b bool) { w.focusable = b }
func (w *Text) Tabbable() bool { return w.tabbable }
func (w *Text) MinW() int { return wh.Longest(w.message) } func (w *Text) MinW() int { return wh.Longest(w.message) }
func (w *Text) MinH() int { return len(w.message) } func (w *Text) MinH() int { return len(w.message) }

View File

@@ -36,7 +36,7 @@ type TimeField struct {
style tcell.Style style tcell.Style
active bool active bool
visible bool visible bool
tabbable bool focusable bool
x, y int x, y int
w, h int w, h int
@@ -92,7 +92,7 @@ func (w *TimeField) Init(id string, style tcell.Style) {
tcell.KeyEnd: w.handleEnd, tcell.KeyEnd: w.handleEnd,
}) })
w.visible = true w.visible = true
w.tabbable = true w.focusable = true
} }
func (w *TimeField) Id() string { return w.id } func (w *TimeField) Id() string { return w.id }
@@ -138,6 +138,17 @@ func (w *TimeField) HandleResize(ev *tcell.EventResize) {
} }
} }
func (w *TimeField) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *TimeField) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *TimeField) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
}
}
func (w *TimeField) HandleKey(ev *tcell.EventKey) bool { func (w *TimeField) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
@@ -182,9 +193,8 @@ func (w *TimeField) SetH(y int) { w.h = y }
func (w *TimeField) GetW() int { return w.w } func (w *TimeField) GetW() int { return w.w }
func (w *TimeField) GetH() int { return w.y } func (w *TimeField) GetH() int { return w.y }
func (w *TimeField) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *TimeField) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *TimeField) Focusable() bool { return true } func (w *TimeField) Focusable() bool { return w.focusable }
func (w *TimeField) SetTabbable(b bool) { w.tabbable = b } func (w *TimeField) SetFocusable(b bool) { w.focusable = b }
func (w *TimeField) Tabbable() bool { return w.tabbable }
func (w *TimeField) WantW() int { return w.MinW() } func (w *TimeField) WantW() int { return w.MinW() }
func (w *TimeField) WantH() int { return w.MinH() } func (w *TimeField) WantH() int { return w.MinH() }
func (w *TimeField) MinW() int { func (w *TimeField) MinW() int {

View File

@@ -41,6 +41,10 @@ type TopMenuLayout struct {
active bool active bool
visible bool visible bool
focusable bool
layoutFlags LayoutFlag
keyMap KeyMap
logger func(string, ...any) logger func(string, ...any)
} }
@@ -62,9 +66,19 @@ func (w *TopMenuLayout) Init(id string, s tcell.Style) {
w.menu = NewMenu(fmt.Sprintf("%s.mainmenu", id), tcell.StyleDefault) w.menu = NewMenu(fmt.Sprintf("%s.mainmenu", id), tcell.StyleDefault)
w.menu.SetActive(false) w.menu.SetActive(false)
w.menu.SetType(MenuTypeH) w.menu.SetType(MenuTypeH)
w.menu.SetTabbable(false)
w.widget = NewBlankWidget("blank") w.widget = NewBlankWidget("blank")
w.keyMap = BlankKeyMap()
w.keyMap.Add(tcell.KeyEscape, func(ev *tcell.EventKey) bool {
if w.menu != nil {
w.menu.SetActive(!w.menu.Active())
if w.widget != nil {
w.widget.SetActive(!w.menu.Active())
}
return true
}
return false
})
} }
func (w *TopMenuLayout) Id() string { return w.id } func (w *TopMenuLayout) Id() string { return w.id }
@@ -76,8 +90,35 @@ func (w *TopMenuLayout) HandleResize(ev *tcell.EventResize) {
} }
if w.widget != nil { if w.widget != nil {
w.widget.SetPos(Coord{X: 0, Y: 1})
w.widget.HandleResize(tcell.NewEventResize(w.w, w.h-1)) w.widget.HandleResize(tcell.NewEventResize(w.w, w.h-1))
w.Log("Widget Size: %d,%d", w.widget.GetW(), w.widget.GetH())
x, y := 0, 1
switch w.layoutFlags.AlignH() {
case LFAlignHRight:
x = w.w - w.widget.GetW()
case LFAlignHCenter:
x = (w.w / 2) - (w.widget.GetW() / 2)
}
switch w.layoutFlags.AlignV() {
case LFAlignVBottom:
y = w.h - w.widget.GetH()
case LFAlignVCenter:
y = (w.h / 2) - (w.widget.GetH() / 2)
}
w.widget.SetPos(Coord{X: x, Y: y})
}
}
func (w *TopMenuLayout) SetKeyMap(km KeyMap) { w.keyMap = km }
func (w *TopMenuLayout) AddToKeyMap(km KeyMap) { w.keyMap.Merge(km) }
func (w *TopMenuLayout) RemoveFromKeyMap(km KeyMap) {
for k := range km.Keys {
w.keyMap.Remove(k)
}
for r := range km.Runes {
w.keyMap.RemoveRune(r)
} }
} }
@@ -85,17 +126,13 @@ func (w *TopMenuLayout) HandleKey(ev *tcell.EventKey) bool {
if !w.active { if !w.active {
return false return false
} }
if ev.Key() == tcell.KeyEscape && w.menu != nil {
w.menu.SetActive(!w.menu.Active()) if w.keyMap.Handle(ev) {
if w.widget != nil {
w.widget.SetActive(!w.menu.Active())
}
return true return true
} }
if w.menu.Active() { if w.menu != nil && w.menu.Active() {
return w.menu.HandleKey(ev) return w.menu.HandleKey(ev)
} }
// Pass the key through to the main widget // Pass the key through to the main widget
if w.widget != nil { if w.widget != nil {
// If we're here, that means the menu isn't active, but we are. So the // If we're here, that means the menu isn't active, but we are. So the
@@ -145,9 +182,8 @@ func (w *TopMenuLayout) SetH(y int) { w.h = y }
func (w *TopMenuLayout) GetW() int { return w.w } func (w *TopMenuLayout) GetW() int { return w.w }
func (w *TopMenuLayout) GetH() int { return w.y } func (w *TopMenuLayout) GetH() int { return w.y }
func (w *TopMenuLayout) SetSize(c Coord) { w.w, w.h = c.X, c.Y } func (w *TopMenuLayout) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
func (w *TopMenuLayout) Focusable() bool { return true } func (w *TopMenuLayout) Focusable() bool { return w.focusable }
func (w *TopMenuLayout) SetTabbable(b bool) {} func (w *TopMenuLayout) SetFocusable(b bool) { w.focusable = b }
func (w *TopMenuLayout) Tabbable() bool { return true }
func (w *TopMenuLayout) WantW() int { return wh.MaxInt } func (w *TopMenuLayout) WantW() int { return wh.MaxInt }
func (w *TopMenuLayout) WantH() int { return wh.MaxInt } func (w *TopMenuLayout) WantH() int { return wh.MaxInt }
@@ -159,6 +195,24 @@ func (w *TopMenuLayout) AddMenuItems(iL ...*MenuItem) { w.menu.AddItems(iL...
func (w *TopMenuLayout) RemoveMenuItems(iL ...*MenuItem) { w.menu.RemoveItems(iL...) } func (w *TopMenuLayout) RemoveMenuItems(iL ...*MenuItem) { w.menu.RemoveItems(iL...) }
func (w *TopMenuLayout) SetWidget(wd Widget) { w.widget = wd } func (w *TopMenuLayout) SetWidget(wd Widget) { w.widget = wd }
func (w *TopMenuLayout) AddLayoutFlag(f LayoutFlag) {
if f.IsAlignH() {
w.layoutFlags.ClearAlignH()
}
if f.IsAlignV() {
w.layoutFlags.ClearAlignV()
}
w.layoutFlags.Add(f)
}
func (w *TopMenuLayout) RemoveLayoutFlag(f LayoutFlag) {
if f.IsAlignH() {
w.layoutFlags.ClearAlignH()
}
if f.IsAlignV() {
w.layoutFlags.ClearAlignV()
}
}
func (w *TopMenuLayout) SetLogger(l func(string, ...any)) { w.logger = l } func (w *TopMenuLayout) SetLogger(l func(string, ...any)) { w.logger = l }
func (w *TopMenuLayout) Log(txt string, args ...any) { func (w *TopMenuLayout) Log(txt string, args ...any) {
@@ -179,11 +233,9 @@ func (w *TopMenuLayout) CreateMenuItem(id, lbl string, do func() bool, subItems
func (w *TopMenuLayout) SetItemVisible(id string, v bool) bool { func (w *TopMenuLayout) SetItemVisible(id string, v bool) bool {
if mi := w.FindItem(id); mi != nil { if mi := w.FindItem(id); mi != nil {
w.Log("%s.SetItemVisible: Found Item: %s (Set Visible: %t)", w.Id(), id, v)
mi.SetVisible(v) mi.SetVisible(v)
return true return true
} }
w.Log("%s.SetItemVisible: Didn't find item with id: %s", w.Id(), id)
return false return false
} }

View File

@@ -32,14 +32,16 @@ type Widget interface {
HandleResize(*tcell.EventResize) HandleResize(*tcell.EventResize)
HandleKey(*tcell.EventKey) bool HandleKey(*tcell.EventKey) bool
HandleTime(*tcell.EventTime) HandleTime(*tcell.EventTime)
SetKeyMap(km KeyMap)
AddToKeyMap(km KeyMap)
RemoveFromKeyMap(km KeyMap)
Draw(tcell.Screen) Draw(tcell.Screen)
Active() bool Active() bool
SetActive(bool) SetActive(bool)
Visible() bool Visible() bool
SetVisible(bool) SetVisible(bool)
Focusable() bool Focusable() bool
Tabbable() bool SetFocusable(bool)
SetTabbable(bool)
SetX(int) SetX(int)
SetY(int) SetY(int)
GetX() int GetX() int