feat(inputfield/autocompletion): Draw selected autocomplete suggestion in `inputfield` without changing it till confirmed with `ENTER`
This commit is contained in:
parent
bace1ac630
commit
75b6d31409
|
@ -76,6 +76,9 @@ type InputField struct {
|
|||
// The background color of the selected ListItem.
|
||||
autocompleteListSelectedBackgroundColor tcell.Color
|
||||
|
||||
// The text color of the suggestion.
|
||||
autocompleteSuggestionTextColor tcell.Color
|
||||
|
||||
// The screen width of the label area. A value of 0 means use the width of
|
||||
// the label text.
|
||||
labelWidth int
|
||||
|
@ -100,6 +103,9 @@ type InputField struct {
|
|||
// nil, the list's main texts represent the current autocomplete entries.
|
||||
autocompleteList *List
|
||||
|
||||
// The suggested completion of the current autocomplete ListItem.
|
||||
autocompleteListSuggestion string
|
||||
|
||||
// An optional function which may reject the last character that was entered.
|
||||
accept func(text string, ch rune) bool
|
||||
|
||||
|
@ -140,6 +146,7 @@ func NewInputField() *InputField {
|
|||
autocompleteListBackgroundColor: Styles.MoreContrastBackgroundColor,
|
||||
autocompleteListSelectedTextColor: Styles.PrimitiveBackgroundColor,
|
||||
autocompleteListSelectedBackgroundColor: Styles.PrimaryTextColor,
|
||||
autocompleteSuggestionTextColor: Styles.ContrastPrimaryTextColor,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,6 +315,12 @@ func (i *InputField) SetAutocompleteListSelectedBackgroundColor(color tcell.Colo
|
|||
return i
|
||||
}
|
||||
|
||||
// SetAutocompleteSuggestionColor sets the text color of the autocomplete suggestion in the input field.
|
||||
func (i *InputField) SetAutocompleteSuggestionTextColor(color tcell.Color) *InputField {
|
||||
i.autocompleteSuggestionTextColor = color
|
||||
return i
|
||||
}
|
||||
|
||||
// SetFormAttributes sets attributes shared by all form items.
|
||||
func (i *InputField) SetFormAttributes(labelWidth int, bgColor, labelColor, labelColorFocused, fieldTextColor, fieldTextColorFocused, fieldBgColor, fieldBgColorFocused tcell.Color) FormItem {
|
||||
i.Lock()
|
||||
|
@ -405,6 +418,7 @@ func (i *InputField) Autocomplete() *InputField {
|
|||
// No entries, no list.
|
||||
i.Lock()
|
||||
i.autocompleteList = nil
|
||||
i.autocompleteListSuggestion = ""
|
||||
i.Unlock()
|
||||
return i
|
||||
}
|
||||
|
@ -415,6 +429,7 @@ func (i *InputField) Autocomplete() *InputField {
|
|||
if i.autocompleteList == nil {
|
||||
i.autocompleteList = NewList()
|
||||
i.autocompleteList.
|
||||
SetChangedFunc(i.autocompleteChanged).
|
||||
ShowSecondaryText(false).
|
||||
SetMainTextColor(i.autocompleteListTextColor).
|
||||
SetSelectedTextColor(i.autocompleteListSelectedTextColor).
|
||||
|
@ -443,6 +458,16 @@ func (i *InputField) Autocomplete() *InputField {
|
|||
return i
|
||||
}
|
||||
|
||||
// autocompleteChanged gets called when another item in the
|
||||
// autocomplete list has been selected.
|
||||
func (i *InputField) autocompleteChanged(_ int, item *ListItem) {
|
||||
if referenceVal, isString := item.reference.(string); isString {
|
||||
i.autocompleteListSuggestion = referenceVal[len(i.text):]
|
||||
} else {
|
||||
i.autocompleteListSuggestion = item.mainText[len(i.text):]
|
||||
}
|
||||
}
|
||||
|
||||
// SetAcceptanceFunc sets a handler which may reject the last character that was
|
||||
// entered (by returning false).
|
||||
//
|
||||
|
@ -554,9 +579,11 @@ func (i *InputField) Draw(screen tcell.Screen) {
|
|||
if i.maskCharacter > 0 {
|
||||
text = strings.Repeat(string(i.maskCharacter), utf8.RuneCountInString(i.text))
|
||||
}
|
||||
drawnText := ""
|
||||
if fieldWidth >= stringWidth(text) {
|
||||
// We have enough space for the full text.
|
||||
Print(screen, Escape(text), x, y, fieldWidth, AlignLeft, fieldTextColor)
|
||||
drawnText = Escape(text)
|
||||
Print(screen, drawnText, x, y, fieldWidth, AlignLeft, fieldTextColor)
|
||||
i.offset = 0
|
||||
iterateString(text, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||
if textPos >= i.cursorPos {
|
||||
|
@ -594,7 +621,12 @@ func (i *InputField) Draw(screen tcell.Screen) {
|
|||
}
|
||||
return false
|
||||
})
|
||||
Print(screen, Escape(text[i.offset:]), x, y, fieldWidth, AlignLeft, fieldTextColor)
|
||||
drawnText = Escape(text[i.offset:])
|
||||
Print(screen, drawnText, x, y, fieldWidth, AlignLeft, fieldTextColor)
|
||||
}
|
||||
// Draw suggestion
|
||||
if i.maskCharacter == 0 && i.autocompleteListSuggestion != "" {
|
||||
Print(screen, i.autocompleteListSuggestion, x+stringWidth(drawnText), y, fieldWidth-stringWidth(drawnText), AlignLeft, i.autocompleteSuggestionTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,14 +799,31 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
|||
home()
|
||||
case tcell.KeyEnd, tcell.KeyCtrlE:
|
||||
end()
|
||||
case tcell.KeyEnter, tcell.KeyEscape: // We might be done.
|
||||
case tcell.KeyEnter: // We might be done.
|
||||
if i.autocompleteList != nil {
|
||||
currentItem := i.autocompleteList.GetCurrentItem()
|
||||
i.Unlock()
|
||||
if referenceVal, isString := currentItem.reference.(string); isString {
|
||||
i.SetText(referenceVal)
|
||||
} else {
|
||||
i.SetText(currentItem.mainText)
|
||||
}
|
||||
i.Lock()
|
||||
i.autocompleteList = nil
|
||||
i.Unlock()
|
||||
i.autocompleteListSuggestion = ""
|
||||
} else {
|
||||
i.Unlock()
|
||||
finish(key)
|
||||
}
|
||||
i.Unlock()
|
||||
return
|
||||
case tcell.KeyEscape:
|
||||
if i.autocompleteList != nil {
|
||||
i.autocompleteList = nil
|
||||
i.autocompleteListSuggestion = ""
|
||||
} else {
|
||||
finish(key)
|
||||
}
|
||||
i.Unlock()
|
||||
return
|
||||
case tcell.KeyDown, tcell.KeyTab: // Autocomplete selection.
|
||||
if i.autocompleteList != nil {
|
||||
|
@ -784,9 +833,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
|||
newEntry = 0
|
||||
}
|
||||
i.autocompleteList.SetCurrentItem(newEntry)
|
||||
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
|
||||
i.Unlock()
|
||||
i.SetText(currentText)
|
||||
} else {
|
||||
i.Unlock()
|
||||
finish(key)
|
||||
|
@ -799,9 +846,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
|||
newEntry = i.autocompleteList.GetItemCount() - 1
|
||||
}
|
||||
i.autocompleteList.SetCurrentItem(newEntry)
|
||||
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
|
||||
i.Unlock()
|
||||
i.SetText(currentText)
|
||||
} else {
|
||||
i.Unlock()
|
||||
finish(key)
|
||||
|
|
|
@ -14,6 +14,7 @@ type Theme struct {
|
|||
SecondaryTextColor tcell.Color // Secondary text (e.g. labels).
|
||||
TertiaryTextColor tcell.Color // Tertiary text (e.g. subtitles, notes).
|
||||
InverseTextColor tcell.Color // Text on primary-colored backgrounds.
|
||||
ContrastPrimaryTextColor tcell.Color // Primary text for contrasting elements.
|
||||
ContrastSecondaryTextColor tcell.Color // Secondary text on ContrastBackgroundColor-colored backgrounds.
|
||||
|
||||
// Background
|
||||
|
@ -46,6 +47,7 @@ var Styles = Theme{
|
|||
SecondaryTextColor: tcell.ColorYellow.TrueColor(),
|
||||
TertiaryTextColor: tcell.ColorGreen.TrueColor(),
|
||||
InverseTextColor: tcell.ColorBlue.TrueColor(),
|
||||
ContrastPrimaryTextColor: tcell.ColorBlack.TrueColor(),
|
||||
ContrastSecondaryTextColor: tcell.ColorDarkCyan.TrueColor(),
|
||||
|
||||
PrimitiveBackgroundColor: tcell.ColorBlack.TrueColor(),
|
||||
|
|
Loading…
Reference in New Issue