|
|
|
@ -32,21 +32,24 @@ namespace NLGUI
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
CSSBorderRenderer::CSSBorderRenderer()
|
|
|
|
|
{
|
|
|
|
|
TopWidth = RightWidth = BottomWidth = LeftWidth = 0;
|
|
|
|
|
TopColor = RightColor = BottomColor = LeftColor = CRGBA(128, 128, 128, 255);
|
|
|
|
|
TopStyle = RightStyle = BottomStyle = LeftStyle = CSS_LINE_STYLE_SOLID;
|
|
|
|
|
CurrentAlpha = 255;
|
|
|
|
|
|
|
|
|
|
m_Scale = 1.f;
|
|
|
|
|
m_RenderLayer = 0;
|
|
|
|
|
m_ModulateGlobalColor = false;
|
|
|
|
|
|
|
|
|
|
m_Border = true;
|
|
|
|
|
m_Dirty = true;
|
|
|
|
|
m_BorderTop = m_BorderRight = m_BorderBottom = m_BorderLeft = false;
|
|
|
|
|
m_MustComputeValues = true;
|
|
|
|
|
m_XReal = 0;
|
|
|
|
|
m_YReal = 0;
|
|
|
|
|
m_WReal = 0;
|
|
|
|
|
m_HReal = 0;
|
|
|
|
|
|
|
|
|
|
m_Viewport = NULL;
|
|
|
|
|
m_FontSize = 16.f;
|
|
|
|
|
m_RootFontSize = 16.f;
|
|
|
|
|
|
|
|
|
|
m_Computed.Top = m_Computed.Right = m_Computed.Bottom = m_Computed.Left = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
@ -69,304 +72,662 @@ namespace NLGUI
|
|
|
|
|
m_WReal = w;
|
|
|
|
|
m_HReal = h;
|
|
|
|
|
|
|
|
|
|
m_Dirty = m_Border = (w > 0 && h > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left)
|
|
|
|
|
{
|
|
|
|
|
TopWidth = top;
|
|
|
|
|
RightWidth = right;
|
|
|
|
|
BottomWidth = bottom;
|
|
|
|
|
LeftWidth = left;
|
|
|
|
|
|
|
|
|
|
m_Dirty = m_Border = (top > 0 || right > 0 || bottom > 0 || left > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left)
|
|
|
|
|
{
|
|
|
|
|
TopStyle = top;
|
|
|
|
|
RightStyle = right;
|
|
|
|
|
BottomStyle = bottom;
|
|
|
|
|
LeftStyle = left;
|
|
|
|
|
|
|
|
|
|
m_Dirty = m_Border = true;
|
|
|
|
|
m_Dirty = (w > 0 && h > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left)
|
|
|
|
|
{
|
|
|
|
|
TopColor = top;
|
|
|
|
|
RightColor = right;
|
|
|
|
|
BottomColor = bottom;
|
|
|
|
|
LeftColor = left;
|
|
|
|
|
|
|
|
|
|
m_Dirty = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getTopWidth() const
|
|
|
|
|
bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style) const
|
|
|
|
|
{
|
|
|
|
|
if (TopStyle == CSS_LINE_STYLE_NONE || TopStyle == CSS_LINE_STYLE_HIDDEN)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return TopWidth;
|
|
|
|
|
return style == CSS_LINE_STYLE_DOUBLE ||
|
|
|
|
|
style == CSS_LINE_STYLE_GROOVE ||
|
|
|
|
|
style == CSS_LINE_STYLE_RIDGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getRightWidth() const
|
|
|
|
|
void CSSBorderRenderer::computeValues()
|
|
|
|
|
{
|
|
|
|
|
if (RightStyle == CSS_LINE_STYLE_NONE || RightStyle == CSS_LINE_STYLE_HIDDEN)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return RightWidth;
|
|
|
|
|
}
|
|
|
|
|
m_MustComputeValues = false;
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getBottomWidth() const
|
|
|
|
|
{
|
|
|
|
|
if (BottomStyle == CSS_LINE_STYLE_NONE || BottomStyle == CSS_LINE_STYLE_HIDDEN)
|
|
|
|
|
return 0;
|
|
|
|
|
// TODO :should save as computed value
|
|
|
|
|
sint32 vpW=0;
|
|
|
|
|
sint32 vpH=0;
|
|
|
|
|
if (m_Viewport)
|
|
|
|
|
{
|
|
|
|
|
vpW = m_Viewport->getWReal();
|
|
|
|
|
vpH = m_Viewport->getHReal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BottomWidth;
|
|
|
|
|
m_Computed.Top = m_Border.Top.empty() ? 0 : m_Border.Top.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
|
|
|
|
|
m_Computed.Right = m_Border.Right.empty() ? 0 : m_Border.Right.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
|
|
|
|
|
m_Computed.Bottom = m_Border.Bottom.empty() ? 0 : m_Border.Bottom.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
|
|
|
|
|
m_Computed.Left = m_Border.Left.empty() ? 0 : m_Border.Left.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getLeftWidth() const
|
|
|
|
|
void CSSBorderRenderer::getAdjacentBorders(EBorderSide side, EBorderSide &adjBorderL, EBorderSide &adjBorderR) const
|
|
|
|
|
{
|
|
|
|
|
if (LeftStyle == CSS_LINE_STYLE_NONE || LeftStyle == CSS_LINE_STYLE_HIDDEN)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return LeftWidth;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
adjBorderL = BORDER_TOP_LEFT;
|
|
|
|
|
adjBorderR = BORDER_TOP_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
adjBorderL = BORDER_RIGHT_BOTTOM;
|
|
|
|
|
adjBorderR = BORDER_RIGHT_TOP;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
adjBorderL = BORDER_BOTTOM_LEFT;
|
|
|
|
|
adjBorderR = BORDER_BOTTOM_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
adjBorderL = BORDER_LEFT_BOTTOM;
|
|
|
|
|
adjBorderR = BORDER_LEFT_TOP;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
adjBorderL = adjBorderR = BORDER_INVALID;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getLeftRightWidth() const
|
|
|
|
|
void CSSBorderRenderer::getAdjacentBorderWidth(EBorderSide side, sint32 &adjWidthL, sint32 &adjWidthR) const
|
|
|
|
|
{
|
|
|
|
|
return getLeftWidth() + getRightWidth();
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
adjWidthL = m_Computed.Left;
|
|
|
|
|
adjWidthR = m_Computed.Right;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
adjWidthL = m_Computed.Bottom;
|
|
|
|
|
adjWidthR = m_Computed.Top;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
adjWidthL = adjWidthR = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
uint32 CSSBorderRenderer::getTopBottomWidth() const
|
|
|
|
|
void CSSBorderRenderer::buildDotCornerStart(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
|
|
|
|
|
{
|
|
|
|
|
return getTopWidth() + getBottomWidth();
|
|
|
|
|
NLMISC::CLine line;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
line.V0.set(m_XReal + m_Computed.Left, m_YReal + m_HReal - m_Computed.Top, 0);
|
|
|
|
|
line.V1.set(m_XReal, m_YReal + m_HReal, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
line.V0.set(m_XReal + m_WReal, m_YReal, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_Computed.Bottom, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
line.V0.set(m_XReal, m_YReal, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_Computed.Left, m_YReal + m_Computed.Bottom, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
line.V0.set(m_XReal + m_Computed.Left, m_YReal + m_Computed.Bottom, 0);
|
|
|
|
|
line.V1.set(m_XReal, m_YReal, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style) const
|
|
|
|
|
void CSSBorderRenderer::buildDotCornerEnd(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
|
|
|
|
|
{
|
|
|
|
|
return style == CSS_LINE_STYLE_DOUBLE ||
|
|
|
|
|
style == CSS_LINE_STYLE_GROOVE ||
|
|
|
|
|
style == CSS_LINE_STYLE_RIDGE;
|
|
|
|
|
NLMISC::CLine line;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
line.V0.set(m_XReal + m_WReal, m_YReal + m_HReal, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_HReal - m_Computed.Top, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
line.V0.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_HReal - m_Computed.Top, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_WReal, m_YReal + m_HReal, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
line.V0.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_Computed.Bottom, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_WReal, m_YReal, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
line.V0.set(m_XReal, m_YReal + m_HReal, 0);
|
|
|
|
|
line.V1.set(m_XReal + m_Computed.Left, m_YReal + m_HReal - m_Computed.Top, 0);
|
|
|
|
|
buildDotCorner(shape, x1, y1, radius, line);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::updateCoords()
|
|
|
|
|
void CSSBorderRenderer::buildDashedBorder(EBorderSide side)
|
|
|
|
|
{
|
|
|
|
|
m_Dirty = false;
|
|
|
|
|
m_DrawBorders.clear();
|
|
|
|
|
if (!m_Border) return;
|
|
|
|
|
CSSBorder border;
|
|
|
|
|
|
|
|
|
|
sint dTop = getTopWidth(); m_BorderTop = dTop > 0;
|
|
|
|
|
sint dRight = getRightWidth(); m_BorderRight = dRight > 0;
|
|
|
|
|
sint dBottom = getBottomWidth(); m_BorderBottom = dBottom > 0;
|
|
|
|
|
sint dLeft = getLeftWidth(); m_BorderLeft = dLeft > 0;
|
|
|
|
|
|
|
|
|
|
m_Border = m_BorderTop || m_BorderRight || m_BorderBottom || m_BorderLeft;
|
|
|
|
|
if (!m_Border) return;
|
|
|
|
|
|
|
|
|
|
sint xTop = m_YReal + m_HReal;
|
|
|
|
|
sint xRight = m_XReal + m_WReal;
|
|
|
|
|
float x, y;
|
|
|
|
|
bool horizontal;
|
|
|
|
|
sint32 width, thickness;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
horizontal = true;
|
|
|
|
|
border = m_Border.Top;
|
|
|
|
|
width = m_WReal;
|
|
|
|
|
thickness = m_Computed.Top;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal + m_HReal - thickness;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
horizontal = false;
|
|
|
|
|
border = m_Border.Right;
|
|
|
|
|
width = m_HReal;
|
|
|
|
|
thickness = m_Computed.Right;
|
|
|
|
|
x = m_XReal + m_WReal - thickness;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
horizontal = true;
|
|
|
|
|
border = m_Border.Bottom;
|
|
|
|
|
width = m_WReal;
|
|
|
|
|
thickness = m_Computed.Bottom;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
horizontal = false;
|
|
|
|
|
border = m_Border.Left;
|
|
|
|
|
width = m_HReal;
|
|
|
|
|
thickness = m_Computed.Left;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sint bLeft = m_XReal + dLeft;
|
|
|
|
|
sint bRight = xRight - dRight;
|
|
|
|
|
sint bTop = xTop - dTop;
|
|
|
|
|
sint bBottom = m_YReal + dBottom;
|
|
|
|
|
if (width < 1) return;
|
|
|
|
|
if (thickness < 1) return;
|
|
|
|
|
|
|
|
|
|
SDrawBorder shape;
|
|
|
|
|
shape.Color = border.Color;
|
|
|
|
|
shape.Quad.Uv0.set(0.f, 0.f);
|
|
|
|
|
shape.Quad.Uv1.set(1.f, 0.f);
|
|
|
|
|
shape.Quad.Uv2.set(1.f, 1.f);
|
|
|
|
|
shape.Quad.Uv3.set(0.f, 1.f);
|
|
|
|
|
|
|
|
|
|
// V3 - top-left
|
|
|
|
|
// V2 - top-right
|
|
|
|
|
// V1 - bottom-right
|
|
|
|
|
// V0 - bottom-left
|
|
|
|
|
if (m_BorderTop)
|
|
|
|
|
EBorderSide adjBorderL, adjBorderR;
|
|
|
|
|
getAdjacentBorders(side, adjBorderL, adjBorderR);
|
|
|
|
|
|
|
|
|
|
sint32 adjWidthL, adjWidthR;
|
|
|
|
|
getAdjacentBorderWidth(side, adjWidthL, adjWidthR);
|
|
|
|
|
|
|
|
|
|
// get alias to x/y
|
|
|
|
|
float &xy = horizontal ? x : y;
|
|
|
|
|
|
|
|
|
|
if (border.Style == CSS_LINE_STYLE_DOTTED)
|
|
|
|
|
{
|
|
|
|
|
if (TopStyle == CSS_LINE_STYLE_INSET || TopStyle == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
shape.Color = blend(TopColor, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = TopColor;
|
|
|
|
|
// thick border with little or no content might try to draw larger dot that fits
|
|
|
|
|
float radius = std::min(thickness / 2.f, width / 2.f);
|
|
|
|
|
float dot = thickness;
|
|
|
|
|
|
|
|
|
|
shape.Quad.V3.x = m_XReal; shape.Quad.V3.y = xTop;
|
|
|
|
|
shape.Quad.V2.x = xRight; shape.Quad.V2.y = xTop;
|
|
|
|
|
shape.Quad.V1.x = bRight; shape.Quad.V1.y = bTop;
|
|
|
|
|
shape.Quad.V0.x = bLeft; shape.Quad.V0.y = bTop;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
sint32 count = std::floor((float)width / dot);
|
|
|
|
|
// 3n (dot, gap, dot) groups; count should be odd
|
|
|
|
|
if ((count % 2) == 0) count += 1;
|
|
|
|
|
|
|
|
|
|
if (hasInnerShape(TopStyle))
|
|
|
|
|
if (count == 1)
|
|
|
|
|
{
|
|
|
|
|
float iLeft, iTop, iRight;
|
|
|
|
|
if (TopStyle == CSS_LINE_STYLE_DOUBLE)
|
|
|
|
|
// fallback to single dot
|
|
|
|
|
if (horizontal)
|
|
|
|
|
{
|
|
|
|
|
iLeft = 2*dLeft / 3.f;
|
|
|
|
|
iTop = 2*dBottom / 3.f;
|
|
|
|
|
iRight = 2*dRight / 3.f;
|
|
|
|
|
} else {
|
|
|
|
|
iLeft = dLeft / 2.f;
|
|
|
|
|
iTop = dTop / 2.f;
|
|
|
|
|
iRight = dRight / 2.f;
|
|
|
|
|
x += width / 2.f;
|
|
|
|
|
y += radius;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TopStyle == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
shape.Color = blend(TopColor, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = TopColor;
|
|
|
|
|
|
|
|
|
|
// create inner border shape and remove overlapping from outer shape
|
|
|
|
|
m_DrawBorders.back().Quad.V0.x -= iLeft; m_DrawBorders.back().Quad.V0.y += iTop;
|
|
|
|
|
m_DrawBorders.back().Quad.V1.x += iRight; m_DrawBorders.back().Quad.V1.y += iTop;
|
|
|
|
|
shape.Quad.V3.x += iLeft; shape.Quad.V3.y -= iTop;
|
|
|
|
|
shape.Quad.V2.x -= iRight; shape.Quad.V2.y -= iTop;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
{
|
|
|
|
|
x += radius;
|
|
|
|
|
y += width / 2.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildDotSegments(shape, x, y, radius);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_BorderBottom)
|
|
|
|
|
{
|
|
|
|
|
if (BottomStyle == CSS_LINE_STYLE_OUTSET || BottomStyle == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
shape.Color = blend(BottomColor, CRGBA::Black, 0.5f);
|
|
|
|
|
// center-to-center spacing for dots
|
|
|
|
|
float spacing = dot + (width - dot * count) / (count-1);
|
|
|
|
|
|
|
|
|
|
x += radius;
|
|
|
|
|
y += radius;
|
|
|
|
|
|
|
|
|
|
if (adjWidthL > 0)
|
|
|
|
|
buildDotCornerStart(side, shape, x, y, radius);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = BottomColor;
|
|
|
|
|
buildDotSegments(shape, x, y, radius);
|
|
|
|
|
|
|
|
|
|
xy += spacing;
|
|
|
|
|
count--;
|
|
|
|
|
|
|
|
|
|
if (adjWidthR > 0)
|
|
|
|
|
count--;
|
|
|
|
|
|
|
|
|
|
bool isDot = false;
|
|
|
|
|
while(count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (isDot)
|
|
|
|
|
buildDotSegments(shape, x, y, radius);
|
|
|
|
|
|
|
|
|
|
isDot = !isDot;
|
|
|
|
|
xy += spacing;
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (adjWidthR > 0)
|
|
|
|
|
buildDotCornerEnd(side, shape, x, y, radius);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sint32 innerWidth = width;
|
|
|
|
|
if (adjWidthL > 0) innerWidth -= adjWidthL;
|
|
|
|
|
if (adjWidthR > 0) innerWidth -= adjWidthR;
|
|
|
|
|
|
|
|
|
|
sint32 count = std::floor((float)innerWidth * 2.f / (thickness * 3));
|
|
|
|
|
|
|
|
|
|
shape.Quad.V3.x = bLeft; shape.Quad.V3.y = bBottom;
|
|
|
|
|
shape.Quad.V2.x = bRight; shape.Quad.V2.y = bBottom;
|
|
|
|
|
shape.Quad.V1.x = xRight; shape.Quad.V1.y = m_YReal;
|
|
|
|
|
shape.Quad.V0.x = m_XReal; shape.Quad.V0.y = m_YReal;
|
|
|
|
|
if ((float)innerWidth < 2.f * thickness)
|
|
|
|
|
{
|
|
|
|
|
buildSolidBorder(side);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4n groups (halfDash, halfGap, halfGap, halfDash)
|
|
|
|
|
if ((count % 4) == 1) count += 3;
|
|
|
|
|
else if ((count % 4) == 2) count += 2;
|
|
|
|
|
else if ((count % 4) == 3) count += 1;
|
|
|
|
|
|
|
|
|
|
float halfDash = (float)innerWidth / (float)count;
|
|
|
|
|
float fullDash = halfDash * 2.f;
|
|
|
|
|
|
|
|
|
|
// draw half dash or full corner
|
|
|
|
|
makeBorderQuad(side, shape, x, y, adjWidthL + halfDash, thickness);
|
|
|
|
|
if (adjWidthL > 0)
|
|
|
|
|
makeCornerQuad(adjBorderL, shape);
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
xy += adjWidthL + halfDash;
|
|
|
|
|
|
|
|
|
|
// start/end half dash that are merged with corners
|
|
|
|
|
count -= 2;
|
|
|
|
|
|
|
|
|
|
if (hasInnerShape(BottomStyle))
|
|
|
|
|
bool isDash = false;
|
|
|
|
|
while(count > 0)
|
|
|
|
|
{
|
|
|
|
|
float iLeft, iBottom, iRight;
|
|
|
|
|
if (BottomStyle == CSS_LINE_STYLE_DOUBLE)
|
|
|
|
|
if (isDash)
|
|
|
|
|
{
|
|
|
|
|
iLeft = 2*dLeft / 3.f;
|
|
|
|
|
iBottom = 2*dBottom / 3.f;
|
|
|
|
|
iRight = 2*dRight / 3.f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
iLeft = dLeft / 2.f;
|
|
|
|
|
iBottom = dBottom / 2.f;
|
|
|
|
|
iRight = dRight / 2.f;
|
|
|
|
|
makeBorderQuad(side, shape, x, y, fullDash, thickness);
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
isDash = !isDash;
|
|
|
|
|
|
|
|
|
|
if (BottomStyle == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
shape.Color = blend(shape.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = BottomColor;
|
|
|
|
|
|
|
|
|
|
m_DrawBorders.back().Quad.V2.x += iRight; m_DrawBorders.back().Quad.V2.y -= iBottom;
|
|
|
|
|
m_DrawBorders.back().Quad.V3.x -= iLeft; m_DrawBorders.back().Quad.V3.y -= iBottom;
|
|
|
|
|
shape.Quad.V1.x -= iRight; shape.Quad.V1.y += iBottom;
|
|
|
|
|
shape.Quad.V0.x += iLeft; shape.Quad.V0.y += iBottom;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
xy += fullDash;
|
|
|
|
|
count -= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw half dash or full corner
|
|
|
|
|
makeBorderQuad(side, shape, x, y, adjWidthR + halfDash, thickness);
|
|
|
|
|
if (adjWidthR > 0)
|
|
|
|
|
makeCornerQuad(adjBorderR, shape);
|
|
|
|
|
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_BorderRight)
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::buildSolidBorder(EBorderSide side)
|
|
|
|
|
{
|
|
|
|
|
float x, y;
|
|
|
|
|
sint width, thickness;
|
|
|
|
|
CSSBorder border;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
if (RightStyle == CSS_LINE_STYLE_OUTSET || RightStyle == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
shape.Color = blend(RightColor, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = RightColor;
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
border = m_Border.Top;
|
|
|
|
|
width = m_WReal;
|
|
|
|
|
thickness = m_Computed.Top;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal + m_HReal - thickness;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
border = m_Border.Right;
|
|
|
|
|
width = m_HReal;
|
|
|
|
|
thickness = m_Computed.Right;
|
|
|
|
|
x = m_XReal + m_WReal - thickness;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
border = m_Border.Bottom;
|
|
|
|
|
width = m_WReal;
|
|
|
|
|
thickness = m_Computed.Bottom;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
border = m_Border.Left;
|
|
|
|
|
width = m_HReal;
|
|
|
|
|
thickness = m_Computed.Left;
|
|
|
|
|
x = m_XReal;
|
|
|
|
|
y = m_YReal;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDrawBorder shape;
|
|
|
|
|
shape.Color = border.Color;
|
|
|
|
|
shape.Quad.Uv0.set(0.f, 0.f);
|
|
|
|
|
shape.Quad.Uv1.set(1.f, 0.f);
|
|
|
|
|
shape.Quad.Uv2.set(1.f, 1.f);
|
|
|
|
|
shape.Quad.Uv3.set(0.f, 1.f);
|
|
|
|
|
|
|
|
|
|
if (border.Style == CSS_LINE_STYLE_INSET && (side == BORDER_TOP || side == BORDER_LEFT))
|
|
|
|
|
shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
else if (border.Style == CSS_LINE_STYLE_OUTSET && (side == BORDER_BOTTOM || side == BORDER_RIGHT))
|
|
|
|
|
shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
|
|
|
|
|
// solid border
|
|
|
|
|
{
|
|
|
|
|
EBorderSide adjBorderL, adjBorderR;
|
|
|
|
|
getAdjacentBorders(side, adjBorderL, adjBorderR);
|
|
|
|
|
|
|
|
|
|
makeBorderQuad(side, shape, x, y, width, thickness);
|
|
|
|
|
makeCornerQuad(adjBorderL, shape);
|
|
|
|
|
makeCornerQuad(adjBorderR, shape);
|
|
|
|
|
|
|
|
|
|
shape.Quad.V3.x = bRight; shape.Quad.V3.y = bTop;
|
|
|
|
|
shape.Quad.V2.x = xRight; shape.Quad.V2.y = xTop;
|
|
|
|
|
shape.Quad.V1.x = xRight; shape.Quad.V1.y = m_YReal;
|
|
|
|
|
shape.Quad.V0.x = bRight; shape.Quad.V0.y = bBottom;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasInnerShape(RightStyle))
|
|
|
|
|
if (hasInnerShape(border.Style))
|
|
|
|
|
{
|
|
|
|
|
if (side == BORDER_TOP || side == BORDER_LEFT)
|
|
|
|
|
{
|
|
|
|
|
float iTop, iRight, iBottom;
|
|
|
|
|
if (RightStyle == CSS_LINE_STYLE_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
iTop = 2*dTop / 3.f;
|
|
|
|
|
iRight = 2*dRight / 3.f;
|
|
|
|
|
iBottom = 2*dBottom / 3.f;
|
|
|
|
|
} else {
|
|
|
|
|
iTop = dTop / 2.f;
|
|
|
|
|
iRight = dRight / 2.f;
|
|
|
|
|
iBottom = dBottom / 2.f;
|
|
|
|
|
}
|
|
|
|
|
if (border.Style == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
m_DrawBorders.back().Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
else if (border.Style == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
else if (side == BORDER_BOTTOM || side == BORDER_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
if (border.Style == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
else if (border.Style == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
m_DrawBorders.back().Color = blend(border.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RightStyle == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
shape.Color = blend(shape.Color, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = RightColor;
|
|
|
|
|
sint32 adjWidthL, adjWidthR;
|
|
|
|
|
getAdjacentBorderWidth(side, adjWidthL, adjWidthR);
|
|
|
|
|
|
|
|
|
|
float iStart, iMiddle, iEnd;
|
|
|
|
|
if (border.Style == CSS_LINE_STYLE_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
iStart = 2 * adjWidthL / 3.f;
|
|
|
|
|
iMiddle = 2 * thickness / 3.f;
|
|
|
|
|
iEnd = 2 * adjWidthR / 3.f;
|
|
|
|
|
} else {
|
|
|
|
|
iStart = adjWidthL / 2.f;
|
|
|
|
|
iMiddle = thickness / 2.f;
|
|
|
|
|
iEnd = adjWidthR / 2.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_DrawBorders.back().Quad.V3.x += iRight; m_DrawBorders.back().Quad.V3.y += iTop;
|
|
|
|
|
m_DrawBorders.back().Quad.V0.x += iRight; m_DrawBorders.back().Quad.V0.y -= iBottom;
|
|
|
|
|
shape.Quad.V2.x -= iRight; shape.Quad.V2.y -= iTop;
|
|
|
|
|
shape.Quad.V1.x -= iRight; shape.Quad.V1.y += iBottom;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
// create inner shape and remove overlapping from outer shape
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP:
|
|
|
|
|
m_DrawBorders.back().Quad.V0.x -= iStart; m_DrawBorders.back().Quad.V0.y += iMiddle;
|
|
|
|
|
m_DrawBorders.back().Quad.V1.x += iEnd; m_DrawBorders.back().Quad.V1.y += iMiddle;
|
|
|
|
|
shape.Quad.V3.x += iStart; shape.Quad.V3.y -= iMiddle;
|
|
|
|
|
shape.Quad.V2.x -= iEnd; shape.Quad.V2.y -= iMiddle;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_BOTTOM:
|
|
|
|
|
m_DrawBorders.back().Quad.V2.x += iEnd; m_DrawBorders.back().Quad.V2.y -= iMiddle;
|
|
|
|
|
m_DrawBorders.back().Quad.V3.x -= iStart; m_DrawBorders.back().Quad.V3.y -= iMiddle;
|
|
|
|
|
shape.Quad.V1.x -= iEnd; shape.Quad.V1.y += iMiddle;
|
|
|
|
|
shape.Quad.V0.x += iStart; shape.Quad.V0.y += iMiddle;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_RIGHT:
|
|
|
|
|
m_DrawBorders.back().Quad.V3.x += iMiddle; m_DrawBorders.back().Quad.V3.y += iEnd;
|
|
|
|
|
m_DrawBorders.back().Quad.V0.x += iMiddle; m_DrawBorders.back().Quad.V0.y -= iStart;
|
|
|
|
|
shape.Quad.V2.x -= iMiddle; shape.Quad.V2.y -= iEnd;
|
|
|
|
|
shape.Quad.V1.x -= iMiddle; shape.Quad.V1.y += iStart;
|
|
|
|
|
break;
|
|
|
|
|
case BORDER_LEFT:
|
|
|
|
|
m_DrawBorders.back().Quad.V2.x -= iMiddle; m_DrawBorders.back().Quad.V2.y += iEnd;
|
|
|
|
|
m_DrawBorders.back().Quad.V1.x -= iMiddle; m_DrawBorders.back().Quad.V1.y -= iStart;
|
|
|
|
|
shape.Quad.V3.x += iMiddle; shape.Quad.V3.y -= iEnd;
|
|
|
|
|
shape.Quad.V0.x += iMiddle; shape.Quad.V0.y += iStart;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_BorderLeft)
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::makeBorderQuad(EBorderSide side, SDrawBorder &shape, float x, float y, float width, float thickness) const
|
|
|
|
|
{
|
|
|
|
|
float quadW, quadH;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
if (LeftStyle == CSS_LINE_STYLE_INSET || LeftStyle == CSS_LINE_STYLE_GROOVE)
|
|
|
|
|
shape.Color = blend(LeftColor, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = LeftColor;
|
|
|
|
|
case BORDER_TOP: quadW = width; quadH = thickness; break;
|
|
|
|
|
case BORDER_BOTTOM:quadW = width; quadH = thickness; break;
|
|
|
|
|
case BORDER_LEFT: quadW = thickness; quadH = width; break;
|
|
|
|
|
case BORDER_RIGHT: quadW = thickness; quadH = width; break;
|
|
|
|
|
default: return;
|
|
|
|
|
}
|
|
|
|
|
shape.Quad.V3.x = x; shape.Quad.V3.y = y + quadH;
|
|
|
|
|
shape.Quad.V2.x = x + quadW; shape.Quad.V2.y = y + quadH;
|
|
|
|
|
shape.Quad.V1.x = x + quadW; shape.Quad.V1.y = y;
|
|
|
|
|
shape.Quad.V0.x = x; shape.Quad.V0.y = y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shape.Quad.V3.x = m_XReal; shape.Quad.V3.y = xTop;
|
|
|
|
|
shape.Quad.V2.x = bLeft; shape.Quad.V2.y = bTop;
|
|
|
|
|
shape.Quad.V1.x = bLeft; shape.Quad.V1.y = bBottom;
|
|
|
|
|
shape.Quad.V0.x = m_XReal; shape.Quad.V0.y = m_YReal;
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::makeCornerQuad(EBorderSide side, SDrawBorder &shape) const
|
|
|
|
|
{
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case BORDER_TOP_LEFT: shape.Quad.V0.x += m_Computed.Left; break;
|
|
|
|
|
case BORDER_TOP_RIGHT: shape.Quad.V1.x -= m_Computed.Right; break;
|
|
|
|
|
case BORDER_RIGHT_TOP: shape.Quad.V3.y -= m_Computed.Top; break;
|
|
|
|
|
case BORDER_RIGHT_BOTTOM: shape.Quad.V0.y += m_Computed.Bottom; break;
|
|
|
|
|
case BORDER_BOTTOM_LEFT: shape.Quad.V3.x += m_Computed.Left; break;
|
|
|
|
|
case BORDER_BOTTOM_RIGHT: shape.Quad.V2.x -= m_Computed.Right; break;
|
|
|
|
|
case BORDER_LEFT_TOP: shape.Quad.V2.y -= m_Computed.Top; break;
|
|
|
|
|
case BORDER_LEFT_BOTTOM: shape.Quad.V1.y += m_Computed.Bottom; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
static bool getCircleLineIntersection(float x, float y, float r, const NLMISC::CLine &line, NLMISC::CLine &result)
|
|
|
|
|
{
|
|
|
|
|
float dx = line.V0.x - line.V1.x;
|
|
|
|
|
float dy = line.V0.y - line.V1.y;
|
|
|
|
|
float rx = line.V0.x-x;
|
|
|
|
|
float ry = line.V0.y-y;
|
|
|
|
|
float a = dx*dx + dy*dy;
|
|
|
|
|
float b = 2*(dx * rx + dy * ry);
|
|
|
|
|
float c = rx * rx + ry * ry - r*r;
|
|
|
|
|
float d = b*b - 4 * a * c;
|
|
|
|
|
|
|
|
|
|
if (d < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (d == 0)
|
|
|
|
|
{
|
|
|
|
|
// single intersection
|
|
|
|
|
//float t = -b / (2*a);
|
|
|
|
|
//result.V0.x = result.V1.x = line.V0.x + t * dx;
|
|
|
|
|
//result.V0.y = result.V1.y = line.V0.y + t * dy;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float t;
|
|
|
|
|
t = (-b + sqrt(d)) / (2 * a);
|
|
|
|
|
result.V0.x = line.V0.x + t * dx;
|
|
|
|
|
result.V0.y = line.V0.y + t * dy;
|
|
|
|
|
|
|
|
|
|
t = (-b - sqrt(d)) / (2 * a);
|
|
|
|
|
result.V1.x = line.V0.x + t * dx;
|
|
|
|
|
result.V1.y = line.V0.y + t * dy;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::buildDotCorner(SDrawBorder shape, float cX, float cY, float cR, const NLMISC::CLine &line)
|
|
|
|
|
{
|
|
|
|
|
static const float twopi = 2 * NLMISC::Pi;
|
|
|
|
|
NLMISC::CLine out;
|
|
|
|
|
if (getCircleLineIntersection(cX, cY, cR, line, out))
|
|
|
|
|
{
|
|
|
|
|
float fromAngle = std::atan2(out.V0.y - cY, out.V0.x - cX);
|
|
|
|
|
float toAngle = std::atan2(out.V1.y - cY, out.V1.x - cX);
|
|
|
|
|
if (fromAngle < 0) fromAngle += twopi;
|
|
|
|
|
if (toAngle < 0) toAngle += twopi;
|
|
|
|
|
fromAngle /= twopi;
|
|
|
|
|
toAngle /= twopi;
|
|
|
|
|
buildDotSegments(shape, cX, cY, cR, fromAngle, toAngle);
|
|
|
|
|
} else {
|
|
|
|
|
buildDotSegments(shape, cX, cY, cR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::buildDotSegments(SDrawBorder shape, float x, float y, float radius, float fromAngle, float toAngle)
|
|
|
|
|
{
|
|
|
|
|
static const float pi = (float)NLMISC::Pi;
|
|
|
|
|
static const float twopi = (float)(NLMISC::Pi * 2);
|
|
|
|
|
static const uint minSectors = 12;
|
|
|
|
|
|
|
|
|
|
// use single quad if dot is small
|
|
|
|
|
if (2 * radius * m_Scale < 4)
|
|
|
|
|
{
|
|
|
|
|
makeBorderQuad(BORDER_TOP, shape, x - radius, y - radius, radius * 2, radius * 2);
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasInnerShape(LeftStyle))
|
|
|
|
|
{
|
|
|
|
|
if (LeftStyle == CSS_LINE_STYLE_RIDGE)
|
|
|
|
|
shape.Color = blend(LeftColor, CRGBA::Black, 0.5f);
|
|
|
|
|
else
|
|
|
|
|
shape.Color = LeftColor;
|
|
|
|
|
// number of sectors for full circle
|
|
|
|
|
uint sectors = std::max(minSectors, (uint)std::ceil(radius * m_Scale));
|
|
|
|
|
|
|
|
|
|
float iTop, iLeft, iBottom;
|
|
|
|
|
if (LeftStyle == CSS_LINE_STYLE_DOUBLE)
|
|
|
|
|
{
|
|
|
|
|
iTop = 2*dTop / 3.f;
|
|
|
|
|
iLeft = 2*dLeft / 3.f;
|
|
|
|
|
iBottom = 2*dBottom / 3.f;
|
|
|
|
|
} else {
|
|
|
|
|
iTop = dTop / 2.f;
|
|
|
|
|
iLeft = dLeft / 2.f;
|
|
|
|
|
dBottom = dBottom / 2.f;
|
|
|
|
|
}
|
|
|
|
|
float arcLength;
|
|
|
|
|
if (toAngle < fromAngle)
|
|
|
|
|
arcLength = twopi * (1 + toAngle - fromAngle);
|
|
|
|
|
else
|
|
|
|
|
arcLength = twopi * (toAngle - fromAngle);
|
|
|
|
|
|
|
|
|
|
m_DrawBorders.back().Quad.V2.x -= iLeft; m_DrawBorders.back().Quad.V2.y += iTop;
|
|
|
|
|
m_DrawBorders.back().Quad.V1.x -= iLeft; m_DrawBorders.back().Quad.V1.y -= iBottom;
|
|
|
|
|
shape.Quad.V3.x += iLeft; shape.Quad.V3.y -= iTop;
|
|
|
|
|
shape.Quad.V0.x += iLeft; shape.Quad.V0.y += iBottom;
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
// sectors to draw
|
|
|
|
|
float arcSectors = ceil(arcLength * sectors / twopi );
|
|
|
|
|
float arcSectorLength = arcLength / arcSectors;
|
|
|
|
|
|
|
|
|
|
if (arcSectors <= 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (arcLength < pi)
|
|
|
|
|
{
|
|
|
|
|
// only small segment is visible
|
|
|
|
|
float px1 = x + radius * cosf(twopi * fromAngle);
|
|
|
|
|
float py1 = y + radius * sinf(twopi * fromAngle);
|
|
|
|
|
float px2 = x + radius * cosf(twopi * toAngle);
|
|
|
|
|
float py2 = y + radius * sinf(twopi * toAngle);
|
|
|
|
|
float cx = (px1 + px2) / 2.f;
|
|
|
|
|
float cy = (py1 + py2) / 2.f;
|
|
|
|
|
shape.Quad.V0.x = cx; shape.Quad.V0.y = cy;
|
|
|
|
|
shape.Quad.V1.x = cx; shape.Quad.V1.y = cy;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
shape.Quad.V0.x = x; shape.Quad.V0.y = y;
|
|
|
|
|
shape.Quad.V1.x = x; shape.Quad.V1.y = y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float a1 = fromAngle * twopi;
|
|
|
|
|
uint step;
|
|
|
|
|
for(step = 0; step < (uint)arcSectors; step++)
|
|
|
|
|
{
|
|
|
|
|
float a2 = a1 + arcSectorLength;
|
|
|
|
|
|
|
|
|
|
shape.Quad.V2.x = x + radius * cosf(a1); shape.Quad.V2.y = y + radius * sinf(a1);
|
|
|
|
|
shape.Quad.V3.x = x + radius * cosf(a2); shape.Quad.V3.y = y + radius * sinf(a2);
|
|
|
|
|
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
|
|
|
|
|
a1 = a2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build last sector if requested range is over 180deg
|
|
|
|
|
if (arcLength > pi && arcLength < twopi)
|
|
|
|
|
{
|
|
|
|
|
float a2 = fromAngle * twopi;
|
|
|
|
|
shape.Quad.V2.x = x + radius * cosf(a1); shape.Quad.V2.y = y + radius * sinf(a1);
|
|
|
|
|
shape.Quad.V3.x = x + radius * cosf(a2); shape.Quad.V3.y = y + radius * sinf(a2);
|
|
|
|
|
m_DrawBorders.push_back(shape);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::updateCoords()
|
|
|
|
|
{
|
|
|
|
|
m_Dirty = false;
|
|
|
|
|
m_DrawBorders.clear();
|
|
|
|
|
|
|
|
|
|
if (m_MustComputeValues)
|
|
|
|
|
computeValues();
|
|
|
|
|
|
|
|
|
|
if (m_Computed.Top > 0 && m_Border.Top.Color.A > 0)
|
|
|
|
|
{
|
|
|
|
|
if (m_Border.Top.Style == CSS_LINE_STYLE_DASHED || m_Border.Top.Style == CSS_LINE_STYLE_DOTTED)
|
|
|
|
|
buildDashedBorder(BORDER_TOP);
|
|
|
|
|
else
|
|
|
|
|
buildSolidBorder(BORDER_TOP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_Computed.Bottom > 0 && m_Border.Bottom.Color.A > 0)
|
|
|
|
|
{
|
|
|
|
|
if (m_Border.Bottom.Style == CSS_LINE_STYLE_DASHED || m_Border.Bottom.Style == CSS_LINE_STYLE_DOTTED)
|
|
|
|
|
buildDashedBorder(BORDER_BOTTOM);
|
|
|
|
|
else
|
|
|
|
|
buildSolidBorder(BORDER_BOTTOM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_Computed.Right > 0 && m_Border.Right.Color.A > 0)
|
|
|
|
|
{
|
|
|
|
|
if (m_Border.Right.Style == CSS_LINE_STYLE_DASHED || m_Border.Right.Style == CSS_LINE_STYLE_DOTTED)
|
|
|
|
|
buildDashedBorder(BORDER_RIGHT);
|
|
|
|
|
else
|
|
|
|
|
buildSolidBorder(BORDER_RIGHT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_Computed.Left > 0 && m_Border.Left.Color.A > 0)
|
|
|
|
|
{
|
|
|
|
|
if (m_Border.Left.Style == CSS_LINE_STYLE_DASHED || m_Border.Left.Style == CSS_LINE_STYLE_DOTTED)
|
|
|
|
|
buildDashedBorder(BORDER_LEFT);
|
|
|
|
|
else
|
|
|
|
|
buildSolidBorder(BORDER_LEFT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
void CSSBorderRenderer::draw() {
|
|
|
|
|
if (m_Dirty) updateCoords();
|
|
|
|
|
if (!m_Border) return;
|
|
|
|
|
if (m_DrawBorders.empty()) return;
|
|
|
|
|
|
|
|
|
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
|
|
|
|
|
|
|
|
|
// TODO: no need for widget manager, if global color is set from parent
|
|
|
|
|
CRGBA globalColor;
|
|
|
|
|
if (m_ModulateGlobalColor)
|
|
|
|
|
globalColor = CWidgetManager::getInstance()->getGlobalColor();
|
|
|
|
|