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.

713 lines
25KB

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