Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / special / juce_DropShadower.cpp
blob278d16393fb92ea588da94286d5c91e8646aad95
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_DropShadower.h"
31 #include "../../graphics/imaging/juce_ImageCache.h"
32 #include "../../graphics/imaging/juce_ImageConvolutionKernel.h"
33 #include "../../graphics/imaging/juce_Image.h"
34 #include "../juce_Desktop.h"
35 #include "../windows/juce_ComponentPeer.h"
36 #include "../../../containers/juce_ScopedValueSetter.h"
39 //==============================================================================
40 class ShadowWindow : public Component
42 public:
43 ShadowWindow (Component& owner, const int type_, const Image shadowImageSections [12])
44 : topLeft (shadowImageSections [type_ * 3]),
45 bottomRight (shadowImageSections [type_ * 3 + 1]),
46 filler (shadowImageSections [type_ * 3 + 2]),
47 type (type_)
49 setInterceptsMouseClicks (false, false);
51 if (owner.isOnDesktop())
53 setSize (1, 1); // to keep the OS happy by not having zero-size windows
54 addToDesktop (ComponentPeer::windowIgnoresMouseClicks
55 | ComponentPeer::windowIsTemporary
56 | ComponentPeer::windowIgnoresKeyPresses);
58 else if (owner.getParentComponent() != nullptr)
60 owner.getParentComponent()->addChildComponent (this);
64 void paint (Graphics& g)
66 g.setOpacity (1.0f);
68 if (type < 2)
70 int imH = jmin (topLeft.getHeight(), getHeight() / 2);
71 g.drawImage (topLeft,
72 0, 0, topLeft.getWidth(), imH,
73 0, 0, topLeft.getWidth(), imH);
75 imH = jmin (bottomRight.getHeight(), getHeight() - getHeight() / 2);
76 g.drawImage (bottomRight,
77 0, getHeight() - imH, bottomRight.getWidth(), imH,
78 0, bottomRight.getHeight() - imH, bottomRight.getWidth(), imH);
80 g.setTiledImageFill (filler, 0, 0, 1.0f);
81 g.fillRect (0, topLeft.getHeight(), getWidth(), getHeight() - (topLeft.getHeight() + bottomRight.getHeight()));
83 else
85 int imW = jmin (topLeft.getWidth(), getWidth() / 2);
86 g.drawImage (topLeft,
87 0, 0, imW, topLeft.getHeight(),
88 0, 0, imW, topLeft.getHeight());
90 imW = jmin (bottomRight.getWidth(), getWidth() - getWidth() / 2);
91 g.drawImage (bottomRight,
92 getWidth() - imW, 0, imW, bottomRight.getHeight(),
93 bottomRight.getWidth() - imW, 0, imW, bottomRight.getHeight());
95 g.setTiledImageFill (filler, 0, 0, 1.0f);
96 g.fillRect (topLeft.getWidth(), 0, getWidth() - (topLeft.getWidth() + bottomRight.getWidth()), getHeight());
100 void resized()
102 repaint(); // (needed for correct repainting)
105 private:
106 const Image topLeft, bottomRight, filler;
107 const int type; // 0 = left, 1 = right, 2 = top, 3 = bottom. left + right are full-height
109 JUCE_DECLARE_NON_COPYABLE (ShadowWindow);
113 //==============================================================================
114 DropShadower::DropShadower (const float alpha_,
115 const int xOffset_,
116 const int yOffset_,
117 const float blurRadius_)
118 : owner (nullptr),
119 xOffset (xOffset_),
120 yOffset (yOffset_),
121 alpha (alpha_),
122 blurRadius (blurRadius_),
123 reentrant (false)
127 DropShadower::~DropShadower()
129 if (owner != nullptr)
130 owner->removeComponentListener (this);
132 reentrant = true;
133 shadowWindows.clear();
136 void DropShadower::setOwner (Component* componentToFollow)
138 if (componentToFollow != owner)
140 if (owner != nullptr)
141 owner->removeComponentListener (this);
143 // (the component can't be null)
144 jassert (componentToFollow != nullptr);
146 owner = componentToFollow;
148 jassert (owner != nullptr);
149 jassert (owner->isOpaque()); // doesn't work properly for semi-transparent comps!
151 owner->addComponentListener (this);
153 updateShadows();
157 void DropShadower::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
159 updateShadows();
162 void DropShadower::componentBroughtToFront (Component&)
164 bringShadowWindowsToFront();
167 void DropShadower::componentParentHierarchyChanged (Component&)
169 shadowWindows.clear();
170 updateShadows();
173 void DropShadower::componentVisibilityChanged (Component&)
175 updateShadows();
178 void DropShadower::updateShadows()
180 if (reentrant || owner == nullptr)
181 return;
183 ComponentPeer* const peer = owner->getPeer();
184 const bool isOwnerVisible = owner->isVisible() && (peer == nullptr || ! peer->isMinimised());
186 const bool createShadowWindows = shadowWindows.size() == 0
187 && owner->getWidth() > 0
188 && owner->getHeight() > 0
189 && isOwnerVisible
190 && (Desktop::canUseSemiTransparentWindows()
191 || owner->getParentComponent() != nullptr);
194 const ScopedValueSetter<bool> setter (reentrant, true, false);
196 const int shadowEdge = jmax (xOffset, yOffset) + (int) blurRadius;
198 if (createShadowWindows)
200 // keep a cached version of the image to save doing the gaussian too often
201 String imageId;
202 imageId << shadowEdge << ',' << xOffset << ',' << yOffset << ',' << alpha;
204 const int hash = imageId.hashCode();
206 Image bigIm (ImageCache::getFromHashCode (hash));
208 if (bigIm.isNull())
210 bigIm = Image (Image::ARGB, shadowEdge * 5, shadowEdge * 5, true, Image::NativeImage);
212 Graphics bigG (bigIm);
213 bigG.setColour (Colours::black.withAlpha (alpha));
214 bigG.fillRect (shadowEdge + xOffset,
215 shadowEdge + yOffset,
216 bigIm.getWidth() - (shadowEdge * 2),
217 bigIm.getHeight() - (shadowEdge * 2));
219 ImageConvolutionKernel blurKernel (roundToInt (blurRadius * 2.0f));
220 blurKernel.createGaussianBlur (blurRadius);
222 blurKernel.applyToImage (bigIm, bigIm,
223 Rectangle<int> (xOffset, yOffset,
224 bigIm.getWidth(), bigIm.getHeight()));
226 ImageCache::addImageToCache (bigIm, hash);
229 const int iw = bigIm.getWidth();
230 const int ih = bigIm.getHeight();
231 const int shadowEdge2 = shadowEdge * 2;
233 setShadowImage (bigIm, 0, shadowEdge, shadowEdge2, 0, 0);
234 setShadowImage (bigIm, 1, shadowEdge, shadowEdge2, 0, ih - shadowEdge2);
235 setShadowImage (bigIm, 2, shadowEdge, shadowEdge, 0, shadowEdge2);
236 setShadowImage (bigIm, 3, shadowEdge, shadowEdge2, iw - shadowEdge, 0);
237 setShadowImage (bigIm, 4, shadowEdge, shadowEdge2, iw - shadowEdge, ih - shadowEdge2);
238 setShadowImage (bigIm, 5, shadowEdge, shadowEdge, iw - shadowEdge, shadowEdge2);
239 setShadowImage (bigIm, 6, shadowEdge, shadowEdge, shadowEdge, 0);
240 setShadowImage (bigIm, 7, shadowEdge, shadowEdge, iw - shadowEdge2, 0);
241 setShadowImage (bigIm, 8, shadowEdge, shadowEdge, shadowEdge2, 0);
242 setShadowImage (bigIm, 9, shadowEdge, shadowEdge, shadowEdge, ih - shadowEdge);
243 setShadowImage (bigIm, 10, shadowEdge, shadowEdge, iw - shadowEdge2, ih - shadowEdge);
244 setShadowImage (bigIm, 11, shadowEdge, shadowEdge, shadowEdge2, ih - shadowEdge);
246 for (int i = 0; i < 4; ++i)
247 shadowWindows.add (new ShadowWindow (*owner, i, shadowImageSections));
250 if (shadowWindows.size() >= 4)
252 const int x = owner->getX();
253 const int y = owner->getY() - shadowEdge;
254 const int w = owner->getWidth();
255 const int h = owner->getHeight() + shadowEdge + shadowEdge;
257 for (int i = shadowWindows.size(); --i >= 0;)
259 // there seem to be rare situations where the dropshadower may be deleted by
260 // callbacks during this loop, so use a weak ref to watch out for this..
261 WeakReference<Component> sw (shadowWindows[i]);
263 if (sw != nullptr)
264 sw->setAlwaysOnTop (owner->isAlwaysOnTop());
266 if (sw != nullptr)
267 sw->setVisible (isOwnerVisible);
269 if (sw != nullptr)
271 switch (i)
273 case 0: sw->setBounds (x - shadowEdge, y, shadowEdge, h); break;
274 case 1: sw->setBounds (x + w, y, shadowEdge, h); break;
275 case 2: sw->setBounds (x, y, w, shadowEdge); break;
276 case 3: sw->setBounds (x, owner->getBottom(), w, shadowEdge); break;
277 default: break;
281 if (sw == nullptr)
282 return;
287 if (createShadowWindows)
288 bringShadowWindowsToFront();
291 void DropShadower::setShadowImage (const Image& src, const int num, const int w, const int h,
292 const int sx, const int sy)
294 shadowImageSections[num] = Image (Image::ARGB, w, h, true, Image::NativeImage);
296 Graphics g (shadowImageSections[num]);
297 g.drawImage (src, 0, 0, w, h, sx, sy, w, h);
300 void DropShadower::bringShadowWindowsToFront()
302 if (! reentrant)
304 updateShadows();
306 const ScopedValueSetter<bool> setter (reentrant, true, false);
308 for (int i = shadowWindows.size(); --i >= 0;)
309 shadowWindows.getUnchecked(i)->toBehind (owner);
313 END_JUCE_NAMESPACE