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.

635 lines
26KB

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