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.

582 lines
17KB

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