2021-02-12 02:49:00 +08:00
|
|
|
package tk
|
2019-08-19 06:11:09 +08:00
|
|
|
|
|
|
|
import (
|
2021-01-27 09:28:38 +08:00
|
|
|
"src.elv.sh/pkg/cli/term"
|
2019-08-19 06:11:09 +08:00
|
|
|
)
|
|
|
|
|
2019-12-25 00:00:55 +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
|
2019-11-15 07:50:35 +08:00
|
|
|
// Returns the embedded codearea widget.
|
2019-12-26 08:52:22 +08:00
|
|
|
CodeArea() CodeArea
|
2019-11-15 07:50:35 +08:00
|
|
|
// Returns the embedded listbox widget.
|
2019-12-26 08:52:22 +08:00
|
|
|
ListBox() ListBox
|
2019-11-15 07:50:35 +08:00
|
|
|
// Forces the filtering to rerun.
|
|
|
|
Refilter()
|
2019-10-31 08:09:07 +08:00
|
|
|
}
|
|
|
|
|
2019-12-25 00:00:55 +08:00
|
|
|
// ComboBoxSpec specifies the configuration and initial state for ComboBox.
|
|
|
|
type ComboBoxSpec struct {
|
2019-12-26 08:52:22 +08:00
|
|
|
CodeArea CodeAreaSpec
|
|
|
|
ListBox ListBoxSpec
|
2019-12-25 00:00:55 +08:00
|
|
|
OnFilter func(ComboBox, string)
|
2019-10-31 08:09:07 +08:00
|
|
|
}
|
|
|
|
|
2019-12-25 00:00:55 +08:00
|
|
|
type comboBox struct {
|
2019-12-26 08:52:22 +08:00
|
|
|
codeArea CodeArea
|
|
|
|
listBox ListBox
|
2019-12-25 00:00:55 +08:00
|
|
|
OnFilter func(ComboBox, string)
|
2019-08-19 06:11:09 +08:00
|
|
|
|
|
|
|
// Last filter value.
|
|
|
|
lastFilter string
|
|
|
|
}
|
|
|
|
|
2019-12-25 00:00:55 +08:00
|
|
|
// NewComboBox creates a new ComboBox from the given spec.
|
|
|
|
func NewComboBox(spec ComboBoxSpec) ComboBox {
|
2019-11-01 06:07:32 +08:00
|
|
|
if spec.OnFilter == nil {
|
2019-12-25 00:00:55 +08:00
|
|
|
spec.OnFilter = func(ComboBox, string) {}
|
2019-08-19 06:11:09 +08:00
|
|
|
}
|
2019-12-25 00:00:55 +08:00
|
|
|
w := &comboBox{
|
2019-12-26 08:52:22 +08:00
|
|
|
codeArea: NewCodeArea(spec.CodeArea),
|
|
|
|
listBox: NewListBox(spec.ListBox),
|
2019-11-01 06:07:32 +08:00
|
|
|
OnFilter: spec.OnFilter,
|
2019-08-19 06:11:09 +08:00
|
|
|
}
|
2019-10-31 08:09:07 +08:00
|
|
|
w.OnFilter(w, "")
|
|
|
|
return w
|
2019-08-19 06:11:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Render renders the codearea and the listbox below it.
|
2019-12-25 00:00:55 +08:00
|
|
|
func (w *comboBox) Render(width, height int) *term.Buffer {
|
2019-10-31 08:09:07 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-05 08:06:12 +08:00
|
|
|
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.
|
2019-12-25 00:00:55 +08:00
|
|
|
func (w *comboBox) Handle(event term.Event) bool {
|
2019-10-31 08:09:07 +08:00
|
|
|
if w.listBox.Handle(event) {
|
2019-08-19 06:11:09 +08:00
|
|
|
return true
|
|
|
|
}
|
2019-10-31 08:09:07 +08:00
|
|
|
if w.codeArea.Handle(event) {
|
2019-11-04 07:22:36 +08:00
|
|
|
filter := w.codeArea.CopyState().Buffer.Content
|
2019-08-19 06:11:09 +08:00
|
|
|
if filter != w.lastFilter {
|
2019-10-31 08:09:07 +08:00
|
|
|
w.OnFilter(w, filter)
|
2019-08-19 06:11:09 +08:00
|
|
|
w.lastFilter = filter
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2019-10-31 08:09:07 +08:00
|
|
|
|
2019-12-25 00:00:55 +08:00
|
|
|
func (w *comboBox) Refilter() {
|
2019-11-15 07:50:35 +08:00
|
|
|
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 }
|