Initial release
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user