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.

213 lines
5.1KB

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