DISTRHO Plugin Framework
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.

559 lines
15KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "tests.hpp"
  17. #include "widgets/ExampleColorWidget.hpp"
  18. #include "widgets/ExampleImagesWidget.hpp"
  19. #include "widgets/ExampleRectanglesWidget.hpp"
  20. #include "widgets/ExampleShapesWidget.hpp"
  21. #ifdef DGL_OPENGL
  22. #include "widgets/ExampleTextWidget.hpp"
  23. #endif
  24. #include "demo_res/DemoArtwork.cpp"
  25. #include "images_res/CatPics.cpp"
  26. #ifdef DGL_CAIRO
  27. #include "../dgl/Cairo.hpp"
  28. typedef DGL_NAMESPACE::CairoImage DemoImage;
  29. #endif
  30. #ifdef DGL_OPENGL
  31. #include "../dgl/OpenGL.hpp"
  32. typedef DGL_NAMESPACE::OpenGLImage DemoImage;
  33. #endif
  34. #ifdef DGL_VULKAN
  35. #include "../dgl/Vulkan.hpp"
  36. typedef DGL_NAMESPACE::VulkanImage DemoImage;
  37. #endif
  38. START_NAMESPACE_DGL
  39. typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget;
  40. typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget;
  41. typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow;
  42. // --------------------------------------------------------------------------------------------------------------------
  43. // Left side tab-like widget
  44. class LeftSideWidget : public SubWidget
  45. {
  46. public:
  47. #ifdef DGL_OPENGL
  48. static const int kPageCount = 5;
  49. #else
  50. static const int kPageCount = 4;
  51. #endif
  52. class Callback
  53. {
  54. public:
  55. virtual ~Callback() {}
  56. virtual void curPageChanged(int curPage) = 0;
  57. };
  58. LeftSideWidget(Widget* parent, Callback* const cb)
  59. : SubWidget(parent),
  60. callback(cb),
  61. curPage(0),
  62. curHover(-1)
  63. {
  64. using namespace DemoArtwork;
  65. img1.loadFromMemory(ico1Data, ico1Width, ico1Height, kImageFormatBGR);
  66. img2.loadFromMemory(ico2Data, ico2Width, ico2Height, kImageFormatBGR);
  67. img3.loadFromMemory(ico3Data, ico3Width, ico2Height, kImageFormatBGR);
  68. img4.loadFromMemory(ico4Data, ico4Width, ico4Height, kImageFormatBGR);
  69. #ifdef DGL_OPENGL
  70. img5.loadFromMemory(ico5Data, ico5Width, ico5Height, kImageFormatBGR);
  71. // for text
  72. nvg.loadSharedResources();
  73. #endif
  74. }
  75. protected:
  76. void onDisplay() override
  77. {
  78. const GraphicsContext& context(getGraphicsContext());
  79. const int iconSize = bgIcon.getWidth();
  80. Color(0.027f, 0.027f, 0.027f).setFor(context);
  81. Rectangle<uint>(0, 0, getSize()).draw(context);
  82. bgIcon.setY(curPage*iconSize + curPage*3);
  83. Color(0.129f, 0.129f, 0.129f).setFor(context);
  84. bgIcon.draw(context);
  85. Color(0.184f, 0.184f, 0.184f).setFor(context);
  86. bgIcon.drawOutline(context);
  87. if (curHover != curPage && curHover != -1)
  88. {
  89. Rectangle<int> rHover(1, curHover*iconSize + curHover*3, iconSize-2, iconSize-2);
  90. Color(0.071f, 0.071f, 0.071f).setFor(context);
  91. rHover.draw(context);
  92. Color(0.102f, 0.102f, 0.102f).setFor(context);
  93. rHover.drawOutline(context);
  94. }
  95. Color(0.184f, 0.184f, 0.184f).setFor(context);
  96. lineSep.draw(context);
  97. // reset color
  98. Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true);
  99. const int pad = iconSize/2 - DemoArtwork::ico1Width/2;
  100. img1.drawAt(context, pad, pad);
  101. img2.drawAt(context, pad, pad + 3 + iconSize);
  102. img3.drawAt(context, pad, pad + 6 + iconSize*2);
  103. img4.drawAt(context, pad, pad + 9 + iconSize*3);
  104. #ifdef DGL_OPENGL
  105. img5.drawAt(context, pad, pad + 12 + iconSize*4);
  106. // draw some text
  107. nvg.beginFrame(this);
  108. nvg.fontSize(23.0f);
  109. nvg.textAlign(NanoVG::ALIGN_LEFT|NanoVG::ALIGN_TOP);
  110. //nvg.textLineHeight(20.0f);
  111. nvg.fillColor(220,220,220,220);
  112. nvg.textBox(10, 420, iconSize, "Haha,", nullptr);
  113. nvg.textBox(15, 440, iconSize, "Look!", nullptr);
  114. nvg.endFrame();
  115. #endif
  116. }
  117. bool onMouse(const MouseEvent& ev) override
  118. {
  119. if (ev.button != 1 || ! ev.press)
  120. return false;
  121. if (! contains(ev.pos))
  122. return false;
  123. const int iconSize = bgIcon.getWidth();
  124. for (int i=0; i<kPageCount; ++i)
  125. {
  126. bgIcon.setY(i*iconSize + i*3);
  127. if (bgIcon.contains(ev.pos))
  128. {
  129. curPage = i;
  130. callback->curPageChanged(i);
  131. repaint();
  132. break;
  133. }
  134. }
  135. return true;
  136. }
  137. bool onMotion(const MotionEvent& ev) override
  138. {
  139. if (contains(ev.pos))
  140. {
  141. const int iconSize = bgIcon.getWidth();
  142. for (int i=0; i<kPageCount; ++i)
  143. {
  144. bgIcon.setY(i*iconSize + i*3);
  145. if (bgIcon.contains(ev.pos))
  146. {
  147. if (curHover == i)
  148. return true;
  149. curHover = i;
  150. repaint();
  151. return true;
  152. }
  153. }
  154. if (curHover == -1)
  155. return true;
  156. curHover = -1;
  157. repaint();
  158. return true;
  159. }
  160. else
  161. {
  162. if (curHover == -1)
  163. return false;
  164. curHover = -1;
  165. repaint();
  166. return true;
  167. }
  168. }
  169. void onResize(const ResizeEvent& ev) override
  170. {
  171. const uint width = ev.size.getWidth();
  172. const uint height = ev.size.getHeight();
  173. bgIcon.setWidth(width-4);
  174. bgIcon.setHeight(width-4);
  175. lineSep.setStartPos(width, 0);
  176. lineSep.setEndPos(width, height);
  177. }
  178. private:
  179. Callback* const callback;
  180. int curPage, curHover;
  181. Rectangle<double> bgIcon;
  182. Line<int> lineSep;
  183. DemoImage img1, img2, img3, img4, img5;
  184. #ifdef DGL_OPENGL
  185. // for text
  186. NanoVG nvg;
  187. #endif
  188. };
  189. // --------------------------------------------------------------------------------------------------------------------
  190. // Resize handle widget
  191. class ResizeHandle : public TopLevelWidget
  192. {
  193. Rectangle<uint> area;
  194. Line<double> l1, l2, l3;
  195. uint baseSize;
  196. // event handling state
  197. bool resizing;
  198. Point<double> lastResizePoint;
  199. Size<double> resizingSize;
  200. public:
  201. explicit ResizeHandle(TopLevelWidget* const tlw)
  202. : TopLevelWidget(tlw->getWindow()),
  203. baseSize(16),
  204. resizing(false)
  205. {
  206. resetArea();
  207. }
  208. explicit ResizeHandle(Window& window)
  209. : TopLevelWidget(window),
  210. baseSize(16),
  211. resizing(false)
  212. {
  213. resetArea();
  214. }
  215. void setBaseSize(const uint size)
  216. {
  217. baseSize = std::max(16u, size);
  218. resetArea();
  219. }
  220. protected:
  221. void onDisplay() override
  222. {
  223. const GraphicsContext& context(getGraphicsContext());
  224. const double offset = getScaleFactor();
  225. // draw white lines, 1px wide
  226. Color(1.0f, 1.0f, 1.0f).setFor(context);
  227. l1.draw(context, 1);
  228. l2.draw(context, 1);
  229. l3.draw(context, 1);
  230. // draw black lines, offset by 1px and 2px wide
  231. Color(0.0f, 0.0f, 0.0f).setFor(context);
  232. Line<double> l1b(l1), l2b(l2), l3b(l3);
  233. l1b.moveBy(offset, offset);
  234. l2b.moveBy(offset, offset);
  235. l3b.moveBy(offset, offset);
  236. l1b.draw(context, 1);
  237. l2b.draw(context, 1);
  238. l3b.draw(context, 1);
  239. }
  240. bool onMouse(const MouseEvent& ev) override
  241. {
  242. if (ev.button != 1)
  243. return false;
  244. if (ev.press && area.contains(ev.pos))
  245. {
  246. resizing = true;
  247. resizingSize = Size<double>(getWidth(), getHeight());
  248. lastResizePoint = ev.pos;
  249. return true;
  250. }
  251. if (resizing && ! ev.press)
  252. {
  253. resizing = false;
  254. return true;
  255. }
  256. return false;
  257. }
  258. bool onMotion(const MotionEvent& ev) override
  259. {
  260. if (! resizing)
  261. return false;
  262. const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
  263. ev.pos.getY() - lastResizePoint.getY());
  264. resizingSize += offset;
  265. lastResizePoint = ev.pos;
  266. // TODO min width, min height
  267. const uint minWidth = 16;
  268. const uint minHeight = 16;
  269. if (resizingSize.getWidth() < minWidth)
  270. resizingSize.setWidth(minWidth);
  271. if (resizingSize.getHeight() < minHeight)
  272. resizingSize.setHeight(minHeight);
  273. setSize(resizingSize.getWidth(), resizingSize.getHeight());
  274. return true;
  275. }
  276. void onResize(const ResizeEvent& ev) override
  277. {
  278. TopLevelWidget::onResize(ev);
  279. resetArea();
  280. }
  281. private:
  282. void resetArea()
  283. {
  284. const double scaleFactor = getScaleFactor();
  285. const uint margin = 0.0 * scaleFactor;
  286. const uint size = baseSize * scaleFactor;
  287. area = Rectangle<uint>(getWidth() - size - margin,
  288. getHeight() - size - margin,
  289. size, size);
  290. recreateLines(area.getX(), area.getY(), size);
  291. }
  292. void recreateLines(const uint x, const uint y, const uint size)
  293. {
  294. uint linesize = size;
  295. uint offset = 0;
  296. // 1st line, full diagonal size
  297. l1.setStartPos(x + size, y);
  298. l1.setEndPos(x, y + size);
  299. // 2nd line, bit more to the right and down, cropped
  300. offset += size / 3;
  301. linesize -= size / 3;
  302. l2.setStartPos(x + linesize + offset, y + offset);
  303. l2.setEndPos(x + offset, y + linesize + offset);
  304. // 3rd line, even more right and down
  305. offset += size / 3;
  306. linesize -= size / 3;
  307. l3.setStartPos(x + linesize + offset, y + offset);
  308. l3.setEndPos(x + offset, y + linesize + offset);
  309. }
  310. };
  311. // --------------------------------------------------------------------------------------------------------------------
  312. // Main Demo Window, having a left-side tab-like widget and main area for current widget
  313. class DemoWindow : public StandaloneWindow,
  314. public LeftSideWidget::Callback
  315. {
  316. static const int kSidebarWidth = 81;
  317. public:
  318. #ifdef DGL_CAIRO
  319. static constexpr const char* const kExampleWidgetName = "Demo - Cairo";
  320. #endif
  321. #ifdef DGL_OPENGL
  322. static constexpr const char* const kExampleWidgetName = "Demo - OpenGL";
  323. #endif
  324. #ifdef DGL_VULKAN
  325. static constexpr const char* const kExampleWidgetName = "Demo - Vulkan";
  326. #endif
  327. DemoWindow(Application& app)
  328. : StandaloneWindow(app),
  329. wColor(this),
  330. wImages(this),
  331. wRects(this),
  332. wShapes(this),
  333. #ifdef DGL_OPENGL
  334. wText(this),
  335. #endif
  336. wLeft(this, this),
  337. resizer(this),
  338. curWidget(nullptr)
  339. {
  340. wColor.hide();
  341. wImages.hide();
  342. wRects.hide();
  343. wShapes.hide();
  344. #ifdef DGL_OPENGL
  345. wText.hide();
  346. #endif
  347. wColor.setAbsoluteX(kSidebarWidth);
  348. wImages.setAbsoluteX(kSidebarWidth);
  349. wRects.setAbsoluteX(kSidebarWidth);
  350. wShapes.setAbsoluteX(kSidebarWidth);
  351. #ifdef DGL_OPENGL
  352. wText.setAbsoluteX(kSidebarWidth);
  353. #endif
  354. wLeft.setAbsolutePos(2, 2);
  355. curPageChanged(0);
  356. }
  357. protected:
  358. void curPageChanged(int curPage) override
  359. {
  360. if (curWidget != nullptr)
  361. curWidget->hide();
  362. switch (curPage)
  363. {
  364. case 0:
  365. curWidget = &wColor;
  366. break;
  367. case 1:
  368. curWidget = &wImages;
  369. break;
  370. case 2:
  371. curWidget = &wRects;
  372. break;
  373. case 3:
  374. curWidget = &wShapes;
  375. break;
  376. #ifdef DGL_OPENGL
  377. case 4:
  378. curWidget = &wText;
  379. break;
  380. #endif
  381. default:
  382. curWidget = nullptr;
  383. break;
  384. }
  385. if (curWidget != nullptr)
  386. curWidget->show();
  387. }
  388. void onDisplay() override
  389. {
  390. }
  391. void onReshape(uint width, uint height) override
  392. {
  393. StandaloneWindow::onReshape(width, height);
  394. if (width < kSidebarWidth)
  395. return;
  396. Size<uint> size(width-kSidebarWidth, height);
  397. wColor.setSize(size);
  398. wImages.setSize(size);
  399. wRects.setSize(size);
  400. wShapes.setSize(size);
  401. #ifdef DGL_OPENGL
  402. wText.setSize(size);
  403. #endif
  404. wLeft.setSize(kSidebarWidth-4, height-4);
  405. }
  406. private:
  407. ExampleColorSubWidget wColor;
  408. ExampleImagesSubWidget wImages;
  409. ExampleRectanglesSubWidget wRects;
  410. ExampleShapesSubWidget wShapes;
  411. #ifdef DGL_OPENGL
  412. ExampleTextSubWidget wText;
  413. #endif
  414. LeftSideWidget wLeft;
  415. ResizeHandle resizer;
  416. Widget* curWidget;
  417. };
  418. // --------------------------------------------------------------------------------------------------------------------
  419. // Special handy function that runs a StandaloneWindow inside the function scope
  420. template <class ExampleWidgetStandaloneWindow>
  421. void createAndShowExampleWidgetStandaloneWindow(Application& app)
  422. {
  423. ExampleWidgetStandaloneWindow swin(app);
  424. swin.setResizable(true);
  425. swin.setSize(600, 500);
  426. swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
  427. swin.show();
  428. app.exec();
  429. }
  430. // --------------------------------------------------------------------------------------------------------------------
  431. END_NAMESPACE_DGL
  432. int main(int argc, char* argv[])
  433. {
  434. USE_NAMESPACE_DGL;
  435. using DGL_NAMESPACE::Window;
  436. Application app;
  437. if (argc > 1)
  438. {
  439. /**/ if (std::strcmp(argv[1], "color") == 0)
  440. createAndShowExampleWidgetStandaloneWindow<ExampleColorStandaloneWindow>(app);
  441. else if (std::strcmp(argv[1], "images") == 0)
  442. createAndShowExampleWidgetStandaloneWindow<ExampleImagesStandaloneWindow>(app);
  443. else if (std::strcmp(argv[1], "rectangles") == 0)
  444. createAndShowExampleWidgetStandaloneWindow<ExampleRectanglesStandaloneWindow>(app);
  445. else if (std::strcmp(argv[1], "shapes") == 0)
  446. createAndShowExampleWidgetStandaloneWindow<ExampleShapesStandaloneWindow>(app);
  447. #ifdef DGL_OPENGL
  448. else if (std::strcmp(argv[1], "text") == 0)
  449. createAndShowExampleWidgetStandaloneWindow<ExampleTextStandaloneWindow>(app);
  450. #endif
  451. else
  452. d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes");
  453. }
  454. else
  455. {
  456. createAndShowExampleWidgetStandaloneWindow<DemoWindow>(app);
  457. }
  458. return 0;
  459. }
  460. // --------------------------------------------------------------------------------------------------------------------