185 lines
3.8 KiB
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()
|
|
}
|