Browse Source

New class: DropShadow, and a complete refactoring of the way shadows are rendered. The DropShadowEffect and DropShadower classes now take a DropShadow object to describe their shadow parameters, instead of the raw numbers.

tags/2021-05-28
jules 13 years ago
parent
commit
3ddc6dd43d
16 changed files with 281 additions and 243 deletions
  1. +4
    -4
      extras/JuceDemo/Source/demos/WidgetsDemo.cpp
  2. +1
    -1
      extras/audio plugin host/Source/GraphEditorPanel.cpp
  3. +111
    -52
      modules/juce_graphics/effects/juce_DropShadowEffect.cpp
  4. +35
    -22
      modules/juce_graphics/effects/juce_DropShadowEffect.h
  5. +47
    -0
      modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp
  6. +12
    -37
      modules/juce_gui_basics/buttons/juce_ArrowButton.cpp
  7. +1
    -12
      modules/juce_gui_basics/buttons/juce_ArrowButton.h
  8. +2
    -2
      modules/juce_gui_basics/buttons/juce_ShapeButton.cpp
  9. +1
    -6
      modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp
  10. +0
    -1
      modules/juce_gui_basics/layout/juce_TabbedButtonBar.h
  11. +21
    -33
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp
  12. +1
    -1
      modules/juce_gui_basics/misc/juce_BubbleComponent.cpp
  13. +32
    -44
      modules/juce_gui_basics/misc/juce_DropShadower.cpp
  14. +11
    -26
      modules/juce_gui_basics/misc/juce_DropShadower.h
  15. +1
    -1
      modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  16. +1
    -1
      modules/juce_gui_extra/lookandfeel/juce_OldSchoolLookAndFeel.cpp

+ 4
- 4
extras/JuceDemo/Source/demos/WidgetsDemo.cpp View File

