1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-13 00:04:19 +00:00

Added Animated App template and examples

This commit is contained in:
Felix Faire 2014-10-29 15:55:23 +00:00
parent fefcf7aca6
commit ff6520a89a
1141 changed files with 438491 additions and 94 deletions

View file

@ -0,0 +1,142 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found 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.juce.com for more information.
==============================================================================
*/
BubbleComponent::BubbleComponent()
: allowablePlacements (above | below | left | right)
{
setInterceptsMouseClicks (false, false);
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.35f), 5, Point<int>()));
setComponentEffect (&shadow);
}
BubbleComponent::~BubbleComponent() {}
//==============================================================================
void BubbleComponent::paint (Graphics& g)
{
getLookAndFeel().drawBubble (g, *this, arrowTip.toFloat(), content.toFloat());
g.reduceClipRegion (content);
g.setOrigin (content.getPosition());
paintContent (g, content.getWidth(), content.getHeight());
}
void BubbleComponent::setAllowedPlacement (const int newPlacement)
{
allowablePlacements = newPlacement;
}
void BubbleComponent::setPosition (Component* componentToPointTo)
{
jassert (componentToPointTo != nullptr);
if (Component* p = getParentComponent())
setPosition (p->getLocalArea (componentToPointTo, componentToPointTo->getLocalBounds()));
else
setPosition (componentToPointTo->getScreenBounds());
}
void BubbleComponent::setPosition (Point<int> pos)
{
setPosition (Rectangle<int> (pos.x, pos.y, 1, 1));
}
//==============================================================================
void BubbleComponent::setPosition (const Rectangle<int>& rectangleToPointTo)
{
const int edgeSpace = 15;
const int arrowLength = 10;
{
int contentW = 150, contentH = 30;
getContentSize (contentW, contentH);
content.setBounds (edgeSpace, edgeSpace, contentW, contentH);
}
const int totalW = content.getWidth() + edgeSpace * 2;
const int totalH = content.getHeight() + edgeSpace * 2;
const Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
: getParentMonitorArea());
int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY() - availableSpace.getY()) : -1;
int spaceBelow = ((allowablePlacements & below) != 0) ? jmax (0, availableSpace.getBottom() - rectangleToPointTo.getBottom()) : -1;
int spaceLeft = ((allowablePlacements & left) != 0) ? jmax (0, rectangleToPointTo.getX() - availableSpace.getX()) : -1;
int spaceRight = ((allowablePlacements & right) != 0) ? jmax (0, availableSpace.getRight() - rectangleToPointTo.getRight()) : -1;
// look at whether the component is elongated, and if so, try to position next to its longer dimension.
if (rectangleToPointTo.getWidth() > rectangleToPointTo.getHeight() * 2
&& (spaceAbove > totalH + 20 || spaceBelow > totalH + 20))
{
spaceLeft = spaceRight = 0;
}
else if (rectangleToPointTo.getWidth() < rectangleToPointTo.getHeight() / 2
&& (spaceLeft > totalW + 20 || spaceRight > totalW + 20))
{
spaceAbove = spaceBelow = 0;
}
int targetX, targetY;
if (jmax (spaceAbove, spaceBelow) >= jmax (spaceLeft, spaceRight))
{
targetX = rectangleToPointTo.getCentre().x;
arrowTip.x = totalW / 2;
if (spaceAbove >= spaceBelow)
{
// above
targetY = rectangleToPointTo.getY();
arrowTip.y = content.getBottom() + arrowLength;
}
else
{
// below
targetY = rectangleToPointTo.getBottom();
arrowTip.y = content.getY() - arrowLength;
}
}
else
{
targetY = rectangleToPointTo.getCentre().y;
arrowTip.y = totalH / 2;
if (spaceLeft > spaceRight)
{
// on the left
targetX = rectangleToPointTo.getX();
arrowTip.x = content.getRight() + arrowLength;
}
else
{
// on the right
targetX = rectangleToPointTo.getRight();
arrowTip.x = content.getX() - arrowLength;
}
}
setBounds (targetX - arrowTip.x, targetY - arrowTip.y, totalW, totalH);
}

View file

