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.

211 lines
5.2KB

  1. #include "ui/TextField.hpp"
  2. namespace rack {
  3. TextField::TextField() {
  4. box.size.y = BND_WIDGET_HEIGHT;
  5. }
  6. void TextField::draw(NVGcontext *vg) {
  7. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  8. BNDwidgetState state;
  9. if (this == app()->event->selectedWidget)
  10. state = BND_ACTIVE;
  11. else if (this == app()->event->hoveredWidget)
  12. state = BND_HOVER;
  13. else
  14. state = BND_DEFAULT;
  15. int begin = std::min(cursor, selection);
  16. int end = std::max(cursor, selection);
  17. bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end);
  18. // Draw placeholder text
  19. if (text.empty() && state != BND_ACTIVE) {
  20. bndIconLabelCaret(vg, 0.0, 0.0, box.size.x, box.size.y, -1, bndGetTheme()->textFieldTheme.itemColor, 13, placeholder.c_str(), bndGetTheme()->textFieldTheme.itemColor, 0, -1);
  21. }
  22. nvgResetScissor(vg);
  23. }
  24. void TextField::onButton(const event::Button &e) {
  25. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
  26. cursor = selection = getTextPosition(e.pos);
  27. }
  28. OpaqueWidget::onButton(e);
  29. }
  30. void TextField::onHover(const event::Hover &e) {
  31. if (this == app()->event->draggedWidget) {
  32. int pos = getTextPosition(e.pos);
  33. if (pos != selection) {
  34. cursor = pos;
  35. }
  36. }
  37. OpaqueWidget::onHover(e);
  38. }
  39. void TextField::onEnter(const event::Enter &e) {
  40. e.consume(this);
  41. }
  42. void TextField::onSelectText(const event::SelectText &e) {
  43. if (e.codepoint < 128) {
  44. std::string newText(1, (char) e.codepoint);
  45. insertText(newText);
  46. }
  47. e.consume(this);
  48. }
  49. void TextField::onSelectKey(const event::SelectKey &e) {
  50. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  51. switch (e.key) {
  52. case GLFW_KEY_BACKSPACE: {
  53. if (cursor == selection) {
  54. cursor--;
  55. if (cursor >= 0) {
  56. text.erase(cursor, 1);
  57. event::Change eChange;
  58. onChange(eChange);
  59. }
  60. selection = cursor;
  61. }
  62. else {
  63. int begin = std::min(cursor, selection);
  64. text.erase(begin, std::abs(selection - cursor));
  65. event::Change eChange;
  66. onChange(eChange);
  67. cursor = selection = begin;
  68. }
  69. } break;
  70. case GLFW_KEY_DELETE: {
  71. if (cursor == selection) {
  72. text.erase(cursor, 1);
  73. event::Change eChange;
  74. onChange(eChange);
  75. }
  76. else {
  77. int begin = std::min(cursor, selection);
  78. text.erase(begin, std::abs(selection - cursor));
  79. event::Change eChange;
  80. onChange(eChange);
  81. cursor = selection = begin;
  82. }
  83. } break;
  84. case GLFW_KEY_LEFT: {
  85. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  86. while (--cursor > 0) {
  87. if (text[cursor] == ' ')
  88. break;
  89. }
  90. }
  91. else {
  92. cursor--;
  93. }
  94. if ((e.mods & WINDOW_MOD_MASK) == 0) {
  95. selection = cursor;
  96. }
  97. } break;
  98. case GLFW_KEY_RIGHT: {
  99. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  100. while (++cursor < (int) text.size()) {
  101. if (text[cursor] == ' ')
  102. break;
  103. }
  104. }
  105. else {
  106. cursor++;
  107. }
  108. if ((e.mods & WINDOW_MOD_MASK) == 0) {
  109. selection = cursor;
  110. }
  111. } break;
  112. case GLFW_KEY_HOME: {
  113. selection = cursor = 0;
  114. } break;
  115. case GLFW_KEY_END: {
  116. selection = cursor = text.size();
  117. } break;
  118. case GLFW_KEY_V: {
  119. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  120. const char *newText = glfwGetClipboardString(app()->window->win);
  121. if (newText)
  122. insertText(newText);
  123. }
  124. } break;
  125. case GLFW_KEY_X: {
  126. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  127. if (cursor != selection) {
  128. int begin = std::min(cursor, selection);
  129. std::string selectedText = text.substr(begin, std::abs(selection - cursor));
  130. glfwSetClipboardString(app()->window->win, selectedText.c_str());
  131. insertText("");
  132. }
  133. }
  134. } break;
  135. case GLFW_KEY_C: {
  136. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  137. if (cursor != selection) {
  138. int begin = std::min(cursor, selection);
  139. std::string selectedText = text.substr(begin, std::abs(selection - cursor));
  140. glfwSetClipboardString(app()->window->win, selectedText.c_str());
  141. }
  142. }
  143. } break;
  144. case GLFW_KEY_A: {
  145. if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
  146. selectAll();
  147. }
  148. } break;
  149. case GLFW_KEY_ENTER: {
  150. if (multiline) {
  151. insertText("\n");
  152. }
  153. else {
  154. event::Action eAction;
  155. onAction(eAction);
  156. }
  157. } break;
  158. }
  159. cursor = math::clamp(cursor, 0, (int) text.size());
  160. selection = math::clamp(selection, 0, (int) text.size());
  161. e.consume(this);
  162. }
  163. }
  164. /** Inserts text at the cursor, replacing the selection if necessary */
  165. void TextField::insertText(std::string text) {
  166. if (cursor != selection) {
  167. int begin = std::min(cursor, selection);
  168. this->text.erase(begin, std::abs(selection - cursor));
  169. cursor = selection = begin;
  170. }
  171. this->text.insert(cursor, text);
  172. cursor += text.size();
  173. selection = cursor;
  174. event::Change eChange;
  175. onChange(eChange);
  176. }
  177. /** Replaces the entire text */
  178. void TextField::setText(std::string text) {
  179. this->text = text;
  180. selection = cursor = text.size();
  181. event::Change eChange;
  182. onChange(eChange);
  183. }
  184. void TextField::selectAll() {
  185. cursor = text.size();
  186. selection = 0;
  187. }
  188. int TextField::getTextPosition(math::Vec mousePos) {
  189. return bndTextFieldTextPosition(app()->window->vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), mousePos.x, mousePos.y);
  190. }
  191. } // namespace rack