@@ -35,7 +35,7 @@ public:
{ {
Random random; Random random;
const int size = 10 + random.nextInt (30);
const float size = 10.0f + random.nextInt (30);
ballBounds.setBounds (random.nextFloat() * 100.0f, ballBounds.setBounds (random.nextFloat() * 100.0f,
random.nextFloat() * 100.0f, random.nextFloat() * 100.0f,
@@ -186,9 +186,9 @@ public:
void timerCallback() void timerCallback()
{ {
Random random; Random random;
blobPosition.setBounds (random.nextInt (getWidth()),
random.nextInt (getHeight()),
40, 30);
blobPosition.setBounds ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()),
40.0f, 30.0f);
repaint(); repaint();
} }


+ 1
- 1
extras/audio plugin host/Source/GraphEditorPanel.cpp View File

@@ -223,7 +223,7 @@ public:
numIns (0), numIns (0),
numOuts (0) numOuts (0)
{ {
shadow.setShadowProperties (2.5f, 0.5f, -1, 0);
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point<int> (0, 1));
setComponentEffect (&shadow); setComponentEffect (&shadow);
setSize (150, 60); setSize (150, 60);


+ 111
- 52
modules/juce_graphics/effects/juce_DropShadowEffect.cpp View File

@@ -27,86 +27,145 @@
#pragma optimize ("t", on) #pragma optimize ("t", on)
#endif #endif
//==============================================================================
DropShadowEffect::DropShadowEffect()
: offsetX (0),
offsetY (0),
radius (4),
opacity (0.6f)
static void blurSingleChannelImage (uint8* const data, const int width, const int height,
const int lineStride, const int repetitions) noexcept
{ {
uint8* line = data;
for (int y = height; --y >= 0;)
{
for (int i = repetitions; --i >= 0;)
{
uint8* p = line;
*p++ = (((int) p[0]) + p[1]) / 2;
for (int x = width - 2; --x >= 0;)
*p++ = (((int) p[-1]) + p[0] + p[1] + 1) / 3;
*p = (((int) p[0]) + p[-1]) / 2;
}
line += lineStride;
}
for (int i = repetitions; --i >= 0;)
{
line = data;
{
uint8* p1 = line;
uint8* p2 = line + lineStride;
for (int x = width; --x >= 0;)
*p1++ = (((int) *p1) + *p2++) / 2;
}
line += lineStride;
for (int y = height - 2; --y >= 0;)
{
uint8* p1 = line;
uint8* p2 = line - lineStride;
uint8* p3 = line + lineStride;
for (int x = width; --x >= 0;)
*p1++ = (((int) *p1) + *p2++ + *p3++ + 1) / 3;
line += lineStride;
}
uint8* p1 = line;
uint8* p2 = line - lineStride;
for (int x = width; --x >= 0;)
*p1++ = (((int) *p1) + *p2++) / 2;
}
} }
DropShadowEffect::~DropShadowEffect()
static void blurSingleChannelImage (Image& image, int radius)
{ {
const Image::BitmapData bm (image, Image::BitmapData::readWrite);
blurSingleChannelImage (bm.data, bm.width, bm.height, bm.lineStride, 2 * radius);
} }
void DropShadowEffect::setShadowProperties (const float newRadius,
const float newOpacity,
const int newShadowOffsetX,
const int newShadowOffsetY)
#if JUCE_MSVC && JUCE_DEBUG
#pragma optimize ("", on) // resets optimisations to the project defaults
#endif
//==============================================================================
DropShadow::DropShadow() noexcept
: colour (0x90000000), radius (4)
{ {
radius = jmax (1.1f, newRadius);
offsetX = newShadowOffsetX;
offsetY = newShadowOffsetY;
opacity = newOpacity;
} }
void DropShadowEffect::drawShadow (Graphics& g, const Image& srcImage,
float radius, float alpha, int offsetX, int offsetY)
DropShadow::DropShadow (const Colour& shadowColour, const int r, const Point<int>& o) noexcept
: colour (shadowColour), radius (r), offset (o)
{ {
const int w = srcImage.getWidth();
const int h = srcImage.getHeight();
Image shadowImage (Image::SingleChannel, w, h, false);
const Image::BitmapData srcData (srcImage, Image::BitmapData::readOnly);
const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite);
jassert (radius > 0);
}
const int filter = roundToInt (63.0f / radius);
const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f);
void DropShadow::drawForImage (Graphics& g, const Image& srcImage) const
{
jassert (radius > 0);
for (int x = w; --x >= 0;)
if (srcImage.isValid())
{ {
int shadowAlpha = 0;
const PixelARGB* src = ((const PixelARGB*) srcData.data) + x;
uint8* shadowPix = destData.data + x;
Image shadowImage (srcImage.convertedToFormat (Image::SingleChannel));
shadowImage.duplicateIfShared();
for (int y = h; --y >= 0;)
{
shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12;
blurSingleChannelImage (shadowImage, radius);
*shadowPix = (uint8) shadowAlpha;
src = addBytesToPointer (src, srcData.lineStride);
shadowPix += destData.lineStride;
}
g.setColour (colour);
g.drawImageAt (shadowImage, offset.x, offset.y, true);
} }
}
void DropShadow::drawForPath (Graphics& g, const Path& path) const
{
jassert (radius > 0);
const Rectangle<int> area (path.getBounds().translated ((float) offset.x, (float) offset.y)
.getSmallestIntegerContainer()
.getIntersection (g.getClipBounds())
.expanded (radius + 1, radius + 1));
for (int y = h; --y >= 0;)
if (area.getWidth() > 2 && area.getHeight() > 2)
{ {
int shadowAlpha = 0;
uint8* shadowPix = destData.getLinePointer (y);
Image renderedPath (Image::SingleChannel, area.getWidth(), area.getHeight(), true);
for (int x = w; --x >= 0;)
{ {
shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12;
*shadowPix++ = (uint8) shadowAlpha;
Graphics g2 (renderedPath);
g2.setColour (Colours::white);
g2.fillPath (path, AffineTransform::translation ((float) (offset.x - area.getX()),
(float) (offset.y - area.getY())));
} }
blurSingleChannelImage (renderedPath, radius);
g.setColour (colour);
g.drawImageAt (renderedPath, area.getX(), area.getY(), true);
} }
}
//==============================================================================
DropShadowEffect::DropShadowEffect() {}
DropShadowEffect::~DropShadowEffect() {}
g.setColour (Colours::black.withAlpha (alpha));
g.drawImageAt (shadowImage, offsetX, offsetY, true);
void DropShadowEffect::setShadowProperties (const DropShadow& newShadow)
{
shadow = newShadow;
} }
void DropShadowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha) void DropShadowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha)
{ {
drawShadow (g, image, radius * scaleFactor, opacity * alpha,
(int) (offsetX * scaleFactor), (int) (offsetY * scaleFactor));
DropShadow s (shadow);
s.radius = roundToInt (s.radius * scaleFactor);
s.colour = s.colour.withMultipliedAlpha (alpha);
s.offset.x = roundToInt (s.offset.x * scaleFactor);
s.offset.y = roundToInt (s.offset.y * scaleFactor);
s.drawForImage (g, image);
g.setOpacity (alpha); g.setOpacity (alpha);
g.drawImageAt (image, 0, 0); g.drawImageAt (image, 0, 0);
} }
#if JUCE_MSVC && JUCE_DEBUG
#pragma optimize ("", on) // resets optimisations to the project defaults
#endif

