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.

331 lines
7.7KB

  1. #pragma once
  2. #include <list>
  3. #include <memory>
  4. #include "../ext/nanovg/src/nanovg.h"
  5. #include "../ext/oui/blendish.h"
  6. #include "../ext/nanosvg/src/nanosvg.h"
  7. #include "math.hpp"
  8. #include "util.hpp"
  9. namespace rack {
  10. ////////////////////
  11. // resources
  12. ////////////////////
  13. // Constructing these directly will load from the disk each time. Use the load() functions to load from disk and cache them as long as the shared_ptr is held.
  14. // Implemented in gui.cpp
  15. struct Font {
  16. int handle;
  17. Font(const std::string &filename);
  18. ~Font();
  19. static std::shared_ptr<Font> load(const std::string &filename);
  20. };
  21. struct Image {
  22. int handle;
  23. Image(const std::string &filename);
  24. ~Image();
  25. static std::shared_ptr<Image> load(const std::string &filename);
  26. };
  27. struct SVG {
  28. NSVGimage *handle;
  29. SVG(const std::string &filename);
  30. ~SVG();
  31. static std::shared_ptr<SVG> load(const std::string &filename);
  32. };
  33. ////////////////////
  34. // base class and traits
  35. ////////////////////
  36. /** A node in the 2D scene graph */
  37. struct Widget {
  38. /** Stores position and size */
  39. Rect box = Rect(Vec(), Vec(INFINITY, INFINITY));
  40. Widget *parent = NULL;
  41. std::list<Widget*> children;
  42. virtual ~Widget();
  43. Vec getAbsolutePos();
  44. Rect getChildrenBoundingBox();
  45. template <class T>
  46. T *getAncestorOfType() {
  47. if (!parent) return NULL;
  48. T *p = dynamic_cast<T*>(parent);
  49. if (p) return p;
  50. return parent->getAncestorOfType<T>();
  51. }
  52. /** Adds widget to list of children.
  53. Gives ownership of widget to this widget instance.
  54. */
  55. void addChild(Widget *widget);
  56. /** Removes widget from list of children if it exists.
  57. Does not delete widget but transfers ownership to caller
  58. Silently fails if widget is not a child
  59. */
  60. void removeChild(Widget *widget);
  61. void clearChildren();
  62. /** Advances the module by one frame */
  63. virtual void step();
  64. /** Draws to NanoVG context */
  65. virtual void draw(NVGcontext *vg);
  66. // Events
  67. /** Called when a mouse button is pressed over this widget
  68. 0 for left, 1 for right, 2 for middle.
  69. Return `this` to accept the event.
  70. Return NULL to reject the event and pass it to the widget behind this one.
  71. */
  72. virtual Widget *onMouseDown(Vec pos, int button);
  73. virtual Widget *onMouseUp(Vec pos, int button);
  74. virtual Widget *onMouseMove(Vec pos, Vec mouseRel);
  75. /** Called when this widget begins responding to `onMouseMove` events */
  76. virtual void onMouseEnter() {}
  77. /** Called when another widget begins responding to `onMouseMove` events */
  78. virtual void onMouseLeave() {}
  79. virtual Widget *onScroll(Vec pos, Vec scrollRel);
  80. /** Called when a widget responds to `onMouseDown` for a left button press */
  81. virtual void onDragStart() {}
  82. /** Called when the left button is released and this widget is being dragged */
  83. virtual void onDragEnd() {}
  84. /** Called when a widget responds to `onMouseMove` and is being dragged */
  85. virtual void onDragMove(Vec mouseRel) {}
  86. /** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
  87. virtual void onDragEnter(Widget *origin) {}
  88. virtual void onDragLeave(Widget *origin) {}
  89. virtual void onDragDrop(Widget *origin) {}
  90. virtual void onAction() {}
  91. virtual void onChange() {}
  92. };
  93. /** Widget that does not respond to events */
  94. struct TransparentWidget : virtual Widget {
  95. Widget *onMouseDown(Vec pos, int button) {return NULL;}
  96. Widget *onMouseUp(Vec pos, int button) {return NULL;}
  97. Widget *onMouseMove(Vec pos, Vec mouseRel) {return NULL;}
  98. Widget *onScroll(Vec pos, Vec scrollRel) {return NULL;}
  99. };
  100. /** Widget that itself responds to mouse events */
  101. struct OpaqueWidget : virtual Widget {
  102. Widget *onMouseDown(Vec pos, int button) {
  103. Widget *w = Widget::onMouseDown(pos, button);
  104. if (w) return w;
  105. onMouseDown(button);
  106. return this;
  107. }
  108. Widget *onMouseUp(Vec pos, int button) {
  109. Widget *w = Widget::onMouseUp(pos, button);
  110. if (w) return w;
  111. onMouseUp(button);
  112. return this;
  113. }
  114. Widget *onMouseMove(Vec pos, Vec mouseRel) {
  115. Widget *w = Widget::onMouseMove(pos, mouseRel);
  116. if (w) return w;
  117. onMouseMove(mouseRel);
  118. return this;
  119. }
  120. /** "High level" events called by the above lower level events.
  121. Use these if you don't care about the clicked position.
  122. */
  123. virtual void onMouseDown(int button) {}
  124. virtual void onMouseUp(int button) {}
  125. virtual void onMouseMove(Vec mouseRel) {}
  126. };
  127. struct SpriteWidget : virtual Widget {
  128. Vec spriteOffset;
  129. Vec spriteSize;
  130. std::shared_ptr<Image> spriteImage;
  131. int index = 0;
  132. void draw(NVGcontext *vg);
  133. };
  134. struct QuantityWidget : virtual Widget {
  135. float value = 0.0;
  136. float minValue = 0.0;
  137. float maxValue = 1.0;
  138. float defaultValue = 0.0;
  139. std::string label;
  140. /** Include a space character if you want a space after the number, e.g. " Hz" */
  141. std::string unit;
  142. /** The digit place to round for displaying values.
  143. A precision of -2 will display as "1.00" for example.
  144. */
  145. int precision = -2;
  146. QuantityWidget();
  147. void setValue(float value);
  148. void setLimits(float minValue, float maxValue);
  149. void setDefaultValue(float defaultValue);
  150. /** Generates the display value */
  151. std::string getText();
  152. };
  153. ////////////////////
  154. // gui elements
  155. ////////////////////
  156. struct Label : Widget {
  157. std::string text;
  158. Label() {
  159. box.size.y = BND_WIDGET_HEIGHT;
  160. }
  161. void draw(NVGcontext *vg);
  162. };
  163. // Deletes itself from parent when clicked
  164. struct MenuOverlay : OpaqueWidget {
  165. void step();
  166. Widget *onScroll(Vec pos, Vec scrollRel) {
  167. return this;
  168. }
  169. void onDragDrop(Widget *origin);
  170. };
  171. struct Menu : OpaqueWidget {
  172. Menu() {
  173. box.size = Vec(0, 0);
  174. }
  175. // Resizes menu and calls addChild()
  176. void pushChild(Widget *child);
  177. void draw(NVGcontext *vg);
  178. };
  179. struct MenuEntry : OpaqueWidget {
  180. std::string text;
  181. MenuEntry() {
  182. box.size = Vec(0, BND_WIDGET_HEIGHT);
  183. }
  184. float computeMinWidth(NVGcontext *vg);
  185. };
  186. struct MenuLabel : MenuEntry {
  187. void draw(NVGcontext *vg);
  188. };
  189. struct MenuItem : MenuEntry {
  190. BNDwidgetState state = BND_DEFAULT;
  191. void draw(NVGcontext *vg);
  192. void onMouseEnter();
  193. void onMouseLeave() ;
  194. void onDragDrop(Widget *origin);
  195. };
  196. struct Button : OpaqueWidget {
  197. std::string text;
  198. BNDwidgetState state = BND_DEFAULT;
  199. Button() {
  200. box.size.y = BND_WIDGET_HEIGHT;
  201. }
  202. void draw(NVGcontext *vg);
  203. void onMouseEnter();
  204. void onMouseLeave();
  205. void onDragStart();
  206. void onDragEnd();
  207. void onDragDrop(Widget *origin);
  208. };
  209. struct ChoiceButton : Button {
  210. void draw(NVGcontext *vg);
  211. };
  212. struct RadioButton : OpaqueWidget, QuantityWidget {
  213. BNDwidgetState state = BND_DEFAULT;
  214. RadioButton() {
  215. box.size.y = BND_WIDGET_HEIGHT;
  216. }
  217. void draw(NVGcontext *vg);
  218. void onMouseEnter();
  219. void onMouseLeave();
  220. void onDragDrop(Widget *origin);
  221. };
  222. struct Slider : OpaqueWidget, QuantityWidget {
  223. BNDwidgetState state = BND_DEFAULT;
  224. Slider() {
  225. box.size.y = BND_WIDGET_HEIGHT;
  226. }
  227. void draw(NVGcontext *vg);
  228. void onDragStart();
  229. void onDragMove(Vec mouseRel);
  230. void onDragEnd();
  231. };
  232. struct ScrollBar : OpaqueWidget {
  233. enum { VERTICAL, HORIZONTAL } orientation;
  234. float containerOffset = 0.0;
  235. float containerSize = 0.0;
  236. BNDwidgetState state = BND_DEFAULT;
  237. ScrollBar() {
  238. box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
  239. }
  240. void draw(NVGcontext *vg);
  241. void move(float delta);
  242. void onDragStart();
  243. void onDragMove(Vec mouseRel);
  244. void onDragEnd();
  245. };
  246. // Handles a container with scrollbars
  247. struct ScrollWidget : OpaqueWidget {
  248. Widget *container;
  249. ScrollBar *hScrollBar;
  250. ScrollBar *vScrollBar;
  251. ScrollWidget();
  252. void step();
  253. void draw(NVGcontext *vg);
  254. Widget *onScroll(Vec pos, Vec scrollRel);
  255. };
  256. struct Tooltip : Widget {
  257. void step();
  258. void draw(NVGcontext *vg);
  259. };
  260. struct Scene : OpaqueWidget {
  261. Widget *overlay = NULL;
  262. void setOverlay(Widget *w);
  263. void step();
  264. };
  265. ////////////////////
  266. // globals
  267. ////////////////////
  268. extern Vec gMousePos;
  269. extern Widget *gHoveredWidget;
  270. extern Widget *gDraggedWidget;
  271. extern Widget *gDragHoveredWidget;
  272. extern Widget *gSelectedWidget;
  273. extern int gGuiFrame;
  274. extern Scene *gScene;
  275. } // namespace rack