gmenu/cmd/gmenu/gui.go

185 lines
3.8 KiB
Go

package main
import (
"strings"
"code.rocketnine.space/tslocum/cview"
"code.rocketnine.space/tslocum/gmenu/pkg/gmenu"
"github.com/gdamore/tcell/v2"
)
var (
app *cview.Application
inputView *cview.InputField
entryList *optionsList
appDetailsView *cview.TextView
closedTUI bool
)
type optionsList struct {
*cview.TextView
options []string
origin int
selected int
shown int
}
func newOptionsList(options []string) *optionsList {
opts := optionsList{
TextView: cview.NewTextView(),
options: options,
}
tv := opts.TextView
tv.SetDynamicColors(true)
tv.SetWrap(true)
tv.SetWordWrap(false)
return &opts
}
func (r *optionsList) Draw(screen tcell.Screen) {
_, height := screen.Size()
var b strings.Builder
r.shown = 0
for i, option := range r.options {
if i < r.origin || i-r.origin >= height-1 {
continue
}
if i == r.selected {
b.WriteString(`[::r]`)
}
if i-r.origin < height-2 {
b.WriteString(option + "\n")
} else {
b.WriteString(option)
}
if i == r.selected {
b.WriteString(`[-:-:-]`)
}
r.shown++
}
tv := r.TextView
tv.SetText(b.String())
tv.Highlight("gmenu")
tv.ScrollToBeginning()
tv.Draw(screen)
}
func initTUI() (*cview.Application, error) {
app = cview.NewApplication()
inputView = cview.NewInputField()
inputView.SetLabel("")
inputView.SetFieldWidth(0)
inputView.SetFieldBackgroundColor(tcell.ColorDefault)
inputView.SetFieldTextColor(tcell.ColorDefault)
inputView.SetChangedFunc(func(text string) {
gmenu.SetInput(text)
})
entryList = newOptionsList(nil)
grid := cview.NewGrid()
grid.SetBorders(false)
grid.SetRows(1, -1)
appDetailsView = cview.NewTextView()
appDetailsView.SetTextAlign(cview.AlignLeft)
appDetailsView.SetWrap(true)
appDetailsView.SetWordWrap(true)
if config.HideAppDetails {
grid.SetColumns(-1)
grid.AddItem(inputView, 0, 0, 1, 1, 0, 0, true)
grid.AddItem(entryList, 1, 0, 1, 1, 0, 0, false)
} else {
grid.SetColumns(-1, -1)
grid.AddItem(inputView, 0, 0, 1, 2, 0, 0, true)
grid.AddItem(entryList, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(appDetailsView, 1, 1, 1, 1, 0, 0, false)
}
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
defer app.QueueUpdateDraw(updateEntryInfo)
if event.Key() == tcell.KeyUp {
if entryList.origin > 0 && entryList.selected == entryList.origin {
entryList.origin--
}
if entryList.selected > 0 {
entryList.selected--
}
event = nil
} else if event.Key() == tcell.KeyDown {
if entryList.selected < len(entryList.options)-1 {
entryList.selected++
if entryList.selected > entryList.origin+entryList.shown-1 {
entryList.origin++
}
}
event = nil
} else if event.Key() == tcell.KeyPgUp {
if entryList.origin == 0 {
entryList.selected = 0
return nil
}
entryList.origin -= entryList.shown - 2
if entryList.origin < 0 {
entryList.origin = 0
}
entryList.selected = entryList.origin
return nil
} else if event.Key() == tcell.KeyPgDn {
numEntries := len(gmenu.FilteredEntries)
if entryList.origin >= numEntries-entryList.shown {
entryList.selected = numEntries - 1
return nil
}
entryList.origin += entryList.shown - 2
if entryList.origin > numEntries-entryList.shown {
entryList.origin = numEntries - entryList.shown
}
entryList.selected = entryList.origin
return nil
} else if event.Key() == tcell.KeyEnter || event.Rune() == '\n' {
runInTerminal := event.Modifiers()&tcell.ModAlt > 0
err := listSelect(runInTerminal)
if err != nil {
panic(err)
}
} else if event.Key() == tcell.KeyEscape {
done <- true
}
return event
})
app.SetRoot(grid, true)
go gmenu.HandleInput(updateEntries)
gmenu.SetInput("")
return app, nil
}
func closeTUI() {
if closedTUI {
return
}
closedTUI = true
app.Stop()
}