+ 35
- 22
modules/juce_graphics/effects/juce_DropShadowEffect.h View File

@@ -29,6 +29,37 @@
#include "juce_ImageEffectFilter.h" #include "juce_ImageEffectFilter.h"
//==============================================================================
/**
Defines a drop-shadow effect.
*/
struct JUCE_API DropShadow
{
/** Creates a default drop-shadow effect. */
DropShadow() noexcept;
/** Creates a drop-shadow object with the given parameters. */
DropShadow (const Colour& shadowColour, int radius, const Point<int>& offset) noexcept;
/** Renders a drop-shadow based on the alpha-channel of the given image. */
void drawForImage (Graphics& g, const Image& srcImage) const;
/** Renders a drop-shadow based on the shape of a path. */
void drawForPath (Graphics& g, const Path& path) const;
/** The colour with which to render the shadow.
In most cases you'll probably want to leave this as black with an alpha
value of around 0.5
*/
Colour colour;
/** The approximate spread of the shadow. */
int radius;
/** The offset of the shadow. */
Point<int> offset;
};
//============================================================================== //==============================================================================
/** /**
An effect filter that adds a drop-shadow behind the image's content. An effect filter that adds a drop-shadow behind the image's content.
@@ -50,9 +81,7 @@ class JUCE_API DropShadowEffect : public ImageEffectFilter
public: public:
//============================================================================== //==============================================================================
/** Creates a default drop-shadow effect. /** Creates a default drop-shadow effect.
To customise the shadow's appearance, use the setShadowProperties()
method.
To customise the shadow's appearance, use the setShadowProperties() method.
*/ */
DropShadowEffect(); DropShadowEffect();
@@ -60,23 +89,8 @@ public:
~DropShadowEffect(); ~DropShadowEffect();
//============================================================================== //==============================================================================
/** Sets up parameters affecting the shadow's appearance.
@param newRadius the (approximate) radius of the blur used
@param newOpacity the opacity with which the shadow is rendered
@param newShadowOffsetX allows the shadow to be shifted in relation to the
component's contents
@param newShadowOffsetY allows the shadow to be shifted in relation to the
component's contents
*/
void setShadowProperties (float newRadius,
float newOpacity,
int newShadowOffsetX,
int newShadowOffsetY);
static void drawShadow (Graphics& g, const Image& srcImage,
float radius, float alpha, int offsetX, int offsetY);
/** Sets up parameters affecting the shadow's appearance. */
void setShadowProperties (const DropShadow& newShadow);
//============================================================================== //==============================================================================
/** @internal */ /** @internal */
@@ -85,8 +99,7 @@ public:
private: private:
//============================================================================== //==============================================================================
int offsetX, offsetY;
float radius, opacity;
DropShadow shadow;
JUCE_LEAK_DETECTOR (DropShadowEffect); JUCE_LEAK_DETECTOR (DropShadowEffect);
}; };


+ 47
- 0
modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp View File

