The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

724 lines
25KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE examples.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. The code included in this file is provided under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  7. To use, copy, modify, and/or distribute this software for any purpose with or
  8. without fee is hereby granted provided that the above copyright notice and
  9. this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
  11. WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
  12. PURPOSE, ARE DISCLAIMED.
  13. ==============================================================================
  14. */
  15. /*******************************************************************************
  16. The block below describes the properties of this PIP. A PIP is a short snippet
  17. of code that can be read by the Projucer and used to generate a JUCE project.
  18. BEGIN_JUCE_PIP_METADATA
  19. name: GraphicsDemo
  20. version: 1.0.0
  21. vendor: JUCE
  22. website: http://juce.com
  23. description: Showcases various graphics features.
  24. dependencies: juce_core, juce_data_structures, juce_events, juce_graphics,
  25. juce_gui_basics
  26. exporters: xcode_mac, vs2017, linux_make, androidstudio, xcode_iphone
  27. type: Component
  28. mainClass: GraphicsDemo
  29. useLocalCopy: 1
  30. END_JUCE_PIP_METADATA
  31. *******************************************************************************/
  32. #pragma once
  33. #include "../Assets/DemoUtilities.h"
  34. //==============================================================================
  35. /** Holds the various toggle buttons for the animation modes. */
  36. class ControllersComponent : public Component
  37. {
  38. public:
  39. ControllersComponent()
  40. {
  41. setOpaque (true);
  42. initialiseToggle (animatePosition, "Animate Position", true);
  43. initialiseToggle (animateRotation, "Animate Rotation", true);
  44. initialiseToggle (animateSize, "Animate Size", false);
  45. initialiseToggle (animateShear, "Animate Shearing", false);
  46. initialiseToggle (animateAlpha, "Animate Alpha", false);
  47. initialiseToggle (clipToRectangle, "Clip to Rectangle", false);
  48. initialiseToggle (clipToPath, "Clip to Path", false);
  49. initialiseToggle (clipToImage, "Clip to Image", false);
  50. initialiseToggle (quality, "Higher quality image interpolation", false);
  51. }
  52. void paint (Graphics& g) override
  53. {
  54. g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground));
  55. }
  56. void resized() override
  57. {
  58. auto r = getLocalBounds().reduced (4);
  59. int buttonHeight = 22;
  60. auto columns = r.removeFromTop (buttonHeight * 4);
  61. auto col = columns.removeFromLeft (200);
  62. animatePosition.setBounds (col.removeFromTop (buttonHeight));
  63. animateRotation.setBounds (col.removeFromTop (buttonHeight));
  64. animateSize .setBounds (col.removeFromTop (buttonHeight));
  65. animateShear .setBounds (col.removeFromTop (buttonHeight));
  66. columns.removeFromLeft (20);
  67. col = columns.removeFromLeft (200);
  68. animateAlpha .setBounds (col.removeFromTop (buttonHeight));
  69. clipToRectangle.setBounds (col.removeFromTop (buttonHeight));
  70. clipToPath .setBounds (col.removeFromTop (buttonHeight));
  71. clipToImage .setBounds (col.removeFromTop (buttonHeight));
  72. r.removeFromBottom (6);
  73. quality.setBounds (r.removeFromTop (buttonHeight));
  74. }
  75. void initialiseToggle (ToggleButton& b, const char* name, bool on)
  76. {
  77. addAndMakeVisible (b);
  78. b.setButtonText (name);
  79. b.setToggleState (on, dontSendNotification);
  80. }
  81. ToggleButton animateRotation, animatePosition, animateAlpha, animateSize, animateShear;
  82. ToggleButton clipToRectangle, clipToPath, clipToImage, quality;
  83. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ControllersComponent)
  84. };
  85. //==============================================================================
  86. class GraphicsDemoBase : public Component
  87. {
  88. public:
  89. GraphicsDemoBase (ControllersComponent& cc, const String& name)
  90. : Component (name),
  91. controls (cc)
  92. {
  93. displayFont = Font (Font::getDefaultMonospacedFontName(), 12.0f, Font::bold);
  94. }
  95. AffineTransform getTransform()
  96. {
  97. auto hw = 0.5f * getWidth();
  98. auto hh = 0.5f * getHeight();
  99. AffineTransform t;
  100. if (controls.animateRotation.getToggleState())
  101. t = t.rotated (rotation.getValue() * MathConstants<float>::twoPi);
  102. if (controls.animateSize.getToggleState())
  103. t = t.scaled (0.3f + size.getValue() * 2.0f);
  104. if (controls.animatePosition.getToggleState())
  105. t = t.translated (hw + hw * (offsetX.getValue() - 0.5f),
  106. hh + hh * (offsetY.getValue() - 0.5f));
  107. else
  108. t = t.translated (hw, hh);
  109. if (controls.animateShear.getToggleState())
  110. t = t.sheared (shear.getValue() * 2.0f - 1.0f, 0.0f);
  111. return t;
  112. }
  113. float getAlpha() const
  114. {
  115. if (controls.animateAlpha.getToggleState())
  116. return alpha.getValue();
  117. return 1.0f;
  118. }
  119. void paint (Graphics& g) override
  120. {
  121. auto startTime = 0.0;
  122. {
  123. // A ScopedSaveState will return the Graphics context to the state it was at the time of
  124. // construction when it goes out of scope. We use it here to avoid clipping the fps text
  125. const Graphics::ScopedSaveState state (g);
  126. if (controls.clipToRectangle.getToggleState()) clipToRectangle (g);
  127. if (controls.clipToPath .getToggleState()) clipToPath (g);
  128. if (controls.clipToImage .getToggleState()) clipToImage (g);
  129. g.setImageResamplingQuality (controls.quality.getToggleState() ? Graphics::highResamplingQuality
  130. : Graphics::mediumResamplingQuality);
  131. // take a note of the time before the render
  132. startTime = Time::getMillisecondCounterHiRes();
  133. // then let the demo draw itself..
  134. drawDemo (g);
  135. }
  136. auto now = Time::getMillisecondCounterHiRes();
  137. auto filtering = 0.08;
  138. auto elapsedMs = now - startTime;
  139. averageTimeMs += (elapsedMs - averageTimeMs) * filtering;
  140. auto sinceLastRender = now - lastRenderStartTime;
  141. lastRenderStartTime = now;
  142. auto effectiveFPS = 1000.0 / averageTimeMs;
  143. auto actualFPS = sinceLastRender > 0 ? (1000.0 / sinceLastRender) : 0;
  144. averageActualFPS += (actualFPS - averageActualFPS) * filtering;
  145. GlyphArrangement ga;
  146. ga.addFittedText (displayFont,
  147. "Time: " + String (averageTimeMs, 2)
  148. + " ms\nEffective FPS: " + String (effectiveFPS, 1)
  149. + "\nActual FPS: " + String (averageActualFPS, 1),
  150. 0, 10.0f, getWidth() - 10.0f, (float) getHeight(), Justification::topRight, 3);
  151. g.setColour (Colours::white.withAlpha (0.5f));
  152. g.fillRect (ga.getBoundingBox (0, ga.getNumGlyphs(), true).getSmallestIntegerContainer().expanded (4));
  153. g.setColour (Colours::black);
  154. ga.draw (g);
  155. }
  156. virtual void drawDemo (Graphics&) = 0;
  157. void clipToRectangle (Graphics& g)
  158. {
  159. auto w = getWidth() / 2;
  160. auto h = getHeight() / 2;
  161. auto x = (int) (w * clipRectX.getValue());
  162. auto y = (int) (h * clipRectY.getValue());
  163. g.reduceClipRegion (x, y, w, h);
  164. }
  165. void clipToPath (Graphics& g)
  166. {
  167. auto pathSize = (float) jmin (getWidth(), getHeight());
  168. Path p;
  169. p.addStar (Point<float> (clipPathX.getValue(),
  170. clipPathY.getValue()) * pathSize,
  171. 7,
  172. pathSize * (0.5f + clipPathDepth.getValue()),
  173. pathSize * 0.5f,
  174. clipPathAngle.getValue());
  175. g.reduceClipRegion (p, AffineTransform());
  176. }
  177. void clipToImage (Graphics& g)
  178. {
  179. if (! clipImage.isValid())
  180. createClipImage();
  181. AffineTransform transform (AffineTransform::translation (clipImage.getWidth() / -2.0f,
  182. clipImage.getHeight() / -2.0f)
  183. .rotated (clipImageAngle.getValue() * MathConstants<float>::twoPi)
  184. .scaled (2.0f + clipImageSize.getValue() * 3.0f)
  185. .translated (getWidth() * 0.5f,
  186. getHeight() * 0.5f));
  187. g.reduceClipRegion (clipImage, transform);
  188. }
  189. void createClipImage()
  190. {
  191. clipImage = Image (Image::ARGB, 300, 300, true);
  192. Graphics g (clipImage);
  193. g.setGradientFill (ColourGradient (Colours::transparentBlack, 0, 0,
  194. Colours::black, 0, 300, false));
  195. for (int i = 0; i < 20; ++i)
  196. g.fillRect (Random::getSystemRandom().nextInt (200),
  197. Random::getSystemRandom().nextInt (200),
  198. Random::getSystemRandom().nextInt (100),
  199. Random::getSystemRandom().nextInt (100));
  200. }
  201. //==============================================================================
  202. ControllersComponent& controls;
  203. SlowerBouncingNumber offsetX, offsetY, rotation, size, shear, alpha, clipRectX,
  204. clipRectY, clipPathX, clipPathY, clipPathDepth, clipPathAngle,
  205. clipImageX, clipImageY, clipImageAngle, clipImageSize;
  206. double lastRenderStartTime = 0.0, averageTimeMs = 0.0, averageActualFPS = 0.0;
  207. Image clipImage;
  208. Font displayFont;
  209. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphicsDemoBase)
  210. };
  211. //==============================================================================
  212. class RectangleFillTypesDemo : public GraphicsDemoBase
  213. {
  214. public:
  215. RectangleFillTypesDemo (ControllersComponent& cc)
  216. : GraphicsDemoBase (cc, "Fill Types: Rectangles")
  217. {}
  218. void drawDemo (Graphics& g) override
  219. {
  220. g.addTransform (getTransform());
  221. const int rectSize = jmin (getWidth(), getHeight()) / 2 - 20;
  222. g.setColour (colour1.withAlpha (getAlpha()));
  223. g.fillRect (-rectSize, -rectSize, rectSize, rectSize);
  224. g.setGradientFill (ColourGradient (colour1, 10.0f, (float) -rectSize,
  225. colour2, 10.0f + rectSize, 0.0f, false));
  226. g.setOpacity (getAlpha());
  227. g.fillRect (10, -rectSize, rectSize, rectSize);
  228. g.setGradientFill (ColourGradient (colour1, rectSize * -0.5f, 10.0f + rectSize * 0.5f,
  229. colour2, 0, 10.0f + rectSize, true));
  230. g.setOpacity (getAlpha());
  231. g.fillRect (-rectSize, 10, rectSize, rectSize);
  232. g.setGradientFill (ColourGradient (colour1, 10.0f, 10.0f,
  233. colour2, 10.0f + rectSize, 10.0f + rectSize, false));
  234. g.setOpacity (getAlpha());
  235. g.drawRect (10, 10, rectSize, rectSize, 5);
  236. }
  237. Colour colour1 { Colours::red }, colour2 { Colours::green };
  238. };
  239. //==============================================================================
  240. class PathsDemo : public GraphicsDemoBase
  241. {
  242. public:
  243. PathsDemo (ControllersComponent& cc, bool linear, bool radial)
  244. : GraphicsDemoBase (cc, String ("Paths") + (radial ? ": Radial Gradients"
  245. : (linear ? ": Linear Gradients"
  246. : ": Solid"))),
  247. useLinearGradient (linear), useRadialGradient (radial)
  248. {
  249. logoPath = getJUCELogoPath();
  250. // rescale the logo path so that it's centred about the origin and has the right size.
  251. logoPath.applyTransform (RectanglePlacement (RectanglePlacement::centred)
  252. .getTransformToFit (logoPath.getBounds(),
  253. Rectangle<float> (-120.0f, -120.0f, 240.0f, 240.0f)));
  254. // Surround it with some other shapes..
  255. logoPath.addStar ({ -300.0f, -50.0f }, 7, 30.0f, 70.0f, 0.1f);
  256. logoPath.addStar ({ 300.0f, 50.0f }, 6, 40.0f, 70.0f, 0.1f);
  257. logoPath.addEllipse (-100.0f, 150.0f, 200.0f, 140.0f);
  258. logoPath.addRectangle (-100.0f, -280.0f, 200.0f, 140.0f);
  259. }
  260. void drawDemo (Graphics& g) override
  261. {
  262. auto& p = logoPath;
  263. if (useLinearGradient || useRadialGradient)
  264. {
  265. Colour c1 (gradientColours[0].getValue(), gradientColours[1].getValue(), gradientColours[2].getValue(), 1.0f);
  266. Colour c2 (gradientColours[3].getValue(), gradientColours[4].getValue(), gradientColours[5].getValue(), 1.0f);
  267. Colour c3 (gradientColours[6].getValue(), gradientColours[7].getValue(), gradientColours[8].getValue(), 1.0f);
  268. auto x1 = gradientPositions[0].getValue() * getWidth() * 0.25f;
  269. auto y1 = gradientPositions[1].getValue() * getHeight() * 0.25f;
  270. auto x2 = gradientPositions[2].getValue() * getWidth() * 0.75f;
  271. auto y2 = gradientPositions[3].getValue() * getHeight() * 0.75f;
  272. ColourGradient gradient (c1, x1, y1,
  273. c2, x2, y2,
  274. useRadialGradient);
  275. gradient.addColour (gradientIntermediate.getValue(), c3);
  276. g.setGradientFill (gradient);
  277. }
  278. else
  279. {
  280. g.setColour (Colours::blue);
  281. }
  282. g.setOpacity (getAlpha());
  283. g.fillPath (p, getTransform());
  284. }
  285. Path logoPath;
  286. bool useLinearGradient, useRadialGradient;
  287. SlowerBouncingNumber gradientColours[9], gradientPositions[4], gradientIntermediate;
  288. };
  289. //==============================================================================
  290. class StrokesDemo : public GraphicsDemoBase
  291. {
  292. public:
  293. StrokesDemo (ControllersComponent& cc)
  294. : GraphicsDemoBase (cc, "Paths: Stroked")
  295. {}
  296. void drawDemo (Graphics& g) override
  297. {
  298. auto w = (float) getWidth();
  299. auto h = (float) getHeight();
  300. Path p;
  301. p.startNewSubPath (points[0].getValue() * w,
  302. points[1].getValue() * h);
  303. for (int i = 2; i < numElementsInArray (points); i += 4)
  304. p.quadraticTo (points[i] .getValue() * w,
  305. points[i + 1].getValue() * h,
  306. points[i + 2].getValue() * w,
  307. points[i + 3].getValue() * h);
  308. p.closeSubPath();
  309. PathStrokeType stroke (0.5f + 10.0f * thickness.getValue());
  310. g.setColour (Colours::purple.withAlpha (getAlpha()));
  311. g.strokePath (p, stroke, AffineTransform());
  312. }
  313. SlowerBouncingNumber points[2 + 4 * 8], thickness;
  314. };
  315. //==============================================================================
  316. class ImagesRenderingDemo : public GraphicsDemoBase
  317. {
  318. public:
  319. ImagesRenderingDemo (ControllersComponent& cc, bool argb, bool tiled)
  320. : GraphicsDemoBase (cc, String ("Images") + (argb ? ": ARGB" : ": RGB") + (tiled ? " Tiled" : String() )),
  321. isArgb (argb), isTiled (tiled)
  322. {
  323. argbImage = getImageFromAssets ("juce_icon.png");
  324. rgbImage = getImageFromAssets ("portmeirion.jpg");
  325. }
  326. void drawDemo (Graphics& g) override
  327. {
  328. auto image = isArgb ? argbImage : rgbImage;
  329. AffineTransform transform (AffineTransform::translation ((float) (image.getWidth() / -2),
  330. (float) (image.getHeight() / -2))
  331. .followedBy (getTransform()));
  332. if (isTiled)
  333. {
  334. FillType fill (image, transform);
  335. fill.setOpacity (getAlpha());
  336. g.setFillType (fill);
  337. g.fillAll();
  338. }
  339. else
  340. {
  341. g.setOpacity (getAlpha());
  342. g.drawImageTransformed (image, transform, false);
  343. }
  344. }
  345. bool isArgb, isTiled;
  346. Image rgbImage, argbImage;
  347. };
  348. //==============================================================================
  349. class GlyphsDemo : public GraphicsDemoBase
  350. {
  351. public:
  352. GlyphsDemo (ControllersComponent& cc)
  353. : GraphicsDemoBase (cc, "Glyphs")
  354. {
  355. glyphs.addFittedText ({ 20.0f }, "The Quick Brown Fox Jumped Over The Lazy Dog",
  356. -120, -50, 240, 100, Justification::centred, 2, 1.0f);
  357. }
  358. void drawDemo (Graphics& g) override
  359. {
  360. g.setColour (Colours::black.withAlpha (getAlpha()));
  361. glyphs.draw (g, getTransform());
  362. }
  363. GlyphArrangement glyphs;
  364. };
  365. //==============================================================================
  366. class SVGDemo : public GraphicsDemoBase
  367. {
  368. public:
  369. SVGDemo (ControllersComponent& cc)
  370. : GraphicsDemoBase (cc, "SVG")
  371. {
  372. createSVGDrawable();
  373. }
  374. void drawDemo (Graphics& g) override
  375. {
  376. if (Time::getCurrentTime().toMilliseconds() > lastSVGLoadTime.toMilliseconds() + 2000)
  377. createSVGDrawable();
  378. svgDrawable->draw (g, getAlpha(), getTransform());
  379. }
  380. void createSVGDrawable()
  381. {
  382. lastSVGLoadTime = Time::getCurrentTime();
  383. ZipFile icons (createAssetInputStream ("icons.zip"), true);
  384. // Load a random SVG file from our embedded icons.zip file.
  385. const std::unique_ptr<InputStream> svgFileStream (icons.createStreamForEntry (Random::getSystemRandom().nextInt (icons.getNumEntries())));
  386. if (svgFileStream.get() != nullptr)
  387. {
  388. svgDrawable.reset (dynamic_cast<DrawableComposite*> (Drawable::createFromImageDataStream (*svgFileStream)));
  389. if (svgDrawable.get() != nullptr)
  390. {
  391. // to make our icon the right size, we'll set its bounding box to the size and position that we want.
  392. svgDrawable->setBoundingBox ({ -100.0f, -100.0f, 200.0f, 200.0f });
  393. }
  394. }
  395. }
  396. Time lastSVGLoadTime;
  397. std::unique_ptr<DrawableComposite> svgDrawable;
  398. };
  399. //==============================================================================
  400. class LinesDemo : public GraphicsDemoBase
  401. {
  402. public:
  403. LinesDemo (ControllersComponent& cc)
  404. : GraphicsDemoBase (cc, "Lines")
  405. {}
  406. void drawDemo (Graphics& g) override
  407. {
  408. {
  409. RectangleList<float> verticalLines;
  410. verticalLines.ensureStorageAllocated (getWidth());
  411. auto pos = offset.getValue();
  412. for (int x = 0; x < getWidth(); ++x)
  413. {
  414. auto y = getHeight() * 0.3f;
  415. auto length = y * std::abs (std::sin (x / 100.0f + 2.0f * pos));
  416. verticalLines.addWithoutMerging (Rectangle<float> ((float) x, y - length * 0.5f, 1.0f, length));
  417. }
  418. g.setColour (Colours::blue.withAlpha (getAlpha()));
  419. g.fillRectList (verticalLines);
  420. }
  421. {
  422. RectangleList<float> horizontalLines;
  423. horizontalLines.ensureStorageAllocated (getHeight());
  424. auto pos = offset.getValue();
  425. for (int y = 0; y < getHeight(); ++y)
  426. {
  427. auto x = getWidth() * 0.3f;
  428. auto length = x * std::abs (std::sin (y / 100.0f + 2.0f * pos));
  429. horizontalLines.addWithoutMerging (Rectangle<float> (x - length * 0.5f, (float) y, length, 1.0f));
  430. }
  431. g.setColour (Colours::green.withAlpha (getAlpha()));
  432. g.fillRectList (horizontalLines);
  433. }
  434. g.setColour (Colours::red.withAlpha (getAlpha()));
  435. auto w = (float) getWidth();
  436. auto h = (float) getHeight();
  437. g.drawLine (positions[0].getValue() * w,
  438. positions[1].getValue() * h,
  439. positions[2].getValue() * w,
  440. positions[3].getValue() * h);
  441. g.drawLine (positions[4].getValue() * w,
  442. positions[5].getValue() * h,
  443. positions[6].getValue() * w,
  444. positions[7].getValue() * h);
  445. }
  446. SlowerBouncingNumber offset, positions[8];
  447. };
  448. //==============================================================================
  449. class DemoHolderComponent : public Component,
  450. private Timer
  451. {
  452. public:
  453. DemoHolderComponent()
  454. {
  455. setOpaque (true);
  456. }
  457. void paint (Graphics& g) override
  458. {
  459. g.fillCheckerBoard (getLocalBounds().toFloat(), 48.0f, 48.0f,
  460. Colours::lightgrey, Colours::white);
  461. }
  462. void timerCallback() override
  463. {
  464. if (currentDemo != nullptr)
  465. currentDemo->repaint();
  466. }
  467. void setDemo (GraphicsDemoBase* newDemo)
  468. {
  469. if (currentDemo != nullptr)
  470. removeChildComponent (currentDemo);
  471. currentDemo = newDemo;
  472. if (currentDemo != nullptr)
  473. {
  474. addAndMakeVisible (currentDemo);
  475. startTimerHz (60);
  476. resized();
  477. }
  478. }
  479. void resized() override
  480. {
  481. if (currentDemo != nullptr)
  482. currentDemo->setBounds (getLocalBounds());
  483. }
  484. private:
  485. GraphicsDemoBase* currentDemo = nullptr;
  486. };
  487. //==============================================================================
  488. class TestListComponent : public Component,
  489. private ListBoxModel
  490. {
  491. public:
  492. TestListComponent (DemoHolderComponent& holder, ControllersComponent& controls)
  493. : demoHolder (holder)
  494. {
  495. demos.add (new PathsDemo (controls, false, true));
  496. demos.add (new PathsDemo (controls, true, false));
  497. demos.add (new PathsDemo (controls, false, false));
  498. demos.add (new RectangleFillTypesDemo (controls));
  499. demos.add (new StrokesDemo (controls));
  500. demos.add (new ImagesRenderingDemo (controls, false, false));
  501. demos.add (new ImagesRenderingDemo (controls, false, true));
  502. demos.add (new ImagesRenderingDemo (controls, true, false));
  503. demos.add (new ImagesRenderingDemo (controls, true, true));
  504. demos.add (new GlyphsDemo (controls));
  505. demos.add (new SVGDemo (controls));
  506. demos.add (new LinesDemo (controls));
  507. addAndMakeVisible (listBox);
  508. listBox.setModel (this);
  509. listBox.selectRow (0);
  510. }
  511. void resized()
  512. {
  513. listBox.setBounds (getLocalBounds());
  514. }
  515. int getNumRows()
  516. {
  517. return demos.size();
  518. }
  519. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
  520. {
  521. if (auto* demo = demos[rowNumber])
  522. {
  523. if (rowIsSelected)
  524. g.fillAll (Colour::contrasting (findColour (ListBox::textColourId),
  525. findColour (ListBox::backgroundColourId)));
  526. g.setColour (findColour (ListBox::textColourId));
  527. g.setFont (14.0f);
  528. g.drawFittedText (demo->getName(), 8, 0, width - 10, height, Justification::centredLeft, 2);
  529. }
  530. }
  531. void selectedRowsChanged (int lastRowSelected)
  532. {
  533. demoHolder.setDemo (demos [lastRowSelected]);
  534. }
  535. private:
  536. DemoHolderComponent& demoHolder;
  537. ListBox listBox;
  538. OwnedArray<GraphicsDemoBase> demos;
  539. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestListComponent)
  540. };
  541. //==============================================================================
  542. class GraphicsDemo : public Component
  543. {
  544. public:
  545. GraphicsDemo()
  546. : testList (demoHolder, controllersComponent)
  547. {
  548. setOpaque (true);
  549. addAndMakeVisible (demoHolder);
  550. addAndMakeVisible (controllersComponent);
  551. addAndMakeVisible (performanceDisplay);
  552. addAndMakeVisible (testList);
  553. setSize (750, 750);
  554. }
  555. void paint (Graphics& g) override
  556. {
  557. g.fillAll (Colours::grey);
  558. }
  559. void resized() override
  560. {
  561. auto area = getLocalBounds();
  562. controllersComponent.setBounds (area.removeFromBottom (150));
  563. testList .setBounds (area.removeFromRight (150));
  564. demoHolder .setBounds (area);
  565. performanceDisplay .setBounds (area.removeFromTop (20).removeFromRight (100));
  566. }
  567. private:
  568. ControllersComponent controllersComponent;
  569. DemoHolderComponent demoHolder;
  570. Label performanceDisplay;
  571. TestListComponent testList;
  572. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphicsDemo)
  573. };