Some Updates
This commit is contained in:
@@ -36,6 +36,11 @@ const (
|
|||||||
AlignRight
|
AlignRight
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Return if r1 and r2 are the same, ignoring case
|
||||||
|
func RuneEqualsNC(r1, r2 rune) bool {
|
||||||
|
return unicode.ToLower(r1) == unicode.ToLower(r2)
|
||||||
|
}
|
||||||
|
|
||||||
func Center(txt string, width int) string {
|
func Center(txt string, width int) string {
|
||||||
if len(txt) >= width {
|
if len(txt) >= width {
|
||||||
// Trim from beg & end until width
|
// Trim from beg & end until width
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ func (f LayoutFlag) SetTopLeft() {
|
|||||||
f = LFAlignHLeft | LFAlignVTop
|
f = LFAlignHLeft | LFAlignVTop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f LayoutFlag) SetBottomCenter() {
|
||||||
|
f.ClearAll()
|
||||||
|
f = LFAlignHCenter | LFAlignVBottom
|
||||||
|
}
|
||||||
|
|
||||||
func (f LayoutFlag) ClearAlignH() {
|
func (f LayoutFlag) ClearAlignH() {
|
||||||
f = f &^ LFAlignH
|
f = f &^ LFAlignH
|
||||||
f.Add(LFAlignHCenter)
|
f.Add(LFAlignHCenter)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ type BlankWidget struct {
|
|||||||
id string
|
id string
|
||||||
x, y int
|
x, y int
|
||||||
keyMap KeyMap
|
keyMap KeyMap
|
||||||
|
|
||||||
|
wantH, wantW int
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Widget = (*BlankWidget)(nil)
|
var _ Widget = (*BlankWidget)(nil)
|
||||||
@@ -71,7 +73,10 @@ func (w *BlankWidget) SetW(wd int) {}
|
|||||||
func (w *BlankWidget) SetH(h int) {}
|
func (w *BlankWidget) SetH(h int) {}
|
||||||
func (w *BlankWidget) GetW() int { return 0 }
|
func (w *BlankWidget) GetW() int { return 0 }
|
||||||
func (w *BlankWidget) GetH() int { return 0 }
|
func (w *BlankWidget) GetH() int { return 0 }
|
||||||
func (w *BlankWidget) WantW() int { return 0 }
|
func (w *BlankWidget) WantW() int { return w.wantW }
|
||||||
func (w *BlankWidget) WantH() int { return 0 }
|
func (w *BlankWidget) WantH() int { return w.wantH }
|
||||||
func (w *BlankWidget) MinW() int { return 0 }
|
func (w *BlankWidget) MinW() int { return 0 }
|
||||||
func (w *BlankWidget) MinH() int { return 0 }
|
func (w *BlankWidget) MinH() int { return 0 }
|
||||||
|
|
||||||
|
func (w *BlankWidget) SetWantH(v int) { w.wantH = v }
|
||||||
|
func (w *BlankWidget) SetWantW(v int) { w.wantW = v }
|
||||||
|
|||||||
17
wdgt_cli.go
17
wdgt_cli.go
@@ -40,6 +40,7 @@ type Cli struct {
|
|||||||
active bool
|
active bool
|
||||||
visible bool
|
visible bool
|
||||||
focusable bool
|
focusable bool
|
||||||
|
minimized bool
|
||||||
|
|
||||||
title string
|
title string
|
||||||
rawLog []string
|
rawLog []string
|
||||||
@@ -77,6 +78,9 @@ func (w *Cli) Init(id string, s tcell.Style) {
|
|||||||
func (w *Cli) Id() string { return w.id }
|
func (w *Cli) Id() string { return w.id }
|
||||||
func (w *Cli) HandleResize(ev *tcell.EventResize) {
|
func (w *Cli) HandleResize(ev *tcell.EventResize) {
|
||||||
w.w, w.h = ev.Size()
|
w.w, w.h = ev.Size()
|
||||||
|
if w.minimized {
|
||||||
|
w.h = 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Cli) SetKeyMap(km KeyMap) { w.keyMap = km }
|
func (w *Cli) SetKeyMap(km KeyMap) { w.keyMap = km }
|
||||||
@@ -174,8 +178,6 @@ func (w *Cli) Draw(screen tcell.Screen) {
|
|||||||
wh.DrawText(x, y, cursor, dStyle.Reverse(w.active), screen)
|
wh.DrawText(x, y, cursor, dStyle.Reverse(w.active), screen)
|
||||||
x += 1
|
x += 1
|
||||||
wh.DrawText(x, y, wh.PadR(post, w.w-x-2), dStyle, screen)
|
wh.DrawText(x, y, wh.PadR(post, w.w-x-2), dStyle, screen)
|
||||||
// wh.DrawText(w.x, y+1, fmt.Sprintf("Index: %d", w.historyPosition), dStyle, screen)
|
|
||||||
// x += len(post) - 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Cli) Active() bool { return w.active }
|
func (w *Cli) Active() bool { return w.active }
|
||||||
@@ -196,7 +198,13 @@ func (w *Cli) SetW(wd int) { w.w = wd }
|
|||||||
func (w *Cli) SetH(h int) { w.h = h }
|
func (w *Cli) SetH(h int) { w.h = h }
|
||||||
func (w *Cli) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
|
func (w *Cli) SetSize(c Coord) { w.w, w.h = c.X, c.Y }
|
||||||
func (w *Cli) WantW() int { return wh.MaxInt }
|
func (w *Cli) WantW() int { return wh.MaxInt }
|
||||||
func (w *Cli) WantH() int { return wh.MaxInt }
|
func (w *Cli) WantH() int {
|
||||||
|
if w.minimized {
|
||||||
|
return 3
|
||||||
|
} else {
|
||||||
|
return wh.MaxInt
|
||||||
|
}
|
||||||
|
}
|
||||||
func (w *Cli) MinW() int { return 20 }
|
func (w *Cli) MinW() int { return 20 }
|
||||||
func (w *Cli) MinH() int { return 6 }
|
func (w *Cli) MinH() int { return 6 }
|
||||||
|
|
||||||
@@ -341,6 +349,9 @@ func (w *Cli) Clear() {
|
|||||||
w.log = []string{}
|
w.log = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Cli) SetMinimized(m bool) { w.minimized = m }
|
||||||
|
func (w *Cli) IsMinimized() bool { return w.minimized }
|
||||||
|
|
||||||
type cliCommand func(args ...string) bool
|
type cliCommand func(args ...string) bool
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ type Field struct {
|
|||||||
x, y int
|
x, y int
|
||||||
w, h int
|
w, h int
|
||||||
|
|
||||||
filter func(*tcell.EventKey) bool
|
filter func(tcell.EventKey) bool
|
||||||
onChange func(prev, curr string)
|
onChange func(prev, curr string)
|
||||||
|
|
||||||
keyMap KeyMap
|
keyMap KeyMap
|
||||||
@@ -60,9 +60,9 @@ func (w *Field) 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.filter = func(ev *tcell.EventKey) bool {
|
w.filter = func(ev tcell.EventKey) bool {
|
||||||
return wh.IsBS(*ev) ||
|
return wh.IsBS(ev) ||
|
||||||
wh.KeyIsDisplayable(*ev)
|
wh.KeyIsDisplayable(ev)
|
||||||
}
|
}
|
||||||
w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{
|
w.keyMap = NewKeyMap(map[tcell.Key]func(ev *tcell.EventKey) bool{
|
||||||
tcell.KeyLeft: w.handleLeft,
|
tcell.KeyLeft: w.handleLeft,
|
||||||
@@ -98,7 +98,7 @@ func (w *Field) HandleKey(ev *tcell.EventKey) bool {
|
|||||||
if ok := w.keyMap.Handle(ev); ok {
|
if ok := w.keyMap.Handle(ev); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if w.filter != nil && !w.filter(ev) {
|
if w.filter != nil && !w.filter(*ev) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if ev.Key() == tcell.KeyRune {
|
if ev.Key() == tcell.KeyRune {
|
||||||
@@ -238,3 +238,17 @@ func (w *Field) doOnChange(prev, curr string) {
|
|||||||
w.onChange(prev, curr)
|
w.onChange(prev, curr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Field) SetFilter(f func(ev tcell.EventKey) bool) {
|
||||||
|
w.filter = func(ev tcell.EventKey) bool {
|
||||||
|
// We always want to make sure we allow backspace.
|
||||||
|
if wh.IsBS(ev) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// We also always want to make sure it's displayable
|
||||||
|
if !wh.KeyIsDisplayable(ev) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return f(ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -275,6 +275,12 @@ func (w *LinearLayout) findActiveOrFirst() Widget {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *LinearLayout) ActivateWidget(n Widget) {
|
||||||
|
for i := range w.widgets {
|
||||||
|
w.widgets[i].SetActive(w.widgets[i] == n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
21
wdgt_menu.go
21
wdgt_menu.go
@@ -140,6 +140,7 @@ func (w *Menu) HandleKey(ev *tcell.EventKey) bool {
|
|||||||
} else if w.items[w.cursor].HandleKey(ev) {
|
} else if w.items[w.cursor].HandleKey(ev) {
|
||||||
// Active menuitem consumes this event
|
// Active menuitem consumes this event
|
||||||
if ev.Key() == tcell.KeyEnter {
|
if ev.Key() == tcell.KeyEnter {
|
||||||
|
w.cursor = 0
|
||||||
w.SetActive(false)
|
w.SetActive(false)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -148,6 +149,21 @@ func (w *Menu) HandleKey(ev *tcell.EventKey) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// See if we can find an item that matches the key pressed
|
// See if we can find an item that matches the key pressed
|
||||||
|
for i := range w.items {
|
||||||
|
if wh.RuneEqualsNC(ev.Rune(), w.items[i].GetHotKey()) {
|
||||||
|
if w.items[i].Active() {
|
||||||
|
if w.items[i].HandleKey(ev) {
|
||||||
|
// Reset the cursor
|
||||||
|
w.cursor = 0
|
||||||
|
w.SetActive(false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.cursor = i
|
||||||
|
// w.items[i].SetActive(true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,9 +194,11 @@ func (w *Menu) drawHMenu(screen tcell.Screen) {
|
|||||||
}
|
}
|
||||||
x += 2
|
x += 2
|
||||||
if w.expanded || (w.active && !w.manualExpand) {
|
if w.expanded || (w.active && !w.manualExpand) {
|
||||||
|
// pos := w.GetPos()
|
||||||
// TODO: Use DrawOffset?
|
// TODO: Use DrawOffset?
|
||||||
for i := range w.items {
|
for i := range w.items {
|
||||||
w.items[i].SetActive(w.active && w.cursor == i)
|
w.items[i].SetActive(w.active && w.cursor == i)
|
||||||
|
// pos.DrawOffset(w.items[i], screen)
|
||||||
w.items[i].SetPos(Coord{X: x, Y: y})
|
w.items[i].SetPos(Coord{X: x, Y: y})
|
||||||
w.items[i].Draw(screen)
|
w.items[i].Draw(screen)
|
||||||
x += len(w.items[i].Label()) + 2
|
x += len(w.items[i].Label()) + 2
|
||||||
@@ -371,8 +389,9 @@ func (w *Menu) MoveDown(ev *tcell.EventKey) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Menu) CreateMenuItem(lbl string, do func() bool, subItems ...*MenuItem) *MenuItem {
|
func (w *Menu) CreateMenuItem(lbl string, do func() bool, hotKey rune, subItems ...*MenuItem) *MenuItem {
|
||||||
d := NewMenuItem(fmt.Sprintf("menuitem-%s", lbl), tcell.StyleDefault)
|
d := NewMenuItem(fmt.Sprintf("menuitem-%s", lbl), tcell.StyleDefault)
|
||||||
|
d.SetHotKey(hotKey)
|
||||||
d.SetLabel(lbl)
|
d.SetLabel(lbl)
|
||||||
d.SetOnPressed(do)
|
d.SetOnPressed(do)
|
||||||
if len(subItems) > 0 {
|
if len(subItems) > 0 {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Sub-Menus
|
||||||
type MenuItem struct {
|
type MenuItem struct {
|
||||||
id string
|
id string
|
||||||
label string
|
label string
|
||||||
@@ -44,6 +45,8 @@ type MenuItem struct {
|
|||||||
items []*MenuItem
|
items []*MenuItem
|
||||||
onPressed func() bool
|
onPressed func() bool
|
||||||
|
|
||||||
|
hotKey rune
|
||||||
|
|
||||||
manualExpand bool
|
manualExpand bool
|
||||||
expanded bool
|
expanded bool
|
||||||
disabled bool
|
disabled bool
|
||||||
@@ -101,6 +104,20 @@ func (w *MenuItem) HandleKey(ev *tcell.EventKey) bool {
|
|||||||
if !w.active {
|
if !w.active {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// If the user hits the hotkey of this active item, call 'Enter' on it
|
||||||
|
if wh.RuneEqualsNC(ev.Rune(), w.hotKey) {
|
||||||
|
w.HandleKey(tcell.NewEventKey(tcell.KeyEnter, 0, 0))
|
||||||
|
}
|
||||||
|
for i := range w.items {
|
||||||
|
if wh.RuneEqualsNC(ev.Rune(), w.items[i].GetHotKey()) {
|
||||||
|
if w.items[i].Active() {
|
||||||
|
return w.items[i].HandleKey(ev)
|
||||||
|
}
|
||||||
|
w.cursor = i
|
||||||
|
w.updateActive()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
// Look for a sub-item that's selected
|
// Look for a sub-item that's selected
|
||||||
return w.keyMap.Handle(ev)
|
return w.keyMap.Handle(ev)
|
||||||
}
|
}
|
||||||
@@ -116,18 +133,30 @@ func (w *MenuItem) Draw(screen tcell.Screen) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
st := w.style.Dim(w.disabled).Italic(w.disabled)
|
st := w.style.Dim(w.disabled).Italic(w.disabled)
|
||||||
// st := w.style.Reverse(w.active).Dim(w.disabled).Italic(w.disabled)
|
|
||||||
x, y := w.x, w.y
|
x, y := w.x, w.y
|
||||||
// wd := w.w
|
fndHotKey := w.GetHotKey() != 0
|
||||||
if w.expanded {
|
if w.expanded {
|
||||||
if len(w.items) > 0 {
|
if len(w.items) > 0 {
|
||||||
wh.DrawText(x, y, fmt.Sprintf("╭%s╮", w.label), st, screen)
|
screen.SetContent(x, y, '╭', nil, st)
|
||||||
wh.DrawText(x+1, y, fmt.Sprintf("%s", w.label), st.Reverse(true), screen)
|
x += 1
|
||||||
y += 1
|
for i := range w.label {
|
||||||
if len(w.items) > 0 {
|
if fndHotKey && wh.RuneEqualsNC(rune(w.label[i]), w.hotKey) {
|
||||||
wh.TitledBorderFilled(w.x-1, y, w.x+w.WantW(), y+w.WantH(), fmt.Sprintf("╯%s╰", strings.Repeat(" ", len(w.label))), wh.BRD_CSIMPLE, w.style, screen)
|
screen.SetContent(x, y, rune(w.label[i]), nil, st.Reverse(true).Underline(true))
|
||||||
|
fndHotKey = false
|
||||||
|
} else {
|
||||||
|
screen.SetContent(x, y, rune(w.label[i]), nil, st.Reverse(true))
|
||||||
}
|
}
|
||||||
x += 1
|
x += 1
|
||||||
|
}
|
||||||
|
screen.SetContent(x, y, '╮', nil, st)
|
||||||
|
x = w.x
|
||||||
|
y += 1
|
||||||
|
if len(w.items) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wh.BorderFilled(w.x-1, y, w.x+w.WantW(), y+w.WantH(), wh.BRD_CSIMPLE, w.style, screen)
|
||||||
|
wh.DrawText(w.x, y, fmt.Sprintf("╯%s╰", strings.Repeat(" ", len(w.label))), w.style, screen)
|
||||||
|
x += 1
|
||||||
y += 1
|
y += 1
|
||||||
// pos := w.GetPos()
|
// pos := w.GetPos()
|
||||||
for i := range w.items {
|
for i := range w.items {
|
||||||
@@ -138,10 +167,32 @@ func (w *MenuItem) Draw(screen tcell.Screen) {
|
|||||||
y++
|
y++
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wh.DrawText(x, y, fmt.Sprintf(" %s ", w.label), st.Reverse(true), screen)
|
screen.SetContent(x, y, ' ', nil, st)
|
||||||
|
x += 1
|
||||||
|
for i := range w.label {
|
||||||
|
if fndHotKey && wh.RuneEqualsNC(rune(w.label[i]), w.hotKey) {
|
||||||
|
screen.SetContent(x, y, rune(w.label[i]), nil, st.Reverse(true).Underline(true))
|
||||||
|
fndHotKey = false
|
||||||
|
} else {
|
||||||
|
screen.SetContent(x, y, rune(w.label[i]), nil, st.Reverse(true))
|
||||||
|
}
|
||||||
|
x += 1
|
||||||
|
}
|
||||||
|
screen.SetContent(x, y, ' ', nil, st)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wh.DrawText(x, y, fmt.Sprintf(" %s ", w.label), st, screen)
|
screen.SetContent(x, y, ' ', nil, st)
|
||||||
|
x += 1
|
||||||
|
for i := range w.label {
|
||||||
|
if fndHotKey && wh.RuneEqualsNC(rune(w.label[i]), w.hotKey) {
|
||||||
|
screen.SetContent(x, y, rune(w.label[i]), nil, st.Underline(true))
|
||||||
|
fndHotKey = false
|
||||||
|
} else {
|
||||||
|
screen.SetContent(x, y, rune(w.label[i]), nil, st)
|
||||||
|
}
|
||||||
|
x += 1
|
||||||
|
}
|
||||||
|
screen.SetContent(x, y, ' ', nil, st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +218,7 @@ func (w *MenuItem) GetH() int { return w.y }
|
|||||||
func (w *MenuItem) MinW() int { return w.w }
|
func (w *MenuItem) MinW() int { return w.w }
|
||||||
func (w *MenuItem) MinH() int { return w.y }
|
func (w *MenuItem) MinH() int { return w.y }
|
||||||
func (w *MenuItem) WantW() int {
|
func (w *MenuItem) WantW() int {
|
||||||
ret := len(w.label) + 2
|
ret := len(w.label) + 4
|
||||||
if len(w.items) > 0 {
|
if len(w.items) > 0 {
|
||||||
for i := range w.items {
|
for i := range w.items {
|
||||||
if w.items[i].WantW() > ret {
|
if w.items[i].WantW() > ret {
|
||||||
@@ -263,3 +314,6 @@ func (w *MenuItem) FindItem(id string) *MenuItem {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *MenuItem) SetHotKey(r rune) { w.hotKey = r }
|
||||||
|
func (w *MenuItem) GetHotKey() rune { return w.hotKey }
|
||||||
|
|||||||
@@ -220,10 +220,11 @@ func (w *TopMenuLayout) Log(txt string, args ...any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TopMenuLayout) CreateMenuItem(id, lbl string, do func() bool, subItems ...*MenuItem) *MenuItem {
|
func (w *TopMenuLayout) CreateMenuItem(id, lbl string, do func() bool, hotKey rune, subItems ...*MenuItem) *MenuItem {
|
||||||
d := NewMenuItem(id, tcell.StyleDefault)
|
d := NewMenuItem(id, tcell.StyleDefault)
|
||||||
d.SetLabel(lbl)
|
d.SetLabel(lbl)
|
||||||
d.SetOnPressed(do)
|
d.SetOnPressed(do)
|
||||||
|
d.SetHotKey(hotKey)
|
||||||
if len(subItems) > 0 {
|
if len(subItems) > 0 {
|
||||||
d.AddItems(subItems...)
|
d.AddItems(subItems...)
|
||||||
}
|
}
|
||||||
@@ -247,3 +248,9 @@ func (w *TopMenuLayout) SetItemDisabled(id string, d bool) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *TopMenuLayout) FindItem(id string) *MenuItem { return w.menu.FindItem(id) }
|
func (w *TopMenuLayout) FindItem(id string) *MenuItem { return w.menu.FindItem(id) }
|
||||||
|
func (w *TopMenuLayout) CloseMenu() {
|
||||||
|
if w.menu != nil && w.menu.Active() {
|
||||||
|
w.menu.SetActive(false)
|
||||||
|
w.widget.SetActive(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user