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.

446 lines
13KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2025 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 "dgl.cpp"
  18. #include "dgl/src/Color.cpp"
  19. #include "dgl/src/EventHandlers.cpp"
  20. #include "dgl/src/ImageBase.cpp"
  21. #ifdef DGL_OPENGL
  22. #include "dgl/src/NanoVG.cpp"
  23. #include "dgl/src/Resources.cpp"
  24. #endif
  25. #include "widgets/ExampleColorWidget.hpp"
  26. #include "widgets/ExampleImagesWidget.hpp"
  27. #include "widgets/ExampleRectanglesWidget.hpp"
  28. #include "widgets/ExampleShapesWidget.hpp"
  29. #ifdef DGL_OPENGL
  30. #include "widgets/ExampleTextWidget.hpp"
  31. #endif
  32. #include "widgets/ResizeHandle.hpp"
  33. #include "demo_res/DemoArtwork.cpp"
  34. #include "images_res/CatPics.cpp"
  35. #ifdef DGL_CAIRO
  36. typedef DGL_NAMESPACE::CairoImage DemoImage;
  37. #endif
  38. #ifdef DGL_OPENGL
  39. typedef DGL_NAMESPACE::OpenGLImage DemoImage;
  40. #endif
  41. #ifdef DGL_VULKAN
  42. typedef DGL_NAMESPACE::VulkanImage DemoImage;
  43. #endif
  44. START_NAMESPACE_DGL
  45. // Partial specialization is not allowed in C++, so we need to define these here
  46. template<> inline
  47. ExampleImagesWidget<SubWidget, DemoImage>::ExampleImagesWidget(Widget* const parentWidget)
  48. : SubWidget(parentWidget) { init(parentWidget->getApp()); }
  49. template<> inline
  50. ExampleImagesWidget<TopLevelWidget, DemoImage>::ExampleImagesWidget(Window& windowToMapTo)
  51. : TopLevelWidget(windowToMapTo) { init(windowToMapTo.getApp()); }
  52. template<>
  53. ExampleImagesWidget<StandaloneWindow, DemoImage>::ExampleImagesWidget(Application& app)
  54. : StandaloneWindow(app) { init(app); done(); }
  55. typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget;
  56. typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget;
  57. typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow;
  58. // --------------------------------------------------------------------------------------------------------------------
  59. // Left side tab-like widget
  60. class LeftSideWidget : public SubWidget
  61. {
  62. public:
  63. #ifdef DGL_OPENGL
  64. static const int kPageCount = 5;
  65. #else
  66. static const int kPageCount = 4;
  67. #endif
  68. class Callback
  69. {
  70. public:
  71. virtual ~Callback() {}
  72. virtual void curPageChanged(int curPage) = 0;
  73. };
  74. LeftSideWidget(Widget* parent, Callback* const cb)
  75. : SubWidget(parent),
  76. callback(cb),
  77. curPage(0),
  78. curHover(-1)
  79. {
  80. using namespace DemoArtwork;
  81. img1.loadFromMemory(ico1Data, ico1Width, ico1Height, kImageFormatBGR);
  82. img2.loadFromMemory(ico2Data, ico2Width, ico2Height, kImageFormatBGR);
  83. img3.loadFromMemory(ico3Data, ico3Width, ico2Height, kImageFormatBGR);
  84. img4.loadFromMemory(ico4Data, ico4Width, ico4Height, kImageFormatBGR);
  85. #ifdef DGL_OPENGL
  86. img5.loadFromMemory(ico5Data, ico5Width, ico5Height, kImageFormatBGR);
  87. // for text
  88. nvg.loadSharedResources();
  89. #endif
  90. }
  91. protected:
  92. void onDisplay() override
  93. {
  94. const GraphicsContext& context(getGraphicsContext());
  95. const double scaleFactor = getWindow().getScaleFactor();
  96. const int iconSize = bgIcon.getWidth();
  97. Color(0.027f, 0.027f, 0.027f).setFor(context);
  98. Rectangle<uint>(0, 0, getSize()).draw(context);
  99. bgIcon.setY(curPage * iconSize + curPage * 3 * scaleFactor);
  100. Color(0.129f, 0.129f, 0.129f).setFor(context);
  101. bgIcon.draw(context);
  102. Color(0.184f, 0.184f, 0.184f).setFor(context);
  103. bgIcon.drawOutline(context);
  104. if (curHover != curPage && curHover != -1)
  105. {
  106. Rectangle<int> rHover(1 * scaleFactor, curHover * iconSize + curHover * 3 * scaleFactor,
  107. iconSize - 2 * scaleFactor, iconSize - 2 * scaleFactor);
  108. Color(0.071f, 0.071f, 0.071f).setFor(context);
  109. rHover.draw(context);
  110. Color(0.102f, 0.102f, 0.102f).setFor(context);
  111. rHover.drawOutline(context);
  112. }
  113. Color(0.184f, 0.184f, 0.184f).setFor(context);
  114. lineSep.draw(context);
  115. // reset color
  116. Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true);
  117. const int pad = iconSize/2 - DemoArtwork::ico1Width/2;
  118. img1.drawAt(context, pad, pad);
  119. img2.drawAt(context, pad, pad + 3 + iconSize);
  120. img3.drawAt(context, pad, pad + 6 + iconSize*2);
  121. img4.drawAt(context, pad, pad + 9 + iconSize*3);
  122. #ifdef DGL_OPENGL
  123. img5.drawAt(context, pad, pad + 12 + iconSize*4);
  124. // draw some text
  125. nvg.beginFrame(this);
  126. nvg.fontSize(23.0f * scaleFactor);
  127. nvg.textAlign(NanoVG::ALIGN_LEFT|NanoVG::ALIGN_TOP);
  128. //nvg.textLineHeight(20.0f);
  129. nvg.fillColor(220,220,220,220);
  130. nvg.textBox(10 * scaleFactor, 420 * scaleFactor, iconSize, "Haha,", nullptr);
  131. nvg.textBox(15 * scaleFactor, 440 * scaleFactor, iconSize, "Look!", nullptr);
  132. nvg.endFrame();
  133. #endif
  134. }
  135. bool onMouse(const MouseEvent& ev) override
  136. {
  137. if (ev.button != 1 || ! ev.press)
  138. return false;
  139. if (! contains(ev.pos))
  140. return false;
  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. curPage = i;
  148. callback->curPageChanged(i);
  149. repaint();
  150. break;
  151. }
  152. }
  153. return true;
  154. }
  155. bool onMotion(const MotionEvent& ev) override
  156. {
  157. if (contains(ev.pos))
  158. {
  159. const int iconSize = bgIcon.getWidth();
  160. for (int i=0; i<kPageCount; ++i)
  161. {
  162. bgIcon.setY(i*iconSize + i*3);
  163. if (bgIcon.contains(ev.pos))
  164. {
  165. if (curHover == i)
  166. return true;
  167. curHover = i;
  168. repaint();
  169. return true;
  170. }
  171. }
  172. if (curHover == -1)
  173. return true;
  174. curHover = -1;
  175. repaint();
  176. return true;
  177. }
  178. else
  179. {
  180. if (curHover == -1)
  181. return false;
  182. curHover = -1;
  183. repaint();
  184. return true;
  185. }
  186. }
  187. void onResize(const ResizeEvent& ev) override
  188. {
  189. const uint width = ev.size.getWidth();
  190. const uint height = ev.size.getHeight();
  191. const double scaleFactor = getWindow().getScaleFactor();
  192. bgIcon.setWidth(width - 4 * scaleFactor);
  193. bgIcon.setHeight(width - 4 * scaleFactor);
  194. lineSep.setStartPos(width, 0);
  195. lineSep.setEndPos(width, height);
  196. }
  197. private:
  198. Callback* const callback;
  199. int curPage, curHover;
  200. Rectangle<double> bgIcon;
  201. Line<int> lineSep;
  202. DemoImage img1, img2, img3, img4, img5;
  203. #ifdef DGL_OPENGL
  204. // for text
  205. NanoVG nvg;
  206. #endif
  207. };
  208. // --------------------------------------------------------------------------------------------------------------------
  209. // Main Demo Window, having a left-side tab-like widget and main area for current widget
  210. class DemoWindow : public StandaloneWindow,
  211. public LeftSideWidget::Callback
  212. {
  213. static const int kSidebarWidth = 81;
  214. public:
  215. #if defined(DGL_CAIRO)
  216. static constexpr const char* const kExampleWidgetName = "Demo - Cairo";
  217. #elif defined(DGL_OPENGL)
  218. static constexpr const char* const kExampleWidgetName = "Demo - OpenGL";
  219. #elif defined(DGL_VULKAN)
  220. static constexpr const char* const kExampleWidgetName = "Demo - Vulkan";
  221. #endif
  222. DemoWindow(Application& app)
  223. : StandaloneWindow(app),
  224. curWidget(nullptr)
  225. {
  226. const ScopedGraphicsContext sgc(*this);
  227. const double scaleFactor = getScaleFactor();
  228. wColor = new ExampleColorSubWidget(this);
  229. wColor->hide();
  230. wColor->setAbsoluteX(kSidebarWidth * scaleFactor);
  231. wImages = new ExampleImagesSubWidget(this);
  232. wImages->hide();
  233. wImages->setAbsoluteX(kSidebarWidth * scaleFactor);
  234. wRects = new ExampleRectanglesSubWidget(this);
  235. wRects->hide();
  236. wRects->setAbsoluteX(kSidebarWidth * scaleFactor);
  237. wShapes = new ExampleShapesSubWidget(this);
  238. wShapes->hide();
  239. wShapes->setAbsoluteX(kSidebarWidth * scaleFactor);
  240. #ifdef DGL_OPENGL
  241. wText = new ExampleTextSubWidget(this),
  242. wText->hide();
  243. wText->setAbsoluteX(kSidebarWidth * scaleFactor);
  244. #endif
  245. wLeft = new LeftSideWidget(this, this),
  246. wLeft->setAbsolutePos(2 * scaleFactor, 2 * scaleFactor);
  247. resizer = new ResizeHandle(this);
  248. curPageChanged(0);
  249. done();
  250. }
  251. protected:
  252. void curPageChanged(int curPage) override
  253. {
  254. if (curWidget != nullptr)
  255. curWidget->hide();
  256. switch (curPage)
  257. {
  258. case 0:
  259. curWidget = wColor;
  260. break;
  261. case 1:
  262. curWidget = wImages;
  263. break;
  264. case 2:
  265. curWidget = wRects;
  266. break;
  267. case 3:
  268. curWidget = wShapes;
  269. break;
  270. #ifdef DGL_OPENGL
  271. case 4:
  272. curWidget = wText;
  273. break;
  274. #endif
  275. default:
  276. curWidget = nullptr;
  277. break;
  278. }
  279. if (curWidget != nullptr)
  280. curWidget->show();
  281. }
  282. void onDisplay() override
  283. {
  284. }
  285. void onReshape(uint width, uint height) override
  286. {
  287. StandaloneWindow::onReshape(width, height);
  288. const double scaleFactor = getScaleFactor();
  289. if (width < kSidebarWidth * scaleFactor)
  290. return;
  291. const Size<uint> size(width - kSidebarWidth * scaleFactor, height);
  292. wColor->setSize(size);
  293. wImages->setSize(size);
  294. wRects->setSize(size);
  295. wShapes->setSize(size);
  296. #ifdef DGL_OPENGL
  297. wText->setSize(size);
  298. #endif
  299. wLeft->setSize((kSidebarWidth - 4) * scaleFactor, (height - 4) * scaleFactor);
  300. }
  301. private:
  302. ScopedPointer<ExampleColorSubWidget> wColor;
  303. ScopedPointer<ExampleImagesSubWidget> wImages;
  304. ScopedPointer<ExampleRectanglesSubWidget> wRects;
  305. ScopedPointer<ExampleShapesSubWidget> wShapes;
  306. #ifdef DGL_OPENGL
  307. ScopedPointer<ExampleTextSubWidget> wText;
  308. #endif
  309. ScopedPointer<LeftSideWidget> wLeft;
  310. ScopedPointer<ResizeHandle> resizer;
  311. Widget* curWidget;
  312. };
  313. // --------------------------------------------------------------------------------------------------------------------
  314. // Special handy function that runs a StandaloneWindow inside the function scope
  315. template <class ExampleWidgetStandaloneWindow>
  316. void createAndShowExampleWidgetStandaloneWindow(Application& app)
  317. {
  318. ExampleWidgetStandaloneWindow swin(app);
  319. const double scaleFactor = swin.getScaleFactor();
  320. swin.setGeometryConstraints(128 * scaleFactor, 128 * scaleFactor);
  321. swin.setResizable(true);
  322. swin.setSize(600 * scaleFactor, 500 * scaleFactor);
  323. swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
  324. swin.show();
  325. app.exec();
  326. }
  327. // --------------------------------------------------------------------------------------------------------------------
  328. END_NAMESPACE_DGL
  329. int main(int argc, char* argv[])
  330. {
  331. using DGL_NAMESPACE::Application;
  332. using DGL_NAMESPACE::DemoWindow;
  333. using DGL_NAMESPACE::ExampleColorStandaloneWindow;
  334. using DGL_NAMESPACE::ExampleImagesStandaloneWindow;
  335. using DGL_NAMESPACE::ExampleRectanglesStandaloneWindow;
  336. using DGL_NAMESPACE::ExampleShapesStandaloneWindow;
  337. #ifdef DGL_OPENGL
  338. using DGL_NAMESPACE::ExampleTextStandaloneWindow;
  339. #endif
  340. using DGL_NAMESPACE::createAndShowExampleWidgetStandaloneWindow;
  341. Application app;
  342. if (argc > 1)
  343. {
  344. /**/ if (std::strcmp(argv[1], "color") == 0)
  345. createAndShowExampleWidgetStandaloneWindow<ExampleColorStandaloneWindow>(app);
  346. else if (std::strcmp(argv[1], "images") == 0)
  347. createAndShowExampleWidgetStandaloneWindow<ExampleImagesStandaloneWindow>(app);
  348. else if (std::strcmp(argv[1], "rectangles") == 0)
  349. createAndShowExampleWidgetStandaloneWindow<ExampleRectanglesStandaloneWindow>(app);
  350. else if (std::strcmp(argv[1], "shapes") == 0)
  351. createAndShowExampleWidgetStandaloneWindow<ExampleShapesStandaloneWindow>(app);
  352. #ifdef DGL_OPENGL
  353. else if (std::strcmp(argv[1], "text") == 0)
  354. createAndShowExampleWidgetStandaloneWindow<ExampleTextStandaloneWindow>(app);
  355. #endif
  356. else
  357. d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes");
  358. }
  359. else
  360. {
  361. createAndShowExampleWidgetStandaloneWindow<DemoWindow>(app);
  362. }
  363. return 0;
  364. }
  365. // --------------------------------------------------------------------------------------------------------------------