/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-12 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../JuceDemoHeader.h" //============================================================================== /** This will be the source of our balls and can be dragged around. */ class BallGeneratorComponent : public Component { public: BallGeneratorComponent() { } void paint (Graphics& g) override { Rectangle area (getLocalBounds().toFloat().reduced (2.0f)); g.setColour (Colours::orange.withAlpha (0.6f)); g.fillRoundedRectangle (area, 10.0f); g.setColour (Colours::darkgrey); g.drawRoundedRectangle (area, 10.0f, 2.0f); AttributedString s; s.setJustification (Justification::centred); s.setWordWrap (AttributedString::none); s.append ("Balls!\n" "(Drag Me)"); s.setColour (Colours::black); s.draw (g, area); } void resized() override { // Just set the limits of our constrainer so that we don't drag ourselves off the screen constrainer.setMinimumOnscreenAmounts (getHeight(), getWidth(), getHeight(), getWidth()); } void mouseDown (const MouseEvent& e) override { // Prepares our dragger to drag this Component dragger.startDraggingComponent (this, e); } void mouseDrag (const MouseEvent& e) override { // Moves this Component according to the mouse drag event and applies our constraints to it dragger.dragComponent (this, e, &constrainer); } private: ComponentBoundsConstrainer constrainer; ComponentDragger dragger; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BallGeneratorComponent) }; //============================================================================== struct BallComponent : public Component { BallComponent (const Point& pos) : position (pos), speed (Random::getSystemRandom().nextFloat() * 4.0f - 2.0f, Random::getSystemRandom().nextFloat() * -6.0f - 2.0f), colour (getRandomBrightColour().withAlpha (0.4f)) { setSize (20, 20); step(); } bool step() { position += speed; speed.y += 0.05f; setCentrePosition ((int) position.x, (int) position.y); if (Component* parent = getParentComponent()) return isPositiveAndBelow (position.x, (float) parent->getWidth()) && position.y < (float) parent->getHeight(); return position.y < 400.0f && position.x >= -10.0f; } void paint (Graphics& g) { g.setColour (colour); g.fillEllipse (2.0f, 2.0f, getWidth() - 4.0f, getHeight() - 4.0f); g.setColour (Colours::darkgrey); g.drawEllipse (2.0f, 2.0f, getWidth() - 4.0f, getHeight() - 4.0f, 1.0f); } Point position, speed; Colour colour; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BallComponent) }; //============================================================================== class AnimationDemo : public Component, private Button::Listener, private Timer { public: AnimationDemo() { setOpaque (true); for (int i = 11; --i >= 0;) { Button* b = createRandomButton(); componentsToAnimate.add (b); addAndMakeVisible (b); b->addListener (this); } ballGenerator = new BallGeneratorComponent(); componentsToAnimate.add (ballGenerator); addAndMakeVisible (ballGenerator); ballGenerator->setBounds (200, 500, 70, 50); int w = 160, h = 80; for (int i = 0; i < componentsToAnimate.size(); ++i) { Rectangle r (w * (i % 3), h * (i / 3), w, h); componentsToAnimate.getUnchecked(i)->setBounds (r.reduced (10)); } startTimer (1000 / 60); } void paint (Graphics& g) override { fillBrushedAluminiumBackground (g); } private: OwnedArray componentsToAnimate; OwnedArray balls; BallGeneratorComponent* ballGenerator; ComponentAnimator animator; Button* createRandomButton() { DrawablePath normal, over; Path star1; star1.addStar (Point(), 5, 20.0f, 50.0f, 0.2f); normal.setPath (star1); normal.setFill (Colours::red); Path star2; star2.addStar (Point(), 7, 30.0f, 50.0f, 0.0f); over.setPath (star2); over.setFill (Colours::pink); over.setStrokeFill (Colours::black); over.setStrokeThickness (5.0f); DrawableImage down; down.setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize)); down.setOverlayColour (Colours::black.withAlpha (0.3f)); if (Random::getSystemRandom().nextInt (10) > 2) { int type = Random::getSystemRandom().nextInt (3); DrawableButton* d = new DrawableButton ("Button", type == 0 ? DrawableButton::ImageOnButtonBackground : (type == 1 ? DrawableButton::ImageFitted : DrawableButton::ImageAboveTextLabel)); d->setImages (&normal, Random::getSystemRandom().nextBool() ? &over : nullptr, Random::getSystemRandom().nextBool() ? &down : nullptr); if (Random::getSystemRandom().nextBool()) { d->setColour (DrawableButton::backgroundColourId, getRandomBrightColour()); d->setColour (DrawableButton::backgroundOnColourId, getRandomBrightColour()); } d->setClickingTogglesState (Random::getSystemRandom().nextBool()); return d; } ImageButton* b = new ImageButton ("ImageButton"); Image image = ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize); b->setImages (true, true, true, image, 0.7f, Colours::transparentBlack, image, 1.0f, getRandomDarkColour().withAlpha (0.2f), image, 1.0f, getRandomBrightColour().withAlpha (0.8f), 0.5f); return b; } void buttonClicked (Button*) override { for (int i = 0; i < componentsToAnimate.size(); ++i) componentsToAnimate.swap (i, Random::getSystemRandom().nextInt (componentsToAnimate.size())); int w = 160, h = 80; for (int i = 0; i < componentsToAnimate.size(); ++i) { Rectangle r (w * (i % 3), h * (i / 3), w, h); animator.animateComponent (componentsToAnimate.getUnchecked(i), r.reduced (10), Random::getSystemRandom().nextBool() ? 1.0f : 0.4f, 500 + Random::getSystemRandom().nextInt (2000), false, Random::getSystemRandom().nextDouble(), Random::getSystemRandom().nextDouble()); } } void timerCallback() override { // Go through each of our balls and update their position for (int i = balls.size(); --i >= 0;) if (! balls.getUnchecked(i)->step()) balls.remove (i); // Randomly generate new balls if (Random::getSystemRandom().nextInt (200) < 4) { BallComponent* ball = new BallComponent (ballGenerator->getBounds().getCentre().toFloat()); addAndMakeVisible (ball); balls.add (ball); } } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimationDemo) }; // This static object will register this demo type in a global list of demos.. static JuceDemoType demo ("10 Components: Animation");