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.

255 lines
6.4KB

  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. // Param map indicator
  109. engine::ParamHandle *paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module, paramQuantity->paramId) : NULL;
  110. if (paramHandle) {
  111. NVGcolor color = nvgRGB(0xff, 0x40, 0xff);
  112. nvgBeginPath(args.vg);
  113. nvgCircle(args.vg, box.size.x - 3, box.size.y - 3, 3.0);
  114. nvgFillColor(args.vg, color);
  115. nvgFill(args.vg);
  116. nvgStrokeColor(args.vg, color::mult(color, 0.5));
  117. nvgStrokeWidth(args.vg, 1.0);
  118. nvgStroke(args.vg);
  119. }
  120. }
  121. void ParamWidget::onButton(const event::Button &e) {
  122. // Touch parameter
  123. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == 0) {
  124. if (paramQuantity) {
  125. APP->scene->rackWidget->touchedParam = this;
  126. }
  127. }
  128. // Right click to open context menu
  129. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) {
  130. createContextMenu();
  131. e.consume(this);
  132. }
  133. if (!e.getConsumed())
  134. OpaqueWidget::onButton(e);
  135. }
  136. void ParamWidget::onDoubleClick(const event::DoubleClick &e) {
  137. resetAction();
  138. }
  139. void ParamWidget::onEnter(const event::Enter &e) {
  140. if (settings.paramTooltip && !tooltip && paramQuantity) {
  141. ParamTooltip *paramTooltip = new ParamTooltip;
  142. paramTooltip->paramWidget = this;
  143. APP->scene->addChild(paramTooltip);
  144. tooltip = paramTooltip;
  145. e.consume(this);
  146. }
  147. }
  148. void ParamWidget::onLeave(const event::Leave &e) {
  149. if (tooltip) {
  150. APP->scene->removeChild(tooltip);
  151. delete tooltip;
  152. tooltip = NULL;
  153. }
  154. }
  155. void ParamWidget::fromJson(json_t *rootJ) {
  156. json_t *valueJ = json_object_get(rootJ, "value");
  157. if (valueJ) {
  158. if (paramQuantity)
  159. paramQuantity->setValue(json_number_value(valueJ));
  160. }
  161. }
  162. void ParamWidget::createContextMenu() {
  163. ui::Menu *menu = createMenu();
  164. ParamLabel *paramLabel = new ParamLabel;
  165. paramLabel->paramWidget = this;
  166. menu->addChild(paramLabel);
  167. ParamField *paramField = new ParamField;
  168. paramField->box.size.x = 100;
  169. paramField->setParamWidget(this);
  170. menu->addChild(paramField);
  171. ParamResetItem *resetItem = new ParamResetItem;
  172. resetItem->text = "Initialize";
  173. resetItem->rightText = "Double-click";
  174. resetItem->paramWidget = this;
  175. menu->addChild(resetItem);
  176. // ParamFineItem *fineItem = new ParamFineItem;
  177. // fineItem->text = "Fine adjust";
  178. // fineItem->rightText = WINDOW_MOD_CTRL_NAME "+drag";
  179. // fineItem->disabled = true;
  180. // menu->addChild(fineItem);
  181. engine::ParamHandle *paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module, paramQuantity->paramId) : NULL;
  182. if (paramHandle) {
  183. ParamUnmapItem *unmapItem = new ParamUnmapItem;
  184. unmapItem->text = "Unmap";
  185. unmapItem->paramWidget = this;
  186. menu->addChild(unmapItem);
  187. }
  188. }
  189. void ParamWidget::resetAction() {
  190. if (paramQuantity && paramQuantity->isBounded()) {
  191. float oldValue = paramQuantity->getValue();
  192. paramQuantity->reset();
  193. float newValue = paramQuantity->getValue();
  194. if (oldValue != newValue) {
  195. // Push ParamChange history action
  196. history::ParamChange *h = new history::ParamChange;
  197. h->name = "reset parameter";
  198. h->moduleId = paramQuantity->module->id;
  199. h->paramId = paramQuantity->paramId;
  200. h->oldValue = oldValue;
  201. h->newValue = newValue;
  202. APP->history->push(h);
  203. }
  204. // Here's another way of doing it, but either works.
  205. // paramQuantity->getParam()->reset();
  206. }
  207. }
  208. } // namespace app
  209. } // namespace rack