505 lines
13 KiB
C++
505 lines
13 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 "cparamdisplay.h"
|
|
#include "../cbitmap.h"
|
|
#include "../cframe.h"
|
|
#include "../cstring.h"
|
|
#include "../cgraphicspath.h"
|
|
#include "../cdrawcontext.h"
|
|
#include <string>
|
|
|
|
namespace VSTGUI {
|
|
|
|
//------------------------------------------------------------------------
|
|
// CParamDisplay
|
|
//------------------------------------------------------------------------
|
|
/*! @class CParamDisplay
|
|
Define a rectangle view where a text-value can be displayed with a given font and color.
|
|
The user can specify its convert function (from float to char) by default the string format is "%2.2f".
|
|
The text-value is centered in the given rect.
|
|
*/
|
|
CParamDisplay::CParamDisplay (const CRect& size, CBitmap* background, int32_t inStyle)
|
|
: CControl (size, nullptr, -1, background)
|
|
, horiTxtAlign (kCenterText)
|
|
, style (inStyle)
|
|
, valuePrecision (2)
|
|
, roundRectRadius (6.)
|
|
, frameWidth (1.)
|
|
, textRotation (0.)
|
|
{
|
|
setBit (style, kAntialias, true);
|
|
backOffset (0, 0);
|
|
|
|
fontID = kNormalFont; fontID->remember ();
|
|
fontColor = kWhiteCColor;
|
|
backColor = kBlackCColor;
|
|
frameColor = kBlackCColor;
|
|
shadowColor = kRedCColor;
|
|
if (hasBit (style, kNoDrawStyle))
|
|
setDirty (false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CParamDisplay::CParamDisplay (const CParamDisplay& v)
|
|
: CControl (v)
|
|
, valueToStringFunction (v.valueToStringFunction)
|
|
, horiTxtAlign (v.horiTxtAlign)
|
|
, style (v.style)
|
|
, valuePrecision (v.valuePrecision)
|
|
, fontID (v.fontID)
|
|
, fontColor (v.fontColor)
|
|
, backColor (v.backColor)
|
|
, frameColor (v.frameColor)
|
|
, shadowColor (v.shadowColor)
|
|
, textInset (v.textInset)
|
|
, backOffset (v.backOffset)
|
|
, roundRectRadius (v.roundRectRadius)
|
|
, frameWidth (v.frameWidth)
|
|
, textRotation (v.textRotation)
|
|
{
|
|
fontID->remember ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CParamDisplay::~CParamDisplay () noexcept
|
|
{
|
|
if (fontID)
|
|
fontID->forget ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool CParamDisplay::removed (CView* parent)
|
|
{
|
|
return CControl::removed (parent);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setStyle (int32_t val)
|
|
{
|
|
setBit (val, kAntialias, hasBit (style, kAntialias));
|
|
if (style != val)
|
|
{
|
|
style = val;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
int32_t CParamDisplay::getStyle () const
|
|
{
|
|
auto tmp = style;
|
|
setBit (tmp, kAntialias, false);
|
|
return tmp;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setPrecision (uint8_t precision)
|
|
{
|
|
if (valuePrecision != precision)
|
|
{
|
|
valuePrecision = precision;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setValueToStringFunction2 (const ValueToStringFunction2& valueToStringFunc)
|
|
{
|
|
valueToStringFunction = valueToStringFunc;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setValueToStringFunction2 (ValueToStringFunction2&& valueToStringFunc)
|
|
{
|
|
valueToStringFunction = std::move (valueToStringFunc);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setValueToStringFunction (const ValueToStringFunction& func)
|
|
{
|
|
if (!func)
|
|
{
|
|
setValueToStringFunction2 (nullptr);
|
|
return;
|
|
}
|
|
setValueToStringFunction2 ([=] (float value, std::string& str, CParamDisplay* display) {
|
|
char string[256];
|
|
string[0] = 0;
|
|
if (func (value, string, display))
|
|
{
|
|
str = string;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setValueToStringFunction (ValueToStringFunction&& func)
|
|
{
|
|
setValueToStringFunction (func);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool CParamDisplay::getFocusPath (CGraphicsPath& outPath)
|
|
{
|
|
if (wantsFocus ())
|
|
{
|
|
auto lineWidth = getFrameWidth ();
|
|
if (lineWidth < 0.)
|
|
lineWidth = 1.;
|
|
CCoord focusWidth = getFrame ()->getFocusWidth ();
|
|
CRect r (getViewSize ());
|
|
if (hasBit (style, kRoundRectStyle))
|
|
{
|
|
r.inset (lineWidth / 2., lineWidth / 2.);
|
|
outPath.addRoundRect (r, roundRectRadius);
|
|
outPath.closeSubpath ();
|
|
r.extend (focusWidth, focusWidth);
|
|
outPath.addRoundRect (r, roundRectRadius);
|
|
}
|
|
else
|
|
{
|
|
r.inset (lineWidth / 2., lineWidth / 2.);
|
|
outPath.addRect (r);
|
|
r.extend (focusWidth, focusWidth);
|
|
outPath.addRect (r);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::draw (CDrawContext *pContext)
|
|
{
|
|
if (hasBit (style, kNoDrawStyle))
|
|
return;
|
|
|
|
std::string string;
|
|
|
|
bool converted = false;
|
|
if (valueToStringFunction)
|
|
converted = valueToStringFunction (value, string, this);
|
|
if (!converted)
|
|
{
|
|
char tmp[255];
|
|
char precisionStr[10];
|
|
snprintf (precisionStr, 10, "%%.%hhuf", valuePrecision);
|
|
snprintf (tmp, 255, precisionStr, value);
|
|
string = tmp;
|
|
}
|
|
|
|
drawBack (pContext);
|
|
drawPlatformText (pContext, UTF8String (string));
|
|
setDirty (false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::drawBack (CDrawContext* pContext, CBitmap* newBack)
|
|
{
|
|
pContext->setDrawMode (kAliasing);
|
|
auto lineWidth = getFrameWidth ();
|
|
if (lineWidth < 0.)
|
|
lineWidth = pContext->getHairlineSize ();
|
|
if (newBack)
|
|
{
|
|
newBack->draw (pContext, getViewSize (), backOffset);
|
|
}
|
|
else if (getDrawBackground ())
|
|
{
|
|
getDrawBackground ()->draw (pContext, getViewSize (), backOffset);
|
|
}
|
|
else
|
|
{
|
|
if (!getTransparency ())
|
|
{
|
|
bool strokePath = !(hasBit (style, (k3DIn|k3DOut|kNoFrame)));
|
|
pContext->setFillColor (backColor);
|
|
if (hasBit (style, kRoundRectStyle))
|
|
{
|
|
CRect pathRect = getViewSize ();
|
|
pathRect.inset (lineWidth/2., lineWidth/2.);
|
|
SharedPointer<CGraphicsPath> path = owned (pContext->createRoundRectGraphicsPath (pathRect, roundRectRadius));
|
|
if (path)
|
|
{
|
|
pContext->setDrawMode (kAntiAliasing);
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
|
if (strokePath)
|
|
{
|
|
pContext->setLineStyle (kLineSolid);
|
|
pContext->setLineWidth (lineWidth);
|
|
pContext->setFrameColor (frameColor);
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pContext->setDrawMode (kAntiAliasing);
|
|
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ());
|
|
if (path)
|
|
{
|
|
CRect frameRect = getViewSize ();
|
|
if (strokePath)
|
|
frameRect.inset (lineWidth/2., lineWidth/2.);
|
|
path->addRect (frameRect);
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
|
if (strokePath)
|
|
{
|
|
pContext->setLineStyle (kLineSolid);
|
|
pContext->setLineWidth (lineWidth);
|
|
pContext->setFrameColor (frameColor);
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pContext->drawRect (getViewSize (), kDrawFilled);
|
|
|
|
if (strokePath)
|
|
{
|
|
CRect frameRect = getViewSize ();
|
|
frameRect.inset (lineWidth/2., lineWidth/2.);
|
|
|
|
pContext->setLineStyle (kLineSolid);
|
|
pContext->setLineWidth (lineWidth);
|
|
pContext->setFrameColor (frameColor);
|
|
pContext->drawRect (frameRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// draw the frame for the 3D effect
|
|
if (hasBit (style, (k3DIn|k3DOut)))
|
|
{
|
|
CRect r (getViewSize ());
|
|
r.inset (lineWidth/2., lineWidth/2.);
|
|
pContext->setDrawMode (kAliasing);
|
|
pContext->setLineWidth (lineWidth);
|
|
pContext->setLineStyle (kLineSolid);
|
|
if (hasBit (style, k3DIn))
|
|
pContext->setFrameColor (backColor);
|
|
else
|
|
pContext->setFrameColor (frameColor);
|
|
|
|
CPoint p;
|
|
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ());
|
|
if (path)
|
|
{
|
|
path->beginSubpath (p (r.left, r.bottom));
|
|
path->addLine (p (r.left, r.top));
|
|
path->addLine (p (r.right, r.top));
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
|
}
|
|
else
|
|
{
|
|
pContext->drawLine (CPoint (r.left, r.bottom), CPoint (r.left, r.top));
|
|
pContext->drawLine (CPoint (r.left, r.top), CPoint (r.right, r.top));
|
|
}
|
|
|
|
if (hasBit (style, k3DIn))
|
|
pContext->setFrameColor (frameColor);
|
|
else
|
|
pContext->setFrameColor (backColor);
|
|
|
|
path = owned (pContext->createGraphicsPath ());
|
|
if (path)
|
|
{
|
|
path->beginSubpath (p (r.right, r.top));
|
|
path->addLine (p (r.right, r.bottom));
|
|
path->addLine (p (r.left, r.bottom));
|
|
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
|
}
|
|
else
|
|
{
|
|
pContext->drawLine (CPoint (r.right, r.top), CPoint (r.right, r.bottom));
|
|
pContext->drawLine (CPoint (r.right, r.bottom), CPoint (r.left, r.bottom));
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::drawPlatformText (CDrawContext* pContext, const UTF8String& string)
|
|
{
|
|
drawPlatformText (pContext, string, getViewSize ());
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::drawPlatformText (CDrawContext* pContext, const UTF8String& string,
|
|
const CRect& size)
|
|
{
|
|
if (!hasBit (style, kNoTextStyle))
|
|
{
|
|
pContext->saveGlobalState ();
|
|
CRect textRect (size);
|
|
textRect.inset (textInset.x, textInset.y);
|
|
|
|
drawClipped (pContext, textRect, [&] () {
|
|
CPoint center (textRect.getCenter ());
|
|
CGraphicsTransform transform;
|
|
transform.rotate (textRotation, center);
|
|
CDrawContext::Transform ctxTransform (*pContext, transform);
|
|
|
|
pContext->setDrawMode (kAntiAliasing);
|
|
pContext->setFont (fontID);
|
|
|
|
// draw darker text (as shadow)
|
|
if (hasBit (style, kShadowText))
|
|
{
|
|
CRect newSize (textRect);
|
|
newSize.offset (shadowTextOffset);
|
|
pContext->setFontColor (shadowColor);
|
|
pContext->drawString (string.getPlatformString (), newSize, horiTxtAlign,
|
|
hasBit (style, kAntialias));
|
|
}
|
|
pContext->setFontColor (fontColor);
|
|
pContext->drawString (string.getPlatformString (), textRect, horiTxtAlign,
|
|
hasBit (style, kAntialias));
|
|
});
|
|
pContext->restoreGlobalState ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setFont (CFontRef inFontID)
|
|
{
|
|
if (fontID)
|
|
fontID->forget ();
|
|
fontID = inFontID;
|
|
if (fontID)
|
|
fontID->remember ();
|
|
drawStyleChanged ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setFontColor (CColor color)
|
|
{
|
|
// to force the redraw
|
|
if (fontColor != color)
|
|
{
|
|
fontColor = color;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setBackColor (CColor color)
|
|
{
|
|
// to force the redraw
|
|
if (backColor != color)
|
|
{
|
|
backColor = color;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setFrameColor (CColor color)
|
|
{
|
|
// to force the redraw
|
|
if (frameColor != color)
|
|
{
|
|
frameColor = color;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setShadowColor (CColor color)
|
|
{
|
|
// to force the redraw
|
|
if (shadowColor != color)
|
|
{
|
|
shadowColor = color;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setShadowTextOffset (const CPoint& offset)
|
|
{
|
|
if (shadowTextOffset != offset)
|
|
{
|
|
shadowTextOffset = offset;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setHoriAlign (CHoriTxtAlign hAlign)
|
|
{
|
|
// to force the redraw
|
|
if (horiTxtAlign != hAlign)
|
|
{
|
|
horiTxtAlign = hAlign;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setTextInset (const CPoint& p)
|
|
{
|
|
if (textInset != p)
|
|
{
|
|
textInset = p;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setTextRotation (double angle)
|
|
{
|
|
while (angle < 0.)
|
|
angle += 360.;
|
|
while (angle > 360.)
|
|
angle -= 360.;
|
|
if (textRotation != angle)
|
|
{
|
|
textRotation = angle;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setRoundRectRadius (const CCoord& radius)
|
|
{
|
|
if (roundRectRadius != radius)
|
|
{
|
|
roundRectRadius = radius;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setFrameWidth (const CCoord& width)
|
|
{
|
|
if (frameWidth != width)
|
|
{
|
|
frameWidth = width;
|
|
drawStyleChanged ();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::drawStyleChanged ()
|
|
{
|
|
setDirty ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CParamDisplay::setBackOffset (const CPoint &offset)
|
|
{
|
|
backOffset = offset;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CParamDisplay::copyBackOffset ()
|
|
{
|
|
backOffset (getViewSize ().left, getViewSize ().top);
|
|
}
|
|
|
|
} // VSTGUI
|