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.

575 lines
16KB

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