Dotted/dashed border styles

develop
Nimetu 3 years ago
parent 2046c4bf6e
commit 37eec8cd7f

@ -0,0 +1,72 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010-2019 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CL_CSS_BORDER_H
#define CL_CSS_BORDER_H
#include "nel/misc/types_nl.h"
#include "nel/misc/rgba.h"
#include "nel/gui/css_types.h"
#include "nel/gui/css_length.h"
namespace NLGUI
{
/**
* \brief CSS border info
* \date 2021-07-23 09:51 GMT
* \author Meelis Mägi (Nimetu)
*/
class CSSBorder
{
public:
CSSBorder()
{
reset();
}
CSSBorder(uint width, CSSLineStyle style, NLMISC::CRGBA color)
{
set(width, style, color);
}
void reset()
{
set(CSS_LINE_WIDTH_MEDIUM, CSS_LINE_STYLE_NONE, NLMISC::CRGBA::Transparent);
}
void set(uint width, CSSLineStyle style, NLMISC::CRGBA color)
{
Width.setFloatValue(width, "px");
Style = style;
Color = color;
}
bool empty() const
{
return Style == CSS_LINE_STYLE_NONE || Style == CSS_LINE_STYLE_HIDDEN
|| Width.getFloat() == 0;
}
CSSLength Width;
CSSLineStyle Style;
NLMISC::CRGBA Color;
};
}//namespace
#endif // CL_CSS_BORDER_H

