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.

622 lines
27KB

  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. //==============================================================================
  21. /** Custom Look And Feel subclasss.
  22. Simply override the methods you need to, anything else will be inherited from the base class.
  23. It's a good idea not to hard code your colours, use the findColour method along with appropriate
  24. ColourIds so you can set these on a per-component basis.
  25. */
  26. struct CustomLookAndFeel : public LookAndFeel_V4
  27. {
  28. void drawRoundThumb (Graphics& g, const float x, const float y,
  29. const float diameter, const Colour& colour, float outlineThickness)
  30. {
  31. const Rectangle<float> a (x, y, diameter, diameter);
  32. const float halfThickness = outlineThickness * 0.5f;
  33. Path p;
  34. p.addEllipse (x + halfThickness, y + halfThickness, diameter - outlineThickness, diameter - outlineThickness);
  35. const DropShadow ds (Colours::black, 1, Point<int> (0, 0));
  36. ds.drawForPath (g, p);
  37. g.setColour (colour);
  38. g.fillPath (p);
  39. g.setColour (colour.brighter());
  40. g.strokePath (p, PathStrokeType (outlineThickness));
  41. }
  42. void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
  43. bool isMouseOverButton, bool isButtonDown) override
  44. {
  45. Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
  46. .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
  47. if (isButtonDown || isMouseOverButton)
  48. baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f);
  49. const bool flatOnLeft = button.isConnectedOnLeft();
  50. const bool flatOnRight = button.isConnectedOnRight();
  51. const bool flatOnTop = button.isConnectedOnTop();
  52. const bool flatOnBottom = button.isConnectedOnBottom();
  53. const float width = button.getWidth() - 1.0f;
  54. const float height = button.getHeight() - 1.0f;
  55. if (width > 0 && height > 0)
  56. {
  57. const float cornerSize = jmin (15.0f, jmin (width, height) * 0.45f);
  58. const float lineThickness = cornerSize * 0.1f;
  59. const float halfThickness = lineThickness * 0.5f;
  60. Path outline;
  61. outline.addRoundedRectangle (0.5f + halfThickness, 0.5f + halfThickness, width - lineThickness, height - lineThickness,
  62. cornerSize, cornerSize,
  63. ! (flatOnLeft || flatOnTop),
  64. ! (flatOnRight || flatOnTop),
  65. ! (flatOnLeft || flatOnBottom),
  66. ! (flatOnRight || flatOnBottom));
  67. const Colour outlineColour (button.findColour (button.getToggleState() ? TextButton::textColourOnId
  68. : TextButton::textColourOffId));
  69. g.setColour (baseColour);
  70. g.fillPath (outline);
  71. if (! button.getToggleState())
  72. {
  73. g.setColour (outlineColour);
  74. g.strokePath (outline, PathStrokeType (lineThickness));
  75. }
  76. }
  77. }
  78. void drawTickBox (Graphics& g, Component& component,
  79. float x, float y, float w, float h,
  80. bool ticked,
  81. bool isEnabled,
  82. bool isMouseOverButton,
  83. bool isButtonDown) override
  84. {
  85. const float boxSize = w * 0.7f;
  86. bool isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown());
  87. const Colour colour (component.findColour (TextButton::buttonColourId).withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
  88. .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f));
  89. drawRoundThumb (g, x, y + (h - boxSize) * 0.5f, boxSize, colour,
  90. isEnabled ? ((isButtonDown || isMouseOverButton) ? 1.1f : 0.5f) : 0.3f);
  91. if (ticked)
  92. {
  93. const Path tick (LookAndFeel_V4::getTickShape (6.0f));
  94. g.setColour (isEnabled ? findColour (TextButton::buttonOnColourId) : Colours::grey);
  95. const float scale = 9.0f;
  96. const AffineTransform trans (AffineTransform::scale (w / scale, h / scale)
  97. .translated (x - 2.5f, y + 1.0f));
  98. g.fillPath (tick, trans);
  99. }
  100. }
  101. void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height,
  102. float sliderPos, float minSliderPos, float maxSliderPos,
  103. const Slider::SliderStyle style, Slider& slider) override
  104. {
  105. const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
  106. bool isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown());
  107. Colour knobColour (slider.findColour (Slider::thumbColourId).withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
  108. .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f));
  109. if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
  110. {
  111. float kx, ky;
  112. if (style == Slider::LinearVertical)
  113. {
  114. kx = x + width * 0.5f;
  115. ky = sliderPos;
  116. }
  117. else
  118. {
  119. kx = sliderPos;
  120. ky = y + height * 0.5f;
  121. }
  122. const float outlineThickness = slider.isEnabled() ? 0.8f : 0.3f;
  123. drawRoundThumb (g,
  124. kx - sliderRadius,
  125. ky - sliderRadius,
  126. sliderRadius * 2.0f,
  127. knobColour, outlineThickness);
  128. }
  129. else
  130. {
  131. // Just call the base class for the demo
  132. LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  133. }
  134. }
  135. void drawLinearSlider (Graphics& g, int x, int y, int width, int height,
  136. float sliderPos, float minSliderPos, float maxSliderPos,
  137. const Slider::SliderStyle style, Slider& slider) override
  138. {
  139. g.fillAll (slider.findColour (Slider::backgroundColourId));
  140. if (style == Slider::LinearBar || style == Slider::LinearBarVertical)
  141. {
  142. const float fx = (float) x, fy = (float) y, fw = (float) width, fh = (float) height;
  143. Path p;
  144. if (style == Slider::LinearBarVertical)
  145. p.addRectangle (fx, sliderPos, fw, 1.0f + fh - sliderPos);
  146. else
  147. p.addRectangle (fx, fy, sliderPos - fx, fh);
  148. Colour baseColour (slider.findColour (Slider::rotarySliderFillColourId)
  149. .withMultipliedSaturation (slider.isEnabled() ? 1.0f : 0.5f)
  150. .withMultipliedAlpha (0.8f));
  151. g.setColour (baseColour);
  152. g.fillPath (p);
  153. const float lineThickness = jmin (15.0f, jmin (width, height) * 0.45f) * 0.1f;
  154. g.drawRect (slider.getLocalBounds().toFloat(), lineThickness);
  155. }
  156. else
  157. {
  158. drawLinearSliderBackground (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  159. drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  160. }
  161. }
  162. void drawLinearSliderBackground (Graphics& g, int x, int y, int width, int height,
  163. float /*sliderPos*/,
  164. float /*minSliderPos*/,
  165. float /*maxSliderPos*/,
  166. const Slider::SliderStyle /*style*/, Slider& slider) override
  167. {
  168. const float sliderRadius = getSliderThumbRadius (slider) - 5.0f;
  169. Path on, off;
  170. if (slider.isHorizontal())
  171. {
  172. const float iy = y + height * 0.5f - sliderRadius * 0.5f;
  173. Rectangle<float> r (x - sliderRadius * 0.5f, iy, width + sliderRadius, sliderRadius);
  174. const float onW = r.getWidth() * ((float) slider.valueToProportionOfLength (slider.getValue()));
  175. on.addRectangle (r.removeFromLeft (onW));
  176. off.addRectangle (r);
  177. }
  178. else
  179. {
  180. const float ix = x + width * 0.5f - sliderRadius * 0.5f;
  181. Rectangle<float> r (ix, y - sliderRadius * 0.5f, sliderRadius, height + sliderRadius);
  182. const float onH = r.getHeight() * ((float) slider.valueToProportionOfLength (slider.getValue()));
  183. on.addRectangle (r.removeFromBottom (onH));
  184. off.addRectangle (r);
  185. }
  186. g.setColour (slider.findColour (Slider::rotarySliderFillColourId));
  187. g.fillPath (on);
  188. g.setColour (slider.findColour (Slider::trackColourId));
  189. g.fillPath (off);
  190. }
  191. void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
  192. float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override
  193. {
  194. const float radius = jmin (width / 2, height / 2) - 2.0f;
  195. const float centreX = x + width * 0.5f;
  196. const float centreY = y + height * 0.5f;
  197. const float rx = centreX - radius;
  198. const float ry = centreY - radius;
  199. const float rw = radius * 2.0f;
  200. const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
  201. const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
  202. if (slider.isEnabled())
  203. g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f));
  204. else
  205. g.setColour (Colour (0x80808080));
  206. {
  207. Path filledArc;
  208. filledArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, angle, 0.0);
  209. g.fillPath (filledArc);
  210. }
  211. {
  212. const float lineThickness = jmin (15.0f, jmin (width, height) * 0.45f) * 0.1f;
  213. Path outlineArc;
  214. outlineArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, 0.0);
  215. g.strokePath (outlineArc, PathStrokeType (lineThickness));
  216. }
  217. }
  218. };
  219. //==============================================================================
  220. /** Another really simple look and feel that is very flat and square.
  221. This inherits from CustomLookAndFeel above for the linear bar and slider backgrounds.
  222. */
  223. struct SquareLookAndFeel : public CustomLookAndFeel
  224. {
  225. void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
  226. bool isMouseOverButton, bool isButtonDown) override
  227. {
  228. Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
  229. .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
  230. if (isButtonDown || isMouseOverButton)
  231. baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f);
  232. const float width = button.getWidth() - 1.0f;
  233. const float height = button.getHeight() - 1.0f;
  234. if (width > 0 && height > 0)
  235. {
  236. g.setGradientFill (ColourGradient (baseColour, 0.0f, 0.0f,
  237. baseColour.darker (0.1f), 0.0f, height,
  238. false));
  239. g.fillRect (button.getLocalBounds());
  240. }
  241. }
  242. void drawTickBox (Graphics& g, Component& component,
  243. float x, float y, float w, float h,
  244. bool ticked,
  245. bool isEnabled,
  246. bool /*isMouseOverButton*/,
  247. bool /*isButtonDown*/) override
  248. {
  249. const float boxSize = w * 0.7f;
  250. bool isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown());
  251. const Colour colour (component.findColour (TextButton::buttonOnColourId).withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
  252. .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f));
  253. g.setColour (colour);
  254. Rectangle<float> r (x, y + (h - boxSize) * 0.5f, boxSize, boxSize);
  255. g.fillRect (r);
  256. if (ticked)
  257. {
  258. const Path tick (LookAndFeel_V4::getTickShape (6.0f));
  259. g.setColour (isEnabled ? findColour (TextButton::buttonColourId) : Colours::grey);
  260. const AffineTransform trans (RectanglePlacement (RectanglePlacement::centred)
  261. .getTransformToFit (tick.getBounds(), r.reduced (r.getHeight() * 0.05f)));
  262. g.fillPath (tick, trans);
  263. }
  264. }
  265. void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height,
  266. float sliderPos, float minSliderPos, float maxSliderPos,
  267. const Slider::SliderStyle style, Slider& slider) override
  268. {
  269. const float sliderRadius = (float) getSliderThumbRadius (slider);
  270. bool isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown());
  271. Colour knobColour (slider.findColour (Slider::rotarySliderFillColourId).withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
  272. .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f));
  273. g.setColour (knobColour);
  274. if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
  275. {
  276. float kx, ky;
  277. if (style == Slider::LinearVertical)
  278. {
  279. kx = x + width * 0.5f;
  280. ky = sliderPos;
  281. g.fillRect (Rectangle<float> (kx - sliderRadius, ky - 2.5f, sliderRadius * 2.0f, 5.0f));
  282. }
  283. else
  284. {
  285. kx = sliderPos;
  286. ky = y + height * 0.5f;
  287. g.fillRect (Rectangle<float> (kx - 2.5f, ky - sliderRadius, 5.0f, sliderRadius * 2.0f));
  288. }
  289. }
  290. else
  291. {
  292. // Just call the base class for the demo
  293. LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  294. }
  295. }
  296. void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
  297. float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override
  298. {
  299. const float diameter = jmin (width, height) - 4.0f;
  300. const float radius = (diameter / 2.0f) * std::cos (float_Pi / 4.0f);
  301. const float centreX = x + width * 0.5f;
  302. const float centreY = y + height * 0.5f;
  303. const float rx = centreX - radius;
  304. const float ry = centreY - radius;
  305. const float rw = radius * 2.0f;
  306. const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
  307. const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
  308. const Colour baseColour (slider.isEnabled() ? slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 0.8f : 1.0f)
  309. : Colour (0x80808080));
  310. Rectangle<float> r (rx, ry, rw, rw);
  311. AffineTransform t (AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY()));
  312. float x1 = r.getTopLeft().getX(), y1 = r.getTopLeft().getY(), x2 = r.getBottomLeft().getX(), y2 = r.getBottomLeft().getY();
  313. t.transformPoints (x1, y1, x2, y2);
  314. g.setGradientFill (ColourGradient (baseColour, x1, y1,
  315. baseColour.darker (0.1f), x2, y2,
  316. false));
  317. Path knob;
  318. knob.addRectangle (r);
  319. g.fillPath (knob, t);
  320. Path needle;
  321. Rectangle<float> r2 (r * 0.1f);
  322. needle.addRectangle (r2.withPosition (Point<float> (r.getCentreX() - (r2.getWidth() / 2.0f), r.getY())));
  323. g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId));
  324. g.fillPath (needle, AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY()));
  325. }
  326. };
  327. //==============================================================================
  328. struct LookAndFeelDemoComponent : public Component
  329. {
  330. LookAndFeelDemoComponent()
  331. {
  332. addAndMakeVisible (rotarySlider);
  333. rotarySlider.setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
  334. rotarySlider.setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
  335. rotarySlider.setValue (2.5);
  336. addAndMakeVisible (verticalSlider);
  337. verticalSlider.setSliderStyle (Slider::LinearVertical);
  338. verticalSlider.setTextBoxStyle (Slider::NoTextBox, false, 90, 20);
  339. verticalSlider.setValue (6.2);
  340. addAndMakeVisible (barSlider);
  341. barSlider.setSliderStyle (Slider::LinearBar);
  342. barSlider.setValue (4.5);
  343. addAndMakeVisible (incDecSlider);
  344. incDecSlider.setSliderStyle (Slider::IncDecButtons);
  345. incDecSlider.setRange (0.0, 10.0, 1.0);
  346. incDecSlider.setIncDecButtonsMode (Slider::incDecButtonsDraggable_Horizontal);
  347. incDecSlider.setTextBoxStyle (Slider::TextBoxBelow, false, 90, 20);
  348. addAndMakeVisible (button1);
  349. button1.setButtonText ("Hello World!");
  350. addAndMakeVisible (button2);
  351. button2.setButtonText ("Hello World!");
  352. button2.setClickingTogglesState (true);
  353. button2.setToggleState (true, dontSendNotification);
  354. addAndMakeVisible (button3);
  355. button3.setButtonText ("Hello World!");
  356. addAndMakeVisible (button4);
  357. button4.setButtonText ("Toggle Me");
  358. button4.setToggleState (true, dontSendNotification);
  359. for (int i = 0; i < 3; ++i)
  360. {
  361. TextButton* b = radioButtons.add (new TextButton());
  362. addAndMakeVisible (b);
  363. b->setRadioGroupId (42);
  364. b->setClickingTogglesState (true);
  365. b->setButtonText ("Button " + String (i + 1));
  366. switch (i)
  367. {
  368. case 0: b->setConnectedEdges (Button::ConnectedOnRight); break;
  369. case 1: b->setConnectedEdges (Button::ConnectedOnRight + Button::ConnectedOnLeft); break;
  370. case 2: b->setConnectedEdges (Button::ConnectedOnLeft); break;
  371. default: break;
  372. }
  373. }
  374. radioButtons.getUnchecked (2)->setToggleState (true, dontSendNotification);
  375. }
  376. void resized() override
  377. {
  378. Rectangle<int> area (getLocalBounds().reduced (10));
  379. Rectangle<int> row (area.removeFromTop (100));
  380. rotarySlider.setBounds (row.removeFromLeft (100).reduced (5));
  381. verticalSlider.setBounds (row.removeFromLeft (100).reduced (5));
  382. barSlider.setBounds (row.removeFromLeft (100).reduced (5, 25));
  383. incDecSlider.setBounds (row.removeFromLeft (100).reduced (5, 28));
  384. row = area.removeFromTop (100);
  385. button1.setBounds (row.removeFromLeft (100).reduced (5));
  386. Rectangle<int> row2 (row.removeFromTop (row.getHeight() / 2).reduced (0, 10));
  387. button2.setBounds (row2.removeFromLeft (100).reduced (5, 0));
  388. button3.setBounds (row2.removeFromLeft (100).reduced (5, 0));
  389. button4.setBounds (row2.removeFromLeft (100).reduced (5, 0));
  390. row2 = (row.removeFromTop (row2.getHeight() + 20).reduced (5, 10));
  391. for (int i = 0; i < radioButtons.size(); ++i)
  392. radioButtons.getUnchecked (i)->setBounds (row2.removeFromLeft (100));
  393. }
  394. Slider rotarySlider, verticalSlider, barSlider, incDecSlider;
  395. TextButton button1, button2, button3;
  396. ToggleButton button4;
  397. OwnedArray<TextButton> radioButtons;
  398. };
  399. //==============================================================================
  400. class LookAndFeelDemo : public Component,
  401. private ComboBox::Listener,
  402. private Button::Listener
  403. {
  404. public:
  405. LookAndFeelDemo()
  406. {
  407. descriptionLabel.setMinimumHorizontalScale (1.0f);
  408. descriptionLabel.setText ("This demonstrates how to create a custom look and feel by overriding only the desired methods.\n\n"
  409. "Components can have their look and feel individually assigned or they will inherit it from their parent. "
  410. "Colours work in a similar way, they can be set for individual components or a look and feel as a whole.",
  411. dontSendNotification);
  412. addAndMakeVisible (descriptionLabel);
  413. addAndMakeVisible (lafBox);
  414. addAndMakeVisible (demoComp);
  415. addLookAndFeel (new LookAndFeel_V1(), "LookAndFeel_V1");
  416. addLookAndFeel (new LookAndFeel_V2(), "LookAndFeel_V2");
  417. addLookAndFeel (new LookAndFeel_V3(), "LookAndFeel_V3");
  418. addLookAndFeel (new LookAndFeel_V4(), "LookAndFeel_V4 (Dark)");
  419. addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getMidnightColourScheme()), "LookAndFeel_V4 (Midnight)");
  420. addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getGreyColourScheme()), "LookAndFeel_V4 (Grey)");
  421. addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getLightColourScheme()), "LookAndFeel_V4 (Light)");
  422. CustomLookAndFeel* claf = new CustomLookAndFeel();
  423. addLookAndFeel (claf, "Custom Look And Feel");
  424. setupCustomLookAndFeelColours (*claf);
  425. SquareLookAndFeel* slaf = new SquareLookAndFeel();
  426. addLookAndFeel (slaf, "Square Look And Feel");
  427. setupSquareLookAndFeelColours (*slaf);
  428. lafBox.addListener (this);
  429. lafBox.setSelectedItemIndex (3);
  430. addAndMakeVisible (randomButton);
  431. randomButton.setButtonText ("Assign Randomly");
  432. randomButton.addListener (this);
  433. }
  434. void paint (Graphics& g) override
  435. {
  436. g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
  437. Colour::greyLevel (0.4f)));
  438. }
  439. void resized() override
  440. {
  441. Rectangle<int> r (getLocalBounds().reduced (10));
  442. demoComp.setBounds (r);
  443. descriptionLabel.setBounds (r.removeFromTop (200));
  444. lafBox.setBounds (r.removeFromTop (22).removeFromLeft (250));
  445. randomButton.setBounds (lafBox.getBounds().withX (lafBox.getRight() + 20).withWidth (140));
  446. demoComp.setBounds (r.withTrimmedTop (10));
  447. }
  448. private:
  449. Label descriptionLabel;
  450. ComboBox lafBox;
  451. TextButton randomButton;
  452. OwnedArray<LookAndFeel> lookAndFeels;
  453. LookAndFeelDemoComponent demoComp;
  454. void addLookAndFeel (LookAndFeel* laf, const String& name)
  455. {
  456. lookAndFeels.add (laf);
  457. lafBox.addItem (name, lafBox.getNumItems() + 1);
  458. }
  459. void setupCustomLookAndFeelColours (LookAndFeel& laf)
  460. {
  461. laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f));
  462. laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite);
  463. laf.setColour (Slider::rotarySliderFillColourId, Colour (0xff00b5f6));
  464. laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white);
  465. laf.setColour (TextButton::buttonColourId, Colours::white);
  466. laf.setColour (TextButton::textColourOffId, Colour (0xff00b5f6));
  467. laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId));
  468. laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId));
  469. }
  470. void setupSquareLookAndFeelColours (LookAndFeel& laf)
  471. {
  472. const Colour baseColour (Colours::red);
  473. laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f));
  474. laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite);
  475. laf.setColour (Slider::rotarySliderFillColourId, baseColour);
  476. laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white);
  477. laf.setColour (Slider::trackColourId, Colours::black);
  478. laf.setColour (TextButton::buttonColourId, Colours::white);
  479. laf.setColour (TextButton::textColourOffId, baseColour);
  480. laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId));
  481. laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId));
  482. }
  483. void setAllLookAndFeels (LookAndFeel* laf)
  484. {
  485. for (int i = 0; i < demoComp.getNumChildComponents(); ++i)
  486. if (Component* c = demoComp.getChildComponent (i))
  487. c->setLookAndFeel (laf);
  488. }
  489. void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override
  490. {
  491. if (comboBoxThatHasChanged == &lafBox)
  492. setAllLookAndFeels (lookAndFeels[lafBox.getSelectedItemIndex()]);
  493. }
  494. void buttonClicked (Button* b) override
  495. {
  496. if (b == &randomButton)
  497. lafBox.setSelectedItemIndex (Random::getSystemRandom().nextInt (lafBox.getNumItems()));
  498. }
  499. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeelDemo)
  500. };
  501. // This static object will register this demo type in a global list of demos..
  502. static JuceDemoType<LookAndFeelDemo> demo ("10 Components: Look And Feel");