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.

561 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. curWidget(nullptr)
  330. {
  331. const ScopedGraphicsContext sgc(*this);
  332. wColor = new ExampleColorSubWidget(this);
  333. wColor->hide();
  334. wColor->setAbsoluteX(kSidebarWidth);
  335. wImages = new ExampleImagesSubWidget(this);
  336. wImages->hide();
  337. wImages->setAbsoluteX(kSidebarWidth);
  338. wRects = new ExampleRectanglesSubWidget(this);
  339. wRects->hide();
  340. wRects->setAbsoluteX(kSidebarWidth);
  341. wShapes = new ExampleShapesSubWidget(this);
  342. wShapes->hide();
  343. wShapes->setAbsoluteX(kSidebarWidth);
  344. #ifdef DGL_OPENGL
  345. wText = new ExampleTextSubWidget(this),
  346. wText->hide();
  347. wText->setAbsoluteX(kSidebarWidth);
  348. #endif
  349. wLeft = new LeftSideWidget(this, this),
  350. wLeft->setAbsolutePos(2, 2);
  351. resizer = new ResizeHandle(this);
  352. curPageChanged(0);
  353. }
  354. protected:
  355. void curPageChanged(int curPage) override
  356. {
  357. if (curWidget != nullptr)
  358. curWidget->hide();
  359. switch (curPage)
  360. {
  361. case 0:
  362. curWidget = wColor;
  363. break;
  364. case 1:
  365. curWidget = wImages;
  366. break;
  367. case 2:
  368. curWidget = wRects;
  369. break;
  370. case 3:
  371. curWidget = wShapes;
  372. break;
  373. #ifdef DGL_OPENGL
  374. case 4:
  375. curWidget = wText;
  376. break;
  377. #endif
  378. default:
  379. curWidget = nullptr;
  380. break;
  381. }
  382. if (curWidget != nullptr)
  383. curWidget->show();
  384. }
  385. void onDisplay() override
  386. {
  387. }
  388. void onReshape(uint width, uint height) override
  389. {
  390. StandaloneWindow::onReshape(width, height);
  391. if (width < kSidebarWidth)
  392. return;
  393. Size<uint> size(width-kSidebarWidth, height);
  394. wColor->setSize(size);
  395. wImages->setSize(size);
  396. wRects->setSize(size);
  397. wShapes->setSize(size);
  398. #ifdef DGL_OPENGL
  399. wText->setSize(size);
  400. #endif
  401. wLeft->setSize(kSidebarWidth-4, height-4);
  402. }
  403. private:
  404. ScopedPointer<ExampleColorSubWidget> wColor;
  405. ScopedPointer<ExampleImagesSubWidget> wImages;
  406. ScopedPointer<ExampleRectanglesSubWidget> wRects;
  407. ScopedPointer<ExampleShapesSubWidget> wShapes;
  408. #ifdef DGL_OPENGL
  409. ScopedPointer<ExampleTextSubWidget> wText;
  410. #endif
  411. ScopedPointer<LeftSideWidget> wLeft;
  412. ScopedPointer<ResizeHandle> resizer;
  413. Widget* curWidget;
  414. };
  415. // --------------------------------------------------------------------------------------------------------------------
  416. // Special handy function that runs a StandaloneWindow inside the function scope
  417. template <class ExampleWidgetStandaloneWindow>
  418. void createAndShowExampleWidgetStandaloneWindow(Application& app)
  419. {
  420. ExampleWidgetStandaloneWindow swin(app);
  421. swin.setResizable(true);
  422. swin.setSize(600, 500);
  423. swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
  424. swin.show();
  425. app.exec();
  426. }
  427. // --------------------------------------------------------------------------------------------------------------------
  428. END_NAMESPACE_DGL
  429. int main(int argc, char* argv[])
  430. {
  431. USE_NAMESPACE_DGL;
  432. using DGL_NAMESPACE::Window;
  433. Application app;
  434. if (argc > 1)
  435. {
  436. /**/ if (std::strcmp(argv[1], "color") == 0)
  437. createAndShowExampleWidgetStandaloneWindow<ExampleColorStandaloneWindow>(app);
  438. else if (std::strcmp(argv[1], "images") == 0)
  439. createAndShowExampleWidgetStandaloneWindow<ExampleImagesStandaloneWindow>(app);
  440. else if (std::strcmp(argv[1], "rectangles") == 0)
  441. createAndShowExampleWidgetStandaloneWindow<ExampleRectanglesStandaloneWindow>(app);
  442. else if (std::strcmp(argv[1], "shapes") == 0)
  443. createAndShowExampleWidgetStandaloneWindow<ExampleShapesStandaloneWindow>(app);
  444. #ifdef DGL_OPENGL
  445. else if (std::strcmp(argv[1], "text") == 0)
  446. createAndShowExampleWidgetStandaloneWindow<ExampleTextStandaloneWindow>(app);
  447. #endif
  448. else
  449. d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes");
  450. }
  451. else
  452. {
  453. createAndShowExampleWidgetStandaloneWindow<DemoWindow>(app);
  454. }
  455. return 0;
  456. }
  457. // --------------------------------------------------------------------------------------------------------------------