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.

widgets.hpp 10KB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #pragma once
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include <math.h>
  5. #include <list>
  6. #include <map>
  7. #include <jansson.h>
  8. #include "../lib/nanovg/src/nanovg.h"
  9. #include "../lib/oui/blendish.h"
  10. #include "util.hpp"
  11. namespace rack {
  12. struct Module;
  13. struct Wire;
  14. struct RackWidget;
  15. struct ParamWidget;
  16. struct InputPort;
  17. struct OutputPort;
  18. ////////////////////
  19. // base class and traits
  20. ////////////////////
  21. /** A node in the 2D scene graph */
  22. struct Widget {
  23. /** Stores position and size */
  24. Rect box = Rect(Vec(), Vec(INFINITY, INFINITY));
  25. Widget *parent = NULL;
  26. std::list<Widget*> children;
  27. virtual ~Widget();
  28. Vec getAbsolutePos();
  29. Rect getChildrenBoundingBox();
  30. template <class T>
  31. T *getAncestorOfType() {
  32. if (!parent) return NULL;
  33. T *p = dynamic_cast<T*>(parent);
  34. if (p) return p;
  35. return parent->getAncestorOfType<T>();
  36. }
  37. /** Adds widget to list of children.
  38. Gives ownership of widget to this widget instance.
  39. */
  40. void addChild(Widget *widget);
  41. // Does not delete widget but transfers ownership to caller
  42. // Silenty fails if widget is not a child
  43. void removeChild(Widget *widget);
  44. void clearChildren();
  45. /** Advances the module by one frame */
  46. virtual void step();
  47. /** Draws to NanoVG context */
  48. virtual void draw(NVGcontext *vg);
  49. // Events
  50. /** Called when a mouse button is pressed over this widget
  51. 0 for left, 1 for right, 2 for middle.
  52. Return `this` to accept the event.
  53. Return NULL to reject the event and pass it to the widget behind this one.
  54. */
  55. virtual Widget *onMouseDown(Vec pos, int button);
  56. virtual Widget *onMouseUp(Vec pos, int button);
  57. virtual Widget *onMouseMove(Vec pos, Vec mouseRel);
  58. /** Called when this widget begins responding to `onMouseMove` events */
  59. virtual void onMouseEnter() {}
  60. /** Called when another widget begins responding to `onMouseMove` events */
  61. virtual void onMouseLeave() {}
  62. virtual Widget *onScroll(Vec pos, Vec scrollRel);
  63. /** Called when a widget responds to `onMouseDown` for a left button press */
  64. virtual void onDragStart() {}
  65. /** Called when a widget responds to `onMouseMove` and is being dragged */
  66. virtual void onDragMove(Vec mouseRel) {}
  67. /** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
  68. virtual void onDragDrop(Widget *origin) {}
  69. /** Called when the left button is released and this widget is being dragged */
  70. virtual void onDragEnd() {}
  71. virtual void onAction() {}
  72. virtual void onChange() {}
  73. };
  74. /** Widget that does not respond to events */
  75. struct TransparentWidget : virtual Widget {
  76. Widget *onMouseDown(Vec pos, int button) {return NULL;}
  77. Widget *onMouseUp(Vec pos, int button) {return NULL;}
  78. Widget *onMouseMove(Vec pos, Vec mouseRel) {return NULL;}
  79. Widget *onScroll(Vec pos, Vec scrollRel) {return NULL;}
  80. };
  81. /** Widget that itself responds to mouse events */
  82. struct OpaqueWidget : virtual Widget {
  83. Widget *onMouseDown(Vec pos, int button) {
  84. Widget *w = Widget::onMouseDown(pos, button);
  85. if (w) return w;
  86. onMouseDown(button);
  87. return this;
  88. }
  89. Widget *onMouseUp(Vec pos, int button) {
  90. Widget *w = Widget::onMouseUp(pos, button);
  91. if (w) return w;
  92. onMouseUp(button);
  93. return this;
  94. }
  95. Widget *onMouseMove(Vec pos, Vec mouseRel) {
  96. Widget *w = Widget::onMouseMove(pos, mouseRel);
  97. if (w) return w;
  98. onMouseMove(mouseRel);
  99. return this;
  100. }
  101. /** "High level" events called by the above lower level events.
  102. Use these if you don't care about the clicked position.
  103. */
  104. virtual void onMouseDown(int button) {}
  105. virtual void onMouseUp(int button) {}
  106. virtual void onMouseMove(Vec mouseRel) {}
  107. };
  108. struct SpriteWidget : virtual Widget {
  109. Vec spriteOffset;
  110. Vec spriteSize;
  111. std::string spriteFilename;
  112. int index = 0;
  113. void draw(NVGcontext *vg);
  114. };
  115. struct QuantityWidget : virtual Widget {
  116. float value = 0.0;
  117. float minValue = 0.0;
  118. float maxValue = 1.0;
  119. float defaultValue = 0.0;
  120. std::string label;
  121. /** Include a space character if you want a space after the number, e.g. " Hz" */
  122. std::string unit;
  123. /** The digit place to round for displaying values.
  124. A precision of -2 will display as "1.00" for example.
  125. */
  126. int precision = -2;
  127. QuantityWidget();
  128. void setValue(float value);
  129. void setLimits(float minValue, float maxValue);
  130. void setDefaultValue(float defaultValue);
  131. /** Generates the display value */
  132. std::string getText();
  133. };
  134. ////////////////////
  135. // gui elements
  136. ////////////////////
  137. struct Label : Widget {
  138. std::string text;
  139. Label() {
  140. box.size.y = BND_WIDGET_HEIGHT;
  141. }
  142. void draw(NVGcontext *vg);
  143. };
  144. // Deletes itself from parent when clicked
  145. struct MenuOverlay : OpaqueWidget {
  146. void step();
  147. Widget *onScroll(Vec pos, Vec scrollRel) {
  148. return this;
  149. }
  150. void onDragDrop(Widget *origin);
  151. };
  152. struct Menu : OpaqueWidget {
  153. Menu() {
  154. box.size = Vec(0, 0);
  155. }
  156. // Resizes menu and calls addChild()
  157. void pushChild(Widget *child);
  158. void draw(NVGcontext *vg);
  159. };
  160. struct MenuEntry : OpaqueWidget {
  161. std::string text;
  162. MenuEntry() {
  163. box.size = Vec(0, BND_WIDGET_HEIGHT);
  164. }
  165. float computeMinWidth(NVGcontext *vg);
  166. };
  167. struct MenuLabel : MenuEntry {
  168. void draw(NVGcontext *vg);
  169. };
  170. struct MenuItem : MenuEntry {
  171. BNDwidgetState state = BND_DEFAULT;
  172. void draw(NVGcontext *vg);
  173. void onMouseEnter();
  174. void onMouseLeave() ;
  175. void onDragDrop(Widget *origin);
  176. };
  177. struct Button : OpaqueWidget {
  178. std::string text;
  179. BNDwidgetState state = BND_DEFAULT;
  180. Button() {
  181. box.size.y = BND_WIDGET_HEIGHT;
  182. }
  183. void draw(NVGcontext *vg);
  184. void onMouseEnter();
  185. void onMouseLeave() ;
  186. void onDragDrop(Widget *origin);
  187. };
  188. struct ChoiceButton : Button {
  189. void draw(NVGcontext *vg);
  190. };
  191. struct Slider : OpaqueWidget, QuantityWidget {
  192. BNDwidgetState state = BND_DEFAULT;
  193. Slider() {
  194. box.size.y = BND_WIDGET_HEIGHT;
  195. }
  196. void draw(NVGcontext *vg);
  197. void onDragStart();
  198. void onDragMove(Vec mouseRel);
  199. void onDragEnd();
  200. };
  201. struct ScrollBar : OpaqueWidget {
  202. enum { VERTICAL, HORIZONTAL } orientation;
  203. float containerOffset = 0.0;
  204. float containerSize = 0.0;
  205. BNDwidgetState state = BND_DEFAULT;
  206. ScrollBar() {
  207. box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
  208. }
  209. void draw(NVGcontext *vg);
  210. void move(float delta);
  211. void onDragStart();
  212. void onDragMove(Vec mouseRel);
  213. void onDragEnd();
  214. };
  215. // Handles a container with scrollbars
  216. struct ScrollWidget : OpaqueWidget {
  217. Widget *container;
  218. ScrollBar *hScrollBar;
  219. ScrollBar *vScrollBar;
  220. ScrollWidget();
  221. void step();
  222. void draw(NVGcontext *vg);
  223. Widget *onScroll(Vec pos, Vec scrollRel);
  224. };
  225. struct Tooltip : Widget {
  226. void step();
  227. void draw(NVGcontext *vg);
  228. };
  229. ////////////////////
  230. // module
  231. ////////////////////
  232. // A 1U module should be 15x380. Thus the width of a module should be a factor of 15.
  233. struct Model;
  234. struct ModuleWidget : OpaqueWidget {
  235. Model *model = NULL;
  236. // Eventually this should be replaced with a `moduleId` which will be used for inter-process communication between the gui world and the audio world.
  237. Module *module = NULL;
  238. // int moduleId;
  239. std::vector<InputPort*> inputs;
  240. std::vector<OutputPort*> outputs;
  241. std::vector<ParamWidget*> params;
  242. ModuleWidget(Module *module);
  243. ~ModuleWidget();
  244. // Convenience functions for adding special widgets (calls addChild())
  245. void addInput(InputPort *input);
  246. void addOutput(OutputPort *output);
  247. void addParam(ParamWidget *param);
  248. json_t *toJson();
  249. void fromJson(json_t *root);
  250. void disconnectPorts();
  251. void resetParams();
  252. void cloneParams(ModuleWidget *source);
  253. void draw(NVGcontext *vg);
  254. bool requested = false;
  255. Vec requestedPos;
  256. Vec dragPos;
  257. void onDragStart();
  258. void onDragMove(Vec mouseRel);
  259. void onDragEnd();
  260. void onMouseDown(int button);
  261. };
  262. struct WireWidget : OpaqueWidget {
  263. OutputPort *outputPort = NULL;
  264. InputPort *inputPort = NULL;
  265. Wire *wire = NULL;
  266. NVGcolor color;
  267. WireWidget();
  268. ~WireWidget();
  269. void updateWire();
  270. void draw(NVGcontext *vg);
  271. void drawOutputPlug(NVGcontext *vg);
  272. void drawInputPlug(NVGcontext *vg);
  273. };
  274. struct RackWidget : OpaqueWidget {
  275. // Only put ModuleWidgets in here
  276. Widget *moduleContainer;
  277. // Only put WireWidgets in here
  278. Widget *wireContainer;
  279. WireWidget *activeWire = NULL;
  280. RackWidget();
  281. ~RackWidget();
  282. void clear();
  283. void savePatch(std::string filename);
  284. void loadPatch(std::string filename);
  285. json_t *toJson();
  286. void fromJson(json_t *root);
  287. int frame = 0;
  288. void repositionModule(ModuleWidget *module);
  289. void step();
  290. void draw(NVGcontext *vg);
  291. void onMouseDown(int button);
  292. };
  293. struct ModulePanel : TransparentWidget {
  294. NVGcolor backgroundColor;
  295. NVGcolor highlightColor;
  296. std::string imageFilename;
  297. void draw(NVGcontext *vg);
  298. };
  299. ////////////////////
  300. // params
  301. ////////////////////
  302. struct Light : TransparentWidget, SpriteWidget {
  303. NVGcolor color;
  304. void draw(NVGcontext *vg);
  305. };
  306. // If you don't add these to your ModuleWidget, it will fall out of the RackWidget
  307. struct Screw : TransparentWidget, SpriteWidget {
  308. Screw();
  309. };
  310. struct ParamWidget : OpaqueWidget, QuantityWidget {
  311. Module *module = NULL;
  312. int paramId;
  313. json_t *toJson();
  314. void fromJson(json_t *root);
  315. void onMouseDown(int button);
  316. void onChange();
  317. };
  318. struct Knob : ParamWidget, SpriteWidget {
  319. int minIndex, maxIndex, spriteCount;
  320. void step();
  321. void onDragStart();
  322. void onDragMove(Vec mouseRel);
  323. void onDragEnd();
  324. };
  325. struct Switch : ParamWidget, SpriteWidget {
  326. };
  327. struct ToggleSwitch : virtual Switch {
  328. void onDragStart() {
  329. index = 1;
  330. }
  331. void onDragEnd() {
  332. index = 0;
  333. }
  334. void onDragDrop(Widget *origin) {
  335. if (origin != this)
  336. return;
  337. // Cycle through modes
  338. // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3.
  339. float v = value + 1.0;
  340. setValue(v > maxValue ? minValue : v);
  341. }
  342. };
  343. struct MomentarySwitch : virtual Switch {
  344. void onDragStart() {
  345. setValue(maxValue);
  346. index = 1;
  347. }
  348. void onDragEnd() {
  349. setValue(minValue);
  350. index = 0;
  351. }
  352. };
  353. ////////////////////
  354. // ports
  355. ////////////////////
  356. struct Port : OpaqueWidget, SpriteWidget {
  357. Module *module = NULL;
  358. WireWidget *connectedWire = NULL;
  359. Port();
  360. ~Port();
  361. void disconnect();
  362. int type;
  363. void drawGlow(NVGcontext *vg);
  364. void onMouseDown(int button);
  365. void onDragEnd();
  366. };
  367. struct InputPort : Port {
  368. int inputId;
  369. void draw(NVGcontext *vg);
  370. void onDragStart();
  371. void onDragDrop(Widget *origin);
  372. };
  373. struct OutputPort : Port {
  374. int outputId;
  375. void draw(NVGcontext *vg);
  376. void onDragStart();
  377. void onDragDrop(Widget *origin);
  378. };
  379. ////////////////////
  380. // scene
  381. ////////////////////
  382. struct Toolbar : OpaqueWidget {
  383. Slider *wireOpacitySlider;
  384. Slider *wireTensionSlider;
  385. Toolbar();
  386. void draw(NVGcontext *vg);
  387. };
  388. struct Scene : OpaqueWidget {
  389. Toolbar *toolbar;
  390. ScrollWidget *scrollWidget;
  391. Widget *overlay = NULL;
  392. Scene();
  393. void setOverlay(Widget *w);
  394. void step();
  395. };
  396. } // namespace rack