inputfield.go (23649B)
1 package tview 2 3 import ( 4 "math" 5 "strconv" 6 "strings" 7 "sync" 8 9 "github.com/gdamore/tcell/v2" 10 "github.com/rivo/uniseg" 11 ) 12 13 const ( 14 AutocompletedNavigate = iota // The user navigated the autocomplete list (using the errow keys). 15 AutocompletedTab // The user selected an autocomplete entry using the tab key. 16 AutocompletedEnter // The user selected an autocomplete entry using the enter key. 17 AutocompletedClick // The user selected an autocomplete entry by clicking the mouse button on it. 18 ) 19 20 // Predefined InputField acceptance functions. 21 var ( 22 // InputFieldInteger accepts integers. 23 InputFieldInteger = func(text string, ch rune) bool { 24 if text == "-" { 25 return true 26 } 27 _, err := strconv.Atoi(text) 28 return err == nil 29 } 30 31 // InputFieldFloat accepts floating-point numbers. 32 InputFieldFloat = func(text string, ch rune) bool { 33 if text == "-" || text == "." || text == "-." { 34 return true 35 } 36 _, err := strconv.ParseFloat(text, 64) 37 return err == nil 38 } 39 40 // InputFieldMaxLength returns an input field accept handler which accepts 41 // input strings up to a given length. Use it like this: 42 // 43 // inputField.SetAcceptanceFunc(InputFieldMaxLength(10)) // Accept up to 10 characters. 44 InputFieldMaxLength = func(maxLength int) func(text string, ch rune) bool { 45 return func(text string, ch rune) bool { 46 return len([]rune(text)) <= maxLength 47 } 48 } 49 ) 50 51 // InputField is a one-line box into which the user can enter text. Use 52 // [InputField.SetAcceptanceFunc] to accept or reject input, 53 // [InputField.SetChangedFunc] to listen for changes, and 54 // [InputField.SetMaskCharacter] to hide input from onlookers (e.g. for password 55 // input). 56 // 57 // The input field also has an optional autocomplete feature. It is initialized 58 // by the [InputField.SetAutocompleteFunc] function. For more control over the 59 // autocomplete drop-down's behavior, you can also set the 60 // [InputField.SetAutocompletedFunc]. 61 // 62 // Navigation and editing is the same as for a [TextArea], with the following 63 // exceptions: 64 // 65 // - Tab, BackTab, Enter, Escape: Finish editing. 66 // 67 // Note that while pressing Tab or Enter is intercepted by the input field, it 68 // is possible to paste such characters into the input field, possibly resulting 69 // in multi-line input. You can use [InputField.SetAcceptanceFunc] to prevent 70 // this. 71 // 72 // If autocomplete functionality is configured: 73 // 74 // - Down arrow: Open the autocomplete drop-down. 75 // - Tab, Enter: Select the current autocomplete entry. 76 // 77 // See https://github.com/rivo/tview/wiki/InputField for an example. 78 type InputField struct { 79 *Box 80 81 // The text area providing the core functionality of the input field. 82 textArea *TextArea 83 84 // The screen width of the input area. A value of 0 means extend as much as 85 // possible. 86 fieldWidth int 87 88 // An optional autocomplete function which receives the current text of the 89 // input field and returns a slice of strings to be displayed in a drop-down 90 // selection. 91 autocomplete func(text string) []string 92 93 // The List object which shows the selectable autocomplete entries. If not 94 // nil, the list's main texts represent the current autocomplete entries. 95 autocompleteList *List 96 autocompleteListMutex sync.Mutex 97 98 // The styles of the autocomplete entries. 99 autocompleteStyles struct { 100 main tcell.Style 101 selected tcell.Style 102 background tcell.Color 103 useTags bool 104 } 105 106 // An optional function which is called when the user selects an 107 // autocomplete entry. The text and index of the selected entry (within the 108 // list) is provided, as well as the user action causing the selection (one 109 // of the "Autocompleted" values). The function should return true if the 110 // autocomplete list should be closed. If nil, the input field will be 111 // updated automatically when the user navigates the autocomplete list. 112 autocompleted func(text string, index int, source int) bool 113 114 // An optional function which may reject the last character that was entered. 115 accept func(text string, ch rune) bool 116 117 // An optional function which is called when the input has changed. 118 changed func(text string) 119 120 // An optional function which is called when the user indicated that they 121 // are done entering text. The key which was pressed is provided (tab, 122 // shift-tab, enter, or escape). 123 done func(tcell.Key) 124 125 // A callback function set by the Form class and called when the user leaves 126 // this form item. 127 finished func(tcell.Key) 128 } 129 130 // NewInputField returns a new input field. 131 func NewInputField() *InputField { 132 i := &InputField{ 133 Box: NewBox(), 134 textArea: NewTextArea().SetWrap(false), 135 } 136 i.textArea.SetChangedFunc(func() { 137 if i.changed != nil { 138 i.changed(i.textArea.GetText()) 139 } 140 }).SetFocusFunc(func() { 141 // Forward focus event to the input field. 142 if i.Box.focus != nil { 143 i.Box.focus() 144 } 145 }) 146 i.textArea.textStyle = tcell.StyleDefault.Background(Styles.ContrastBackgroundColor).Foreground(Styles.PrimaryTextColor) 147 i.textArea.placeholderStyle = tcell.StyleDefault.Background(Styles.ContrastBackgroundColor).Foreground(Styles.ContrastSecondaryTextColor) 148 i.autocompleteStyles.main = tcell.StyleDefault.Background(Styles.MoreContrastBackgroundColor).Foreground(Styles.PrimitiveBackgroundColor) 149 i.autocompleteStyles.selected = tcell.StyleDefault.Background(Styles.PrimaryTextColor).Foreground(Styles.PrimitiveBackgroundColor) 150 i.autocompleteStyles.background = Styles.MoreContrastBackgroundColor 151 i.autocompleteStyles.useTags = true 152 return i 153 } 154 155 // SetText sets the current text of the input field. This can be undone by the 156 // user. Calling this function will also trigger a "changed" event. 157 func (i *InputField) SetText(text string) *InputField { 158 i.textArea.Replace(0, i.textArea.GetTextLength(), text) 159 return i 160 } 161 162 // GetText returns the current text of the input field. 163 func (i *InputField) GetText() string { 164 return i.textArea.GetText() 165 } 166 167 // SetLabel sets the text to be displayed before the input area. 168 func (i *InputField) SetLabel(label string) *InputField { 169 i.textArea.SetLabel(label) 170 return i 171 } 172 173 // GetLabel returns the text to be displayed before the input area. 174 func (i *InputField) GetLabel() string { 175 return i.textArea.GetLabel() 176 } 177 178 // SetLabelWidth sets the screen width of the label. A value of 0 will cause the 179 // primitive to use the width of the label string. 180 func (i *InputField) SetLabelWidth(width int) *InputField { 181 i.textArea.SetLabelWidth(width) 182 return i 183 } 184 185 // SetPlaceholder sets the text to be displayed when the input text is empty. 186 func (i *InputField) SetPlaceholder(text string) *InputField { 187 i.textArea.SetPlaceholder(text) 188 return i 189 } 190 191 // SetLabelColor sets the text color of the label. 192 func (i *InputField) SetLabelColor(color tcell.Color) *InputField { 193 i.textArea.SetLabelStyle(i.textArea.GetLabelStyle().Foreground(color)) 194 return i 195 } 196 197 // SetLabelStyle sets the style of the label. 198 func (i *InputField) SetLabelStyle(style tcell.Style) *InputField { 199 i.textArea.SetLabelStyle(style) 200 return i 201 } 202 203 // GetLabelStyle returns the style of the label. 204 func (i *InputField) GetLabelStyle() tcell.Style { 205 return i.textArea.GetLabelStyle() 206 } 207 208 // SetFieldBackgroundColor sets the background color of the input area. 209 func (i *InputField) SetFieldBackgroundColor(color tcell.Color) *InputField { 210 i.textArea.SetTextStyle(i.textArea.GetTextStyle().Background(color)) 211 return i 212 } 213 214 // SetFieldTextColor sets the text color of the input area. 215 func (i *InputField) SetFieldTextColor(color tcell.Color) *InputField { 216 i.textArea.SetTextStyle(i.textArea.GetTextStyle().Foreground(color)) 217 return i 218 } 219 220 // SetFieldStyle sets the style of the input area (when no placeholder is 221 // shown). 222 func (i *InputField) SetFieldStyle(style tcell.Style) *InputField { 223 i.textArea.SetTextStyle(style) 224 return i 225 } 226 227 // GetFieldStyle returns the style of the input area (when no placeholder is 228 // shown). 229 func (i *InputField) GetFieldStyle() tcell.Style { 230 return i.textArea.GetTextStyle() 231 } 232 233 // SetPlaceholderTextColor sets the text color of placeholder text. 234 func (i *InputField) SetPlaceholderTextColor(color tcell.Color) *InputField { 235 i.textArea.SetPlaceholderStyle(i.textArea.GetPlaceholderStyle().Foreground(color)) 236 return i 237 } 238 239 // SetPlaceholderStyle sets the style of the input area (when a placeholder is 240 // shown). 241 func (i *InputField) SetPlaceholderStyle(style tcell.Style) *InputField { 242 i.textArea.SetPlaceholderStyle(style) 243 return i 244 } 245 246 // GetPlaceholderStyle returns the style of the input area (when a placeholder 247 // is shown). 248 func (i *InputField) GetPlaceholderStyle() tcell.Style { 249 return i.textArea.GetPlaceholderStyle() 250 } 251 252 // SetAutocompleteStyles sets the colors and style of the autocomplete entries. 253 // For details, see [List.SetMainTextStyle], [List.SetSelectedStyle], and 254 // [Box.SetBackgroundColor]. 255 func (i *InputField) SetAutocompleteStyles(background tcell.Color, main, selected tcell.Style) *InputField { 256 i.autocompleteStyles.background = background 257 i.autocompleteStyles.main = main 258 i.autocompleteStyles.selected = selected 259 return i 260 } 261 262 // SetAutocompleteUseTags sets whether or not the autocomplete entries may 263 // contain style tags affecting their appearance. The default is true. 264 func (i *InputField) SetAutocompleteUseTags(useTags bool) *InputField { 265 i.autocompleteStyles.useTags = useTags 266 return i 267 } 268 269 // SetFormAttributes sets attributes shared by all form items. 270 func (i *InputField) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem { 271 i.textArea.SetFormAttributes(labelWidth, labelColor, bgColor, fieldTextColor, fieldBgColor) 272 return i 273 } 274 275 // SetFieldWidth sets the screen width of the input area. A value of 0 means 276 // extend as much as possible. 277 func (i *InputField) SetFieldWidth(width int) *InputField { 278 i.fieldWidth = width 279 return i 280 } 281 282 // GetFieldWidth returns this primitive's field width. 283 func (i *InputField) GetFieldWidth() int { 284 return i.fieldWidth 285 } 286 287 // GetFieldHeight returns this primitive's field height. 288 func (i *InputField) GetFieldHeight() int { 289 return 1 290 } 291 292 // SetDisabled sets whether or not the item is disabled / read-only. 293 func (i *InputField) SetDisabled(disabled bool) FormItem { 294 i.textArea.SetDisabled(disabled) 295 if i.finished != nil { 296 i.finished(-1) 297 } 298 return i 299 } 300 301 // SetMaskCharacter sets a character that masks user input on a screen. A value 302 // of 0 disables masking. 303 func (i *InputField) SetMaskCharacter(mask rune) *InputField { 304 if mask == 0 { 305 i.textArea.setTransform(nil) 306 return i 307 } 308 maskStr := string(mask) 309 maskWidth := uniseg.StringWidth(maskStr) 310 i.textArea.setTransform(func(cluster, rest string, boundaries int) (newCluster string, newBoundaries int) { 311 return maskStr, maskWidth << uniseg.ShiftWidth 312 }) 313 return i 314 } 315 316 // SetAutocompleteFunc sets an autocomplete callback function which may return 317 // strings to be selected from a drop-down based on the current text of the 318 // input field. The drop-down appears only if len(entries) > 0. The callback is 319 // invoked in this function and whenever the current text changes or when 320 // [InputField.Autocomplete] is called. Entries are cleared when the user 321 // selects an entry or presses Escape. 322 func (i *InputField) SetAutocompleteFunc(callback func(currentText string) (entries []string)) *InputField { 323 i.autocomplete = callback 324 i.Autocomplete() 325 return i 326 } 327 328 // SetAutocompletedFunc sets a callback function which is invoked when the user 329 // selects an entry from the autocomplete drop-down list. The function is passed 330 // the text of the selected entry (stripped of any style tags), the index of the 331 // entry, and the user action that caused the selection, for example 332 // [AutocompletedNavigate]. It returns true if the autocomplete drop-down should 333 // be closed after the callback returns or false if it should remain open, in 334 // which case [InputField.Autocomplete] is called to update the drop-down's 335 // contents. 336 // 337 // If no such callback is set (or nil is provided), the input field will be 338 // updated with the selection any time the user navigates the autocomplete 339 // drop-down list. So this function essentially gives you more control over the 340 // autocomplete functionality. 341 func (i *InputField) SetAutocompletedFunc(autocompleted func(text string, index int, source int) bool) *InputField { 342 i.autocompleted = autocompleted 343 return i 344 } 345 346 // Autocomplete invokes the autocomplete callback (if there is one, see 347 // [InputField.SetAutocompleteFunc]). If the length of the returned autocomplete 348 // entries slice is greater than 0, the input field will present the user with a 349 // corresponding drop-down list the next time the input field is drawn. 350 // 351 // It is safe to call this function from any goroutine. Note that the input 352 // field is not redrawn automatically unless called from the main goroutine 353 // (e.g. in response to events). 354 func (i *InputField) Autocomplete() *InputField { 355 i.autocompleteListMutex.Lock() 356 defer i.autocompleteListMutex.Unlock() 357 if i.autocomplete == nil { 358 return i 359 } 360 361 // Do we have any autocomplete entries? 362 text := i.textArea.GetText() 363 entries := i.autocomplete(text) 364 if len(entries) == 0 { 365 // No entries, no list. 366 i.autocompleteList = nil 367 return i 368 } 369 370 // Make a list if we have none. 371 if i.autocompleteList == nil { 372 i.autocompleteList = NewList() 373 i.autocompleteList.ShowSecondaryText(false). 374 SetMainTextStyle(i.autocompleteStyles.main). 375 SetSelectedStyle(i.autocompleteStyles.selected). 376 SetUseStyleTags(i.autocompleteStyles.useTags, i.autocompleteStyles.useTags). 377 SetHighlightFullLine(true). 378 SetBackgroundColor(i.autocompleteStyles.background) 379 } 380 381 // Fill it with the entries. 382 currentIndex := i.autocompleteList.GetCurrentItem() 383 var currentSelection string 384 if currentIndex >= 0 && currentIndex < i.autocompleteList.GetItemCount() { 385 currentSelection, _ = i.autocompleteList.GetItemText(currentIndex) 386 } 387 currentEntry := -1 388 suffixLength := math.MaxInt 389 i.autocompleteList.Clear() 390 for index, entry := range entries { 391 i.autocompleteList.AddItem(entry, "", 0, nil) 392 if currentSelection != "" && entry == currentSelection { 393 currentEntry = index 394 } 395 if currentSelection == "" && strings.HasPrefix(entry, text) && len(entry)-len(text) < suffixLength { 396 currentEntry = index 397 suffixLength = len(text) - len(entry) 398 } 399 } 400 401 // Set the selection if we have one. 402 if currentEntry >= 0 { 403 i.autocompleteList.SetCurrentItem(currentEntry) 404 } 405 406 return i 407 } 408 409 // SetAcceptanceFunc sets a handler which may reject the last character that was 410 // entered, by returning false. The handler receives the text as it would be 411 // after the change and the last character entered. If the handler is nil, all 412 // input is accepted. The function is only called when a single rune is inserted 413 // at the current cursor position. 414 // 415 // This package defines a number of variables prefixed with InputField which may 416 // be used for common input (e.g. numbers, maximum text length). See for example 417 // [InputFieldInteger]. 418 // 419 // When text is pasted, lastChar is 0. 420 func (i *InputField) SetAcceptanceFunc(handler func(textToCheck string, lastChar rune) bool) *InputField { 421 i.accept = handler 422 return i 423 } 424 425 // SetChangedFunc sets a handler which is called whenever the text of the input 426 // field has changed. It receives the current text (after the change). 427 func (i *InputField) SetChangedFunc(handler func(text string)) *InputField { 428 i.changed = handler 429 return i 430 } 431 432 // SetDoneFunc sets a handler which is called when the user is done entering 433 // text. The callback function is provided with the key that was pressed, which 434 // is one of the following: 435 // 436 // - KeyEnter: Done entering text. 437 // - KeyEscape: Abort text input. 438 // - KeyTab: Move to the next field. 439 // - KeyBacktab: Move to the previous field. 440 func (i *InputField) SetDoneFunc(handler func(key tcell.Key)) *InputField { 441 i.done = handler 442 return i 443 } 444 445 // SetFinishedFunc sets a callback invoked when the user leaves this form item. 446 func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) FormItem { 447 i.finished = handler 448 return i 449 } 450 451 // Focus is called when this primitive receives focus. 452 func (i *InputField) Focus(delegate func(p Primitive)) { 453 // If we're part of a form and this item is disabled, there's nothing the 454 // user can do here so we're finished. 455 if i.finished != nil && i.textArea.GetDisabled() { 456 i.finished(-1) 457 return 458 } 459 460 i.Box.Focus(delegate) 461 } 462 463 // HasFocus returns whether or not this primitive has focus. 464 func (i *InputField) HasFocus() bool { 465 return i.textArea.HasFocus() || i.Box.HasFocus() 466 } 467 468 // Blur is called when this primitive loses focus. 469 func (i *InputField) Blur() { 470 i.textArea.Blur() 471 i.Box.Blur() 472 i.autocompleteList = nil // Hide the autocomplete drop-down. 473 } 474 475 // Draw draws this primitive onto the screen. 476 func (i *InputField) Draw(screen tcell.Screen) { 477 i.Box.DrawForSubclass(screen, i) 478 479 // Prepare 480 x, y, width, height := i.GetInnerRect() 481 if height < 1 || width < 1 { 482 return 483 } 484 485 // Resize text area. 486 labelWidth := i.textArea.GetLabelWidth() 487 if labelWidth == 0 { 488 labelWidth = TaggedStringWidth(i.textArea.GetLabel()) 489 } 490 fieldWidth := i.fieldWidth 491 if fieldWidth == 0 { 492 fieldWidth = width - labelWidth 493 } 494 i.textArea.SetRect(x, y, labelWidth+fieldWidth, 1) 495 i.textArea.setMinCursorPadding(fieldWidth-1, 1) 496 497 // Draw text area. 498 i.textArea.hasFocus = i.HasFocus() // Force cursor positioning. 499 i.textArea.Draw(screen) 500 501 // Draw autocomplete list. 502 i.autocompleteListMutex.Lock() 503 defer i.autocompleteListMutex.Unlock() 504 if i.autocompleteList != nil && i.HasFocus() { 505 // How much space do we need? 506 lheight := i.autocompleteList.GetItemCount() 507 lwidth := 0 508 for index := 0; index < lheight; index++ { 509 entry, _ := i.autocompleteList.GetItemText(index) 510 width := TaggedStringWidth(entry) 511 if width > lwidth { 512 lwidth = width 513 } 514 } 515 516 // We prefer to drop down but if there is no space, maybe drop up? 517 lx := x + labelWidth 518 ly := y + 1 519 _, sheight := screen.Size() 520 if ly+lheight >= sheight && ly-2 > lheight-ly { 521 ly = y - lheight 522 if ly < 0 { 523 ly = 0 524 } 525 } 526 if ly+lheight >= sheight { 527 lheight = sheight - ly 528 } 529 i.autocompleteList.SetRect(lx, ly, lwidth, lheight) 530 i.autocompleteList.Draw(screen) 531 } 532 } 533 534 // InputHandler returns the handler for this primitive. 535 func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { 536 return i.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { 537 if i.textArea.GetDisabled() { 538 return 539 } 540 541 // Trigger changed events. 542 var skipAutocomplete bool 543 currentText := i.textArea.GetText() 544 defer func() { 545 if skipAutocomplete { 546 return 547 } 548 if i.textArea.GetText() != currentText { 549 i.Autocomplete() 550 } 551 }() 552 553 // If we have an autocomplete list, there are certain keys we will 554 // forward to it. 555 i.autocompleteListMutex.Lock() 556 defer i.autocompleteListMutex.Unlock() 557 if i.autocompleteList != nil { 558 i.autocompleteList.SetChangedFunc(nil) 559 i.autocompleteList.SetSelectedFunc(nil) 560 switch key := event.Key(); key { 561 case tcell.KeyEscape: // Close the list. 562 i.autocompleteList = nil 563 return 564 case tcell.KeyEnter, tcell.KeyTab: // Intentional selection. 565 index := i.autocompleteList.GetCurrentItem() 566 text, _ := i.autocompleteList.GetItemText(index) 567 if i.autocompleted != nil { 568 source := AutocompletedEnter 569 if key == tcell.KeyTab { 570 source = AutocompletedTab 571 } 572 if i.autocompleted(stripTags(text), index, source) { 573 i.autocompleteList = nil 574 currentText = i.GetText() 575 } 576 } else { 577 i.SetText(text) 578 skipAutocomplete = true 579 i.autocompleteList = nil 580 } 581 return 582 case tcell.KeyDown, tcell.KeyUp, tcell.KeyPgDn, tcell.KeyPgUp: 583 i.autocompleteList.SetChangedFunc(func(index int, text, secondaryText string, shortcut rune) { 584 text = stripTags(text) 585 if i.autocompleted != nil { 586 if i.autocompleted(text, index, AutocompletedNavigate) { 587 i.autocompleteList = nil 588 currentText = i.GetText() 589 } 590 } else { 591 i.SetText(text) 592 currentText = stripTags(text) // We want to keep the autocomplete list open and unchanged. 593 } 594 }) 595 i.autocompleteList.InputHandler()(event, setFocus) 596 return 597 } 598 } 599 600 // Finish up. 601 finish := func(key tcell.Key) { 602 if i.done != nil { 603 i.done(key) 604 } 605 if i.finished != nil { 606 i.finished(key) 607 } 608 } 609 610 // Process special key events for the input field. 611 switch key := event.Key(); key { 612 case tcell.KeyDown: 613 i.autocompleteListMutex.Unlock() // We're still holding a lock. 614 i.Autocomplete() 615 i.autocompleteListMutex.Lock() 616 case tcell.KeyEnter, tcell.KeyEscape, tcell.KeyTab, tcell.KeyBacktab: 617 finish(key) 618 case tcell.KeyCtrlV: 619 if i.accept != nil && !i.accept(i.textArea.getTextBeforeCursor()+i.textArea.GetClipboardText()+i.textArea.getTextAfterCursor(), 0) { 620 return 621 } 622 i.textArea.InputHandler()(event, setFocus) 623 case tcell.KeyRune: 624 if event.Modifiers()&tcell.ModAlt == 0 && i.accept != nil { 625 // Check if this rune is accepted. 626 r := event.Rune() 627 if !i.accept(i.textArea.getTextBeforeCursor()+string(r)+i.textArea.getTextAfterCursor(), r) { 628 return 629 } 630 } 631 fallthrough 632 default: 633 // Forward other key events to the text area. 634 i.textArea.InputHandler()(event, setFocus) 635 } 636 }) 637 } 638 639 // MouseHandler returns the mouse handler for this primitive. 640 func (i *InputField) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { 641 return i.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { 642 if i.textArea.GetDisabled() { 643 return false, nil 644 } 645 646 var skipAutocomplete bool 647 currentText := i.GetText() 648 defer func() { 649 if skipAutocomplete { 650 return 651 } 652 if i.textArea.GetText() != currentText { 653 i.Autocomplete() 654 } 655 }() 656 657 // If we have an autocomplete list, forward the mouse event to it. 658 i.autocompleteListMutex.Lock() 659 defer i.autocompleteListMutex.Unlock() 660 if i.autocompleteList != nil { 661 i.autocompleteList.SetChangedFunc(nil) 662 i.autocompleteList.SetSelectedFunc(func(index int, text, secondaryText string, shortcut rune) { 663 text = stripTags(text) 664 if i.autocompleted != nil { 665 if i.autocompleted(text, index, AutocompletedClick) { 666 i.autocompleteList = nil 667 currentText = i.GetText() 668 } 669 return 670 } 671 i.SetText(text) 672 skipAutocomplete = true 673 i.autocompleteList = nil 674 }) 675 if consumed, _ = i.autocompleteList.MouseHandler()(action, event, setFocus); consumed { 676 setFocus(i) 677 return 678 } 679 } 680 681 // Is mouse event within the input field? 682 x, y := event.Position() 683 if !i.InRect(x, y) { 684 return false, nil 685 } 686 687 // Forward mouse event to the text area. 688 consumed, capture = i.textArea.MouseHandler()(action, event, setFocus) 689 690 return 691 }) 692 } 693 694 // PasteHandler returns the handler for this primitive. 695 func (i *InputField) PasteHandler() func(pastedText string, setFocus func(p Primitive)) { 696 return i.WrapPasteHandler(func(pastedText string, setFocus func(p Primitive)) { 697 // Input field may be disabled. 698 if i.textArea.GetDisabled() { 699 return 700 } 701 702 // The autocomplete drop down may be open. 703 i.autocompleteListMutex.Lock() 704 defer i.autocompleteListMutex.Unlock() 705 if i.autocompleteList != nil { 706 return 707 } 708 709 // We may not accept this text. 710 if i.accept != nil && !i.accept(i.textArea.getTextBeforeCursor()+pastedText+i.textArea.getTextAfterCursor(), 0) { 711 return 712 } 713 714 // Forward the pasted text to the text area. 715 i.textArea.PasteHandler()(pastedText, setFocus) 716 }) 717 }