@ -0,0 +1,180 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found 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.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_BUBBLECOMPONENT_H_INCLUDED
#define JUCE_BUBBLECOMPONENT_H_INCLUDED
//==============================================================================
/**
A component for showing a message or other graphics inside a speech-bubble-shaped
outline, pointing at a location on the screen.
This is a base class that just draws and positions the bubble shape, but leaves
the drawing of any content up to a subclass. See BubbleMessageComponent for a subclass
that draws a text message.
To use it, create your subclass, then either add it to a parent component or
put it on the desktop with addToDesktop (0), use setPosition() to
resize and position it, then make it visible.
@see BubbleMessageComponent
*/
class JUCE_API BubbleComponent : public Component
{
protected:
//==============================================================================
/** Creates a BubbleComponent.
Your subclass will need to implement the getContentSize() and paintContent()
methods to draw the bubble's contents.
*/
BubbleComponent();
public:
/** Destructor. */
~BubbleComponent();
//==============================================================================
/** A list of permitted placements for the bubble, relative to the coordinates
at which it should be pointing.
@see setAllowedPlacement
*/
enum BubblePlacement
{
above = 1,
below = 2,
left = 4,
right = 8
};
/** Tells the bubble which positions it's allowed to put itself in, relative to the
point at which it's pointing.
By default when setPosition() is called, the bubble will place itself either
above, below, left, or right of the target area. You can pass in a bitwise-'or' of
the values in BubblePlacement to restrict this choice.
E.g. if you only want your bubble to appear above or below the target area,
use setAllowedPlacement (above | below);
@see BubblePlacement
*/
void setAllowedPlacement (int newPlacement);
//==============================================================================
/** Moves and resizes the bubble to point at a given component.
This will resize the bubble to fit its content, then find a position for it
so that it's next to, but doesn't overlap the given component.
It'll put itself either above, below, or to the side of the component depending
on where there's the most space, honouring any restrictions that were set
with setAllowedPlacement().
*/
void setPosition (Component* componentToPointTo);
/** Moves and resizes the bubble to point at a given point.
This will resize the bubble to fit its content, then position it
so that the tip of the bubble points to the given coordinate. The coordinates
are relative to either the bubble component's parent component if it has one, or
they are screen coordinates if not.
It'll put itself either above, below, or to the side of this point, depending
on where there's the most space, honouring any restrictions that were set
with setAllowedPlacement().
*/
void setPosition (Point<int> arrowTipPosition);
/** Moves and resizes the bubble to point at a given rectangle.
This will resize the bubble to fit its content, then find a position for it
so that it's next to, but doesn't overlap the given rectangle. The rectangle's
coordinates are relative to either the bubble component's parent component
if it has one, or they are screen coordinates if not.
It'll put itself either above, below, or to the side of the component depending
on where there's the most space, honouring any restrictions that were set
with setAllowedPlacement().
*/
void setPosition (const Rectangle<int>& rectangleToPointTo);
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the bubble component.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
backgroundColourId = 0x1000af0, /**< A background colour to fill the bubble with. */
outlineColourId = 0x1000af1 /**< The colour to use for an outline around the bubble. */
};
//==============================================================================
/** This abstract base class is implemented by LookAndFeel classes.
*/
struct JUCE_API LookAndFeelMethods
{
virtual ~LookAndFeelMethods() {}
virtual void drawBubble (Graphics&, BubbleComponent&,
const Point<float>& positionOfTip,
const Rectangle<float>& body) = 0;
};
protected:
//==============================================================================
/** Subclasses should override this to return the size of the content they
want to draw inside the bubble.
*/
virtual void getContentSize (int& width, int& height) = 0;
/** Subclasses should override this to draw their bubble's contents.
The graphics object's clip region and the dimensions passed in here are
set up to paint just the rectangle inside the bubble.
*/
virtual void paintContent (Graphics& g, int width, int height) = 0;
public:
/** @internal */
void paint (Graphics&) override;
private:
Rectangle<int> content;
Point<int> arrowTip;
int allowablePlacements;
DropShadowEffect shadow;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent)
};
#endif // JUCE_BUBBLECOMPONENT_H_INCLUDED

View file

