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.

widgets.hpp 11KB

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