@@ -241,4 +241,51 @@ void ImageConvolutionKernel::applyToImage (Image& destImage,
} }
} }
} }
else if (destData.pixelStride == 1)
{
for (int y = area.getY(); y < bottom; ++y)
{
uint8* dest = line;
line += destData.lineStride;
for (int x = area.getX(); x < right; ++x)
{
float c1 = 0;
for (int yy = 0; yy < size; ++yy)
{
const int sy = y + yy - (size >> 1);
if (sy >= srcData.height)
break;
if (sy >= 0)
{
int sx = x - (size >> 1);
const uint8* src = srcData.getPixelPointer (sx, sy);
for (int xx = 0; xx < size; ++xx)
{
if (sx >= srcData.width)
break;
if (sx >= 0)
{
const float kernelMult = values [xx + yy * size];
c1 += kernelMult * *src++;
}
else
{
src += 3;
}
++sx;
}
}
}
*dest++ = (uint8) roundToInt (c1);
}
}
}
} }

+ 12
- 37
modules/juce_gui_basics/buttons/juce_ArrowButton.cpp View File

@@ -23,49 +23,24 @@
============================================================================== ==============================================================================
*/ */
ArrowButton::ArrowButton (const String& name,
float arrowDirectionInRadians,
const Colour& arrowColour)
: Button (name),
colour (arrowColour)
ArrowButton::ArrowButton (const String& name, float arrowDirectionInRadians, const Colour& arrowColour)
: Button (name), colour (arrowColour)
{ {
path.lineTo (0.0f, 1.0f);
path.lineTo (1.0f, 0.5f);
path.closeSubPath();
path.applyTransform (AffineTransform::rotation (float_Pi * 2.0f * arrowDirectionInRadians,
0.5f, 0.5f));
setComponentEffect (&shadow);
updateShadowAndOffset();
path.addTriangle (0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f);
path.applyTransform (AffineTransform::rotation (float_Pi * 2.0f * arrowDirectionInRadians, 0.5f, 0.5f));
} }
ArrowButton::~ArrowButton()
{
}
ArrowButton::~ArrowButton() {}
void ArrowButton::paintButton (Graphics& g,
bool /*isMouseOverButton*/,
bool /*isButtonDown*/)
void ArrowButton::paintButton (Graphics& g, bool /*isMouseOverButton*/, bool isButtonDown)
{ {
g.setColour (colour);
Path p (path);
g.fillPath (path, path.getTransformToScaleToFit ((float) offset,
(float) offset,
(float) (getWidth() - 3),
(float) (getHeight() - 3),
false));
}
const float offset = isButtonDown ? 1.0f : 0.0f;
p.applyTransform (path.getTransformToScaleToFit (offset, offset, getWidth() - 3.0f, getHeight() - 3.0f, false));
void ArrowButton::buttonStateChanged()
{
updateShadowAndOffset();
}
DropShadow (Colours::black.withAlpha (0.3f), isButtonDown ? 2 : 4, Point<int>()).drawForPath (g, p);
void ArrowButton::updateShadowAndOffset()
{
offset = (isDown()) ? 1 : 0;
shadow.setShadowProperties ((isDown()) ? 1.2f : 3.0f,
0.3f, -1, 0);
g.setColour (colour);
g.fillPath (p);
} }

+ 1
- 12
modules/juce_gui_basics/buttons/juce_ArrowButton.h View File

@@ -55,23 +55,12 @@ public:
protected: protected:
//==============================================================================
/** @internal */
void paintButton (Graphics& g,
bool isMouseOverButton,
bool isButtonDown);
/** @internal */ /** @internal */
void buttonStateChanged();
void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown);
private: private:
//==============================================================================
Colour colour; Colour colour;
DropShadowEffect shadow;
Path path; Path path;
int offset;
void updateShadowAndOffset();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton);
}; };


+ 2
- 2
modules/juce_gui_basics/buttons/juce_ShapeButton.cpp View File

