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.

249 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.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. }
  63. };
  64. struct ParamLabel : ui::MenuLabel {
  65. ParamWidget* paramWidget;
  66. void step() override {
  67. text = paramWidget->paramQuantity->getString();
  68. MenuLabel::step();
  69. }
  70. };
  71. struct ParamResetItem : ui::MenuItem {
  72. ParamWidget* paramWidget;
  73. void onAction(const event::Action& e) override {
  74. paramWidget->resetAction();
  75. }
  76. };
  77. struct ParamFineItem : ui::MenuItem {
  78. };
  79. struct ParamUnmapItem : ui::MenuItem {
  80. ParamWidget* paramWidget;
  81. void onAction(const event::Action& e) override {
  82. engine::ParamHandle* paramHandle = APP->engine->getParamHandle(paramWidget->paramQuantity->module->id, paramWidget->paramQuantity->paramId);
  83. if (paramHandle) {
  84. APP->engine->updateParamHandle(paramHandle, -1, 0);
  85. }
  86. }
  87. };
  88. void ParamWidget::step() {
  89. if (paramQuantity) {
  90. float value = paramQuantity->getValue();
  91. // Trigger change event when paramQuantity value changes
  92. if (value != dirtyValue) {
  93. dirtyValue = value;
  94. event::Change eChange;
  95. onChange(eChange);
  96. }
  97. }
  98. Widget::step();
  99. }
  100. void ParamWidget::draw(const DrawArgs& args) {
  101. Widget::draw(args);
  102. // Param map indicator
  103. engine::ParamHandle* paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module->id, paramQuantity->paramId) : NULL;
  104. if (paramHandle) {
  105. NVGcolor color = paramHandle->color;
  106. nvgBeginPath(args.vg);
  107. const float radius = 6;
  108. // nvgCircle(args.vg, box.size.x / 2, box.size.y / 2, radius);
  109. nvgRect(args.vg, box.size.x - radius, box.size.y - radius, radius, radius);
  110. nvgFillColor(args.vg, color);
  111. nvgFill(args.vg);
  112. nvgStrokeColor(args.vg, color::mult(color, 0.5));
  113. nvgStrokeWidth(args.vg, 1.0);
  114. nvgStroke(args.vg);
  115. }
  116. }
  117. void ParamWidget::onButton(const event::Button& e) {
  118. OpaqueWidget::onButton(e);
  119. // Touch parameter
  120. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == 0) {
  121. if (paramQuantity) {
  122. APP->scene->rack->touchedParam = this;
  123. }
  124. e.consume(this);
  125. }
  126. // Right click to open context menu
  127. if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & RACK_MOD_MASK) == 0) {
  128. createContextMenu();
  129. e.consume(this);
  130. }
  131. }
  132. void ParamWidget::onDoubleClick(const event::DoubleClick& e) {
  133. resetAction();
  134. }
  135. void ParamWidget::onEnter(const event::Enter& e) {
  136. if (settings::paramTooltip && !tooltip && paramQuantity) {
  137. ParamTooltip* paramTooltip = new ParamTooltip;
  138. paramTooltip->paramWidget = this;
  139. APP->scene->addChild(paramTooltip);
  140. tooltip = paramTooltip;
  141. }
  142. }
  143. void ParamWidget::onLeave(const event::Leave& e) {
  144. if (tooltip) {
  145. APP->scene->removeChild(tooltip);
  146. delete tooltip;
  147. tooltip = NULL;
  148. }
  149. }
  150. void ParamWidget::fromJson(json_t* rootJ) {
  151. json_t* valueJ = json_object_get(rootJ, "value");
  152. if (valueJ) {
  153. if (paramQuantity)
  154. paramQuantity->setValue(json_number_value(valueJ));
  155. }
  156. }
  157. void ParamWidget::createContextMenu() {
  158. ui::Menu* menu = createMenu();
  159. ParamLabel* paramLabel = new ParamLabel;
  160. paramLabel->paramWidget = this;
  161. menu->addChild(paramLabel);
  162. ParamField* paramField = new ParamField;
  163. paramField->box.size.x = 100;
  164. paramField->setParamWidget(this);
  165. menu->addChild(paramField);
  166. ParamResetItem* resetItem = new ParamResetItem;
  167. resetItem->text = "Initialize";
  168. resetItem->rightText = "Double-click";
  169. resetItem->paramWidget = this;
  170. menu->addChild(resetItem);
  171. // ParamFineItem *fineItem = new ParamFineItem;
  172. // fineItem->text = "Fine adjust";
  173. // fineItem->rightText = RACK_MOD_CTRL_NAME "+drag";
  174. // fineItem->disabled = true;
  175. // menu->addChild(fineItem);
  176. engine::ParamHandle* paramHandle = paramQuantity ? APP->engine->getParamHandle(paramQuantity->module->id, paramQuantity->paramId) : NULL;
  177. if (paramHandle) {
  178. ParamUnmapItem* unmapItem = new ParamUnmapItem;
  179. unmapItem->text = "Unmap";
  180. unmapItem->rightText = paramHandle->text;
  181. unmapItem->paramWidget = this;
  182. menu->addChild(unmapItem);
  183. }
  184. }
  185. void ParamWidget::resetAction() {
  186. if (paramQuantity && paramQuantity->isBounded()) {
  187. float oldValue = paramQuantity->getValue();
  188. reset();
  189. // Here's another way of doing it, but either works.
  190. // paramQuantity->getParam()->reset();
  191. float newValue = paramQuantity->getValue();
  192. if (oldValue != newValue) {
  193. // Push ParamChange history action
  194. history::ParamChange* h = new history::ParamChange;
  195. h->name = "reset parameter";
  196. h->moduleId = paramQuantity->module->id;
  197. h->paramId = paramQuantity->paramId;
  198. h->oldValue = oldValue;
  199. h->newValue = newValue;
  200. APP->history->push(h);
  201. }
  202. }
  203. }
  204. } // namespace app
  205. } // namespace rack