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.

180 lines
3.6KB

  1. #include "ui.hpp"
  2. // for gVg
  3. #include "window.hpp"
  4. // for key codes
  5. #include <GLFW/glfw3.h>
  6. namespace rack {
  7. void TextField::draw(NVGcontext *vg) {
  8. nvgScissor(vg, 0, 0, box.size.x, box.size.y);
  9. BNDwidgetState state;
  10. if (this == gFocusedWidget)
  11. state = BND_ACTIVE;
  12. else if (this == gHoveredWidget)
  13. state = BND_HOVER;
  14. else
  15. state = BND_DEFAULT;
  16. bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end);
  17. // Draw placeholder text
  18. if (text.empty() && state != BND_ACTIVE) {
  19. 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);
  20. }
  21. nvgResetScissor(vg);
  22. }
  23. void TextField::onMouseDown(EventMouseDown &e) {
  24. dragPos = getTextPosition(e.pos);
  25. begin = end = dragPos;
  26. OpaqueWidget::onMouseDown(e);
  27. }
  28. void TextField::onMouseMove(EventMouseMove &e) {
  29. if (this == gDraggedWidget) {
  30. int pos = getTextPosition(e.pos);
  31. if (pos != dragPos) {
  32. begin = min(dragPos, pos);
  33. end = max(dragPos, pos);
  34. }
  35. }
  36. OpaqueWidget::onMouseMove(e);
  37. }
  38. void TextField::onFocus(EventFocus &e) {
  39. begin = 0;
  40. end = text.size();
  41. e.consumed = true;
  42. }
  43. void TextField::onText(EventText &e) {
  44. if (e.codepoint < 128) {
  45. std::string newText(1, (char) e.codepoint);
  46. insertText(newText);
  47. }
  48. e.consumed = true;
  49. }
  50. void TextField::onKey(EventKey &e) {
  51. switch (e.key) {
  52. case GLFW_KEY_BACKSPACE:
  53. if (begin < end) {
  54. text.erase(begin, end - begin);
  55. onTextChange();
  56. }
  57. else {
  58. begin--;
  59. if (begin >= 0) {
  60. text.erase(begin, 1);
  61. onTextChange();
  62. }
  63. }
  64. end = begin;
  65. break;
  66. case GLFW_KEY_DELETE:
  67. if (begin < end) {
  68. text.erase(begin, end - begin);
  69. onTextChange();
  70. }
  71. else {
  72. text.erase(begin, 1);
  73. onTextChange();
  74. }
  75. end = begin;
  76. break;
  77. case GLFW_KEY_LEFT:
  78. if (begin < end) {
  79. }
  80. else {
  81. begin--;
  82. }
  83. end = begin;
  84. break;
  85. case GLFW_KEY_RIGHT:
  86. if (begin < end) {
  87. begin = end;
  88. }
  89. else {
  90. begin++;
  91. }
  92. end = begin;
  93. break;
  94. case GLFW_KEY_HOME:
  95. end = begin = 0;
  96. break;
  97. case GLFW_KEY_END:
  98. end = begin = text.size();
  99. break;
  100. case GLFW_KEY_V:
  101. if (windowIsModPressed()) {
  102. const char *newText = glfwGetClipboardString(gWindow);
  103. if (newText)
  104. insertText(newText);
  105. }
  106. break;
  107. case GLFW_KEY_X:
  108. if (windowIsModPressed()) {
  109. if (begin < end) {
  110. std::string selectedText = text.substr(begin, end - begin);
  111. glfwSetClipboardString(gWindow, selectedText.c_str());
  112. insertText("");
  113. }
  114. }
  115. break;
  116. case GLFW_KEY_C:
  117. if (windowIsModPressed()) {
  118. if (begin < end) {
  119. std::string selectedText = text.substr(begin, end - begin);
  120. glfwSetClipboardString(gWindow, selectedText.c_str());
  121. }
  122. }
  123. break;
  124. case GLFW_KEY_A:
  125. if (windowIsModPressed()) {
  126. begin = 0;
  127. end = text.size();
  128. }
  129. break;
  130. case GLFW_KEY_ENTER:
  131. if (multiline) {
  132. insertText("\n");
  133. }
  134. else {
  135. EventAction e;
  136. onAction(e);
  137. }
  138. break;
  139. }
  140. begin = clamp(begin, 0, text.size());
  141. end = clamp(end, 0, text.size());
  142. e.consumed = true;
  143. }
  144. void TextField::insertText(std::string text) {
  145. if (begin < end)
  146. this->text.erase(begin, end - begin);
  147. this->text.insert(begin, text);
  148. begin += text.size();
  149. end = begin;
  150. onTextChange();
  151. }
  152. void TextField::setText(std::string text) {
  153. this->text = text;
  154. begin = clamp(begin, 0, text.size());
  155. end = clamp(end, 0, text.size());
  156. onTextChange();
  157. }
  158. int TextField::getTextPosition(Vec mousePos) {
  159. return bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), mousePos.x, mousePos.y);
  160. }
  161. } // namespace rack