diff --git a/nel/include/nel/gui/css_border.h b/nel/include/nel/gui/css_border.h
new file mode 100644
index 000000000..787b71710
--- /dev/null
+++ b/nel/include/nel/gui/css_border.h
@@ -0,0 +1,72 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#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
+
+
diff --git a/nel/include/nel/gui/css_border_renderer.h b/nel/include/nel/gui/css_border_renderer.h
index b70f1c169..54505a686 100644
--- a/nel/include/nel/gui/css_border_renderer.h
+++ b/nel/include/nel/gui/css_border_renderer.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 m_Border;
+ CSSRect 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 &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
diff --git a/nel/include/nel/gui/css_style.h b/nel/include/nel/gui/css_style.h
index 990b24e20..042486d17 100644
--- a/nel/include/nel/gui/css_style.h
+++ b/nel/include/nel/gui/css_style.h
@@ -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 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 ¤tWidth) const;
void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA ¤tColor, const NLMISC::CRGBA &textColor) const;
void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle ¤tStyle) 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;
diff --git a/nel/include/nel/gui/css_types.h b/nel/include/nel/gui/css_types.h
index ac59af422..172c21d18 100644
--- a/nel/include/nel/gui/css_types.h
+++ b/nel/include/nel/gui/css_types.h
@@ -85,6 +85,15 @@ namespace NLGUI
CSS_VALUE_CONTAIN
};
+ template
+ struct CSSRect
+ {
+ T Top;
+ T Right;
+ T Bottom;
+ T Left;
+ };
+
}//namespace
#endif // CL_CSS_TYPES_H
diff --git a/nel/src/gui/css_border_renderer.cpp b/nel/src/gui/css_border_renderer.cpp
index aa44073f4..cb2ef9709 100644
--- a/nel/src/gui/css_border_renderer.cpp
+++ b/nel/src/gui/css_border_renderer.cpp
@@ -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();
diff --git a/nel/src/gui/css_style.cpp b/nel/src/gui/css_style.cpp
index 7a9b725af..912ff04d4 100644
--- a/nel/src/gui/css_style.cpp
+++ b/nel/src/gui/css_style.cpp
@@ -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 ¤tWidth) 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);