Desktop application launcher
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.3 KiB

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 *cview.List
detailView *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()
// TODO this breaks highlighting the line
/*
cview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
cview.Styles.PrimaryTextColor = tcell.ColorDefault
cview.Styles.ScrollBarColor = tcell.ColorDefault
*/
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 = cview.NewList()
entryList.ShowSecondaryText(false)
entryList.SetHighlightFullLine(true)
grid := cview.NewGrid()
grid.SetBorders(false)
grid.SetRows(1, -1)
detailView = cview.NewTextView()
detailView.SetTextAlign(cview.AlignLeft)
detailView.SetWrap(true)
detailView.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 {
box := cview.NewBox()
box.SetVisible(false)
grid.SetColumns(-1, 1, -1)
grid.AddItem(inputView, 0, 0, 1, 2, 0, 0, true)
grid.AddItem(entryList, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(box, 1, 1, 1, 1, 0, 0, false)
grid.AddItem(detailView, 1, 2, 1, 1, 0, 0, false)
}
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
defer app.QueueUpdateDraw(updateEntryInfo)
if event.Key() == tcell.KeyUp || event.Key() == tcell.KeyDown || event.Key() == tcell.KeyPgUp || event.Key() == tcell.KeyPgDn {
entryList.InputHandler()(event, func(p cview.Primitive) {
app.SetFocus(p)
})
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)
updateEntries("")
go gmenu.HandleInput(func(input string) {
gmenu.FilterEntries()
app.QueueUpdateDraw(updateEntryInfo)
})
gmenu.SetInput("")
app.SetFocus(entryList)
return app, nil
}
func closeTUI() {
if closedTUI {
return
}
closedTUI = true
app.Stop()
}