mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
First check-in of the "jucequake": a major re-organisation of the library to break it up into modules. For more details about this, see the website forum..
This commit is contained in:
parent
1a21c89755
commit
b70e0a28d2
1527 changed files with 90380 additions and 396643 deletions
302
modules/juce_gui_basics/misc/juce_DropShadower.cpp
Normal file
302
modules/juce_gui_basics/misc/juce_DropShadower.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-11 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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
//==============================================================================
|
||||
class ShadowWindow : public Component
|
||||
{
|
||||
public:
|
||||
ShadowWindow (Component& owner, const int type_, const Image shadowImageSections [12])
|
||||
: topLeft (shadowImageSections [type_ * 3]),
|
||||
bottomRight (shadowImageSections [type_ * 3 + 1]),
|
||||
filler (shadowImageSections [type_ * 3 + 2]),
|
||||
type (type_)
|
||||
{
|
||||
setInterceptsMouseClicks (false, false);
|
||||
|
||||
if (owner.isOnDesktop())
|
||||
{
|
||||
setSize (1, 1); // to keep the OS happy by not having zero-size windows
|
||||
addToDesktop (ComponentPeer::windowIgnoresMouseClicks
|
||||
| ComponentPeer::windowIsTemporary
|
||||
| ComponentPeer::windowIgnoresKeyPresses);
|
||||
}
|
||||
else if (owner.getParentComponent() != nullptr)
|
||||
{
|
||||
owner.getParentComponent()->addChildComponent (this);
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
g.setOpacity (1.0f);
|
||||
|
||||
if (type < 2)
|
||||
{
|
||||
int imH = jmin (topLeft.getHeight(), getHeight() / 2);
|
||||
g.drawImage (topLeft,
|
||||
0, 0, topLeft.getWidth(), imH,
|
||||
0, 0, topLeft.getWidth(), imH);
|
||||
|
||||
imH = jmin (bottomRight.getHeight(), getHeight() - getHeight() / 2);
|
||||
g.drawImage (bottomRight,
|
||||
0, getHeight() - imH, bottomRight.getWidth(), imH,
|
||||
0, bottomRight.getHeight() - imH, bottomRight.getWidth(), imH);
|
||||
|
||||
g.setTiledImageFill (filler, 0, 0, 1.0f);
|
||||
g.fillRect (0, topLeft.getHeight(), getWidth(), getHeight() - (topLeft.getHeight() + bottomRight.getHeight()));
|
||||
}
|
||||
else
|
||||
{
|
||||
int imW = jmin (topLeft.getWidth(), getWidth() / 2);
|
||||
g.drawImage (topLeft,
|
||||
0, 0, imW, topLeft.getHeight(),
|
||||
0, 0, imW, topLeft.getHeight());
|
||||
|
||||
imW = jmin (bottomRight.getWidth(), getWidth() - getWidth() / 2);
|
||||
g.drawImage (bottomRight,
|
||||
getWidth() - imW, 0, imW, bottomRight.getHeight(),
|
||||
bottomRight.getWidth() - imW, 0, imW, bottomRight.getHeight());
|
||||
|
||||
g.setTiledImageFill (filler, 0, 0, 1.0f);
|
||||
g.fillRect (topLeft.getWidth(), 0, getWidth() - (topLeft.getWidth() + bottomRight.getWidth()), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
repaint(); // (needed for correct repainting)
|
||||
}
|
||||
|
||||
private:
|
||||
const Image topLeft, bottomRight, filler;
|
||||
const int type; // 0 = left, 1 = right, 2 = top, 3 = bottom. left + right are full-height
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ShadowWindow);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
DropShadower::DropShadower (const float alpha_,
|
||||
const int xOffset_,
|
||||
const int yOffset_,
|
||||
const float blurRadius_)
|
||||
: owner (nullptr),
|
||||
xOffset (xOffset_),
|
||||
yOffset (yOffset_),
|
||||
alpha (alpha_),
|
||||
blurRadius (blurRadius_),
|
||||
reentrant (false)
|
||||
{
|
||||
}
|
||||
|
||||
DropShadower::~DropShadower()
|
||||
{
|
||||
if (owner != nullptr)
|
||||
owner->removeComponentListener (this);
|
||||
|
||||
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);
|
||||
jassert (owner->isOpaque()); // doesn't work properly for semi-transparent comps!
|
||||
|
||||
owner->addComponentListener (this);
|
||||
|
||||
updateShadows();
|
||||
}
|
||||
}
|
||||
|
||||
void DropShadower::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
|
||||
{
|
||||
updateShadows();
|
||||
}
|
||||
|
||||
void DropShadower::componentBroughtToFront (Component&)
|
||||
{
|
||||
bringShadowWindowsToFront();
|
||||
}
|
||||
|
||||
void DropShadower::componentParentHierarchyChanged (Component&)
|
||||
{
|
||||
shadowWindows.clear();
|
||||
updateShadows();
|
||||
}
|
||||
|
||||
void DropShadower::componentVisibilityChanged (Component&)
|
||||
{
|
||||
updateShadows();
|
||||
}
|
||||
|
||||
void DropShadower::updateShadows()
|
||||
{
|
||||
if (reentrant || owner == nullptr)
|
||||
return;
|
||||
|
||||
ComponentPeer* const peer = owner->getPeer();
|
||||
const bool isOwnerVisible = owner->isVisible() && (peer == nullptr || ! peer->isMinimised());
|
||||
|
||||
const bool createShadowWindows = shadowWindows.size() == 0
|
||||
&& owner->getWidth() > 0
|
||||
&& owner->getHeight() > 0
|
||||
&& isOwnerVisible
|
||||
&& (Desktop::canUseSemiTransparentWindows()
|
||||
|| owner->getParentComponent() != nullptr);
|
||||
|
||||
{
|
||||
const ScopedValueSetter<bool> setter (reentrant, true, false);
|
||||
|
||||
const int shadowEdge = jmax (xOffset, yOffset) + (int) blurRadius;
|
||||
|
||||
if (createShadowWindows)
|
||||
{
|
||||
// keep a cached version of the image to save doing the gaussian too often
|
||||
String imageId;
|
||||
imageId << shadowEdge << ',' << xOffset << ',' << yOffset << ',' << alpha;
|
||||
|
||||
const int hash = imageId.hashCode();
|
||||
|
||||
Image bigIm (ImageCache::getFromHashCode (hash));
|
||||
|
||||
if (bigIm.isNull())
|
||||
{
|
||||
bigIm = Image (Image::ARGB, shadowEdge * 5, shadowEdge * 5, true, Image::NativeImage);
|
||||
|
||||
Graphics bigG (bigIm);
|
||||
bigG.setColour (Colours::black.withAlpha (alpha));
|
||||
bigG.fillRect (shadowEdge + xOffset,
|
||||
shadowEdge + yOffset,
|
||||
bigIm.getWidth() - (shadowEdge * 2),
|
||||
bigIm.getHeight() - (shadowEdge * 2));
|
||||
|
||||
ImageConvolutionKernel blurKernel (roundToInt (blurRadius * 2.0f));
|
||||
blurKernel.createGaussianBlur (blurRadius);
|
||||
|
||||
blurKernel.applyToImage (bigIm, bigIm,
|
||||
Rectangle<int> (xOffset, yOffset,
|
||||
bigIm.getWidth(), bigIm.getHeight()));
|
||||
|
||||
ImageCache::addImageToCache (bigIm, hash);
|
||||
}
|
||||
|
||||
const int iw = bigIm.getWidth();
|
||||
const int ih = bigIm.getHeight();
|
||||
const int shadowEdge2 = shadowEdge * 2;
|
||||
|
||||
setShadowImage (bigIm, 0, shadowEdge, shadowEdge2, 0, 0);
|
||||
setShadowImage (bigIm, 1, shadowEdge, shadowEdge2, 0, ih - shadowEdge2);
|
||||
setShadowImage (bigIm, 2, shadowEdge, shadowEdge, 0, shadowEdge2);
|
||||
setShadowImage (bigIm, 3, shadowEdge, shadowEdge2, iw - shadowEdge, 0);
|
||||
setShadowImage (bigIm, 4, shadowEdge, shadowEdge2, iw - shadowEdge, ih - shadowEdge2);
|
||||
setShadowImage (bigIm, 5, shadowEdge, shadowEdge, iw - shadowEdge, shadowEdge2);
|
||||
setShadowImage (bigIm, 6, shadowEdge, shadowEdge, shadowEdge, 0);
|
||||
setShadowImage (bigIm, 7, shadowEdge, shadowEdge, iw - shadowEdge2, 0);
|
||||
setShadowImage (bigIm, 8, shadowEdge, shadowEdge, shadowEdge2, 0);
|
||||
setShadowImage (bigIm, 9, shadowEdge, shadowEdge, shadowEdge, ih - shadowEdge);
|
||||
setShadowImage (bigIm, 10, shadowEdge, shadowEdge, iw - shadowEdge2, ih - shadowEdge);
|
||||
setShadowImage (bigIm, 11, shadowEdge, shadowEdge, shadowEdge2, ih - shadowEdge);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
shadowWindows.add (new ShadowWindow (*owner, i, shadowImageSections));
|
||||
}
|
||||
|
||||
if (shadowWindows.size() >= 4)
|
||||
{
|
||||
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 = shadowWindows.size(); --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)
|
||||
sw->setVisible (isOwnerVisible);
|
||||
|
||||
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)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (createShadowWindows)
|
||||
bringShadowWindowsToFront();
|
||||
}
|
||||
|
||||
void DropShadower::setShadowImage (const Image& src, const int num, const int w, const int h,
|
||||
const int sx, const int sy)
|
||||
{
|
||||
shadowImageSections[num] = Image (Image::ARGB, w, h, true, Image::NativeImage);
|
||||
|
||||
Graphics g (shadowImageSections[num]);
|
||||
g.drawImage (src, 0, 0, w, h, sx, sy, w, h);
|
||||
}
|
||||
|
||||
void DropShadower::bringShadowWindowsToFront()
|
||||
{
|
||||
if (! reentrant)
|
||||
{
|
||||
updateShadows();
|
||||
|
||||
const ScopedValueSetter<bool> setter (reentrant, true, false);
|
||||
|
||||
for (int i = shadowWindows.size(); --i >= 0;)
|
||||
shadowWindows.getUnchecked(i)->toBehind (owner);
|
||||
}
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
Loading…
Add table
Add a link
Reference in a new issue