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.

252 lines
6.5KB

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