forking tview to fork tcell to increase terminal input buffer length for password/key pasting
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

modal.go 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package tview
  2. import (
  3. "github.com/gdamore/tcell"
  4. )
  5. // Modal is a centered message window used to inform the user or prompt them
  6. // for an immediate decision. It needs to have at least one button (added via
  7. // AddButtons()) or it will never disappear.
  8. //
  9. // See https://github.com/rivo/tview/wiki/Modal for an example.
  10. type Modal struct {
  11. *Box
  12. // The framed embedded in the modal.
  13. frame *Frame
  14. // The form embedded in the modal's frame.
  15. form *Form
  16. // The message text (original, not word-wrapped).
  17. text string
  18. // The text color.
  19. textColor tcell.Color
  20. // The optional callback for when the user clicked one of the buttons. It
  21. // receives the index of the clicked button and the button's label.
  22. done func(buttonIndex int, buttonLabel string)
  23. }
  24. // NewModal returns a new modal message window.
  25. func NewModal() *Modal {
  26. m := &Modal{
  27. Box: NewBox(),
  28. textColor: Styles.PrimaryTextColor,
  29. }
  30. m.form = NewForm().
  31. SetButtonsAlign(AlignCenter).
  32. SetButtonBackgroundColor(Styles.PrimitiveBackgroundColor).
  33. SetButtonTextColor(Styles.PrimaryTextColor)
  34. m.form.SetBackgroundColor(Styles.ContrastBackgroundColor).SetBorderPadding(0, 0, 0, 0)
  35. m.form.SetCancelFunc(func() {
  36. if m.done != nil {
  37. m.done(-1, "")
  38. }
  39. })
  40. m.frame = NewFrame(m.form).SetBorders(0, 0, 1, 0, 0, 0)
  41. m.frame.SetBorder(true).
  42. SetBackgroundColor(Styles.ContrastBackgroundColor).
  43. SetBorderPadding(1, 1, 1, 1)
  44. m.focus = m
  45. return m
  46. }
  47. // SetTextColor sets the color of the message text.
  48. func (m *Modal) SetTextColor(color tcell.Color) *Modal {
  49. m.textColor = color
  50. return m
  51. }
  52. // SetDoneFunc sets a handler which is called when one of the buttons was
  53. // pressed. It receives the index of the button as well as its label text. The
  54. // handler is also called when the user presses the Escape key. The index will
  55. // then be negative and the label text an emptry string.
  56. func (m *Modal) SetDoneFunc(handler func(buttonIndex int, buttonLabel string)) *Modal {
  57. m.done = handler
  58. return m
  59. }
  60. // SetText sets the message text of the window. The text may contain line
  61. // breaks. Note that words are wrapped, too, based on the final size of the
  62. // window.
  63. func (m *Modal) SetText(text string) *Modal {
  64. m.text = text
  65. return m
  66. }
  67. // AddButtons adds buttons to the window. There must be at least one button and
  68. // a "done" handler so the window can be closed again.
  69. func (m *Modal) AddButtons(labels []string) *Modal {
  70. for index, label := range labels {
  71. func(i int, l string) {
  72. m.form.AddButton(label, func() {
  73. if m.done != nil {
  74. m.done(i, l)
  75. }
  76. })
  77. button := m.form.GetButton(m.form.GetButtonCount() - 1)
  78. button.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
  79. switch event.Key() {
  80. case tcell.KeyDown, tcell.KeyRight:
  81. return tcell.NewEventKey(tcell.KeyTab, 0, tcell.ModNone)
  82. case tcell.KeyUp, tcell.KeyLeft:
  83. return tcell.NewEventKey(tcell.KeyBacktab, 0, tcell.ModNone)
  84. }
  85. return event
  86. })
  87. }(index, label)
  88. }
  89. return m
  90. }
  91. // Focus is called when this primitive receives focus.
  92. func (m *Modal) Focus(delegate func(p Primitive)) {
  93. delegate(m.form)
  94. }
  95. // HasFocus returns whether or not this primitive has focus.
  96. func (m *Modal) HasFocus() bool {
  97. return m.form.HasFocus()
  98. }
  99. // Draw draws this primitive onto the screen.
  100. func (m *Modal) Draw(screen tcell.Screen) {
  101. // Calculate the width of this modal.
  102. buttonsWidth := 0
  103. for _, button := range m.form.buttons {
  104. buttonsWidth += TaggedStringWidth(button.label) + 4 + 2
  105. }
  106. buttonsWidth -= 2
  107. screenWidth, screenHeight := screen.Size()
  108. width := screenWidth / 3
  109. if width < buttonsWidth {
  110. width = buttonsWidth
  111. }
  112. // width is now without the box border.
  113. // Reset the text and find out how wide it is.
  114. m.frame.Clear()
  115. lines := WordWrap(m.text, width)
  116. for _, line := range lines {
  117. m.frame.AddText(line, true, AlignCenter, m.textColor)
  118. }
  119. // Set the modal's position and size.
  120. height := len(lines) + 6
  121. width += 4
  122. x := (screenWidth - width) / 2
  123. y := (screenHeight - height) / 2
  124. m.SetRect(x, y, width, height)
  125. // Draw the frame.
  126. m.frame.SetRect(x, y, width, height)
  127. m.frame.Draw(screen)
  128. }