@@ -64,8 +64,8 @@ void ShapeButton::setShape (const Path& newShape,
shape = newShape; shape = newShape;
maintainShapeProportions = maintainShapeProportions_; maintainShapeProportions = maintainShapeProportions_;
shadow.setShadowProperties (3.0f, 0.5f, 0, 0);
setComponentEffect ((hasShadow) ? &shadow : 0);
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point<int>()));
setComponentEffect (hasShadow ? &shadow : nullptr);
if (resizeNowToFitThisShape) if (resizeNowToFitThisShape)
{ {


+ 1
- 6
modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp View File

@@ -24,13 +24,8 @@
*/ */
TabBarButton::TabBarButton (const String& name, TabbedButtonBar& owner_) TabBarButton::TabBarButton (const String& name, TabbedButtonBar& owner_)
: Button (name),
owner (owner_),
overlapPixels (0),
extraCompPlacement (afterText)
: Button (name), owner (owner_), overlapPixels (0), extraCompPlacement (afterText)
{ {
shadow.setShadowProperties (2.2f, 0.7f, 0, 0);
setComponentEffect (&shadow);
setWantsKeyboardFocus (false); setWantsKeyboardFocus (false);
} }


+ 0
- 1
modules/juce_gui_basics/layout/juce_TabbedButtonBar.h View File

@@ -109,7 +109,6 @@ public:
protected: protected:
friend class TabbedButtonBar; friend class TabbedButtonBar;
TabbedButtonBar& owner; TabbedButtonBar& owner;
DropShadowEffect shadow;
int overlapPixels; int overlapPixels;
ScopedPointer<Component> extraComponent; ScopedPointer<Component> extraComponent;


+ 21
- 33
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp View File

@@ -1977,10 +1977,9 @@ int LookAndFeel::getDefaultMenuBarHeight()
//============================================================================== //==============================================================================
DropShadower* LookAndFeel::createDropShadowerForComponent (Component*) DropShadower* LookAndFeel::createDropShadowerForComponent (Component*)
{ {
return new DropShadower (0.4f, 1, 5, 10);
return new DropShadower (DropShadow (Colours::black.withAlpha (0.4f), 10, Point<int> (0, 2)));
} }
//============================================================================== //==============================================================================
void LookAndFeel::drawStretchableLayoutResizerBar (Graphics& g, void LookAndFeel::drawStretchableLayoutResizerBar (Graphics& g,
int w, int h, int w, int h,
@@ -2085,7 +2084,7 @@ int LookAndFeel::getTabButtonBestWidth (TabBarButton& button, int tabDepth)
+ getTabButtonOverlap (tabDepth) * 2; + getTabButtonOverlap (tabDepth) * 2;
} }
void LookAndFeel::createTabButtonShape (TabBarButton& button, Path& p, bool isMouseOver, bool isMouseDown)
void LookAndFeel::createTabButtonShape (TabBarButton& button, Path& p, bool /*isMouseOver*/, bool /*isMouseDown*/)
{ {
const Rectangle<int> activeArea (button.getActiveArea()); const Rectangle<int> activeArea (button.getActiveArea());
const float w = (float) activeArea.getWidth(); const float w = (float) activeArea.getWidth();
@@ -2144,7 +2143,7 @@ void LookAndFeel::createTabButtonShape (TabBarButton& button, Path& p, bool isMo
p = p.createPathWithRoundedCorners (3.0f); p = p.createPathWithRoundedCorners (3.0f);
} }
void LookAndFeel::fillTabButtonShape (TabBarButton& button, Graphics& g, const Path& path, bool isMouseOver, bool isMouseDown)
void LookAndFeel::fillTabButtonShape (TabBarButton& button, Graphics& g, const Path& path, bool /*isMouseOver*/, bool /*isMouseDown*/)
{ {
const Colour tabBackground (button.getTabBackgroundColour()); const Colour tabBackground (button.getTabBackgroundColour());
const bool isFrontTab = button.isFrontTab(); const bool isFrontTab = button.isFrontTab();
@@ -2165,8 +2164,8 @@ void LookAndFeel::drawTabButtonText (TabBarButton& button, Graphics& g, bool isM
{ {
const Rectangle<float> area (button.getTextArea().toFloat()); const Rectangle<float> area (button.getTextArea().toFloat());
int length = area.getWidth();
int depth = area.getHeight();
float length = area.getWidth();
float depth = area.getHeight();
if (button.getTabbedButtonBar().isVertical()) if (button.getTabbedButtonBar().isVertical())
std::swap (length, depth); std::swap (length, depth);
@@ -2178,7 +2177,7 @@ void LookAndFeel::drawTabButtonText (TabBarButton& button, Graphics& g, bool isM
textLayout.addFittedText (font, button.getButtonText().trim(), textLayout.addFittedText (font, button.getButtonText().trim(),
0.0f, 0.0f, (float) length, (float) depth, 0.0f, 0.0f, (float) length, (float) depth,
Justification::centred, Justification::centred,
jmax (1, depth / 12));
jmax (1, ((int) depth) / 12));
AffineTransform t; AffineTransform t;
@@ -2191,21 +2190,20 @@ void LookAndFeel::drawTabButtonText (TabBarButton& button, Graphics& g, bool isM
default: jassertfalse; break; default: jassertfalse; break;
} }
Colour col;
if (button.isFrontTab() && (button.isColourSpecified (TabbedButtonBar::frontTextColourId) if (button.isFrontTab() && (button.isColourSpecified (TabbedButtonBar::frontTextColourId)
|| isColourSpecified (TabbedButtonBar::frontTextColourId))) || isColourSpecified (TabbedButtonBar::frontTextColourId)))
g.setColour (findColour (TabbedButtonBar::frontTextColourId));
col = findColour (TabbedButtonBar::frontTextColourId);
else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId) else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId)
|| isColourSpecified (TabbedButtonBar::tabTextColourId)) || isColourSpecified (TabbedButtonBar::tabTextColourId))
g.setColour (findColour (TabbedButtonBar::tabTextColourId));
col = findColour (TabbedButtonBar::tabTextColourId);
else else
g.setColour (button.getTabBackgroundColour().contrasting());
col = button.getTabBackgroundColour().contrasting();
if (! (isMouseOver || isMouseDown))
g.setOpacity (0.8f);
if (! button.isEnabled())
g.setOpacity (0.3f);
const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
g.setColour (col.withMultipliedAlpha (alpha));
textLayout.draw (g, t); textLayout.draw (g, t);
} }
@@ -2218,8 +2216,9 @@ void LookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouse
tabShape.applyTransform (AffineTransform::translation ((float) activeArea.getX(), tabShape.applyTransform (AffineTransform::translation ((float) activeArea.getX(),
(float) activeArea.getY())); (float) activeArea.getY()));
fillTabButtonShape (button, g, tabShape, isMouseOver, isMouseDown);
DropShadow (Colours::black.withAlpha (0.5f), 2, Point<int> (0, 1)).drawForPath (g, tabShape);
fillTabButtonShape (button, g, tabShape, isMouseOver, isMouseDown);
drawTabButtonText (button, g, isMouseOver, isMouseDown); drawTabButtonText (button, g, isMouseOver, isMouseDown);
} }
@@ -2458,21 +2457,10 @@ void LookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g,
{ {
if (cachedImage.isNull()) if (cachedImage.isNull())
{ {
const int w = box.getWidth();
const int h = box.getHeight();
Image renderedPath (Image::ARGB, w, h, true);
{
Graphics g2 (renderedPath);
g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
g2.fillPath (path);
}
cachedImage = Image (Image::ARGB, w, h, true);
cachedImage = Image (Image::ARGB, box.getWidth(), box.getHeight(), true);
Graphics g2 (cachedImage); Graphics g2 (cachedImage);
DropShadowEffect::drawShadow (g2, renderedPath, 5.0f, 0.4f, 0, 2);
DropShadow (Colours::black.withAlpha (0.7f), 8, Point<int> (0, 2)).drawForPath (g2, path);
} }
g.setColour (Colours::black); g.setColour (Colours::black);
@@ -2779,16 +2767,16 @@ void LookAndFeel::drawShinyButtonShape (Graphics& g,
Path outline; Path outline;
LookAndFeelHelpers::createRoundedPath (outline, x, y, w, h, cs, LookAndFeelHelpers::createRoundedPath (outline, x, y, w, h, cs,
! (flatOnLeft || flatOnTop),
! (flatOnLeft || flatOnTop),
! (flatOnRight || flatOnTop), ! (flatOnRight || flatOnTop),
! (flatOnLeft || flatOnBottom),
! (flatOnLeft || flatOnBottom),
! (flatOnRight || flatOnBottom)); ! (flatOnRight || flatOnBottom));
ColourGradient cg (baseColour, 0.0f, y, ColourGradient cg (baseColour, 0.0f, y,
baseColour.overlaidWith (Colour (0x070000ff)), 0.0f, y + h, baseColour.overlaidWith (Colour (0x070000ff)), 0.0f, y + h,
false); false);
cg.addColour (0.5, baseColour.overlaidWith (Colour (0x33ffffff)));
cg.addColour (0.5, baseColour.overlaidWith (Colour (0x33ffffff)));
cg.addColour (0.51, baseColour.overlaidWith (Colour (0x110000ff))); cg.addColour (0.51, baseColour.overlaidWith (Colour (0x110000ff)));
g.setGradientFill (cg); g.setGradientFill (cg);


+ 1
- 1
modules/juce_gui_basics/misc/juce_BubbleComponent.cpp View File

@@ -28,7 +28,7 @@ BubbleComponent::BubbleComponent()
{ {
setInterceptsMouseClicks (false, false); setInterceptsMouseClicks (false, false);
shadow.setShadowProperties (5.0f, 0.35f, 0, 0);
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.35f), 5, Point<int>()));
setComponentEffect (&shadow); setComponentEffect (&shadow);
} }


