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