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.

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