src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/cli/tk/combobox.go (about) 1 package tk 2 3 import ( 4 "src.elv.sh/pkg/cli/term" 5 ) 6 7 // ComboBox is a Widget that combines a ListBox and a CodeArea. 8 type ComboBox interface { 9 Widget 10 // Returns the embedded codearea widget. 11 CodeArea() CodeArea 12 // Returns the embedded listbox widget. 13 ListBox() ListBox 14 // Forces the filtering to rerun. 15 Refilter() 16 } 17 18 // ComboBoxSpec specifies the configuration and initial state for ComboBox. 19 type ComboBoxSpec struct { 20 CodeArea CodeAreaSpec 21 ListBox ListBoxSpec 22 OnFilter func(ComboBox, string) 23 } 24 25 type comboBox struct { 26 codeArea CodeArea 27 listBox ListBox 28 OnFilter func(ComboBox, string) 29 30 // Last filter value. 31 lastFilter string 32 } 33 34 // NewComboBox creates a new ComboBox from the given spec. 35 func NewComboBox(spec ComboBoxSpec) ComboBox { 36 if spec.OnFilter == nil { 37 spec.OnFilter = func(ComboBox, string) {} 38 } 39 w := &comboBox{ 40 codeArea: NewCodeArea(spec.CodeArea), 41 listBox: NewListBox(spec.ListBox), 42 OnFilter: spec.OnFilter, 43 } 44 w.OnFilter(w, "") 45 return w 46 } 47 48 // Render renders the codearea and the listbox below it. 49 func (w *comboBox) Render(width, height int) *term.Buffer { 50 buf := w.codeArea.Render(width, height) 51 bufListBox := w.listBox.Render(width, height-len(buf.Lines)) 52 buf.Extend(bufListBox, false) 53 return buf 54 } 55 56 func (w *comboBox) MaxHeight(width, height int) int { 57 return w.codeArea.MaxHeight(width, height) + w.listBox.MaxHeight(width, height) 58 } 59 60 // Handle first lets the listbox handle the event, and if it is unhandled, lets 61 // the codearea handle it. If the codearea has handled the event and the code 62 // content has changed, it calls OnFilter with the new content. 63 func (w *comboBox) Handle(event term.Event) bool { 64 if w.listBox.Handle(event) { 65 return true 66 } 67 if w.codeArea.Handle(event) { 68 filter := w.codeArea.CopyState().Buffer.Content 69 if filter != w.lastFilter { 70 w.OnFilter(w, filter) 71 w.lastFilter = filter 72 } 73 return true 74 } 75 return false 76 } 77 78 func (w *comboBox) Refilter() { 79 w.OnFilter(w, w.codeArea.CopyState().Buffer.Content) 80 } 81 82 func (w *comboBox) CodeArea() CodeArea { return w.codeArea } 83 func (w *comboBox) ListBox() ListBox { return w.listBox }