@ -0,0 +1,215 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found 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.juce.com for more information.
==============================================================================
*/
class DropShadower::ShadowWindow : public Component
{
public:
ShadowWindow (Component* comp, const DropShadow& ds)
: target (comp), shadow (ds)
{
setVisible (true);
setInterceptsMouseClicks (false, false);
if (comp->isOnDesktop())
{
setSize (1, 1); // to keep the OS happy by not having zero-size windows
addToDesktop (ComponentPeer::windowIgnoresMouseClicks
| ComponentPeer::windowIsTemporary
| ComponentPeer::windowIgnoresKeyPresses);
}
else if (Component* const parent = comp->getParentComponent())
{
parent->addChildComponent (this);
}
}
void paint (Graphics& g) override
{
if (Component* c = target)
shadow.drawForRectangle (g, getLocalArea (c, c->getLocalBounds()));
}
void resized() override
{
repaint(); // (needed for correct repainting)
}
float getDesktopScaleFactor() const override
{
if (target != nullptr)
return target->getDesktopScaleFactor();
return Component::getDesktopScaleFactor();
}
private:
WeakReference<Component> target;
DropShadow shadow;
JUCE_DECLARE_NON_COPYABLE (ShadowWindow)
};
//==============================================================================
DropShadower::DropShadower (const DropShadow& ds)
: owner (nullptr), shadow (ds), reentrant (false)
{
}
DropShadower::~DropShadower()
{
if (owner != nullptr)
{
owner->removeComponentListener (this);
owner = nullptr;
}
updateParent();
reentrant = true;
shadowWindows.clear();
}
void DropShadower::setOwner (Component* componentToFollow)
{
if (componentToFollow != owner)
{
if (owner != nullptr)
owner->removeComponentListener (this);
// (the component can't be null)
jassert (componentToFollow != nullptr);
owner = componentToFollow;
jassert (owner != nullptr);
updateParent();
owner->addComponentListener (this);
updateShadows();
}
}
void DropShadower::updateParent()
{
if (Component* p = lastParentComp)
p->removeComponentListener (this);
lastParentComp = owner != nullptr ? owner->getParentComponent() : nullptr;
if (Component* p = lastParentComp)
p->addComponentListener (this);
}
void DropShadower::componentMovedOrResized (Component& c, bool /*wasMoved*/, bool /*wasResized*/)
{
if (owner == &c)
updateShadows();
}
void DropShadower::componentBroughtToFront (Component& c)
{
if (owner == &c)
updateShadows();
}
void DropShadower::componentChildrenChanged (Component&)
{
updateShadows();
}
void DropShadower::componentParentHierarchyChanged (Component& c)
{
if (owner == &c)
{
updateParent();
updateShadows();
}
}
void DropShadower::componentVisibilityChanged (Component& c)
{
if (owner == &c)
updateShadows();
}
void DropShadower::updateShadows()
{
if (reentrant)
return;
const ScopedValueSetter<bool> setter (reentrant, true, false);
if (owner == nullptr)
{
shadowWindows.clear();
return;
}
if (owner->isShowing()
&& owner->getWidth() > 0 && owner->getHeight() > 0
&& (Desktop::canUseSemiTransparentWindows() || owner->getParentComponent() != nullptr))
{
while (shadowWindows.size() < 4)
shadowWindows.add (new ShadowWindow (owner, shadow));
const int shadowEdge = jmax (shadow.offset.x, shadow.offset.y) + shadow.radius;
const int x = owner->getX();
const int y = owner->getY() - shadowEdge;
const int w = owner->getWidth();
const int h = owner->getHeight() + shadowEdge + shadowEdge;
for (int i = 4; --i >= 0;)
{
// there seem to be rare situations where the dropshadower may be deleted by
// callbacks during this loop, so use a weak ref to watch out for this..
WeakReference<Component> sw (shadowWindows[i]);
if (sw != nullptr)
sw->setAlwaysOnTop (owner->isAlwaysOnTop());
if (sw != nullptr)
{
switch (i)
{
case 0: sw->setBounds (x - shadowEdge, y, shadowEdge, h); break;
case 1: sw->setBounds (x + w, y, shadowEdge, h); break;
case 2: sw->setBounds (x, y, w, shadowEdge); break;
case 3: sw->setBounds (x, owner->getBottom(), w, shadowEdge); break;
default: break;
}
}
if (sw != nullptr)
sw->toBehind (i == 3 ? owner : shadowWindows.getUnchecked (i + 1));
if (sw == nullptr)
return;
}
}
else
{
shadowWindows.clear();
}
}

View file

@ -0,0 +1,80 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found 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.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_DROPSHADOWER_H_INCLUDED
#define JUCE_DROPSHADOWER_H_INCLUDED
//==============================================================================
/**
Adds a drop-shadow to a component.
This object creates and manages a set of components which sit around a
component, creating a gaussian shadow around it. The components will track
the position of the component and if it's brought to the front they'll also
follow this.
For desktop windows you don't need to use this class directly - just
set the Component::windowHasDropShadow flag when calling
Component::addToDesktop(), and the system will create one of these if it's
needed (which it obviously isn't on the Mac, for example).
*/
class JUCE_API DropShadower : private ComponentListener
{
public:
//==============================================================================
/** Creates a DropShadower. */
DropShadower (const DropShadow& shadowType);
/** Destructor. */
~DropShadower();
/** Attaches the DropShadower to the component you want to shadow. */
void setOwner (Component* componentToFollow);
private:
//==============================================================================
class ShadowWindow;
Component* owner;
OwnedArray<Component> shadowWindows;
DropShadow shadow;
bool reentrant;
WeakReference<Component> lastParentComp;
void componentMovedOrResized (Component&, bool, bool) override;
void componentBroughtToFront (Component&) override;
void componentChildrenChanged (Component&) override;
void componentParentHierarchyChanged (Component&) override;
void componentVisibilityChanged (Component&) override;
void updateParent();
void updateShadows();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower)
};
#endif // JUCE_DROPSHADOWER_H_INCLUDED