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.

267 lines
6.8KB

  1. #include "app/ParamWidget.hpp"
  2. #include "ui/MenuOverlay.hpp"
  3. #include "ui/TextField.hpp"
  4. #include "app/Scene.hpp"
  5. #include "app/ParamQuantity.hpp"
  6. #include "app.hpp"
  7. #include "engine/Engine.hpp"
  8. #include "settings.hpp"
  9. #include "random.hpp"
  10. #include "history.hpp"
  11. #include "helpers.hpp"
  12. namespace rack {
  13. namespace app {
  14. struct ParamField : ui::TextField {
  15. ParamWidget *paramWidget;
  16. void step() override {
  17. // Keep selected
  18. APP->event->setSelected(this);
  19. TextField::step();
  20. }
  21. void setParamWidget(ParamWidget *paramWidget) {
  22. this->paramWidget = paramWidget;
  23. if (paramWidget->paramQuantity)
  24. text = paramWidget->paramQuantity->getDisplayValueString();
  25. selectAll();
  26. }
  27. void onSelectKey(const event::SelectKey &e) override {
  28. if (e.action == GLFW_PRESS && (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER)) {
  29. float oldValue = paramWidget->paramQuantity->getValue();
  30. if (paramWidget->paramQuantity)
  31. paramWidget->paramQuantity->setDisplayValueString(text);
  32. float newValue = paramWidget->paramQuantity->getValue();
  33. if (oldValue != newValue) {
  34. // Push ParamChange history action
  35. history::ParamChange *h = new history::ParamChange;
  36. h->moduleId = paramWidget->paramQuantity->module->id;
  37. h->paramId = paramWidget->paramQuantity->paramId;
  38. h->oldValue = oldValue;
  39. h->newValue = newValue;
  40. APP->history->push(h);
  41. }
  42. ui::MenuOverlay *overlay = getAncestorOfType<ui::MenuOverlay>();
  43. overlay->requestedDelete = true;
  44. e.consume(this);
  45. }
  46. if (!e.getConsumed())
  47. TextField::onSelectKey(e);
  48. }
  49. };
  50. struct ParamTooltip : ui::Tooltip {
  51. ParamWidget *paramWidget;
  52. void step() override {
  53. if (paramWidget->paramQuantity) {
  54. // ui::Quantity string
  55. text = paramWidget->paramQuantity->getString();
  56. // Param description
  57. std::string description = paramWidget->paramQuantity->getParam()->description;
  58. if (!description.empty())
  59. text += "\n" + description;
  60. }
  61. // Position at bottom-right of parameter
  62. box.pos = paramWidget->getAbsoluteOffset(paramWidget->box.size).round();
  63. Tooltip::step();
  64. }
  65. };
  66. struct ParamLabel : ui::MenuLabel {
  67. ParamWidget *paramWidget;
  68. void step() override {
  69. text = paramWidget->paramQuantity->getString();
  70. MenuLabel::step();
  71. }
  72. };
  73. struct ParamResetItem : ui::MenuItem {
  74. ParamWidget *paramWidget;
  75. void onAction(const event::Action &e) override {
  76. paramWidget->resetAction();
  77. }
  78. };
  79. struct ParamFineItem : ui::MenuItem {
  80. };
  81. struct ParamUnmapItem : ui::MenuItem {
  82. ParamWidget *paramWidget;
  83. void onAction(const event::Action &e) override {
  84. engine::ParamHandle *paramHandle = APP->engine->getParamHandle(paramWidget->paramQuantity->module, paramWidget->paramQuantity->paramId);
  85. if (paramHandle) {
  86. APP->engine->updateParamHandle(paramHandle, -1, 0);
  87. }
  88. }
  89. };
  90. ParamWidget::~ParamWidget() {
  91. if (paramQuantity)
  92. delete paramQuantity;
  93. }
  94. void ParamWidget::step() {
  95. if (paramQuantity) {
  96. float value = paramQuantity->getValue();
  97. // Trigger change event when paramQuantity value changes
  98. if (value != dirtyValue) {
  99. dirtyValue = value;
  100. event::Change eChange;
  101. onChange(eChange);
  102. }
  103. }
  104. OpaqueWidget::step();
  105. }
  106. void ParamWidget::draw(const DrawArgs &args) {
  107. Widget::draw(args);
  108. // if (paramQuantity) {
  109. // nvgBeginPath(args.vg);
  110. // nvgRect(args.vg,
  111. // box.size.x - 12, box.size.y - 12,
  112. // 12, 12);
  113. // nvgFillColor(args.vg, nvgRGBAf(1, 0, 1, 0.9));
  114. // nvgFill(args.vg);
  115. // std::string mapText = string::f("%d", paramQuantity->paramId);
  116. // bndLabel(args.vg, box.size.x - 17.0, box.size.y - 16.0, INFINITY, INFINITY, -1, mapText.c_str());
  117. // }
  118. // Param map indicator
  119. engine::ParamHandle *paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module, paramQuantity->paramId) : NULL;
  120. if (paramHandle) {
  121. NVGcolor color = nvgRGB(0xff, 0x40, 0xff);
  122. nvgBeginPath(args.vg);
  123. nvgCircle(args.vg, box.size.x - 3, box.size.y - 3, 3.0);
  124. nvgFillColor(args.vg, color);
  125. nvgFill(args.vg);
  126. nvgStrokeColor(args.vg, color::mult(color, 0.5));
  127. nvgStrokeWidth(args.vg, 1.0);
  128. nvgStroke(args.vg);
  129. }
  130. }
  131. void ParamWidget::onButton(const event::Button &e) {
  132. // Touch parameter
  133. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == 0) {
  134. if (paramQuantity) {
  135. APP->scene->rackWidget->touchedParam = this;
  136. }
  137. }
  138. // Right click to open context menu
  139. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) {
  140. createContextMenu();
  141. e.consume(this);
  142. }
  143. if (!e.getConsumed())
  144. OpaqueWidget::onButton(e);
  145. }
  146. void ParamWidget::onDoubleClick(const event::DoubleClick &e) {
  147. resetAction();
  148. }
  149. void ParamWidget::onEnter(const event::Enter &e) {
  150. if (settings.paramTooltip && !tooltip && paramQuantity) {
  151. ParamTooltip *paramTooltip = new ParamTooltip;
  152. paramTooltip->paramWidget = this;
  153. APP->scene->addChild(paramTooltip);
  154. tooltip = paramTooltip;
  155. e.consume(this);
  156. }
  157. }
  158. void ParamWidget::onLeave(const event::Leave &e) {
  159. if (tooltip) {
  160. APP->scene->removeChild(tooltip);
  161. delete tooltip;
  162. tooltip = NULL;
  163. }
  164. }
  165. void ParamWidget::fromJson(json_t *rootJ) {
  166. json_t *valueJ = json_object_get(rootJ, "value");
  167. if (valueJ) {
  168. if (paramQuantity)
  169. paramQuantity->setValue(json_number_value(valueJ));
  170. }
  171. }
  172. void ParamWidget::createContextMenu() {
  173. ui::Menu *menu = createMenu();
  174. ParamLabel *paramLabel = new ParamLabel;
  175. paramLabel->paramWidget = this;
  176. menu->addChild(paramLabel);
  177. ParamField *paramField = new ParamField;
  178. paramField->box.size.x = 100;
  179. paramField->setParamWidget(this);
  180. menu->addChild(paramField);
  181. ParamResetItem *resetItem = new ParamResetItem;
  182. resetItem->text = "Initialize";
  183. resetItem->rightText = "Double-click";
  184. resetItem->paramWidget = this;
  185. menu->addChild(resetItem);
  186. // ParamFineItem *fineItem = new ParamFineItem;
  187. // fineItem->text = "Fine adjust";
  188. // fineItem->rightText = WINDOW_MOD_CTRL_NAME "+drag";
  189. // fineItem->disabled = true;
  190. // menu->addChild(fineItem);
  191. engine::ParamHandle *paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module, paramQuantity->paramId) : NULL;
  192. if (paramHandle) {
  193. ParamUnmapItem *unmapItem = new ParamUnmapItem;
  194. unmapItem->text = "Unmap";
  195. unmapItem->paramWidget = this;
  196. menu->addChild(unmapItem);
  197. }
  198. }
  199. void ParamWidget::resetAction() {
  200. if (paramQuantity && paramQuantity->isBounded()) {
  201. float oldValue = paramQuantity->getValue();
  202. paramQuantity->reset();
  203. float newValue = paramQuantity->getValue();
  204. if (oldValue != newValue) {
  205. // Push ParamChange history action
  206. history::ParamChange *h = new history::ParamChange;
  207. h->name = "reset parameter";
  208. h->moduleId = paramQuantity->module->id;
  209. h->paramId = paramQuantity->paramId;
  210. h->oldValue = oldValue;
  211. h->newValue = newValue;
  212. APP->history->push(h);
  213. }
  214. // Here's another way of doing it, but either works.
  215. // paramQuantity->getParam()->reset();
  216. }
  217. }
  218. } // namespace app
  219. } // namespace rack