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.

326 lines
7.5KB

  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 *image;
  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. // Does not delete widget but transfers ownership to caller
  57. // Silenty fails if widget is not a child
  58. void removeChild(Widget *widget);
  59. void clearChildren();
  60. /** Advances the module by one frame */
  61. virtual void step();
  62. /** Draws to NanoVG context */
  63. virtual void draw(NVGcontext *vg);
  64. // Events
  65. /** Called when a mouse button is pressed over this widget
  66. 0 for left, 1 for right, 2 for middle.
  67. Return `this` to accept the event.
  68. Return NULL to reject the event and pass it to the widget behind this one.
  69. */
  70. virtual Widget *onMouseDown(Vec pos, int button);
  71. virtual Widget *onMouseUp(Vec pos, int button);
  72. virtual Widget *onMouseMove(Vec pos, Vec mouseRel);
  73. /** Called when this widget begins responding to `onMouseMove` events */
  74. virtual void onMouseEnter() {}
  75. /** Called when another widget begins responding to `onMouseMove` events */
  76. virtual void onMouseLeave() {}
  77. virtual Widget *onScroll(Vec pos, Vec scrollRel);
  78. /** Called when a widget responds to `onMouseDown` for a left button press */
  79. virtual void onDragStart() {}
  80. /** Called when the left button is released and this widget is being dragged */
  81. virtual void onDragEnd() {}
  82. /** Called when a widget responds to `onMouseMove` and is being dragged */
  83. virtual void onDragMove(Vec mouseRel) {}
  84. /** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
  85. virtual void onDragDrop(Widget *origin) {}
  86. virtual void onAction() {}
  87. virtual void onChange() {}
  88. };
  89. /** Widget that does not respond to events */
  90. struct TransparentWidget : virtual Widget {
  91. Widget *onMouseDown(Vec pos, int button) {return NULL;}
  92. Widget *onMouseUp(Vec pos, int button) {return NULL;}
  93. Widget *onMouseMove(Vec pos, Vec mouseRel) {return NULL;}
  94. Widget *onScroll(Vec pos, Vec scrollRel) {return NULL;}
  95. };
  96. /** Widget that itself responds to mouse events */
  97. struct OpaqueWidget : virtual Widget {
  98. Widget *onMouseDown(Vec pos, int button) {
  99. Widget *w = Widget::onMouseDown(pos, button);
  100. if (w) return w;
  101. onMouseDown(button);
  102. return this;
  103. }
  104. Widget *onMouseUp(Vec pos, int button) {
  105. Widget *w = Widget::onMouseUp(pos, button);
  106. if (w) return w;
  107. onMouseUp(button);
  108. return this;
  109. }
  110. Widget *onMouseMove(Vec pos, Vec mouseRel) {
  111. Widget *w = Widget::onMouseMove(pos, mouseRel);
  112. if (w) return w;
  113. onMouseMove(mouseRel);
  114. return this;
  115. }
  116. /** "High level" events called by the above lower level events.
  117. Use these if you don't care about the clicked position.
  118. */
  119. virtual void onMouseDown(int button) {}
  120. virtual void onMouseUp(int button) {}
  121. virtual void onMouseMove(Vec mouseRel) {}
  122. };
  123. struct SpriteWidget : virtual Widget {
  124. Vec spriteOffset;
  125. Vec spriteSize;
  126. std::shared_ptr<Image> spriteImage;
  127. int index = 0;
  128. void draw(NVGcontext *vg);
  129. };
  130. struct QuantityWidget : virtual Widget {
  131. float value = 0.0;
  132. float minValue = 0.0;
  133. float maxValue = 1.0;
  134. float defaultValue = 0.0;
  135. std::string label;
  136. /** Include a space character if you want a space after the number, e.g. " Hz" */
  137. std::string unit;
  138. /** The digit place to round for displaying values.
  139. A precision of -2 will display as "1.00" for example.
  140. */
  141. int precision = -2;
  142. QuantityWidget();
  143. void setValue(float value);
  144. void setLimits(float minValue, float maxValue);
  145. void setDefaultValue(float defaultValue);
  146. /** Generates the display value */
  147. std::string getText();
  148. };
  149. ////////////////////
  150. // gui elements
  151. ////////////////////
  152. struct Label : Widget {
  153. std::string text;
  154. Label() {
  155. box.size.y = BND_WIDGET_HEIGHT;
  156. }
  157. void draw(NVGcontext *vg);
  158. };
  159. // Deletes itself from parent when clicked
  160. struct MenuOverlay : OpaqueWidget {
  161. void step();
  162. Widget *onScroll(Vec pos, Vec scrollRel) {
  163. return this;
  164. }
  165. void onDragDrop(Widget *origin);
  166. };
  167. struct Menu : OpaqueWidget {
  168. Menu() {
  169. box.size = Vec(0, 0);
  170. }
  171. // Resizes menu and calls addChild()
  172. void pushChild(Widget *child);
  173. void draw(NVGcontext *vg);
  174. };
  175. struct MenuEntry : OpaqueWidget {
  176. std::string text;
  177. MenuEntry() {
  178. box.size = Vec(0, BND_WIDGET_HEIGHT);
  179. }
  180. float computeMinWidth(NVGcontext *vg);
  181. };
  182. struct MenuLabel : MenuEntry {
  183. void draw(NVGcontext *vg);
  184. };
  185. struct MenuItem : MenuEntry {
  186. BNDwidgetState state = BND_DEFAULT;
  187. void draw(NVGcontext *vg);
  188. void onMouseEnter();
  189. void onMouseLeave() ;
  190. void onDragDrop(Widget *origin);
  191. };
  192. struct Button : OpaqueWidget {
  193. std::string text;
  194. BNDwidgetState state = BND_DEFAULT;
  195. Button() {
  196. box.size.y = BND_WIDGET_HEIGHT;
  197. }
  198. void draw(NVGcontext *vg);
  199. void onMouseEnter();
  200. void onMouseLeave();
  201. void onDragStart();
  202. void onDragEnd();
  203. void onDragDrop(Widget *origin);
  204. };
  205. struct ChoiceButton : Button {
  206. void draw(NVGcontext *vg);
  207. };
  208. struct RadioButton : OpaqueWidget, QuantityWidget {
  209. BNDwidgetState state = BND_DEFAULT;
  210. RadioButton() {
  211. box.size.y = BND_WIDGET_HEIGHT;
  212. }
  213. void draw(NVGcontext *vg);
  214. void onMouseEnter();
  215. void onMouseLeave();
  216. void onDragDrop(Widget *origin);
  217. };
  218. struct Slider : OpaqueWidget, QuantityWidget {
  219. BNDwidgetState state = BND_DEFAULT;
  220. Slider() {
  221. box.size.y = BND_WIDGET_HEIGHT;
  222. }
  223. void draw(NVGcontext *vg);
  224. void onDragStart();
  225. void onDragMove(Vec mouseRel);
  226. void onDragEnd();
  227. };
  228. struct ScrollBar : OpaqueWidget {
  229. enum { VERTICAL, HORIZONTAL } orientation;
  230. float containerOffset = 0.0;
  231. float containerSize = 0.0;
  232. BNDwidgetState state = BND_DEFAULT;
  233. ScrollBar() {
  234. box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
  235. }
  236. void draw(NVGcontext *vg);
  237. void move(float delta);
  238. void onDragStart();
  239. void onDragMove(Vec mouseRel);
  240. void onDragEnd();
  241. };
  242. // Handles a container with scrollbars
  243. struct ScrollWidget : OpaqueWidget {
  244. Widget *container;
  245. ScrollBar *hScrollBar;
  246. ScrollBar *vScrollBar;
  247. ScrollWidget();
  248. void step();
  249. void draw(NVGcontext *vg);
  250. Widget *onScroll(Vec pos, Vec scrollRel);
  251. };
  252. struct Tooltip : Widget {
  253. void step();
  254. void draw(NVGcontext *vg);
  255. };
  256. struct Scene : OpaqueWidget {
  257. Widget *overlay = NULL;
  258. void setOverlay(Widget *w);
  259. void step();
  260. };
  261. ////////////////////
  262. // globals
  263. ////////////////////
  264. extern Vec gMousePos;
  265. extern Widget *gHoveredWidget;
  266. extern Widget *gDraggedWidget;
  267. extern Widget *gSelectedWidget;
  268. extern int gGuiFrame;
  269. extern Scene *gScene;
  270. } // namespace rack