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.

417 lines
9.8KB

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