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.

400 lines
9.3KB

  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 widget
  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 void onSelect() {}
  80. virtual void onDeselect() {}
  81. virtual void onText(int codepoint) {}
  82. virtual void onKey(int key) {}
  83. virtual Widget *onScroll(Vec pos, Vec scrollRel);
  84. /** Called when a widget responds to `onMouseDown` for a left button press */
  85. virtual void onDragStart() {}
  86. /** Called when the left button is released and this widget is being dragged */
  87. virtual void onDragEnd() {}
  88. /** Called when a widget responds to `onMouseMove` and is being dragged */
  89. virtual void onDragMove(Vec mouseRel) {}
  90. /** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */
  91. virtual void onDragEnter(Widget *origin) {}
  92. virtual void onDragLeave(Widget *origin) {}
  93. virtual void onDragDrop(Widget *origin) {}
  94. virtual void onAction() {}
  95. virtual void onChange() {}
  96. };
  97. struct TransformWidget : Widget {
  98. /** The transformation matrix */
  99. float transform[6];
  100. TransformWidget();
  101. void identity();
  102. void translate(Vec delta);
  103. void rotate(float angle);
  104. void scale(Vec s);
  105. void draw(NVGcontext *vg);
  106. };
  107. ////////////////////
  108. // Trait widgets
  109. ////////////////////
  110. /** Widget that does not respond to events */
  111. struct TransparentWidget : virtual Widget {
  112. Widget *onMouseDown(Vec pos, int button) {return NULL;}
  113. Widget *onMouseUp(Vec pos, int button) {return NULL;}
  114. Widget *onMouseMove(Vec pos, Vec mouseRel) {return NULL;}
  115. Widget *onScroll(Vec pos, Vec scrollRel) {return NULL;}
  116. };
  117. /** Widget that itself responds to mouse events */
  118. struct OpaqueWidget : virtual Widget {
  119. Widget *onMouseDown(Vec pos, int button) {
  120. Widget *w = Widget::onMouseDown(pos, button);
  121. if (w) return w;
  122. onMouseDown(button);
  123. return this;
  124. }
  125. Widget *onMouseUp(Vec pos, int button) {
  126. Widget *w = Widget::onMouseUp(pos, button);
  127. if (w) return w;
  128. onMouseUp(button);
  129. return this;
  130. }
  131. Widget *onMouseMove(Vec pos, Vec mouseRel) {
  132. Widget *w = Widget::onMouseMove(pos, mouseRel);
  133. if (w) return w;
  134. onMouseMove(mouseRel);
  135. return this;
  136. }
  137. /** "High level" events called by the above lower level events.
  138. Use these if you don't care about the clicked position.
  139. */
  140. virtual void onMouseDown(int button) {}
  141. virtual void onMouseUp(int button) {}
  142. virtual void onMouseMove(Vec mouseRel) {}
  143. };
  144. struct SpriteWidget : virtual Widget {
  145. Vec spriteOffset;
  146. Vec spriteSize;
  147. std::shared_ptr<Image> spriteImage;
  148. int index = 0;
  149. void draw(NVGcontext *vg);
  150. };
  151. struct SVGWidget : virtual Widget {
  152. std::shared_ptr<SVG> svg;
  153. /** Sets the box size to the svg image size */
  154. void wrap();
  155. void draw(NVGcontext *vg);
  156. };
  157. /** Caches a widget's draw() result to a framebuffer so it is called less frequently
  158. When `dirty` is true, `scene` will be re-rendered on the next call to step().
  159. Events are not passed to the underlying scene.
  160. */
  161. struct FramebufferWidget : virtual Widget {
  162. /** Set this to true to re-render the scene to the framebuffer in the next step() */
  163. bool dirty = true;
  164. /** The root object in the framebuffer scene
  165. The FramebufferWidget owns the pointer
  166. */
  167. Widget *scene = NULL;
  168. struct Internal;
  169. Internal *internal;
  170. FramebufferWidget();
  171. ~FramebufferWidget();
  172. void setScene(Widget *w) {
  173. scene = w;
  174. }
  175. void step();
  176. void draw(NVGcontext *vg);
  177. };
  178. struct QuantityWidget : virtual Widget {
  179. float value = 0.0;
  180. float minValue = 0.0;
  181. float maxValue = 1.0;
  182. float defaultValue = 0.0;
  183. std::string label;
  184. /** Include a space character if you want a space after the number, e.g. " Hz" */
  185. std::string unit;
  186. /** The digit place to round for displaying values.
  187. A precision of -2 will display as "1.00" for example.
  188. */
  189. int precision = -2;
  190. QuantityWidget();
  191. void setValue(float value);
  192. void setLimits(float minValue, float maxValue);
  193. void setDefaultValue(float defaultValue);
  194. /** Generates the display value */
  195. std::string getText();
  196. };
  197. ////////////////////
  198. // GUI widgets
  199. ////////////////////
  200. struct Label : Widget {
  201. std::string text;
  202. Label() {
  203. box.size.y = BND_WIDGET_HEIGHT;
  204. }
  205. void draw(NVGcontext *vg);
  206. };
  207. // Deletes itself from parent when clicked
  208. struct MenuOverlay : OpaqueWidget {
  209. void step();
  210. Widget *onScroll(Vec pos, Vec scrollRel) {
  211. return this;
  212. }
  213. void onDragDrop(Widget *origin);
  214. };
  215. struct Menu : OpaqueWidget {
  216. Menu() {
  217. box.size = Vec(0, 0);
  218. }
  219. // Resizes menu and calls addChild()
  220. void pushChild(Widget *child);
  221. void draw(NVGcontext *vg);
  222. };
  223. struct MenuEntry : OpaqueWidget {
  224. std::string text;
  225. MenuEntry() {
  226. box.size = Vec(0, BND_WIDGET_HEIGHT);
  227. }
  228. float computeMinWidth(NVGcontext *vg);
  229. };
  230. struct MenuLabel : MenuEntry {
  231. void draw(NVGcontext *vg);
  232. };
  233. struct MenuItem : MenuEntry {
  234. BNDwidgetState state = BND_DEFAULT;
  235. void draw(NVGcontext *vg);
  236. void onMouseEnter();
  237. void onMouseLeave() ;
  238. void onDragDrop(Widget *origin);
  239. };
  240. struct Button : OpaqueWidget {
  241. std::string text;
  242. BNDwidgetState state = BND_DEFAULT;
  243. Button() {
  244. box.size.y = BND_WIDGET_HEIGHT;
  245. }
  246. void draw(NVGcontext *vg);
  247. void onMouseEnter();
  248. void onMouseLeave();
  249. void onDragStart();
  250. void onDragEnd();
  251. void onDragDrop(Widget *origin);
  252. };
  253. struct ChoiceButton : Button {
  254. void draw(NVGcontext *vg);
  255. };
  256. struct RadioButton : OpaqueWidget, QuantityWidget {
  257. BNDwidgetState state = BND_DEFAULT;
  258. RadioButton() {
  259. box.size.y = BND_WIDGET_HEIGHT;
  260. }
  261. void draw(NVGcontext *vg);
  262. void onMouseEnter();
  263. void onMouseLeave();
  264. void onDragDrop(Widget *origin);
  265. };
  266. struct Slider : OpaqueWidget, QuantityWidget {
  267. BNDwidgetState state = BND_DEFAULT;
  268. Slider() {
  269. box.size.y = BND_WIDGET_HEIGHT;
  270. }
  271. void draw(NVGcontext *vg);
  272. void onDragStart();
  273. void onDragMove(Vec mouseRel);
  274. void onDragEnd();
  275. };
  276. struct ScrollBar : OpaqueWidget {
  277. enum { VERTICAL, HORIZONTAL } orientation;
  278. float containerOffset = 0.0;
  279. float containerSize = 0.0;
  280. BNDwidgetState state = BND_DEFAULT;
  281. ScrollBar() {
  282. box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
  283. }
  284. void draw(NVGcontext *vg);
  285. void move(float delta);
  286. void onDragStart();
  287. void onDragMove(Vec mouseRel);
  288. void onDragEnd();
  289. };
  290. // Handles a container with scrollbars
  291. struct ScrollWidget : OpaqueWidget {
  292. Widget *container;
  293. ScrollBar *hScrollBar;
  294. ScrollBar *vScrollBar;
  295. ScrollWidget();
  296. void step();
  297. void draw(NVGcontext *vg);
  298. Widget *onScroll(Vec pos, Vec scrollRel);
  299. };
  300. struct TextField : OpaqueWidget {
  301. std::string text;
  302. int begin = 0;
  303. int end = 0;
  304. TextField() {
  305. box.size.y = BND_WIDGET_HEIGHT;
  306. }
  307. void draw(NVGcontext *vg);
  308. Widget *onMouseDown(Vec pos, int button);
  309. void onText(int codepoint);
  310. void onKey(int scancode);
  311. void onSelect();
  312. };
  313. struct PasswordField : TextField {
  314. void draw(NVGcontext *vg);
  315. };
  316. struct Tooltip : Widget {
  317. void step();
  318. void draw(NVGcontext *vg);
  319. };
  320. struct Scene : OpaqueWidget {
  321. Widget *overlay = NULL;
  322. void setOverlay(Widget *w);
  323. void step();
  324. };
  325. ////////////////////
  326. // globals
  327. ////////////////////
  328. extern Vec gMousePos;
  329. extern Widget *gHoveredWidget;
  330. extern Widget *gDraggedWidget;
  331. extern Widget *gDragHoveredWidget;
  332. extern Widget *gSelectedWidget;
  333. extern int gGuiFrame;
  334. extern Scene *gScene;
  335. } // namespace rack