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.

247 lines
8.0KB

  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. /** Simple message that holds a Colour. */
  22. struct ColourMessage : public Message
  23. {
  24. ColourMessage (Colour col) : colour (col)
  25. {
  26. }
  27. /** Returns the colour of a ColourMessage of white if the message is not a ColourMessage. */
  28. static Colour getColour (const Message& message)
  29. {
  30. if (auto* cm = dynamic_cast<const ColourMessage*> (&message))
  31. return cm->colour;
  32. return Colours::white;
  33. }
  34. Colour colour;
  35. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourMessage)
  36. };
  37. //==============================================================================
  38. /** Simple component that can be triggered to flash.
  39. The flash will then fade using a Timer to repaint itself and will send a change
  40. message once it is finished.
  41. */
  42. class FlashingComponent : public Component,
  43. public MessageListener,
  44. public ChangeBroadcaster,
  45. private Timer
  46. {
  47. public:
  48. FlashingComponent()
  49. {
  50. }
  51. void startFlashing()
  52. {
  53. flashAlpha = 1.0f;
  54. startTimerHz (25);
  55. }
  56. /** Stops this component flashing without sending a change message. */
  57. void stopFlashing()
  58. {
  59. flashAlpha = 0.0f;
  60. stopTimer();
  61. repaint();
  62. }
  63. /** Sets the colour of the component. */
  64. void setFlashColour (const Colour newColour)
  65. {
  66. colour = newColour;
  67. repaint();
  68. }
  69. /** Draws our component. */
  70. void paint (Graphics& g) override
  71. {
  72. g.setColour (colour.overlaidWith (Colours::white.withAlpha (flashAlpha)));
  73. g.fillEllipse (getLocalBounds().toFloat());
  74. }
  75. /** Custom mouse handler to trigger a flash. */
  76. void mouseDown (const MouseEvent&) override
  77. {
  78. startFlashing();
  79. }
  80. /** Message listener callback used to change our colour */
  81. void handleMessage (const Message& message) override
  82. {
  83. setFlashColour (ColourMessage::getColour (message));
  84. }
  85. private:
  86. float flashAlpha = 0;
  87. Colour colour { Colours::red };
  88. void timerCallback() override
  89. {
  90. // Reduce the alpha level of the flash slightly so it fades out
  91. flashAlpha -= 0.075f;
  92. if (flashAlpha < 0.05f)
  93. {
  94. stopFlashing();
  95. sendChangeMessage();
  96. // Once we've finsihed flashing send a change message to trigger the next component to flash
  97. }
  98. repaint();
  99. }
  100. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlashingComponent)
  101. };
  102. //==============================================================================
  103. class TimersAndEventsDemo : public Component,
  104. private ChangeListener
  105. {
  106. public:
  107. TimersAndEventsDemo()
  108. {
  109. setOpaque (true);
  110. // Create and add our FlashingComponents with some random colours and sizes
  111. for (int i = 0; i < numFlashingComponents; ++i)
  112. {
  113. auto* newFlasher = new FlashingComponent();
  114. flashingComponents.add (newFlasher);
  115. newFlasher->setFlashColour (getRandomBrightColour());
  116. newFlasher->addChangeListener (this);
  117. const int diameter = 25 + random.nextInt (75);
  118. newFlasher->setSize (diameter, diameter);
  119. addAndMakeVisible (newFlasher);
  120. }
  121. addAndMakeVisible (stopButton);
  122. stopButton.setButtonText ("Stop");
  123. stopButton.onClick = [this] { stopButtonClicked(); };
  124. addAndMakeVisible (randomColourButton);
  125. randomColourButton.setButtonText ("Set Random Colour");
  126. randomColourButton.onClick = [this] { randomColourButtonClicked(); };
  127. // lay out our components in a psudo random grid
  128. Rectangle<int> area (0, 100, 150, 150);
  129. for (auto* comp : flashingComponents)
  130. {
  131. auto buttonArea = area.withSize (comp->getWidth(), comp->getHeight());
  132. buttonArea.translate (random.nextInt (area.getWidth() - comp->getWidth()),
  133. random.nextInt (area.getHeight() - comp->getHeight()));
  134. comp->setBounds (buttonArea);
  135. area.translate (area.getWidth(), 0);
  136. // if we go off the right start a new row
  137. if (area.getRight() > (800 - area.getWidth()))
  138. {
  139. area.translate (0, area.getWidth());
  140. area.setX (0);
  141. }
  142. }
  143. }
  144. ~TimersAndEventsDemo()
  145. {
  146. for (auto* fc : flashingComponents)
  147. fc->removeChangeListener (this);
  148. }
  149. void paint (Graphics& g) override
  150. {
  151. g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
  152. Colours::darkgrey));
  153. }
  154. void paintOverChildren (Graphics& g) override
  155. {
  156. auto explanationArea = getLocalBounds().removeFromTop (100);
  157. AttributedString s;
  158. s.append ("Click on a circle to make it flash. When it has finished flashing it will send a message which causes the next circle to flash");
  159. s.append (newLine);
  160. s.append ("Click the \"Set Random Colour\" button to change the colour of one of the circles.");
  161. s.append (newLine);
  162. s.setFont (Font (16.0f));
  163. s.setColour (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::defaultText, Colours::lightgrey));
  164. s.draw (g, explanationArea.reduced (10).toFloat());
  165. }
  166. void resized() override
  167. {
  168. auto area = getLocalBounds().removeFromBottom (40);
  169. randomColourButton.setBounds (area.removeFromLeft (166).reduced (8));
  170. stopButton.setBounds (area.removeFromRight (166).reduced (8));
  171. }
  172. private:
  173. enum { numFlashingComponents = 9 };
  174. OwnedArray<FlashingComponent> flashingComponents;
  175. TextButton randomColourButton, stopButton;
  176. Random random;
  177. void changeListenerCallback (ChangeBroadcaster* source) override
  178. {
  179. for (int i = 0; i < flashingComponents.size(); ++i)
  180. if (source == flashingComponents.getUnchecked (i))
  181. flashingComponents.getUnchecked ((i + 1) % flashingComponents.size())->startFlashing();
  182. }
  183. void randomColourButtonClicked()
  184. {
  185. // Here we post a new ColourMessage with a random colour to a random flashing component.
  186. // This will send a message to the component asynchronously and trigger its handleMessage callback
  187. flashingComponents.getUnchecked (random.nextInt (flashingComponents.size()))->postMessage (new ColourMessage (getRandomBrightColour()));
  188. }
  189. void stopButtonClicked()
  190. {
  191. for (auto* fc : flashingComponents)
  192. fc->stopFlashing();
  193. }
  194. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimersAndEventsDemo)
  195. };
  196. // This static object will register this demo type in a global list of demos..
  197. static JuceDemoType<TimersAndEventsDemo> demo ("40 Timers & Events");