Initial release
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
// 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 "cdrawcontext.h"
|
||||
#include "cgradient.h"
|
||||
#include "cgraphicspath.h"
|
||||
#include "cgraphicstransform.h"
|
||||
#include "platform/iplatformgraphicspath.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addRoundRect (const CRect& size, CCoord radius)
|
||||
{
|
||||
if (radius <= 0.)
|
||||
{
|
||||
addRect (size);
|
||||
return;
|
||||
}
|
||||
CRect rect2 (size);
|
||||
rect2.normalize ();
|
||||
const CCoord left = rect2.left;
|
||||
const CCoord right = rect2.right;
|
||||
const CCoord top = rect2.top;
|
||||
const CCoord bottom = rect2.bottom;
|
||||
|
||||
beginSubpath (CPoint (right - radius, top));
|
||||
addArc (CRect (right - 2.0 * radius, top, right, top + 2.0 * radius), 270., 360., true);
|
||||
addArc (CRect (right - 2.0 * radius, bottom - 2.0 * radius, right, bottom), 0., 90., true);
|
||||
addArc (CRect (left, bottom - 2.0 * radius, left + 2.0 * radius, bottom), 90., 180., true);
|
||||
addArc (CRect (left, top, left + 2.0 * radius, top + 2.0 * radius), 180., 270., true);
|
||||
closeSubpath ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addPath (const CGraphicsPath& inPath, CGraphicsTransform* transformation)
|
||||
{
|
||||
for (auto e : inPath.elements)
|
||||
{
|
||||
if (transformation)
|
||||
{
|
||||
switch (e.type)
|
||||
{
|
||||
case Element::kArc:
|
||||
{
|
||||
transformation->transform (
|
||||
e.instruction.arc.rect.left, e.instruction.arc.rect.right,
|
||||
e.instruction.arc.rect.top, e.instruction.arc.rect.bottom);
|
||||
break;
|
||||
}
|
||||
case Element::kEllipse:
|
||||
case Element::kRect:
|
||||
{
|
||||
transformation->transform (e.instruction.rect.left, e.instruction.rect.right,
|
||||
e.instruction.rect.top, e.instruction.rect.bottom);
|
||||
break;
|
||||
}
|
||||
case Element::kBeginSubpath:
|
||||
case Element::kLine:
|
||||
{
|
||||
transformation->transform (e.instruction.point.x, e.instruction.point.y);
|
||||
break;
|
||||
}
|
||||
case Element::kBezierCurve:
|
||||
{
|
||||
transformation->transform (e.instruction.curve.control1.x,
|
||||
e.instruction.curve.control1.y);
|
||||
transformation->transform (e.instruction.curve.control2.x,
|
||||
e.instruction.curve.control2.y);
|
||||
transformation->transform (e.instruction.curve.end.x,
|
||||
e.instruction.curve.end.y);
|
||||
break;
|
||||
}
|
||||
case Element::kCloseSubpath:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elements.emplace_back (e);
|
||||
}
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addArc (const CRect& rect, double startAngle, double endAngle, bool clockwise)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kArc;
|
||||
CRect2Rect (rect, e.instruction.arc.rect);
|
||||
e.instruction.arc.startAngle = startAngle;
|
||||
e.instruction.arc.endAngle = endAngle;
|
||||
e.instruction.arc.clockwise = clockwise;
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addEllipse (const CRect& rect)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kEllipse;
|
||||
CRect2Rect (rect, e.instruction.rect);
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addRect (const CRect& rect)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kRect;
|
||||
CRect2Rect (rect, e.instruction.rect);
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addLine (const CPoint& to)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kLine;
|
||||
CPoint2Point (to, e.instruction.point);
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::addBezierCurve (const CPoint& control1, const CPoint& control2,
|
||||
const CPoint& end)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kBezierCurve;
|
||||
CPoint2Point (control1, e.instruction.curve.control1);
|
||||
CPoint2Point (control2, e.instruction.curve.control2);
|
||||
CPoint2Point (end, e.instruction.curve.end);
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::beginSubpath (const CPoint& start)
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kBeginSubpath;
|
||||
CPoint2Point (start, e.instruction.point);
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::closeSubpath ()
|
||||
{
|
||||
Element e;
|
||||
e.type = Element::kCloseSubpath;
|
||||
elements.emplace_back (e);
|
||||
dirty ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CGraphicsPath::CGraphicsPath (const PlatformGraphicsPathFactoryPtr& factory,
|
||||
PlatformGraphicsPathPtr&& path)
|
||||
: factory (factory), path (std::move (path))
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CGraphicsPath::CGraphicsPath (const CGraphicsPath& p) : elements (p.elements), factory (p.factory)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CGraphicsPath::~CGraphicsPath () noexcept {}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CGradient* CGraphicsPath::createGradient (double color1Start, double color2Start,
|
||||
const CColor& color1, const CColor& color2)
|
||||
{
|
||||
return CGradient::create (color1Start, color2Start, color1, color2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::makePlatformGraphicsPath (PlatformGraphicsPathFillMode fillMode)
|
||||
{
|
||||
if (!factory)
|
||||
return;
|
||||
path = factory->createPath (fillMode);
|
||||
if (!path)
|
||||
return;
|
||||
for (const auto& e : elements)
|
||||
{
|
||||
switch (e.type)
|
||||
{
|
||||
case Element::kArc:
|
||||
{
|
||||
path->addArc (rect2CRect (e.instruction.arc.rect), e.instruction.arc.startAngle,
|
||||
e.instruction.arc.endAngle, e.instruction.arc.clockwise);
|
||||
break;
|
||||
}
|
||||
case Element::kEllipse:
|
||||
{
|
||||
path->addEllipse (rect2CRect (e.instruction.rect));
|
||||
break;
|
||||
}
|
||||
case Element::kRect:
|
||||
{
|
||||
path->addRect (rect2CRect (e.instruction.rect));
|
||||
break;
|
||||
}
|
||||
case Element::kLine:
|
||||
{
|
||||
path->addLine (point2CPoint (e.instruction.point));
|
||||
break;
|
||||
}
|
||||
case Element::kBezierCurve:
|
||||
{
|
||||
path->addBezierCurve (point2CPoint (e.instruction.curve.control1),
|
||||
point2CPoint (e.instruction.curve.control2),
|
||||
point2CPoint (e.instruction.curve.end));
|
||||
break;
|
||||
}
|
||||
case Element::kBeginSubpath:
|
||||
{
|
||||
path->beginSubpath (point2CPoint (e.instruction.point));
|
||||
break;
|
||||
}
|
||||
case Element::kCloseSubpath:
|
||||
{
|
||||
path->closeSubpath ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
path->finishBuilding ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CGraphicsPath::ensurePlatformGraphicsPathValid (PlatformGraphicsPathFillMode fillMode)
|
||||
{
|
||||
if (path == nullptr || (path->getFillMode () != PlatformGraphicsPathFillMode::Ignored &&
|
||||
path->getFillMode () != fillMode))
|
||||
{
|
||||
makePlatformGraphicsPath (fillMode);
|
||||
}
|
||||
return path != nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGraphicsPath::dirty ()
|
||||
{
|
||||
path = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CGraphicsPath::hitTest (const CPoint& p, bool evenOddFilled, CGraphicsTransform* transform)
|
||||
{
|
||||
ensurePlatformGraphicsPathValid (evenOddFilled ? PlatformGraphicsPathFillMode::Alternate
|
||||
: PlatformGraphicsPathFillMode::Winding);
|
||||
return path ? path->hitTest (p, evenOddFilled, transform) : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CPoint CGraphicsPath::getCurrentPosition ()
|
||||
{
|
||||
CPoint res;
|
||||
if (!elements.empty ())
|
||||
{
|
||||
const auto& e = elements.back ();
|
||||
switch (e.type)
|
||||
{
|
||||
case Element::kBeginSubpath:
|
||||
{
|
||||
res = point2CPoint (e.instruction.point);
|
||||
break;
|
||||
}
|
||||
case Element::kCloseSubpath:
|
||||
{
|
||||
// TODO: find opening point
|
||||
break;
|
||||
}
|
||||
case Element::kArc:
|
||||
{
|
||||
// TODO: calculate end point
|
||||
break;
|
||||
}
|
||||
case Element::kEllipse:
|
||||
{
|
||||
res = {e.instruction.rect.left +
|
||||
(e.instruction.rect.right - e.instruction.rect.left) / 2.,
|
||||
e.instruction.rect.bottom};
|
||||
break;
|
||||
}
|
||||
case Element::kRect:
|
||||
{
|
||||
res = rect2CRect (e.instruction.rect).getTopLeft ();
|
||||
break;
|
||||
}
|
||||
case Element::kLine:
|
||||
{
|
||||
res = point2CPoint (e.instruction.point);
|
||||
break;
|
||||
}
|
||||
case Element::kBezierCurve:
|
||||
{
|
||||
res = point2CPoint (e.instruction.curve.end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CRect CGraphicsPath::getBoundingBox ()
|
||||
{
|
||||
ensurePlatformGraphicsPathValid (path ? path->getFillMode ()
|
||||
: PlatformGraphicsPathFillMode::Winding);
|
||||
return path ? path->getBoundingBox () : CRect ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const PlatformGraphicsPathPtr&
|
||||
CGraphicsPath::getPlatformPath (PlatformGraphicsPathFillMode fillMode)
|
||||
{
|
||||
ensurePlatformGraphicsPathValid (fillMode);
|
||||
return path;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
Reference in New Issue
Block a user