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.

715 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() * float_Pi * 2.0f);
  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() * float_Pi * 2.0f)
  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 (RelativeParallelogram (Point<float> (-100, -100),
  385. Point<float> (100, -100),
  386. Point<float> (-100, 100)));
  387. }
  388. }
  389. }
  390. Time lastSVGLoadTime;
  391. ScopedPointer<DrawableComposite> svgDrawable;
  392. };
  393. //==============================================================================
  394. class LinesDemo : public GraphicsDemoBase
  395. {
  396. public:
  397. LinesDemo (ControllersComponent& cc)
  398. : GraphicsDemoBase (cc, "Lines")
  399. {
  400. }
  401. void drawDemo (Graphics& g) override
  402. {
  403. {
  404. RectangleList<float> verticalLines;
  405. verticalLines.ensureStorageAllocated (getWidth());
  406. float pos = offset.getValue();
  407. for (int x = 0; x < getWidth(); ++x)
  408. {
  409. float y = getHeight() * 0.3f;
  410. float length = y * std::abs (std::sin (x / 100.0f + 2.0f * pos));
  411. verticalLines.addWithoutMerging (Rectangle<float> ((float) x, y - length * 0.5f, 1.0f, length));
  412. }
  413. g.setColour (Colours::blue.withAlpha (getAlpha()));
  414. g.fillRectList (verticalLines);
  415. }
  416. {
  417. RectangleList<float> horizontalLines;
  418. horizontalLines.ensureStorageAllocated (getHeight());
  419. float pos = offset.getValue();
  420. for (int y = 0; y < getHeight(); ++y)
  421. {
  422. float x = getWidth() * 0.3f;
  423. float length = x * std::abs (std::sin (y / 100.0f + 2.0f * pos));
  424. horizontalLines.addWithoutMerging (Rectangle<float> (x - length * 0.5f, (float) y, length, 1.0f));
  425. }
  426. g.setColour (Colours::green.withAlpha (getAlpha()));
  427. g.fillRectList (horizontalLines);
  428. }
  429. g.setColour (Colours::red.withAlpha (getAlpha()));
  430. const float w = (float) getWidth();
  431. const float h = (float) getHeight();
  432. g.drawLine (positions[0].getValue() * w,
  433. positions[1].getValue() * h,
  434. positions[2].getValue() * w,
  435. positions[3].getValue() * h);
  436. g.drawLine (positions[4].getValue() * w,
  437. positions[5].getValue() * h,
  438. positions[6].getValue() * w,
  439. positions[7].getValue() * h);
  440. }
  441. SlowerBouncingNumber offset, positions[8];
  442. };
  443. //==============================================================================
  444. class DemoHolderComponent : public Component,
  445. private Timer
  446. {
  447. public:
  448. DemoHolderComponent()
  449. : currentDemo (nullptr)
  450. {
  451. setOpaque (true);
  452. }
  453. void paint (Graphics& g) override
  454. {
  455. g.fillCheckerBoard (getLocalBounds(), 48, 48,
  456. Colours::lightgrey, Colours::white);
  457. }
  458. void timerCallback() override
  459. {
  460. if (currentDemo != nullptr)
  461. currentDemo->repaint();
  462. }
  463. void setDemo (GraphicsDemoBase* newDemo)
  464. {
  465. if (currentDemo != nullptr)
  466. removeChildComponent (currentDemo);
  467. currentDemo = newDemo;
  468. if (currentDemo != nullptr)
  469. {
  470. addAndMakeVisible (currentDemo);
  471. startTimerHz (60);
  472. resized();
  473. }
  474. }
  475. void resized() override
  476. {
  477. if (currentDemo != nullptr)
  478. currentDemo->setBounds (getLocalBounds());
  479. }
  480. private:
  481. GraphicsDemoBase* currentDemo;
  482. };
  483. //==============================================================================
  484. class TestListComponent : public Component,
  485. private ListBoxModel
  486. {
  487. public:
  488. TestListComponent (DemoHolderComponent& holder, ControllersComponent& controls)
  489. : demoHolder (holder)
  490. {
  491. demos.add (new PathsDemo (controls, false, true));
  492. demos.add (new PathsDemo (controls, true, false));
  493. demos.add (new PathsDemo (controls, false, false));
  494. demos.add (new RectangleFillTypesDemo (controls));
  495. demos.add (new StrokesDemo (controls));
  496. demos.add (new ImagesRenderingDemo (controls, false, false));
  497. demos.add (new ImagesRenderingDemo (controls, false, true));
  498. demos.add (new ImagesRenderingDemo (controls, true, false));
  499. demos.add (new ImagesRenderingDemo (controls, true, true));
  500. demos.add (new GlyphsDemo (controls));
  501. demos.add (new SVGDemo (controls));
  502. demos.add (new LinesDemo (controls));
  503. addAndMakeVisible (listBox);
  504. listBox.setModel (this);
  505. listBox.selectRow (0);
  506. }
  507. void resized()
  508. {
  509. listBox.setBounds (getLocalBounds());
  510. }
  511. int getNumRows()
  512. {
  513. return demos.size();
  514. }
  515. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
  516. {
  517. if (auto* demo = demos[rowNumber])
  518. {
  519. if (rowIsSelected)
  520. g.fillAll (Colour::contrasting (findColour (ListBox::textColourId),
  521. findColour (ListBox::backgroundColourId)));
  522. g.setColour (findColour (ListBox::textColourId));
  523. g.setFont (14.0f);
  524. g.drawFittedText (demo->getName(), 8, 0, width - 10, height, Justification::centredLeft, 2);
  525. }
  526. }
  527. void selectedRowsChanged (int lastRowSelected)
  528. {
  529. demoHolder.setDemo (demos [lastRowSelected]);
  530. }
  531. private:
  532. DemoHolderComponent& demoHolder;
  533. ListBox listBox;
  534. OwnedArray<GraphicsDemoBase> demos;
  535. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestListComponent)
  536. };
  537. //==============================================================================
  538. class GraphicsDemo : public Component
  539. {
  540. public:
  541. GraphicsDemo()
  542. : testList (demoHolder, controllersComponent)
  543. {
  544. setOpaque (true);
  545. addAndMakeVisible (demoHolder);
  546. addAndMakeVisible (controllersComponent);
  547. addAndMakeVisible (performanceDisplay);
  548. addAndMakeVisible (testList);
  549. }
  550. void paint (Graphics& g) override
  551. {
  552. g.fillAll (Colours::grey);
  553. }
  554. void resized() override
  555. {
  556. auto area = getLocalBounds();
  557. controllersComponent.setBounds (area.removeFromBottom (150));
  558. testList.setBounds (area.removeFromRight (150));
  559. demoHolder.setBounds (area);
  560. performanceDisplay.setBounds (area.removeFromTop (20).removeFromRight (100));
  561. }
  562. private:
  563. ControllersComponent controllersComponent;
  564. DemoHolderComponent demoHolder;
  565. Label performanceDisplay;
  566. TestListComponent testList;
  567. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphicsDemo)
  568. };
  569. // This static object will register this demo type in a global list of demos..
  570. static JuceDemoType<GraphicsDemo> demo ("20 Graphics: 2D Rendering");