1 /* 2 ============================================================================== 3 4 This file is part of the JUCE examples. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 The code included in this file is provided under the terms of the ISC license 8 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 9 To use, copy, modify, and/or distribute this software for any purpose with or 10 without fee is hereby granted provided that the above copyright notice and 11 this permission notice appear in all copies. 12 13 THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, 14 WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 15 PURPOSE, ARE DISCLAIMED. 16 17 ============================================================================== 18 */ 19 20 /******************************************************************************* 21 The block below describes the properties of this PIP. A PIP is a short snippet 22 of code that can be read by the Projucer and used to generate a JUCE project. 23 24 BEGIN_JUCE_PIP_METADATA 25 26 name: LookAndFeelDemo 27 version: 1.0.0 28 vendor: JUCE 29 website: http://juce.com 30 description: Showcases custom look and feel components. 31 32 dependencies: juce_core, juce_data_structures, juce_events, juce_graphics, 33 juce_gui_basics 34 exporters: xcode_mac, vs2019, linux_make, androidstudio, xcode_iphone 35 36 moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1 37 38 type: Component 39 mainClass: LookAndFeelDemo 40 41 useLocalCopy: 1 42 43 END_JUCE_PIP_METADATA 44 45 *******************************************************************************/ 46 47 #pragma once 48 49 #include "../Assets/DemoUtilities.h" 50 51 //============================================================================== 52 /** Custom Look And Feel subclasss. 53 54 Simply override the methods you need to, anything else will be inherited from the base class. 55 It's a good idea not to hard code your colours, use the findColour method along with appropriate 56 ColourIds so you can set these on a per-component basis. 57 */ 58 struct CustomLookAndFeel : public LookAndFeel_V4 59 { drawRoundThumbCustomLookAndFeel60 void drawRoundThumb (Graphics& g, float x, float y, float diameter, Colour colour, float outlineThickness) 61 { 62 auto halfThickness = outlineThickness * 0.5f; 63 64 Path p; 65 p.addEllipse (x + halfThickness, 66 y + halfThickness, 67 diameter - outlineThickness, 68 diameter - outlineThickness); 69 70 DropShadow (Colours::black, 1, {}).drawForPath (g, p); 71 72 g.setColour (colour); 73 g.fillPath (p); 74 75 g.setColour (colour.brighter()); 76 g.strokePath (p, PathStrokeType (outlineThickness)); 77 } 78 drawButtonBackgroundCustomLookAndFeel79 void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, 80 bool isMouseOverButton, bool isButtonDown) override 81 { 82 auto baseColour = backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f) 83 .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f); 84 85 if (isButtonDown || isMouseOverButton) 86 baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f); 87 88 auto flatOnLeft = button.isConnectedOnLeft(); 89 auto flatOnRight = button.isConnectedOnRight(); 90 auto flatOnTop = button.isConnectedOnTop(); 91 auto flatOnBottom = button.isConnectedOnBottom(); 92 93 auto width = (float) button.getWidth() - 1.0f; 94 auto height = (float) button.getHeight() - 1.0f; 95 96 if (width > 0 && height > 0) 97 { 98 auto cornerSize = jmin (15.0f, jmin (width, height) * 0.45f); 99 auto lineThickness = cornerSize * 0.1f; 100 auto halfThickness = lineThickness * 0.5f; 101 102 Path outline; 103 outline.addRoundedRectangle (0.5f + halfThickness, 0.5f + halfThickness, width - lineThickness, height - lineThickness, 104 cornerSize, cornerSize, 105 ! (flatOnLeft || flatOnTop), 106 ! (flatOnRight || flatOnTop), 107 ! (flatOnLeft || flatOnBottom), 108 ! (flatOnRight || flatOnBottom)); 109 110 auto outlineColour = button.findColour (button.getToggleState() ? TextButton::textColourOnId 111 : TextButton::textColourOffId); 112 113 g.setColour (baseColour); 114 g.fillPath (outline); 115 116 if (! button.getToggleState()) 117 { 118 g.setColour (outlineColour); 119 g.strokePath (outline, PathStrokeType (lineThickness)); 120 } 121 } 122 } 123 drawTickBoxCustomLookAndFeel124 void drawTickBox (Graphics& g, Component& component, 125 float x, float y, float w, float h, 126 bool ticked, 127 bool isEnabled, 128 bool isMouseOverButton, 129 bool isButtonDown) override 130 { 131 auto boxSize = w * 0.7f; 132 133 auto isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown()); 134 135 auto colour = component.findColour (TextButton::buttonColourId) 136 .withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f) 137 .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f); 138 139 drawRoundThumb (g, x, y + (h - boxSize) * 0.5f, boxSize, colour, 140 isEnabled ? ((isButtonDown || isMouseOverButton) ? 1.1f : 0.5f) : 0.3f); 141 142 if (ticked) 143 { 144 g.setColour (isEnabled ? findColour (TextButton::buttonOnColourId) : Colours::grey); 145 146 auto scale = 9.0f; 147 auto trans = AffineTransform::scale (w / scale, h / scale).translated (x - 2.5f, y + 1.0f); 148 149 g.fillPath (LookAndFeel_V4::getTickShape (6.0f), trans); 150 } 151 } 152 drawLinearSliderThumbCustomLookAndFeel153 void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height, 154 float sliderPos, float minSliderPos, float maxSliderPos, 155 const Slider::SliderStyle style, Slider& slider) override 156 { 157 auto sliderRadius = (float) (getSliderThumbRadius (slider) - 2); 158 159 auto isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown()); 160 161 auto knobColour = slider.findColour (Slider::thumbColourId) 162 .withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f) 163 .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f); 164 165 if (style == Slider::LinearHorizontal || style == Slider::LinearVertical) 166 { 167 float kx, ky; 168 169 if (style == Slider::LinearVertical) 170 { 171 kx = (float) x + (float) width * 0.5f; 172 ky = sliderPos; 173 } 174 else 175 { 176 kx = sliderPos; 177 ky = (float) y + (float) height * 0.5f; 178 } 179 180 auto outlineThickness = slider.isEnabled() ? 0.8f : 0.3f; 181 182 drawRoundThumb (g, 183 kx - sliderRadius, 184 ky - sliderRadius, 185 sliderRadius * 2.0f, 186 knobColour, outlineThickness); 187 } 188 else 189 { 190 // Just call the base class for the demo 191 LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider); 192 } 193 } 194 drawLinearSliderCustomLookAndFeel195 void drawLinearSlider (Graphics& g, int x, int y, int width, int height, 196 float sliderPos, float minSliderPos, float maxSliderPos, 197 const Slider::SliderStyle style, Slider& slider) override 198 { 199 g.fillAll (slider.findColour (Slider::backgroundColourId)); 200 201 if (style == Slider::LinearBar || style == Slider::LinearBarVertical) 202 { 203 Path p; 204 205 if (style == Slider::LinearBarVertical) 206 p.addRectangle ((float) x, sliderPos, (float) width, 1.0f + (float) height - sliderPos); 207 else 208 p.addRectangle ((float) x, (float) y, sliderPos - (float) x, (float) height); 209 210 auto baseColour = slider.findColour (Slider::rotarySliderFillColourId) 211 .withMultipliedSaturation (slider.isEnabled() ? 1.0f : 0.5f) 212 .withMultipliedAlpha (0.8f); 213 214 g.setColour (baseColour); 215 g.fillPath (p); 216 217 auto lineThickness = jmin (15.0f, (float) jmin (width, height) * 0.45f) * 0.1f; 218 g.drawRect (slider.getLocalBounds().toFloat(), lineThickness); 219 } 220 else 221 { 222 drawLinearSliderBackground (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider); 223 drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider); 224 } 225 } 226 drawLinearSliderBackgroundCustomLookAndFeel227 void drawLinearSliderBackground (Graphics& g, int x, int y, int width, int height, 228 float /*sliderPos*/, 229 float /*minSliderPos*/, 230 float /*maxSliderPos*/, 231 const Slider::SliderStyle /*style*/, Slider& slider) override 232 { 233 auto sliderRadius = (float) getSliderThumbRadius (slider) - 5.0f; 234 Path on, off; 235 236 if (slider.isHorizontal()) 237 { 238 auto iy = (float) y + (float) height * 0.5f - sliderRadius * 0.5f; 239 Rectangle<float> r ((float) x - sliderRadius * 0.5f, iy, (float) width + sliderRadius, sliderRadius); 240 auto onW = r.getWidth() * ((float) slider.valueToProportionOfLength (slider.getValue())); 241 242 on.addRectangle (r.removeFromLeft (onW)); 243 off.addRectangle (r); 244 } 245 else 246 { 247 auto ix = (float) x + (float) width * 0.5f - sliderRadius * 0.5f; 248 Rectangle<float> r (ix, (float) y - sliderRadius * 0.5f, sliderRadius, (float) height + sliderRadius); 249 auto onH = r.getHeight() * ((float) slider.valueToProportionOfLength (slider.getValue())); 250 251 on.addRectangle (r.removeFromBottom (onH)); 252 off.addRectangle (r); 253 } 254 255 g.setColour (slider.findColour (Slider::rotarySliderFillColourId)); 256 g.fillPath (on); 257 258 g.setColour (slider.findColour (Slider::trackColourId)); 259 g.fillPath (off); 260 } 261 drawRotarySliderCustomLookAndFeel262 void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos, 263 float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override 264 { 265 auto radius = (float) jmin (width / 2, height / 2) - 2.0f; 266 auto centreX = (float) x + (float) width * 0.5f; 267 auto centreY = (float) y + (float) height * 0.5f; 268 auto rx = centreX - radius; 269 auto ry = centreY - radius; 270 auto rw = radius * 2.0f; 271 auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); 272 auto isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled(); 273 274 if (slider.isEnabled()) 275 g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f)); 276 else 277 g.setColour (Colour (0x80808080)); 278 279 { 280 Path filledArc; 281 filledArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, angle, 0.0); 282 g.fillPath (filledArc); 283 } 284 285 { 286 auto lineThickness = jmin (15.0f, (float) jmin (width, height) * 0.45f) * 0.1f; 287 Path outlineArc; 288 outlineArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, 0.0); 289 g.strokePath (outlineArc, PathStrokeType (lineThickness)); 290 } 291 } 292 }; 293 294 //============================================================================== 295 /** Another really simple look and feel that is very flat and square. 296 297 This inherits from CustomLookAndFeel above for the linear bar and slider backgrounds. 298 */ 299 struct SquareLookAndFeel : public CustomLookAndFeel 300 { drawButtonBackgroundSquareLookAndFeel301 void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, 302 bool isMouseOverButton, bool isButtonDown) override 303 { 304 auto baseColour = backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f) 305 .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f); 306 307 if (isButtonDown || isMouseOverButton) 308 baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f); 309 310 auto width = (float) button.getWidth() - 1.0f; 311 auto height = (float) button.getHeight() - 1.0f; 312 313 if (width > 0 && height > 0) 314 { 315 g.setGradientFill (ColourGradient::vertical (baseColour, 0.0f, 316 baseColour.darker (0.1f), height)); 317 318 g.fillRect (button.getLocalBounds()); 319 } 320 } 321 drawTickBoxSquareLookAndFeel322 void drawTickBox (Graphics& g, Component& component, 323 float x, float y, float w, float h, 324 bool ticked, 325 bool isEnabled, 326 bool /*isMouseOverButton*/, 327 bool /*isButtonDown*/) override 328 { 329 auto boxSize = w * 0.7f; 330 331 auto isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown()); 332 333 auto colour = component.findColour (TextButton::buttonOnColourId) 334 .withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f) 335 .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f); 336 337 g.setColour (colour); 338 339 Rectangle<float> r (x, y + (h - boxSize) * 0.5f, boxSize, boxSize); 340 g.fillRect (r); 341 342 if (ticked) 343 { 344 auto tickPath = LookAndFeel_V4::getTickShape (6.0f); 345 g.setColour (isEnabled ? findColour (TextButton::buttonColourId) : Colours::grey); 346 347 auto transform = RectanglePlacement (RectanglePlacement::centred) 348 .getTransformToFit (tickPath.getBounds(), 349 r.reduced (r.getHeight() * 0.05f)); 350 351 g.fillPath (tickPath, transform); 352 } 353 } 354 drawLinearSliderThumbSquareLookAndFeel355 void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height, 356 float sliderPos, float minSliderPos, float maxSliderPos, 357 const Slider::SliderStyle style, Slider& slider) override 358 { 359 auto sliderRadius = (float) getSliderThumbRadius (slider); 360 361 bool isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown()); 362 363 auto knobColour = slider.findColour (Slider::rotarySliderFillColourId) 364 .withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f) 365 .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f); 366 367 g.setColour (knobColour); 368 369 if (style == Slider::LinearHorizontal || style == Slider::LinearVertical) 370 { 371 float kx, ky; 372 373 if (style == Slider::LinearVertical) 374 { 375 kx = (float) x + (float) width * 0.5f; 376 ky = sliderPos; 377 g.fillRect (Rectangle<float> (kx - sliderRadius, ky - 2.5f, sliderRadius * 2.0f, 5.0f)); 378 } 379 else 380 { 381 kx = sliderPos; 382 ky = (float) y + (float) height * 0.5f; 383 g.fillRect (Rectangle<float> (kx - 2.5f, ky - sliderRadius, 5.0f, sliderRadius * 2.0f)); 384 } 385 } 386 else 387 { 388 // Just call the base class for the demo 389 LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider); 390 } 391 } 392 drawRotarySliderSquareLookAndFeel393 void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos, 394 float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override 395 { 396 auto diameter = (float) jmin (width, height) - 4.0f; 397 auto radius = (diameter / 2.0f) * std::cos (MathConstants<float>::pi / 4.0f); 398 auto centreX = (float) x + (float) width * 0.5f; 399 auto centreY = (float) y + (float) height * 0.5f; 400 auto rx = centreX - radius; 401 auto ry = centreY - radius; 402 auto rw = radius * 2.0f; 403 auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); 404 bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled(); 405 406 auto baseColour = slider.isEnabled() ? slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 0.8f : 1.0f) 407 : Colour (0x80808080); 408 409 Rectangle<float> r (rx, ry, rw, rw); 410 auto transform = AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY()); 411 412 auto x1 = r.getTopLeft() .getX(); 413 auto y1 = r.getTopLeft() .getY(); 414 auto x2 = r.getBottomLeft().getX(); 415 auto y2 = r.getBottomLeft().getY(); 416 417 transform.transformPoints (x1, y1, x2, y2); 418 419 g.setGradientFill (ColourGradient (baseColour, x1, y1, 420 baseColour.darker (0.1f), x2, y2, 421 false)); 422 423 Path knob; 424 knob.addRectangle (r); 425 g.fillPath (knob, transform); 426 427 Path needle; 428 auto r2 = r * 0.1f; 429 needle.addRectangle (r2.withPosition ({ r.getCentreX() - (r2.getWidth() / 2.0f), r.getY() })); 430 431 g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId)); 432 g.fillPath (needle, AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY())); 433 } 434 }; 435 436 //============================================================================== 437 struct LookAndFeelDemoComponent : public Component 438 { LookAndFeelDemoComponentLookAndFeelDemoComponent439 LookAndFeelDemoComponent() 440 { 441 addAndMakeVisible (rotarySlider); 442 rotarySlider.setValue (2.5); 443 444 addAndMakeVisible (verticalSlider); 445 verticalSlider.setValue (6.2); 446 447 addAndMakeVisible (barSlider); 448 barSlider.setValue (4.5); 449 450 addAndMakeVisible (incDecSlider); 451 incDecSlider.setRange (0.0, 10.0, 1.0); 452 incDecSlider.setIncDecButtonsMode (Slider::incDecButtonsDraggable_Horizontal); 453 454 addAndMakeVisible (button1); 455 456 addAndMakeVisible (button2); 457 button2.setClickingTogglesState (true); 458 button2.setToggleState (true, dontSendNotification); 459 460 addAndMakeVisible (button3); 461 462 addAndMakeVisible (button4); 463 button4.setToggleState (true, dontSendNotification); 464 465 for (int i = 0; i < 3; ++i) 466 { 467 auto* b = radioButtons.add (new TextButton ("Button " + String (i + 1))); 468 469 addAndMakeVisible (b); 470 b->setRadioGroupId (42); 471 b->setClickingTogglesState (true); 472 473 switch (i) 474 { 475 case 0: b->setConnectedEdges (Button::ConnectedOnRight); break; 476 case 1: b->setConnectedEdges (Button::ConnectedOnRight + Button::ConnectedOnLeft); break; 477 case 2: b->setConnectedEdges (Button::ConnectedOnLeft); break; 478 default: break; 479 } 480 } 481 482 radioButtons.getUnchecked (2)->setToggleState (true, dontSendNotification); 483 } 484 resizedLookAndFeelDemoComponent485 void resized() override 486 { 487 auto area = getLocalBounds().reduced (10); 488 auto row = area.removeFromTop (100); 489 490 rotarySlider .setBounds (row.removeFromLeft (100).reduced (5)); 491 verticalSlider.setBounds (row.removeFromLeft (100).reduced (5)); 492 barSlider .setBounds (row.removeFromLeft (100).reduced (5, 25)); 493 incDecSlider .setBounds (row.removeFromLeft (100).reduced (5, 28)); 494 495 row = area.removeFromTop (100); 496 button1.setBounds (row.removeFromLeft (100).reduced (5)); 497 498 auto row2 = row.removeFromTop (row.getHeight() / 2).reduced (0, 10); 499 button2.setBounds (row2.removeFromLeft (100).reduced (5, 0)); 500 button3.setBounds (row2.removeFromLeft (100).reduced (5, 0)); 501 button4.setBounds (row2.removeFromLeft (100).reduced (5, 0)); 502 503 row2 = (row.removeFromTop (row2.getHeight() + 20).reduced (5, 10)); 504 505 for (auto* b : radioButtons) 506 b->setBounds (row2.removeFromLeft (100)); 507 } 508 509 Slider rotarySlider { Slider::RotaryHorizontalVerticalDrag, Slider::NoTextBox}, 510 verticalSlider { Slider::LinearVertical, Slider::NoTextBox }, 511 barSlider { Slider::LinearBar, Slider::NoTextBox }, 512 incDecSlider { Slider::IncDecButtons, Slider::TextBoxBelow }; 513 514 TextButton button1 { "Hello World!" }, 515 button2 { "Hello World!" }, 516 button3 { "Hello World!" }; 517 518 ToggleButton button4 { "Toggle Me" }; 519 520 OwnedArray<TextButton> radioButtons; 521 }; 522 523 //============================================================================== 524 class LookAndFeelDemo : public Component 525 { 526 public: LookAndFeelDemo()527 LookAndFeelDemo() 528 { 529 descriptionLabel.setMinimumHorizontalScale (1.0f); 530 descriptionLabel.setText ("This demonstrates how to create a custom look and feel by overriding only the desired methods.\n\n" 531 "Components can have their look and feel individually assigned or they will inherit it from their parent. " 532 "Colours work in a similar way, they can be set for individual components or a look and feel as a whole.", 533 dontSendNotification); 534 535 addAndMakeVisible (descriptionLabel); 536 addAndMakeVisible (lafBox); 537 addAndMakeVisible (demoComp); 538 539 addLookAndFeel (new LookAndFeel_V1(), "LookAndFeel_V1"); 540 addLookAndFeel (new LookAndFeel_V2(), "LookAndFeel_V2"); 541 addLookAndFeel (new LookAndFeel_V3(), "LookAndFeel_V3"); 542 addLookAndFeel (new LookAndFeel_V4(), "LookAndFeel_V4 (Dark)"); 543 addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getMidnightColourScheme()), "LookAndFeel_V4 (Midnight)"); 544 addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getGreyColourScheme()), "LookAndFeel_V4 (Grey)"); 545 addLookAndFeel (new LookAndFeel_V4 (LookAndFeel_V4::getLightColourScheme()), "LookAndFeel_V4 (Light)"); 546 547 auto* claf = new CustomLookAndFeel(); 548 addLookAndFeel (claf, "Custom Look And Feel"); 549 setupCustomLookAndFeelColours (*claf); 550 551 auto* slaf = new SquareLookAndFeel(); 552 addLookAndFeel (slaf, "Square Look And Feel"); 553 setupSquareLookAndFeelColours (*slaf); 554 555 lafBox.onChange = [this] { setAllLookAndFeels (lookAndFeels[lafBox.getSelectedItemIndex()]); }; 556 lafBox.setSelectedItemIndex (3); 557 558 addAndMakeVisible (randomButton); 559 randomButton.onClick = [this] { lafBox.setSelectedItemIndex (Random().nextInt (lafBox.getNumItems())); }; 560 561 setSize (500, 500); 562 } 563 paint(Graphics & g)564 void paint (Graphics& g) override 565 { 566 g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground, 567 Colour::greyLevel (0.4f))); 568 } 569 resized()570 void resized() override 571 { 572 auto r = getLocalBounds().reduced (10); 573 574 descriptionLabel.setBounds (r.removeFromTop (150)); 575 lafBox .setBounds (r.removeFromTop (22).removeFromLeft (250)); 576 randomButton .setBounds (lafBox.getBounds().withX (lafBox.getRight() + 20).withWidth (140)); 577 demoComp .setBounds (r.withTrimmedTop (10)); 578 } 579 580 private: 581 Label descriptionLabel; 582 ComboBox lafBox; 583 TextButton randomButton { "Assign Randomly" }; 584 OwnedArray<LookAndFeel> lookAndFeels; 585 LookAndFeelDemoComponent demoComp; 586 addLookAndFeel(LookAndFeel * laf,const String & name)587 void addLookAndFeel (LookAndFeel* laf, const String& name) 588 { 589 lookAndFeels.add (laf); 590 lafBox.addItem (name, lafBox.getNumItems() + 1); 591 } 592 setupCustomLookAndFeelColours(LookAndFeel & laf)593 void setupCustomLookAndFeelColours (LookAndFeel& laf) 594 { 595 laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f)); 596 laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite); 597 laf.setColour (Slider::rotarySliderFillColourId, Colour (0xff00b5f6)); 598 laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white); 599 600 laf.setColour (TextButton::buttonColourId, Colours::white); 601 laf.setColour (TextButton::textColourOffId, Colour (0xff00b5f6)); 602 603 laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId)); 604 laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId)); 605 } 606 setupSquareLookAndFeelColours(LookAndFeel & laf)607 void setupSquareLookAndFeelColours (LookAndFeel& laf) 608 { 609 auto baseColour = Colours::red; 610 611 laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f)); 612 laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite); 613 laf.setColour (Slider::rotarySliderFillColourId, baseColour); 614 laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white); 615 laf.setColour (Slider::trackColourId, Colours::black); 616 617 laf.setColour (TextButton::buttonColourId, Colours::white); 618 laf.setColour (TextButton::textColourOffId, baseColour); 619 620 laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId)); 621 laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId)); 622 } 623 setAllLookAndFeels(LookAndFeel * laf)624 void setAllLookAndFeels (LookAndFeel* laf) 625 { 626 for (auto* child : demoComp.getChildren()) 627 child->setLookAndFeel (laf); 628 } 629 630 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeelDemo) 631 }; 632