+ 32
- 44
modules/juce_gui_basics/misc/juce_DropShadower.cpp View File

@@ -97,16 +97,8 @@ private:
//============================================================================== //==============================================================================
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 (const DropShadow& shadow_)
: owner (nullptr), shadow (shadow_), reentrant (false)
{ {
} }
@@ -179,55 +171,51 @@ void DropShadower::updateShadows()
{ {
const ScopedValueSetter<bool> setter (reentrant, true, false); const ScopedValueSetter<bool> setter (reentrant, true, false);
const int shadowEdge = jmax (xOffset, yOffset) + (int) blurRadius;
const int shadowEdge = jmax (shadow.offset.x, shadow.offset.y) + shadow.radius;
if (createShadowWindows) 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 shadowEdge2 = shadowEdge * 2;
const int imageSize = shadowEdge * 5;
const int hash = imageId.hashCode();
// keep a cached version of the image to save doing the gaussian too often
int64 hash = shadow.radius ^ 0x2342dfa7;
hash = hash * 101 + shadow.offset.x;
hash = hash * 101 + shadow.offset.y;
hash = hash * 65537 + shadow.colour.getARGB();
Image bigIm (ImageCache::getFromHashCode (hash)); Image bigIm (ImageCache::getFromHashCode (hash));
if (bigIm.isNull()) if (bigIm.isNull())
{ {
bigIm = Image (Image::ARGB, shadowEdge * 5, shadowEdge * 5, true);
bigIm = Image (Image::ARGB, imageSize, imageSize, true);
Graphics g (bigIm);
Graphics bigG (bigIm);
bigG.setColour (Colours::black.withAlpha (alpha));
bigG.fillRect (shadowEdge + xOffset,
shadowEdge + yOffset,
bigIm.getWidth() - (shadowEdge * 2),
bigIm.getHeight() - (shadowEdge * 2));
Path p;
p.addRectangle ((float) (shadowEdge + shadow.offset.x),
(float) (shadowEdge + shadow.offset.y),
(float) (imageSize - shadowEdge2),
(float) (imageSize - shadowEdge2));
ImageConvolutionKernel blurKernel (roundToInt (blurRadius * 2.0f));
blurKernel.createGaussianBlur (blurRadius);
blurKernel.applyToImage (bigIm, bigIm,
Rectangle<int> (xOffset, yOffset,
bigIm.getWidth(), bigIm.getHeight()));
shadow.drawForPath (g, p);
ImageCache::addImageToCache (bigIm, hash); 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);
jassert (imageSize == bigIm.getWidth() && imageSize == bigIm.getHeight());
setShadowImage (bigIm, 0, shadowEdge, shadowEdge2, 0, 0);
setShadowImage (bigIm, 1, shadowEdge, shadowEdge2, 0, imageSize - shadowEdge2);
setShadowImage (bigIm, 2, shadowEdge, shadowEdge, 0, shadowEdge2);
setShadowImage (bigIm, 3, shadowEdge, shadowEdge2, imageSize - shadowEdge, 0);
setShadowImage (bigIm, 4, shadowEdge, shadowEdge2, imageSize - shadowEdge, imageSize - shadowEdge2);
setShadowImage (bigIm, 5, shadowEdge, shadowEdge, imageSize - shadowEdge, shadowEdge2);
setShadowImage (bigIm, 6, shadowEdge, shadowEdge, shadowEdge, 0);
setShadowImage (bigIm, 7, shadowEdge, shadowEdge, imageSize - shadowEdge2, 0);
setShadowImage (bigIm, 8, shadowEdge, shadowEdge, shadowEdge2, 0);
setShadowImage (bigIm, 9, shadowEdge, shadowEdge, shadowEdge, imageSize - shadowEdge);
setShadowImage (bigIm, 10, shadowEdge, shadowEdge, imageSize - shadowEdge2, imageSize - shadowEdge);
setShadowImage (bigIm, 11, shadowEdge, shadowEdge, shadowEdge2, imageSize - shadowEdge);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
shadowWindows.add (new ShadowWindow (*owner, i, shadowImageSections)); shadowWindows.add (new ShadowWindow (*owner, i, shadowImageSections));


+ 11
- 26
modules/juce_gui_basics/misc/juce_DropShadower.h View File

@@ -43,50 +43,35 @@
Component::addToDesktop(), and the system will create one of these if it's Component::addToDesktop(), and the system will create one of these if it's
needed (which it obviously isn't on the Mac, for example). needed (which it obviously isn't on the Mac, for example).
*/ */
class JUCE_API DropShadower : public ComponentListener
class JUCE_API DropShadower : private ComponentListener
{ {
public: public:
//============================================================================== //==============================================================================
/** Creates a DropShadower.
@param alpha the opacity of the shadows, from 0 to 1.0
@param xOffset the horizontal displacement of the shadow, in pixels
@param yOffset the vertical displacement of the shadow, in pixels
@param blurRadius the radius of the blur to use for creating the shadow
*/
DropShadower (float alpha = 0.5f,
int xOffset = 1,
int yOffset = 5,
float blurRadius = 10.0f);
/** Creates a DropShadower. */
DropShadower (const DropShadow& shadowType);
/** Destructor. */ /** Destructor. */
virtual ~DropShadower();
~DropShadower();
/** Attaches the DropShadower to the component you want to shadow. */ /** Attaches the DropShadower to the component you want to shadow. */
void setOwner (Component* componentToFollow); void setOwner (Component* componentToFollow);
//==============================================================================
/** @internal */
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized);
/** @internal */
void componentBroughtToFront (Component& component);
/** @internal */
void componentParentHierarchyChanged (Component& component);
/** @internal */
void componentVisibilityChanged (Component& component);
private: private:
//============================================================================== //==============================================================================
Component* owner; Component* owner;
OwnedArray<Component> shadowWindows; OwnedArray<Component> shadowWindows;
Image shadowImageSections[12]; Image shadowImageSections[12];
const int xOffset, yOffset;
const float alpha, blurRadius;
DropShadow shadow;
bool reentrant; bool reentrant;
void componentMovedOrResized (Component&, bool, bool);
void componentBroughtToFront (Component&);
void componentParentHierarchyChanged (Component&);
void componentVisibilityChanged (Component&);
void updateShadows(); void updateShadows();
void setShadowImage (const Image& src, int num, int w, int h, int sx, int sy);
void setShadowImage (const Image&, int num, int w, int h, int sx, int sy);
void bringShadowWindowsToFront(); void bringShadowWindowsToFront();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower);


+ 1
- 1
modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -759,7 +759,7 @@ public:
shouldDeactivateTitleBar = oldDeactivate; shouldDeactivateTitleBar = oldDeactivate;
if (shadower != nullptr) if (shadower != nullptr)
shadower->componentBroughtToFront (*component);
handleBroughtToFront();
return true; return true;
} }


+ 1
- 1
modules/juce_gui_extra/lookandfeel/juce_OldSchoolLookAndFeel.cpp View File

@@ -39,7 +39,7 @@ OldSchoolLookAndFeel::OldSchoolLookAndFeel()
setColour (PopupMenu::highlightedTextColourId, Colours::black); setColour (PopupMenu::highlightedTextColourId, Colours::black);
setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId)); setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId));
scrollbarShadow.setShadowProperties (2.2f, 0.5f, 0, 0);
scrollbarShadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 2, Point<int>()));
} }
OldSchoolLookAndFeel::~OldSchoolLookAndFeel() OldSchoolLookAndFeel::~OldSchoolLookAndFeel()


Loading…
Cancel
Save