@ -23,9 +23,12 @@
#include "nel/misc/rgba.h"
#include "nel/misc/geom_ext.h"
#include "nel/gui/css_types.h"
#include "nel/gui/css_border.h"
namespace NLGUI
{
class CInterfaceElement;
/**
* \brief Border renderer for GUI classes
* \date 2019-09-03 10:50 GMT
@ -34,6 +37,22 @@ namespace NLGUI
class CSSBorderRenderer
{
private:
enum EBorderSide
{
BORDER_TOP_LEFT = 0,
BORDER_TOP_RIGHT,
BORDER_BOTTOM_LEFT,
BORDER_BOTTOM_RIGHT,
BORDER_LEFT_TOP,
BORDER_RIGHT_TOP,
BORDER_LEFT_BOTTOM,
BORDER_RIGHT_BOTTOM,
BORDER_TOP,
BORDER_RIGHT,
BORDER_BOTTOM,
BORDER_LEFT,
BORDER_INVALID
};
// parent element screen coordinates
sint32 m_XReal, m_YReal;
sint32 m_WReal, m_HReal;
@ -50,15 +69,44 @@ namespace NLGUI
// if true, then updateCoords() is called from draw()
bool m_Dirty;
// if true, then at least one border is set
bool m_Border;
bool m_BorderTop, m_BorderRight, m_BorderBottom, m_BorderLeft;
// UI scale, used to calculate number of segments to draw for circle
float m_Scale;
public:
uint32 TopWidth, RightWidth, BottomWidth, LeftWidth;
NLMISC::CRGBA TopColor, RightColor, BottomColor, LeftColor;
CSSLineStyle TopStyle, RightStyle, BottomStyle, LeftStyle;
CSSRect<CSSBorder> m_Border;
CSSRect<sint32> m_Computed;
// font size for 'rem'
float m_RootFontSize;
// font size for 'em'
float m_FontSize;
// if true, then CSSLength values are recomputed
bool m_MustComputeValues;
// viewport element for vw,wh,vmin,vmax
CInterfaceElement* m_Viewport;
// update CSSLength values
void computeValues();
void getAdjacentBorders(EBorderSide side, EBorderSide &adjBorderL, EBorderSide &adjBorderR) const;
void getAdjacentBorderWidth(EBorderSide side, sint32 &adjWidthL, sint32 &adjWidthR) const;
// dot
void buildDotCornerStart(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius);
void buildDotCornerEnd(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius);
void buildDotCorner(SDrawBorder shape, float x, float y, float r, const NLMISC::CLine &line);
// draw circle, angle is CCW between 0..1 (3'o'clock being 0deg).
void buildDotSegments(SDrawBorder shape, float x, float y, float radius, float fromAngle=0.f, float toAngle=1.f);
// dash
void makeBorderQuad(EBorderSide side, SDrawBorder &shape, float x, float y, float width, float thickness) const;
void makeCornerQuad(EBorderSide side, SDrawBorder &shape) const;
void buildDashedBorder(EBorderSide side);
void buildSolidBorder(EBorderSide side);
bool hasInnerShape(CSSLineStyle style) const;
public:
// alpha value from parent
uint8 CurrentAlpha;
@ -70,23 +118,67 @@ namespace NLGUI
void setRect(sint32 x, sint32 y, sint32 w, sint32 h);
void setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left);
void setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left);
void setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left);
void setBorder(const CSSRect<CSSBorder> &b) { m_Dirty = true; m_Border = b; }
void updateCoords();
void invalidateCoords() { m_Dirty = m_Border = true; }
void invalidateContent() { m_Dirty = m_Border = true; };
void invalidateCoords() { m_Dirty = true; }
void invalidateContent() { m_Dirty = true; }
uint32 getTopWidth() const;
uint32 getRightWidth() const;
uint32 getBottomWidth() const;
uint32 getLeftWidth() const;
bool isEmpty() const {
return (m_Border.Top.Width.getFloat() +
m_Border.Right.Width.getFloat() +
m_Border.Bottom.Width.getFloat() +
m_Border.Left.Width.getFloat()) == 0;
}
uint32 getLeftRightWidth() const;
uint32 getTopBottomWidth() const;
uint32 getTopWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Top; }
uint32 getRightWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Right; }
uint32 getBottomWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Bottom; }
uint32 getLeftWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Left; }
bool hasInnerShape(CSSLineStyle style) const;
uint32 getLeftRightWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Left + m_Computed.Right; }
uint32 getTopBottomWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Top + m_Computed.Bottom; }
NLMISC::CRGBA getTopColor() const { return m_Border.Top.Color; }
NLMISC::CRGBA getRightColor() const { return m_Border.Right.Color; }
NLMISC::CRGBA getBottomColor() const { return m_Border.Bottom.Color; }
NLMISC::CRGBA getLeftColor() const { return m_Border.Left.Color; }
void setWidth(uint width)
{
m_Dirty = true;
m_MustComputeValues = true;
m_Border.Top.Width.setFloatValue(width, "px");
m_Border.Right.Width.setFloatValue(width, "px");
m_Border.Bottom.Width.setFloatValue(width, "px");
m_Border.Left.Width.setFloatValue(width, "px");
}
void setColor(const NLMISC::CRGBA &color)
{
m_Dirty = true;
m_Border.Top.Color = color;
m_Border.Right.Color = color;
m_Border.Bottom.Color = color;
m_Border.Left.Color = color;
}
// sizes for em, rem units
void setFontSize(float rootFontSize, float fontSize)
{
m_Dirty = true;
m_MustComputeValues = true;
m_RootFontSize = rootFontSize;
m_FontSize = fontSize;
}
void setViewport(CInterfaceElement *root)
{
m_Dirty = true;
m_MustComputeValues = true;
m_Viewport = root;
}
void draw();
}; // CSSBorderRenderer

@ -23,6 +23,7 @@
#include "nel/gui/css_types.h"
#include "nel/gui/css_length.h"
#include "nel/gui/css_background.h"
#include "nel/gui/css_border.h"
namespace NLGUI
{
@ -67,10 +68,6 @@ namespace NLGUI
Height=-1;
MaxWidth=-1;
MaxHeight=-1;
// border style
BorderTopWidth = BorderRightWidth = BorderBottomWidth = BorderLeftWidth = CSS_LINE_WIDTH_MEDIUM;
BorderTopStyle = BorderRightStyle = BorderBottomStyle = BorderLeftStyle = CSS_LINE_STYLE_NONE;
BorderTopColor = BorderRightColor = BorderBottomColor = BorderLeftColor = NLMISC::CRGBA::Transparent;
// background
BackgroundColorOver=NLMISC::CRGBA::Black;
MarginTop = MarginRight = MarginBottom = MarginLeft = 0;
@ -103,9 +100,7 @@ namespace NLGUI
sint32 Height;
sint32 MaxWidth;
sint32 MaxHeight;
uint32 BorderTopWidth, BorderRightWidth, BorderBottomWidth, BorderLeftWidth;
CSSLineStyle BorderTopStyle, BorderRightStyle, BorderBottomStyle, BorderLeftStyle;
NLMISC::CRGBA BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor;
CSSRect<CSSBorder> Border;
CSSBackground Background;
NLMISC::CRGBA BackgroundColorOver;
uint32 MarginTop, MarginRight, MarginBottom, MarginLeft;
@ -187,7 +182,7 @@ namespace NLGUI
void expandShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
// parse string value into corresponding value
void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const;
void applyBorderWidth(const std::string &value, CSSLength *dest, const CSSLength &currentWidth) const;
void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA &currentColor, const NLMISC::CRGBA &textColor) const;
void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle &currentStyle) const;
void applyPaddingWidth(const std::string &value, uint32 *dest, const uint32 currentPadding, uint32 fontSize) const;
@ -226,9 +221,10 @@ namespace NLGUI
Current.MaxWidth=-1;
Current.MaxHeight=-1;
Current.BorderTopWidth = Current.BorderRightWidth = Current.BorderBottomWidth = Current.BorderLeftWidth = CSS_LINE_WIDTH_MEDIUM;
Current.BorderTopStyle = Current.BorderRightStyle = Current.BorderBottomStyle = Current.BorderLeftStyle = CSS_LINE_STYLE_NONE;
Current.BorderTopColor = Current.BorderRightColor = Current.BorderBottomColor = Current.BorderLeftColor = Current.TextColor;
Current.Border.Top.reset();
Current.Border.Right.reset();
Current.Border.Bottom.reset();
Current.Border.Left.reset();
Current.Background = CSSBackground();
Current.BackgroundColorOver = NLMISC::CRGBA::Transparent;

@ -85,6 +85,15 @@ namespace NLGUI
CSS_VALUE_CONTAIN
};
template<typename T>
struct CSSRect
{
T Top;
T Right;
T Bottom;
T Left;
};
}//namespace
#endif // CL_CSS_TYPES_H

@ -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();

@ -504,7 +504,7 @@ namespace NLGUI
}
}
void CCssStyle::applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const
void CCssStyle::applyBorderWidth(const std::string &value, CSSLength *dest, const CSSLength &currentWidth) const
{
if (!dest) return;
if (value == "inherit")
@ -513,37 +513,19 @@ namespace NLGUI
}
else if (value == "thin")
{
*dest = 1;
dest->setFloatValue(1, "px");
}
else if (value == "medium")
{
*dest = 3;
dest->setFloatValue(3, "px");
}
else if (value == "thick")
{
*dest = 5;
}
else if (value == "0")
{
*dest = 0;
dest->setFloatValue(5, "px");
}
else
{
float tmpf;
std::string unit;
if (getCssLength(tmpf, unit, value.c_str()))
{
if (unit == "rem")
*dest = fontSize * tmpf;
else if (unit == "em")
*dest = fontSize * tmpf;
else if (unit == "pt")
*dest = tmpf / 0.75f;
else if (unit == "%")
*dest = 0; // no support for % in border width
else
*dest = tmpf;
}
dest->parseValue(value, false, false);
}
}
@ -656,18 +638,18 @@ namespace NLGUI
TStyle::const_iterator it;
for (it=style.StyleRules.begin(); it != style.StyleRules.end(); ++it)
{
if (it->first == "border-top-width") applyBorderWidth(it->second, &style.BorderTopWidth, current.BorderTopWidth, current.FontSize);
else if (it->first == "border-top-color") applyBorderColor(it->second, &style.BorderTopColor, current.BorderTopColor, current.TextColor);
else if (it->first == "border-top-style") applyLineStyle(it->second, &style.BorderTopStyle, current.BorderTopStyle);
else if (it->first == "border-right-width") applyBorderWidth(it->second, &style.BorderRightWidth, current.BorderRightWidth, current.FontSize);
else if (it->first == "border-right-color") applyBorderColor(it->second, &style.BorderRightColor, current.BorderRightColor, current.TextColor);
else if (it->first == "border-right-style") applyLineStyle(it->second, &style.BorderRightStyle, current.BorderRightStyle);
else if (it->first == "border-bottom-width") applyBorderWidth(it->second, &style.BorderBottomWidth, current.BorderBottomWidth, current.FontSize);
else if (it->first == "border-bottom-color") applyBorderColor(it->second, &style.BorderBottomColor, current.BorderBottomColor, current.TextColor);
else if (it->first == "border-bottom-style") applyLineStyle(it->second, &style.BorderBottomStyle, current.BorderBottomStyle);
else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.BorderLeftWidth, current.BorderLeftWidth, current.FontSize);
else if (it->first == "border-left-color") applyBorderColor(it->second, &style.BorderLeftColor, current.BorderLeftColor, current.TextColor);
else if (it->first == "border-left-style") applyLineStyle(it->second, &style.BorderLeftStyle, current.BorderLeftStyle);
if (it->first == "border-top-width") applyBorderWidth(it->second, &style.Border.Top.Width, current.Border.Top.Width);
else if (it->first == "border-top-color") applyBorderColor(it->second, &style.Border.Top.Color, current.Border.Top.Color, current.TextColor);
else if (it->first == "border-top-style") applyLineStyle(it->second, &style.Border.Top.Style, current.Border.Top.Style);
else if (it->first == "border-right-width") applyBorderWidth(it->second, &style.Border.Right.Width, current.Border.Right.Width);
else if (it->first == "border-right-color") applyBorderColor(it->second, &style.Border.Right.Color, current.Border.Right.Color, current.TextColor);
else if (it->first == "border-right-style") applyLineStyle(it->second, &style.Border.Right.Style, current.Border.Right.Style);
else if (it->first == "border-bottom-width") applyBorderWidth(it->second, &style.Border.Bottom.Width, current.Border.Bottom.Width);
else if (it->first == "border-bottom-color") applyBorderColor(it->second, &style.Border.Bottom.Color, current.Border.Bottom.Color, current.TextColor);
else if (it->first == "border-bottom-style") applyLineStyle(it->second, &style.Border.Bottom.Style, current.Border.Bottom.Style);
else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.Border.Left.Width, current.Border.Left.Width);
else if (it->first == "border-left-color") applyBorderColor(it->second, &style.Border.Left.Color, current.Border.Left.Color, current.TextColor);
else if (it->first == "border-left-style") applyLineStyle(it->second, &style.Border.Left.Style, current.Border.Left.Style);
else if (it->first == "margin-top") applyMarginWidth(it->second, &style.MarginTop, current.MarginTop, current.FontSize);
else if (it->first == "margin-right") applyMarginWidth(it->second, &style.MarginRight, current.MarginRight, current.FontSize);
else if (it->first == "margin-bottom") applyMarginWidth(it->second, &style.MarginBottom, current.MarginBottom, current.FontSize);

Loading…
Cancel
Save