diff --git a/contextmenu.go b/contextmenu.go index 13649f7..85a337e 100644 --- a/contextmenu.go +++ b/contextmenu.go @@ -60,11 +60,11 @@ func (c *ContextMenu) AddContextItem(text string, shortcut rune, selected func(i c.initializeList() - c.list.AddItem(text, "", shortcut, c.wrap(selected)) + c.list.AddItem(NewListItem(text).SetShortcut(shortcut).SetSelectedFunc(c.wrap(selected))) if text == "" && shortcut == 0 { c.list.Lock() index := len(c.list.items) - 1 - c.list.items[index].Enabled = false + c.list.items[index].enabled = false c.list.Unlock() } @@ -139,14 +139,14 @@ func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) { c.list.Lock() for i, item := range c.list.items { - if item.Enabled { + if item.enabled { c.list.currentItem = i break } } c.list.Unlock() - c.list.SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) { + c.list.SetSelectedFunc(func(index int, item *ListItem) { c.l.Lock() // A context item was selected. Close the menu. @@ -154,7 +154,7 @@ func (c *ContextMenu) show(item int, x int, y int, setFocus func(Primitive)) { if c.selected != nil { c.l.Unlock() - c.selected(index, mainText, shortcut) + c.selected(index, item.mainText, item.shortcut) } else { c.l.Unlock() } diff --git a/demos/inputfield/autocomplete/main.go b/demos/inputfield/autocomplete/main.go index 0d5b3a8..72809f1 100644 --- a/demos/inputfield/autocomplete/main.go +++ b/demos/inputfield/autocomplete/main.go @@ -19,13 +19,13 @@ func main() { SetDoneFunc(func(key tcell.Key) { app.Stop() }) - inputField.SetAutocompleteFunc(func(currentText string) (entries []string) { + inputField.SetAutocompleteFunc(func(currentText string) (entries []*cview.ListItem) { if len(currentText) == 0 { return } for _, word := range words { if strings.HasPrefix(strings.ToLower(word), strings.ToLower(currentText)) { - entries = append(entries, word) + entries = append(entries, cview.NewListItem(word)) } } if len(entries) <= 1 { diff --git a/demos/inputfield/autocompleteasync/main.go b/demos/inputfield/autocompleteasync/main.go index f866194..40380d2 100644 --- a/demos/inputfield/autocompleteasync/main.go +++ b/demos/inputfield/autocompleteasync/main.go @@ -26,8 +26,8 @@ func main() { // Set up autocomplete function. var mutex sync.Mutex - prefixMap := make(map[string][]string) - inputField.SetAutocompleteFunc(func(currentText string) []string { + prefixMap := make(map[string][]*cview.ListItem) + inputField.SetAutocompleteFunc(func(currentText string) []*cview.ListItem { // Ignore empty text. prefix := strings.TrimSpace(strings.ToLower(currentText)) if prefix == "" { @@ -57,9 +57,9 @@ func main() { if err := dec.Decode(&companies); err != nil { return } - entries := make([]string, 0, len(companies)) + entries := make([]*cview.ListItem, 0, len(companies)) for _, c := range companies { - entries = append(entries, c.Name) + entries = append(entries, cview.NewListItem(c.Name)) } mutex.Lock() prefixMap[prefix] = entries diff --git a/demos/list/main.go b/demos/list/main.go index e194116..f1860c8 100644 --- a/demos/list/main.go +++ b/demos/list/main.go @@ -12,13 +12,13 @@ func main() { reset := func() { list. Clear(). - AddItem("List item 1", "Some explanatory text", 'a', nil). - AddItem("List item 2", "Some explanatory text", 'b', nil). - AddItem("List item 3", "Some explanatory text", 'c', nil). - AddItem("List item 4", "Some explanatory text", 'd', nil). - AddItem("Quit", "Press to exit", 'q', func() { + AddItem(cview.NewListItem("List item 1").SetSecondaryText("Some explanatory text").SetShortcut('a')). + AddItem(cview.NewListItem("List item 2").SetSecondaryText("Some explanatory text").SetShortcut('b')). + AddItem(cview.NewListItem("List item 3").SetSecondaryText("Some explanatory text").SetShortcut('c')). + AddItem(cview.NewListItem("List item 4").SetSecondaryText("Some explanatory text").SetShortcut('d')). + AddItem(cview.NewListItem("Quit").SetSecondaryText("Press to exit").SetShortcut('q').SetSelectedFunc(func() { app.Stop() - }) + })) list.ContextMenuList().SetItemEnabled(3, false) } diff --git a/demos/presentation/introduction.go b/demos/presentation/introduction.go index 2a0bd03..63a53a8 100644 --- a/demos/presentation/introduction.go +++ b/demos/presentation/introduction.go @@ -9,12 +9,12 @@ func Introduction(nextSlide func()) (title string, content cview.Primitive) { reset := func() { list. Clear(). - AddItem("A Go package for terminal based UIs", "with a special focus on rich interactive widgets", '1', nextSlide). - AddItem("Based on github.com/gdamore/tcell", "Like termbox but better (see tcell docs)", '2', nextSlide). - AddItem("Designed to be simple", `"Hello world" is 5 lines of code`, '3', nextSlide). - AddItem("Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`, '4', nextSlide). - AddItem("Supports context menus", "Right click on one of these items or press Alt+Enter", '5', nextSlide). - AddItem("Extensive documentation", "Demo code is available for each widget", '6', nextSlide) + AddItem(cview.NewListItem("A Go package for terminal based UIs").SetSecondaryText("with a special focus on rich interactive widgets").SetShortcut('1').SetSelectedFunc(nextSlide)). + AddItem(cview.NewListItem("Based on github.com/gdamore/tcell").SetSecondaryText("Like termbox but better (see tcell docs)").SetShortcut('2').SetSelectedFunc(nextSlide)). + AddItem(cview.NewListItem("Designed to be simple").SetSecondaryText(`"Hello world" is 5 lines of code`).SetShortcut('3').SetSelectedFunc(nextSlide)). + AddItem(cview.NewListItem("Good for data entry").SetSecondaryText(`For charts, use "termui" - for low-level views, use "gocui" - ...`).SetShortcut('4').SetSelectedFunc(nextSlide)). + AddItem(cview.NewListItem("Supports context menus").SetSecondaryText("Right click on one of these items or press Alt+Enter").SetShortcut('5').SetSelectedFunc(nextSlide)). + AddItem(cview.NewListItem("Extensive documentation").SetSecondaryText("Demo code is available for each widget").SetShortcut('6').SetSelectedFunc(nextSlide)) list.ContextMenuList().SetItemEnabled(3, false) } diff --git a/demos/presentation/table.go b/demos/presentation/table.go index e11b9ea..91fb99d 100644 --- a/demos/presentation/table.go +++ b/demos/presentation/table.go @@ -341,14 +341,14 @@ func Table(nextSlide func()) (title string, content cview.Primitive) { } list.ShowSecondaryText(false). - AddItem("Basic table", "", 'b', basic). - AddItem("Table with separator", "", 's', separator). - AddItem("Table with borders", "", 'o', borders). - AddItem("Selectable rows", "", 'r', selectRow). - AddItem("Selectable columns", "", 'c', selectColumn). - AddItem("Selectable cells", "", 'l', selectCell). - AddItem("Navigate", "", 'n', navigate). - AddItem("Next slide", "", 'x', nextSlide) + AddItem(cview.NewListItem("Basic table").SetShortcut('b').SetSelectedFunc(basic)). + AddItem(cview.NewListItem("Table with separator").SetShortcut('s').SetSelectedFunc(separator)). + AddItem(cview.NewListItem("Table with borders").SetShortcut('o').SetSelectedFunc(borders)). + AddItem(cview.NewListItem("Selectable rows").SetShortcut('r').SetSelectedFunc(selectRow)). + AddItem(cview.NewListItem("Selectable columns").SetShortcut('c').SetSelectedFunc(selectColumn)). + AddItem(cview.NewListItem("Selectable cells").SetShortcut('l').SetSelectedFunc(selectCell)). + AddItem(cview.NewListItem("Navigate").SetShortcut('n').SetSelectedFunc(navigate)). + AddItem(cview.NewListItem("Next slide").SetShortcut('x').SetSelectedFunc(nextSlide)) list.SetBorderPadding(1, 1, 2, 2) basic() diff --git a/dropdown.go b/dropdown.go index d3d0a07..0d921ad 100644 --- a/dropdown.go +++ b/dropdown.go @@ -28,7 +28,7 @@ type DropDown struct { // currently selected. currentOption int - // Strings to be placed beefore and after the current option. + // Strings to be placed before and after the current option. currentOptionPrefix, currentOptionSuffix string // The text to be displayed when no option has yet been selected. @@ -370,7 +370,7 @@ func (d *DropDown) AddOption(text string, selected func()) *DropDown { func (d *DropDown) addOption(text string, selected func()) *DropDown { d.options = append(d.options, &dropDownOption{Text: text, Selected: selected}) - d.list.AddItem(d.optionPrefix+text+d.optionSuffix, "", 0, nil) + d.list.AddItem(NewListItem(d.optionPrefix + text + d.optionSuffix)) return d } @@ -507,7 +507,7 @@ func (d *DropDown) Draw(screen tcell.Screen) { // Show the prefix. currentOptionPrefixWidth := TaggedStringWidth(d.currentOptionPrefix) prefixWidth := stringWidth(d.prefix) - listItemText := d.options[d.list.GetCurrentItem()].Text + listItemText := d.options[d.list.GetCurrentItemIndex()].Text Print(screen, d.currentOptionPrefix, x, y, fieldWidth, AlignLeft, fieldTextColor) Print(screen, d.prefix, x+currentOptionPrefixWidth, y, fieldWidth-currentOptionPrefixWidth, AlignLeft, d.prefixTextColor) if len(d.prefix) < len(listItemText) { @@ -598,7 +598,7 @@ func (d *DropDown) openList(setFocus func(Primitive)) { d.open = true optionBefore := d.currentOption - d.list.SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) { + d.list.SetSelectedFunc(func(index int, item *ListItem) { if d.dragging { return // If we're dragging the mouse, we don't want to trigger any events. } diff --git a/inputfield.go b/inputfield.go index 6de2061..0fb6333 100644 --- a/inputfield.go +++ b/inputfield.go @@ -92,9 +92,9 @@ type InputField struct { cursorPos int // An optional autocomplete function which receives the current text of the - // input field and returns a slice of strings to be displayed in a drop-down + // input field and returns a slice of ListItems to be displayed in a drop-down // selection. - autocomplete func(text string) []string + autocomplete func(text string) []*ListItem // The List object which shows the selectable autocomplete entries. If not // nil, the list's main texts represent the current autocomplete entries. @@ -369,12 +369,12 @@ func (i *InputField) SetMaskCharacter(mask rune) *InputField { } // SetAutocompleteFunc sets an autocomplete callback function which may return -// strings to be selected from a drop-down based on the current text of the +// ListItems to be selected from a drop-down based on the current text of the // input field. The drop-down appears only if len(entries) > 0. The callback is // invoked in this function and whenever the current text changes or when // Autocomplete() is called. Entries are cleared when the user selects an entry // or presses Escape. -func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []string)) *InputField { +func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []*ListItem)) *InputField { i.Lock() i.autocomplete = callback i.Unlock() @@ -427,8 +427,9 @@ func (i *InputField) Autocomplete() *InputField { currentEntry := -1 i.autocompleteList.Clear() for index, entry := range entries { - i.autocompleteList.AddItem(entry, "", 0, nil) - if currentEntry < 0 && entry == i.text { + entry.enabled = true + i.autocompleteList.AddItem(entry) + if currentEntry < 0 && entry.mainText == i.text { currentEntry = index } } @@ -778,7 +779,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p case tcell.KeyDown, tcell.KeyTab: // Autocomplete selection. if i.autocompleteList != nil { count := i.autocompleteList.GetItemCount() - newEntry := i.autocompleteList.GetCurrentItem() + 1 + newEntry := i.autocompleteList.GetCurrentItemIndex() + 1 if newEntry >= count { newEntry = 0 } @@ -793,7 +794,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p return case tcell.KeyUp, tcell.KeyBacktab: // Autocomplete selection. if i.autocompleteList != nil { - newEntry := i.autocompleteList.GetCurrentItem() - 1 + newEntry := i.autocompleteList.GetCurrentItemIndex() - 1 if newEntry < 0 { newEntry = i.autocompleteList.GetItemCount() - 1 } diff --git a/list.go b/list.go index 5fbdeae..a695784 100644 --- a/list.go +++ b/list.go @@ -8,13 +8,60 @@ import ( "github.com/gdamore/tcell/v2" ) -// listItem represents one item in a List. -type listItem struct { - Enabled bool // Whether or not the list item is selectable. - MainText string // The main text of the list item. - SecondaryText string // A secondary text to be shown underneath the main text. - Shortcut rune // The key to select the list item directly, 0 if there is no shortcut. - Selected func() // The optional function which is called when the item is selected. +// ListItem represents an item in a List. +type ListItem struct { + enabled bool // Whether or not the list item is selectable. + mainText string // The main text of the list item. + secondaryText string // A secondary text to be shown underneath the main text. + shortcut rune // The key to select the list item directly, 0 if there is no shortcut. + selected func() // The optional function which is called when the item is selected. +} + +// NewListItem returns a new item for the list. +func NewListItem(mainText string) *ListItem { + return &ListItem{ + mainText: mainText, + enabled: true, + } +} + +// SetMainText sets the main text of the list item. +func (l *ListItem) SetMainText(val string) *ListItem { + l.mainText = val + return l +} + +// GetMainText returns the item's main text. +func (l *ListItem) GetMainText() string { + return l.mainText +} + +// SetSecondaryText sets a secondary text to be shown underneath the main text. +func (l *ListItem) SetSecondaryText(val string) *ListItem { + l.secondaryText = val + return l +} + +// GetSecondaryText returns the item's secondary text. +func (l *ListItem) GetSecondaryText() string { + return l.secondaryText +} + +// SetShortcut sets the key to select the ListItem directly, 0 if there is no shortcut. +func (l *ListItem) SetShortcut(val rune) *ListItem { + l.shortcut = val + return l +} + +// GetShortcut returns the ListItem's shortcut. +func (l *ListItem) GetShortcut() rune { + return l.shortcut +} + +// SetSelectedFunc sets a function which is called when the ListItem is selected. +func (l *ListItem) SetSelectedFunc(handler func()) *ListItem { + l.selected = handler + return l } // List displays rows of items, each of which can be selected. @@ -23,7 +70,7 @@ type List struct { *ContextMenu // The items of the list. - items []*listItem + items []*ListItem // The index of the currently selected item. currentItem int @@ -78,11 +125,11 @@ type List struct { // An optional function which is called when the user has navigated to a list // item. - changed func(index int, mainText, secondaryText string, shortcut rune) + changed func(index int, item *ListItem) // An optional function which is called when a list item was selected. This // function will be called even if the list item defines its own callback. - selected func(index int, mainText, secondaryText string, shortcut rune) + selected func(index int, item *ListItem) // An optional function which is called when the user presses the Escape key. done func() @@ -140,7 +187,7 @@ func (l *List) SetCurrentItem(index int) *List { if index != previousItem && l.changed != nil { item := l.items[index] l.Unlock() - l.changed(index, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(index, item) l.Lock() } @@ -148,15 +195,33 @@ func (l *List) SetCurrentItem(index int) *List { return l } -// GetCurrentItem returns the index of the currently selected list item, -// starting at 0 for the first item. -func (l *List) GetCurrentItem() int { +// GetCurrentItem returns the currently selected list item, +// Returns nil if no item is selected. +func (l *List) GetCurrentItem() *ListItem { l.RLock() defer l.RUnlock() + if len(l.items) == 0 || l.currentItem >= len(l.items) { + return nil + } + return l.items[l.currentItem] +} + +// GetCurrentItemIndex returns the index of the currently selected list item, +// starting at 0 for the first item and its struct. +func (l *List) GetCurrentItemIndex() int { + l.RLock() + defer l.RUnlock() return l.currentItem } +// GetItems returns all list items. +func (l *List) GetItems() []*ListItem { + l.RLock() + defer l.RUnlock() + return l.items +} + // RemoveItem removes the item with the given index (starting at 0) from the // list. If a negative index is provided, items are referred to from the back // (-1 = last item, -2 = second-to-last item, and so on). Out of range indices @@ -203,7 +268,7 @@ func (l *List) RemoveItem(index int) *List { if previousItem == index && l.changed != nil { item := l.items[l.currentItem] l.Unlock() - l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(l.currentItem, item) } else { l.Unlock() } @@ -383,11 +448,11 @@ func (l *List) SetWrapAround(wrapAround bool) *List { // SetChangedFunc sets the function which is called when the user navigates to // a list item. The function receives the item's index in the list of items -// (starting with 0), its main text, secondary text, and its shortcut rune. +// (starting with 0) and the list item. // // This function is also called when the first item is added or when // SetCurrentItem() is called. -func (l *List) SetChangedFunc(handler func(index int, mainText string, secondaryText string, shortcut rune)) *List { +func (l *List) SetChangedFunc(handler func(index int, item *ListItem)) *List { l.Lock() defer l.Unlock() @@ -397,9 +462,8 @@ func (l *List) SetChangedFunc(handler func(index int, mainText string, secondary // SetSelectedFunc sets the function which is called when the user selects a // list item by pressing Enter on the current selection. The function receives -// the item's index in the list of items (starting with 0), its main text, -// secondary text, and its shortcut rune. -func (l *List) SetSelectedFunc(handler func(int, string, string, rune)) *List { +// the item's index in the list of items (starting with 0) and its struct. +func (l *List) SetSelectedFunc(handler func(int, *ListItem)) *List { l.Lock() defer l.Unlock() @@ -418,8 +482,8 @@ func (l *List) SetDoneFunc(handler func()) *List { } // AddItem calls InsertItem() with an index of -1. -func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List { - l.InsertItem(-1, mainText, secondaryText, shortcut, selected) +func (l *List) AddItem(item *ListItem) *List { + l.InsertItem(-1, item) return l } @@ -445,16 +509,10 @@ func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected f // The currently selected item will shift its position accordingly. If the list // was previously empty, a "changed" event is fired because the new item becomes // selected. -func (l *List) InsertItem(index int, mainText, secondaryText string, shortcut rune, selected func()) *List { +func (l *List) InsertItem(index int, item *ListItem) *List { l.Lock() - item := &listItem{ - Enabled: true, - MainText: mainText, - SecondaryText: secondaryText, - Shortcut: shortcut, - Selected: selected, - } + item.enabled = true // Shift index to range. if index < 0 { @@ -482,7 +540,7 @@ func (l *List) InsertItem(index int, mainText, secondaryText string, shortcut ru if len(l.items) == 1 && l.changed != nil { item := l.items[0] l.Unlock() - l.changed(0, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(0, item) } else { l.Unlock() } @@ -490,6 +548,15 @@ func (l *List) InsertItem(index int, mainText, secondaryText string, shortcut ru return l } +// GetItem returns the ListItem at the given index. +// Returns nil when index is out of bounds. +func (l *List) GetItem(index int) *ListItem { + if index > len(l.items)-1 { + return nil + } + return l.items[index] +} + // GetItemCount returns the number of items in the list. func (l *List) GetItemCount() int { l.RLock() @@ -503,8 +570,7 @@ func (l *List) GetItemCount() int { func (l *List) GetItemText(index int) (main, secondary string) { l.RLock() defer l.RUnlock() - - return l.items[index].MainText, l.items[index].SecondaryText + return l.items[index].mainText, l.items[index].secondaryText } // SetItemText sets an item's main and secondary text. Panics if the index is @@ -514,8 +580,8 @@ func (l *List) SetItemText(index int, main, secondary string) *List { defer l.Unlock() item := l.items[index] - item.MainText = main - item.SecondaryText = secondary + item.mainText = main + item.secondaryText = secondary return l } @@ -526,7 +592,7 @@ func (l *List) SetItemEnabled(index int, enabled bool) *List { defer l.Unlock() item := l.items[index] - item.Enabled = enabled + item.enabled = enabled return l } @@ -554,8 +620,8 @@ func (l *List) FindItems(mainSearch, secondarySearch string, mustContainBoth, ig } for index, item := range l.items { - mainText := item.MainText - secondaryText := item.SecondaryText + mainText := item.mainText + secondaryText := item.secondaryText if ignoreCase { mainText = strings.ToLower(mainText) secondaryText = strings.ToLower(secondaryText) @@ -660,7 +726,7 @@ func (l *List) transform(tr Transformation) { } item := l.items[l.currentItem] - if item.Enabled { + if item.enabled { break } @@ -738,7 +804,7 @@ func (l *List) Draw(screen tcell.Screen) { // Do we show any shortcuts? var showShortcuts bool for _, item := range l.items { - if item.Shortcut != 0 { + if item.shortcut != 0 { showShortcuts = true x += 4 width -= 4 @@ -761,7 +827,7 @@ func (l *List) Draw(screen tcell.Screen) { break } - if item.MainText == "" && item.SecondaryText == "" && item.Shortcut == 0 { // Divider + if item.mainText == "" && item.secondaryText == "" && item.shortcut == 0 { // Divider Print(screen, string(tcell.RuneLTee), (x-5)-l.paddingLeft, y, 1, AlignLeft, l.mainTextColor) Print(screen, strings.Repeat(string(tcell.RuneHLine), width+4+l.paddingLeft+l.paddingRight), (x-4)-l.paddingLeft, y, width+4+l.paddingLeft+l.paddingRight, AlignLeft, l.mainTextColor) Print(screen, string(tcell.RuneRTee), (x-5)+width+5+l.paddingRight, y, 1, AlignLeft, l.mainTextColor) @@ -769,14 +835,14 @@ func (l *List) Draw(screen tcell.Screen) { RenderScrollBar(screen, l.scrollBarVisibility, scrollBarX, y, scrollBarHeight, len(l.items), l.currentItem, index-l.offset, l.hasFocus, l.scrollBarColor) y++ continue - } else if !item.Enabled { // Disabled item + } else if !item.enabled { // Disabled item // Shortcuts. - if showShortcuts && item.Shortcut != 0 { - Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, tcell.ColorDarkSlateGray.TrueColor()) + if showShortcuts && item.shortcut != 0 { + Print(screen, fmt.Sprintf("(%s)", string(item.shortcut)), x-5, y, 4, AlignRight, tcell.ColorDarkSlateGray.TrueColor()) } // Main text. - Print(screen, item.MainText, x, y, width, AlignLeft, tcell.ColorGray.TrueColor()) + Print(screen, item.mainText, x, y, width, AlignLeft, tcell.ColorGray.TrueColor()) RenderScrollBar(screen, l.scrollBarVisibility, scrollBarX, y, scrollBarHeight, len(l.items), l.currentItem, index-l.offset, l.hasFocus, l.scrollBarColor) y++ @@ -784,18 +850,18 @@ func (l *List) Draw(screen tcell.Screen) { } // Shortcuts. - if showShortcuts && item.Shortcut != 0 { - Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, l.shortcutColor) + if showShortcuts && item.shortcut != 0 { + Print(screen, fmt.Sprintf("(%s)", string(item.shortcut)), x-5, y, 4, AlignRight, l.shortcutColor) } // Main text. - Print(screen, item.MainText, x, y, width, AlignLeft, l.mainTextColor) + Print(screen, item.mainText, x, y, width, AlignLeft, l.mainTextColor) // Background color of selected text. if index == l.currentItem && (!l.selectedFocusOnly || hasFocus) { textWidth := width if !l.highlightFullLine { - if w := TaggedStringWidth(item.MainText); w < textWidth { + if w := TaggedStringWidth(item.mainText); w < textWidth { textWidth = w } } @@ -821,7 +887,7 @@ func (l *List) Draw(screen tcell.Screen) { // Secondary text. if l.showSecondaryText { - Print(screen, item.SecondaryText, x, y, width, AlignLeft, l.secondaryTextColor) + Print(screen, item.secondaryText, x, y, width, AlignLeft, l.secondaryTextColor) RenderScrollBar(screen, l.scrollBarVisibility, scrollBarX, y, scrollBarHeight, len(l.items), l.currentItem, index-l.offset, l.hasFocus, l.scrollBarColor) @@ -845,8 +911,8 @@ func (l *List) Draw(screen tcell.Screen) { // What's the longest option text? maxWidth := 0 for _, option := range ctx.items { - strWidth := TaggedStringWidth(option.MainText) - if option.Shortcut != 0 { + strWidth := TaggedStringWidth(option.mainText) + if option.shortcut != 0 { strWidth += 4 } if strWidth > maxWidth { @@ -928,15 +994,15 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit } else if HitShortcut(event, Keys.Select, Keys.Select2) { if l.currentItem >= 0 && l.currentItem < len(l.items) { item := l.items[l.currentItem] - if item.Enabled { - if item.Selected != nil { + if item.enabled { + if item.selected != nil { l.Unlock() - item.Selected() + item.selected() l.Lock() } if l.selected != nil { l.Unlock() - l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + l.selected(l.currentItem, item) l.Lock() } } @@ -954,20 +1020,20 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit if ch != ' ' { // It's not a space bar. Is it a shortcut? for index, item := range l.items { - if item.Enabled && item.Shortcut == ch { + if item.enabled && item.shortcut == ch { // We have a shortcut. matchesShortcut = true l.currentItem = index item := l.items[l.currentItem] - if item.Selected != nil { + if item.selected != nil { l.Unlock() - item.Selected() + item.selected() l.Lock() } if l.selected != nil { l.Unlock() - l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + l.selected(l.currentItem, item) l.Lock() } @@ -996,7 +1062,7 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit if l.currentItem != previousItem && l.currentItem < len(l.items) && l.changed != nil { item := l.items[l.currentItem] l.Unlock() - l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(l.currentItem, item) } else { l.Unlock() } @@ -1078,21 +1144,21 @@ func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse, index := l.indexAtPoint(event.Position()) if index != -1 { item := l.items[index] - if item.Enabled { + if item.enabled { l.currentItem = index - if item.Selected != nil { + if item.selected != nil { l.Unlock() - item.Selected() + item.selected() l.Lock() } if l.selected != nil { l.Unlock() - l.selected(index, item.MainText, item.SecondaryText, item.Shortcut) + l.selected(index, item) l.Lock() } if index != l.currentItem && l.changed != nil { l.Unlock() - l.changed(index, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(index, item) l.Lock() } } @@ -1116,11 +1182,11 @@ func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse, index := l.indexAtPoint(event.Position()) if index != -1 { item := l.items[index] - if item.Enabled { + if item.enabled { l.currentItem = index if index != l.currentItem && l.changed != nil { l.Unlock() - l.changed(index, item.MainText, item.SecondaryText, item.Shortcut) + l.changed(index, item) l.Lock() } } @@ -1135,7 +1201,7 @@ func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse, index := l.indexAtY(y) if index >= 0 { item := l.items[index] - if item.Enabled { + if item.enabled { l.currentItem = index } } diff --git a/list_test.go b/list_test.go index 3950a94..4f2f2ae 100644 --- a/list_test.go +++ b/list_test.go @@ -18,17 +18,17 @@ func TestList(t *testing.T) { l := NewList() if l.GetItemCount() != 0 { t.Errorf("failed to initialize List: expected item count 0, got %d", l.GetItemCount()) - } else if l.GetCurrentItem() != 0 { - t.Errorf("failed to initialize List: expected current item 0, got %d", l.GetCurrentItem()) + } else if l.GetCurrentItemIndex() != 0 { + t.Errorf("failed to initialize List: expected current item 0, got %d", l.GetCurrentItemIndex()) } // Add item 0 - l.AddItem(listTextA, listTextB, 'a', nil) + l.AddItem(NewListItem(listTextA).SetSecondaryText(listTextB).SetShortcut('a')) if l.GetItemCount() != 1 { t.Errorf("failed to update List: expected item count 1, got %d", l.GetItemCount()) - } else if l.GetCurrentItem() != 0 { - t.Errorf("failed to update List: expected current item 0, got %d", l.GetCurrentItem()) + } else if l.GetCurrentItemIndex() != 0 { + t.Errorf("failed to update List: expected current item 0, got %d", l.GetCurrentItemIndex()) } // Get item 0 text @@ -42,11 +42,11 @@ func TestList(t *testing.T) { // Add item 1 - l.AddItem(listTextB, listTextC, 'a', nil) + l.AddItem(NewListItem(listTextB).SetSecondaryText(listTextC).SetShortcut('a')) if l.GetItemCount() != 2 { t.Errorf("failed to update List: expected item count 1, got %v", l.GetItemCount()) - } else if l.GetCurrentItem() != 0 { - t.Errorf("failed to update List: expected current item 0, got %v", l.GetCurrentItem()) + } else if l.GetCurrentItemIndex() != 0 { + t.Errorf("failed to update List: expected current item 0, got %v", l.GetCurrentItemIndex()) } // Get item 1 text