elvish/pkg/cli/tk/combobox.go

84 lines
2.1 KiB
Go
Raw Normal View History

package tk
2019-08-19 06:11:09 +08:00
import (
"src.elv.sh/pkg/cli/term"
2019-08-19 06:11:09 +08:00
)
// ComboBox is a Widget that combines a ListBox and a CodeArea.
type ComboBox interface {
2019-12-26 08:52:22 +08:00
Widget
// Returns the embedded codearea widget.
2019-12-26 08:52:22 +08:00
CodeArea() CodeArea
// Returns the embedded listbox widget.
2019-12-26 08:52:22 +08:00
ListBox() ListBox
// Forces the filtering to rerun.
Refilter()
}
// ComboBoxSpec specifies the configuration and initial state for ComboBox.
type ComboBoxSpec struct {
2019-12-26 08:52:22 +08:00
CodeArea CodeAreaSpec
ListBox ListBoxSpec
OnFilter func(ComboBox, string)
}
type comboBox struct {
2019-12-26 08:52:22 +08:00
codeArea CodeArea
listBox ListBox
OnFilter func(ComboBox, string)
2019-08-19 06:11:09 +08:00
// Last filter value.
lastFilter string
}
// NewComboBox creates a new ComboBox from the given spec.
func NewComboBox(spec ComboBoxSpec) ComboBox {
if spec.OnFilter == nil {
spec.OnFilter = func(ComboBox, string) {}
2019-08-19 06:11:09 +08:00
}
w := &comboBox{
2019-12-26 08:52:22 +08:00
codeArea: NewCodeArea(spec.CodeArea),
listBox: NewListBox(spec.ListBox),
OnFilter: spec.OnFilter,
2019-08-19 06:11:09 +08:00
}
w.OnFilter(w, "")
return w
2019-08-19 06:11:09 +08:00
}
// Render renders the codearea and the listbox below it.
func (w *comboBox) Render(width, height int) *term.Buffer {
buf := w.codeArea.Render(width, height)
bufListBox := w.listBox.Render(width, height-len(buf.Lines))
2019-08-19 06:11:09 +08:00
buf.Extend(bufListBox, false)
return buf
}
func (w *comboBox) MaxHeight(width, height int) int {
return w.codeArea.MaxHeight(width, height) + w.listBox.MaxHeight(width, height)
}
2019-08-19 06:11:09 +08:00
// Handle first lets the listbox handle the event, and if it is unhandled, lets
// the codearea handle it. If the codearea has handled the event and the code
// content has changed, it calls OnFilter with the new content.
func (w *comboBox) Handle(event term.Event) bool {
if w.listBox.Handle(event) {
2019-08-19 06:11:09 +08:00
return true
}
if w.codeArea.Handle(event) {
filter := w.codeArea.CopyState().Buffer.Content
2019-08-19 06:11:09 +08:00
if filter != w.lastFilter {
w.OnFilter(w, filter)
2019-08-19 06:11:09 +08:00
w.lastFilter = filter
}
return true
}
return false
}
func (w *comboBox) Refilter() {
w.OnFilter(w, w.codeArea.CopyState().Buffer.Content)
}
2019-12-26 08:52:22 +08:00
func (w *comboBox) CodeArea() CodeArea { return w.codeArea }
func (w *comboBox) ListBox() ListBox { return w.listBox }