252 lines
8.1 KiB
C++
252 lines
8.1 KiB
C++
// This file is part of VSTGUI. It is subject to the license terms
|
|
// in the LICENSE file found in the top-level directory of this
|
|
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
|
|
|
#include "cshadowviewcontainer.h"
|
|
#include "coffscreencontext.h"
|
|
#include "cbitmapfilter.h"
|
|
#include "cframe.h"
|
|
#include "cbitmap.h"
|
|
#include <cassert>
|
|
#include <array>
|
|
|
|
namespace VSTGUI {
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CShadowViewContainer::CShadowViewContainer (const CRect& size)
|
|
: CViewContainer (size)
|
|
, dontDrawBackground (false)
|
|
, shadowIntensity (0.3f)
|
|
, shadowBlurSize (4)
|
|
, scaleFactorUsed (0.)
|
|
{
|
|
registerViewContainerListener (this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CShadowViewContainer::CShadowViewContainer (const CShadowViewContainer& copy)
|
|
: CViewContainer (copy)
|
|
, dontDrawBackground (false)
|
|
, shadowIntensity (copy.shadowIntensity)
|
|
, shadowBlurSize (copy.shadowBlurSize)
|
|
, scaleFactorUsed (0.)
|
|
{
|
|
registerViewContainerListener (this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CShadowViewContainer::~CShadowViewContainer () noexcept = default;
|
|
|
|
//------------------------------------------------------------------------
|
|
void CShadowViewContainer::beforeDelete ()
|
|
{
|
|
unregisterViewContainerListener (this);
|
|
CViewContainer::beforeDelete ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CShadowViewContainer::removed (CView* parent)
|
|
{
|
|
getFrame ()->unregisterScaleFactorChangedListener (this);
|
|
setBackground (nullptr);
|
|
return CViewContainer::removed (parent);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CShadowViewContainer::attached (CView* parent)
|
|
{
|
|
if (CViewContainer::attached (parent))
|
|
{
|
|
invalidateShadow ();
|
|
getFrame ()->registerScaleFactorChangedListener (this);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::onScaleFactorChanged (CFrame* frame, double newScaleFactor)
|
|
{
|
|
invalidateShadow ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::setShadowOffset (const CPoint& offset)
|
|
{
|
|
if (shadowOffset != offset)
|
|
{
|
|
shadowOffset = offset;
|
|
invalidateShadow ();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::setShadowIntensity (float intensity)
|
|
{
|
|
if (shadowIntensity != intensity)
|
|
{
|
|
shadowIntensity = intensity;
|
|
invalid ();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::setShadowBlurSize (double size)
|
|
{
|
|
if (shadowBlurSize != size)
|
|
{
|
|
shadowBlurSize = size;
|
|
invalidateShadow ();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::invalidateShadow ()
|
|
{
|
|
scaleFactorUsed = 0.;
|
|
invalid ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CMessageResult CShadowViewContainer::notify (CBaseObject* sender, IdStringPtr message)
|
|
{
|
|
if (message == kMsgViewSizeChanged)
|
|
invalidateShadow ();
|
|
return CViewContainer::notify(sender, message);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
template <size_t numBoxes>
|
|
static std::array<int32_t, numBoxes> boxesForGauss (double sigma)
|
|
{
|
|
std::array<int32_t, numBoxes> boxes;
|
|
double ideal = std::sqrt ((12 * sigma * sigma / numBoxes) + 1);
|
|
uint16_t l = static_cast<uint16_t> (std::floor (ideal));
|
|
if (l % 2 == 0)
|
|
l--;
|
|
int32_t u = l + 2;
|
|
ideal = ((12. * sigma * sigma) - (numBoxes * l * l) - (4. * numBoxes * l) - (3. * numBoxes)) / ((-4. * l) - 4.);
|
|
int32_t m = static_cast<int32_t> (std::floor (ideal));
|
|
for (int32_t i = 0; i < numBoxes; ++i)
|
|
boxes[i] = (i < m ? l : u);
|
|
return boxes;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
static bool isUniformScaled (const CGraphicsTransform& matrix)
|
|
{
|
|
return matrix.m11 == matrix.m22;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::drawRect (CDrawContext* pContext, const CRect& updateRect)
|
|
{
|
|
double scaleFactor = pContext->getScaleFactor ();
|
|
CGraphicsTransform matrix = pContext->getCurrentTransform ();
|
|
if (isUniformScaled (matrix))
|
|
{
|
|
double matrixScale = std::floor (matrix.m11 + 0.5);
|
|
if (matrixScale != 0.)
|
|
scaleFactor *= matrixScale;
|
|
}
|
|
if (scaleFactor != scaleFactorUsed && getWidth () > 0. && getHeight () > 0.)
|
|
{
|
|
scaleFactorUsed = scaleFactor;
|
|
CCoord width = getWidth ();
|
|
CCoord height = getHeight ();
|
|
|
|
if (auto offscreenContext = COffscreenContext::create ({width, height}, scaleFactor))
|
|
{
|
|
offscreenContext->beginDraw ();
|
|
CDrawContext::Transform transform (*offscreenContext, CGraphicsTransform ().translate (-getViewSize ().left - shadowOffset.x, -getViewSize ().top - shadowOffset.y));
|
|
dontDrawBackground = true;
|
|
CViewContainer::draw (offscreenContext);
|
|
dontDrawBackground = false;
|
|
offscreenContext->endDraw ();
|
|
CBitmap* bitmap = offscreenContext->getBitmap ();
|
|
if (bitmap)
|
|
{
|
|
setBackground (bitmap);
|
|
SharedPointer<BitmapFilter::IFilter> setColorFilter = owned (BitmapFilter::Factory::getInstance ().createFilter (BitmapFilter::Standard::kSetColor));
|
|
if (setColorFilter)
|
|
{
|
|
setColorFilter->setProperty (BitmapFilter::Standard::Property::kInputBitmap, bitmap);
|
|
setColorFilter->setProperty (BitmapFilter::Standard::Property::kInputColor, kBlackCColor);
|
|
setColorFilter->setProperty (BitmapFilter::Standard::Property::kIgnoreAlphaColorValue, (int32_t)1);
|
|
if (setColorFilter->run (true))
|
|
{
|
|
SharedPointer<BitmapFilter::IFilter> boxBlurFilter = owned (BitmapFilter::Factory::getInstance ().createFilter (BitmapFilter::Standard::kBoxBlur));
|
|
if (boxBlurFilter)
|
|
{
|
|
auto boxSizes = boxesForGauss<3> (shadowBlurSize);
|
|
boxBlurFilter->setProperty (BitmapFilter::Standard::Property::kInputBitmap, bitmap);
|
|
boxBlurFilter->setProperty (BitmapFilter::Standard::Property::kRadius, boxSizes[0]);
|
|
boxBlurFilter->setProperty (BitmapFilter::Standard::Property::kAlphaChannelOnly, 1);
|
|
if (boxBlurFilter->run (true))
|
|
{
|
|
boxBlurFilter->setProperty (BitmapFilter::Standard::Property::kRadius, boxSizes[1]);
|
|
boxBlurFilter->run (true);
|
|
boxBlurFilter->setProperty (BitmapFilter::Standard::Property::kRadius, boxSizes[2]);
|
|
boxBlurFilter->run (true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CViewContainer::drawRect (pContext, updateRect);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CViewContainer::drawRect (pContext, updateRect);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::drawBackgroundRect (CDrawContext* pContext, const CRect& _updateRect)
|
|
{
|
|
if (!dontDrawBackground)
|
|
{
|
|
float tmp = pContext->getGlobalAlpha ();
|
|
pContext->setGlobalAlpha (tmp * shadowIntensity);
|
|
CViewContainer::drawBackgroundRect (pContext, _updateRect);
|
|
pContext->setGlobalAlpha (tmp);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::setViewSize (const CRect& rect, bool invalid)
|
|
{
|
|
if (getViewSize () != rect)
|
|
{
|
|
bool diffSize = (getWidth () != rect.getWidth () || getHeight () != rect.getHeight ());
|
|
CViewContainer::setViewSize (rect, invalid);
|
|
if (diffSize)
|
|
invalidateShadow ();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::viewContainerViewAdded (CViewContainer* container, CView* view)
|
|
{
|
|
vstgui_assert (container == this);
|
|
invalidateShadow ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::viewContainerViewRemoved (CViewContainer* container, CView* view)
|
|
{
|
|
vstgui_assert (container == this);
|
|
invalidateShadow ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CShadowViewContainer::viewContainerViewZOrderChanged (CViewContainer* container, CView* view)
|
|
{
|
|
vstgui_assert (container == this);
|
|
invalidateShadow ();
|
|
}
|
|
|
|
} // VSTGUI
|