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