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/rgba.h"
#include "nel/misc/geom_ext.h" #include "nel/misc/geom_ext.h"
#include "nel/gui/css_types.h" #include "nel/gui/css_types.h"
#include "nel/gui/css_border.h"
namespace NLGUI namespace NLGUI
{ {
class CInterfaceElement;
/** /**
* \brief Border renderer for GUI classes * \brief Border renderer for GUI classes
* \date 2019-09-03 10:50 GMT * \date 2019-09-03 10:50 GMT
@ -34,6 +37,22 @@ namespace NLGUI
class CSSBorderRenderer class CSSBorderRenderer
{ {
private: 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 // parent element screen coordinates
sint32 m_XReal, m_YReal; sint32 m_XReal, m_YReal;
sint32 m_WReal, m_HReal; sint32 m_WReal, m_HReal;
@ -50,15 +69,44 @@ namespace NLGUI
// if true, then updateCoords() is called from draw() // if true, then updateCoords() is called from draw()
bool m_Dirty; bool m_Dirty;
// if true, then at least one border is set // UI scale, used to calculate number of segments to draw for circle
bool m_Border; float m_Scale;
bool m_BorderTop, m_BorderRight, m_BorderBottom, m_BorderLeft;
public: CSSRect<CSSBorder> m_Border;
uint32 TopWidth, RightWidth, BottomWidth, LeftWidth; CSSRect<sint32> m_Computed;
NLMISC::CRGBA TopColor, RightColor, BottomColor, LeftColor;
CSSLineStyle TopStyle, RightStyle, BottomStyle, LeftStyle; // 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 // alpha value from parent
uint8 CurrentAlpha; uint8 CurrentAlpha;
@ -70,23 +118,67 @@ namespace NLGUI
void setRect(sint32 x, sint32 y, sint32 w, sint32 h); void setRect(sint32 x, sint32 y, sint32 w, sint32 h);
void setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left); void setBorder(const CSSRect<CSSBorder> &b) { m_Dirty = true; m_Border = b; }
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 updateCoords(); void updateCoords();
void invalidateCoords() { m_Dirty = m_Border = true; } void invalidateCoords() { m_Dirty = true; }
void invalidateContent() { m_Dirty = m_Border = true; }; void invalidateContent() { m_Dirty = true; }
uint32 getTopWidth() const; bool isEmpty() const {
uint32 getRightWidth() const; return (m_Border.Top.Width.getFloat() +
uint32 getBottomWidth() const; m_Border.Right.Width.getFloat() +
uint32 getLeftWidth() const; m_Border.Bottom.Width.getFloat() +
m_Border.Left.Width.getFloat()) == 0;
}
uint32 getLeftRightWidth() const; uint32 getTopWidth() { if (m_MustComputeValues) computeValues(); return m_Computed.Top; }
uint32 getTopBottomWidth() const; 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(); void draw();
}; // CSSBorderRenderer }; // CSSBorderRenderer

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

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

@ -32,21 +32,24 @@ namespace NLGUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
CSSBorderRenderer::CSSBorderRenderer() 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; CurrentAlpha = 255;
m_Scale = 1.f;
m_RenderLayer = 0; m_RenderLayer = 0;
m_ModulateGlobalColor = false; m_ModulateGlobalColor = false;
m_Border = true;
m_Dirty = true; m_Dirty = true;
m_BorderTop = m_BorderRight = m_BorderBottom = m_BorderLeft = false; m_MustComputeValues = true;
m_XReal = 0; m_XReal = 0;
m_YReal = 0; m_YReal = 0;
m_WReal = 0; m_WReal = 0;
m_HReal = 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_WReal = w;
m_HReal = h; m_HReal = h;
m_Dirty = m_Border = (w > 0 && h > 0); m_Dirty = (w > 0 && h > 0);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CSSBorderRenderer::setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left) bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style) const
{ {
TopWidth = top; return style == CSS_LINE_STYLE_DOUBLE ||
RightWidth = right; style == CSS_LINE_STYLE_GROOVE ||
BottomWidth = bottom; style == CSS_LINE_STYLE_RIDGE;
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) void CSSBorderRenderer::computeValues()
{ {
TopStyle = top; m_MustComputeValues = false;
RightStyle = right;
BottomStyle = bottom; // TODO :should save as computed value
LeftStyle = left; sint32 vpW=0;
sint32 vpH=0;
if (m_Viewport)
{
vpW = m_Viewport->getWReal();
vpH = m_Viewport->getHReal();
}
m_Dirty = m_Border = true; 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);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CSSBorderRenderer::setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left) void CSSBorderRenderer::getAdjacentBorders(EBorderSide side, EBorderSide &adjBorderL, EBorderSide &adjBorderR) const
{ {
TopColor = top; switch(side)
RightColor = right; {
BottomColor = bottom; case BORDER_TOP:
LeftColor = left; adjBorderL = BORDER_TOP_LEFT;
adjBorderR = BORDER_TOP_RIGHT;
m_Dirty = true; 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::getTopWidth() const void CSSBorderRenderer::getAdjacentBorderWidth(EBorderSide side, sint32 &adjWidthL, sint32 &adjWidthR) const
{ {
if (TopStyle == CSS_LINE_STYLE_NONE || TopStyle == CSS_LINE_STYLE_HIDDEN) switch(side)
return 0; {
case BORDER_TOP:
return TopWidth; 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::getRightWidth() const void CSSBorderRenderer::buildDotCornerStart(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
{ {
if (RightStyle == CSS_LINE_STYLE_NONE || RightStyle == CSS_LINE_STYLE_HIDDEN) NLMISC::CLine line;
return 0; switch(side)
{
return RightWidth; 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;
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getBottomWidth() const void CSSBorderRenderer::buildDotCornerEnd(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
{ {
if (BottomStyle == CSS_LINE_STYLE_NONE || BottomStyle == CSS_LINE_STYLE_HIDDEN) NLMISC::CLine line;
return 0; switch(side)
{
return BottomWidth; 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;
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getLeftWidth() const void CSSBorderRenderer::buildDashedBorder(EBorderSide side)
{ {
if (LeftStyle == CSS_LINE_STYLE_NONE || LeftStyle == CSS_LINE_STYLE_HIDDEN) CSSBorder border;
return 0;
return LeftWidth; 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;
} }
// ---------------------------------------------------------------------------- if (width < 1) return;
uint32 CSSBorderRenderer::getLeftRightWidth() const 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);
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)
{
// 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;
sint32 count = std::floor((float)width / dot);
// 3n (dot, gap, dot) groups; count should be odd
if ((count % 2) == 0) count += 1;
if (count == 1)
{
// fallback to single dot
if (horizontal)
{ {
return getLeftWidth() + getRightWidth(); x += width / 2.f;
y += radius;
}
else
{
x += radius;
y += width / 2.f;
} }
// ---------------------------------------------------------------------------- buildDotSegments(shape, x, y, radius);
uint32 CSSBorderRenderer::getTopBottomWidth() const return;
}
// 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
buildDotSegments(shape, x, y, radius);
xy += spacing;
count--;
if (adjWidthR > 0)
count--;
bool isDot = false;
while(count > 0)
{ {
return getTopWidth() + getBottomWidth(); if (isDot)
buildDotSegments(shape, x, y, radius);
isDot = !isDot;
xy += spacing;
count--;
} }
// ---------------------------------------------------------------------------- if (adjWidthR > 0)
bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style) const buildDotCornerEnd(side, shape, x, y, radius);
}
else
{ {
return style == CSS_LINE_STYLE_DOUBLE || sint32 innerWidth = width;
style == CSS_LINE_STYLE_GROOVE || if (adjWidthL > 0) innerWidth -= adjWidthL;
style == CSS_LINE_STYLE_RIDGE; if (adjWidthR > 0) innerWidth -= adjWidthR;
sint32 count = std::floor((float)innerWidth * 2.f / (thickness * 3));
if ((float)innerWidth < 2.f * thickness)
{
buildSolidBorder(side);
return;
} }
// ---------------------------------------------------------------------------- // 4n groups (halfDash, halfGap, halfGap, halfDash)
void CSSBorderRenderer::updateCoords() 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;
bool isDash = false;
while(count > 0)
{ {
m_Dirty = false; if (isDash)
m_DrawBorders.clear(); {
if (!m_Border) return; makeBorderQuad(side, shape, x, y, fullDash, thickness);
m_DrawBorders.push_back(shape);
}
isDash = !isDash;
sint dTop = getTopWidth(); m_BorderTop = dTop > 0; xy += fullDash;
sint dRight = getRightWidth(); m_BorderRight = dRight > 0; count -= 2;
sint dBottom = getBottomWidth(); m_BorderBottom = dBottom > 0; }
sint dLeft = getLeftWidth(); m_BorderLeft = dLeft > 0;
m_Border = m_BorderTop || m_BorderRight || m_BorderBottom || m_BorderLeft; // draw half dash or full corner
if (!m_Border) return; makeBorderQuad(side, shape, x, y, adjWidthR + halfDash, thickness);
if (adjWidthR > 0)
makeCornerQuad(adjBorderR, shape);
sint xTop = m_YReal + m_HReal; m_DrawBorders.push_back(shape);
sint xRight = m_XReal + m_WReal; }
}
sint bLeft = m_XReal + dLeft; // ----------------------------------------------------------------------------
sint bRight = xRight - dRight; void CSSBorderRenderer::buildSolidBorder(EBorderSide side)
sint bTop = xTop - dTop; {
sint bBottom = m_YReal + dBottom; float x, y;
sint width, thickness;
CSSBorder border;
switch(side)
{
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; SDrawBorder shape;
shape.Color = border.Color;
shape.Quad.Uv0.set(0.f, 0.f); shape.Quad.Uv0.set(0.f, 0.f);
shape.Quad.Uv1.set(1.f, 0.f); shape.Quad.Uv1.set(1.f, 0.f);
shape.Quad.Uv2.set(1.f, 1.f); shape.Quad.Uv2.set(1.f, 1.f);
shape.Quad.Uv3.set(0.f, 1.f); shape.Quad.Uv3.set(0.f, 1.f);
// V3 - top-left if (border.Style == CSS_LINE_STYLE_INSET && (side == BORDER_TOP || side == BORDER_LEFT))
// V2 - top-right shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
// V1 - bottom-right else if (border.Style == CSS_LINE_STYLE_OUTSET && (side == BORDER_BOTTOM || side == BORDER_RIGHT))
// V0 - bottom-left shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
if (m_BorderTop)
// solid border
{ {
if (TopStyle == CSS_LINE_STYLE_INSET || TopStyle == CSS_LINE_STYLE_GROOVE) EBorderSide adjBorderL, adjBorderR;
shape.Color = blend(TopColor, CRGBA::Black, 0.5f); getAdjacentBorders(side, adjBorderL, adjBorderR);
else
shape.Color = TopColor; makeBorderQuad(side, shape, x, y, width, thickness);
makeCornerQuad(adjBorderL, shape);
makeCornerQuad(adjBorderR, shape);
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); m_DrawBorders.push_back(shape);
}
if (hasInnerShape(TopStyle)) if (hasInnerShape(border.Style))
{ {
float iLeft, iTop, iRight; if (side == BORDER_TOP || side == BORDER_LEFT)
if (TopStyle == CSS_LINE_STYLE_DOUBLE)
{ {
iLeft = 2*dLeft / 3.f; if (border.Style == CSS_LINE_STYLE_GROOVE)
iTop = 2*dBottom / 3.f; m_DrawBorders.back().Color = blend(border.Color, CRGBA::Black, 0.5f);
iRight = 2*dRight / 3.f; else if (border.Style == CSS_LINE_STYLE_RIDGE)
} else { shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
iLeft = dLeft / 2.f; }
iTop = dTop / 2.f; else if (side == BORDER_BOTTOM || side == BORDER_RIGHT)
iRight = dRight / 2.f; {
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 (TopStyle == CSS_LINE_STYLE_RIDGE) sint32 adjWidthL, adjWidthR;
shape.Color = blend(TopColor, CRGBA::Black, 0.5f); getAdjacentBorderWidth(side, adjWidthL, adjWidthR);
else
shape.Color = TopColor; 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;
}
// create inner border shape and remove overlapping from outer shape // create inner shape and remove overlapping from outer shape
m_DrawBorders.back().Quad.V0.x -= iLeft; m_DrawBorders.back().Quad.V0.y += iTop; switch(side)
m_DrawBorders.back().Quad.V1.x += iRight; m_DrawBorders.back().Quad.V1.y += iTop; {
shape.Quad.V3.x += iLeft; shape.Quad.V3.y -= iTop; case BORDER_TOP:
shape.Quad.V2.x -= iRight; shape.Quad.V2.y -= iTop; 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); m_DrawBorders.push_back(shape);
} }
} }
if (m_BorderBottom) // ----------------------------------------------------------------------------
void CSSBorderRenderer::makeBorderQuad(EBorderSide side, SDrawBorder &shape, float x, float y, float width, float thickness) const
{ {
if (BottomStyle == CSS_LINE_STYLE_OUTSET || BottomStyle == CSS_LINE_STYLE_RIDGE) float quadW, quadH;
shape.Color = blend(BottomColor, CRGBA::Black, 0.5f); switch(side)
else {
shape.Color = BottomColor; case BORDER_TOP: quadW = width; quadH = thickness; break;
case BORDER_BOTTOM:quadW = width; quadH = thickness; break;
shape.Quad.V3.x = bLeft; shape.Quad.V3.y = bBottom; case BORDER_LEFT: quadW = thickness; quadH = width; break;
shape.Quad.V2.x = bRight; shape.Quad.V2.y = bBottom; case BORDER_RIGHT: quadW = thickness; quadH = width; break;
shape.Quad.V1.x = xRight; shape.Quad.V1.y = m_YReal; default: return;
shape.Quad.V0.x = m_XReal; shape.Quad.V0.y = m_YReal; }
m_DrawBorders.push_back(shape); 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;
}
if (hasInnerShape(BottomStyle)) // ----------------------------------------------------------------------------
void CSSBorderRenderer::makeCornerQuad(EBorderSide side, SDrawBorder &shape) const
{ {
float iLeft, iBottom, iRight; switch(side)
if (BottomStyle == CSS_LINE_STYLE_DOUBLE)
{ {
iLeft = 2*dLeft / 3.f; case BORDER_TOP_LEFT: shape.Quad.V0.x += m_Computed.Left; break;
iBottom = 2*dBottom / 3.f; case BORDER_TOP_RIGHT: shape.Quad.V1.x -= m_Computed.Right; break;
iRight = 2*dRight / 3.f; 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;
} }
else }
// ----------------------------------------------------------------------------
static bool getCircleLineIntersection(float x, float y, float r, const NLMISC::CLine &line, NLMISC::CLine &result)
{ {
iLeft = dLeft / 2.f; float dx = line.V0.x - line.V1.x;
iBottom = dBottom / 2.f; float dy = line.V0.y - line.V1.y;
iRight = dRight / 2.f; 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;
} }
if (BottomStyle == CSS_LINE_STYLE_GROOVE) float t;
shape.Color = blend(shape.Color, CRGBA::Black, 0.5f); t = (-b + sqrt(d)) / (2 * a);
else result.V0.x = line.V0.x + t * dx;
shape.Color = BottomColor; result.V0.y = line.V0.y + t * dy;
m_DrawBorders.back().Quad.V2.x += iRight; m_DrawBorders.back().Quad.V2.y -= iBottom; t = (-b - sqrt(d)) / (2 * a);
m_DrawBorders.back().Quad.V3.x -= iLeft; m_DrawBorders.back().Quad.V3.y -= iBottom; result.V1.x = line.V0.x + t * dx;
shape.Quad.V1.x -= iRight; shape.Quad.V1.y += iBottom; result.V1.y = line.V0.y + t * dy;
shape.Quad.V0.x += iLeft; shape.Quad.V0.y += iBottom;
m_DrawBorders.push_back(shape); 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);
} }
} }
if (m_BorderRight) // ----------------------------------------------------------------------------
void CSSBorderRenderer::buildDotSegments(SDrawBorder shape, float x, float y, float radius, float fromAngle, float toAngle)
{ {
if (RightStyle == CSS_LINE_STYLE_OUTSET || RightStyle == CSS_LINE_STYLE_RIDGE) static const float pi = (float)NLMISC::Pi;
shape.Color = blend(RightColor, CRGBA::Black, 0.5f); static const float twopi = (float)(NLMISC::Pi * 2);
else static const uint minSectors = 12;
shape.Color = RightColor;
shape.Quad.V3.x = bRight; shape.Quad.V3.y = bTop; // use single quad if dot is small
shape.Quad.V2.x = xRight; shape.Quad.V2.y = xTop; if (2 * radius * m_Scale < 4)
shape.Quad.V1.x = xRight; shape.Quad.V1.y = m_YReal; {
shape.Quad.V0.x = bRight; shape.Quad.V0.y = bBottom; makeBorderQuad(BORDER_TOP, shape, x - radius, y - radius, radius * 2, radius * 2);
m_DrawBorders.push_back(shape); m_DrawBorders.push_back(shape);
return;
}
// number of sectors for full circle
uint sectors = std::max(minSectors, (uint)std::ceil(radius * m_Scale));
float arcLength;
if (toAngle < fromAngle)
arcLength = twopi * (1 + toAngle - fromAngle);
else
arcLength = twopi * (toAngle - fromAngle);
// sectors to draw
float arcSectors = ceil(arcLength * sectors / twopi );
float arcSectorLength = arcLength / arcSectors;
if (arcSectors <= 1)
return;
if (hasInnerShape(RightStyle)) if (arcLength < pi)
{ {
float iTop, iRight, iBottom; // only small segment is visible
if (RightStyle == CSS_LINE_STYLE_DOUBLE) 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
{ {
iTop = 2*dTop / 3.f; shape.Quad.V0.x = x; shape.Quad.V0.y = y;
iRight = 2*dRight / 3.f; shape.Quad.V1.x = x; shape.Quad.V1.y = y;
iBottom = 2*dBottom / 3.f;
} else {
iTop = dTop / 2.f;
iRight = dRight / 2.f;
iBottom = dBottom / 2.f;
} }
if (RightStyle == CSS_LINE_STYLE_GROOVE) float a1 = fromAngle * twopi;
shape.Color = blend(shape.Color, CRGBA::Black, 0.5f); uint step;
else for(step = 0; step < (uint)arcSectors; step++)
shape.Color = RightColor; {
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.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); m_DrawBorders.push_back(shape);
}
a1 = a2;
} }
if (m_BorderLeft) // build last sector if requested range is over 180deg
if (arcLength > pi && arcLength < twopi)
{ {
if (LeftStyle == CSS_LINE_STYLE_INSET || LeftStyle == CSS_LINE_STYLE_GROOVE) float a2 = fromAngle * twopi;
shape.Color = blend(LeftColor, CRGBA::Black, 0.5f); shape.Quad.V2.x = x + radius * cosf(a1); shape.Quad.V2.y = y + radius * sinf(a1);
else shape.Quad.V3.x = x + radius * cosf(a2); shape.Quad.V3.y = y + radius * sinf(a2);
shape.Color = LeftColor; m_DrawBorders.push_back(shape);
}
}
shape.Quad.V3.x = m_XReal; shape.Quad.V3.y = xTop; // ----------------------------------------------------------------------------
shape.Quad.V2.x = bLeft; shape.Quad.V2.y = bTop; void CSSBorderRenderer::updateCoords()
shape.Quad.V1.x = bLeft; shape.Quad.V1.y = bBottom; {
shape.Quad.V0.x = m_XReal; shape.Quad.V0.y = m_YReal; m_Dirty = false;
m_DrawBorders.clear();
m_DrawBorders.push_back(shape); if (m_MustComputeValues)
computeValues();
if (hasInnerShape(LeftStyle)) if (m_Computed.Top > 0 && m_Border.Top.Color.A > 0)
{ {
if (LeftStyle == CSS_LINE_STYLE_RIDGE) if (m_Border.Top.Style == CSS_LINE_STYLE_DASHED || m_Border.Top.Style == CSS_LINE_STYLE_DOTTED)
shape.Color = blend(LeftColor, CRGBA::Black, 0.5f); buildDashedBorder(BORDER_TOP);
else else
shape.Color = LeftColor; buildSolidBorder(BORDER_TOP);
}
float iTop, iLeft, iBottom; if (m_Computed.Bottom > 0 && m_Border.Bottom.Color.A > 0)
if (LeftStyle == CSS_LINE_STYLE_DOUBLE)
{ {
iTop = 2*dTop / 3.f; if (m_Border.Bottom.Style == CSS_LINE_STYLE_DASHED || m_Border.Bottom.Style == CSS_LINE_STYLE_DOTTED)
iLeft = 2*dLeft / 3.f; buildDashedBorder(BORDER_BOTTOM);
iBottom = 2*dBottom / 3.f; else
} else { buildSolidBorder(BORDER_BOTTOM);
iTop = dTop / 2.f;
iLeft = dLeft / 2.f;
dBottom = dBottom / 2.f;
} }
m_DrawBorders.back().Quad.V2.x -= iLeft; m_DrawBorders.back().Quad.V2.y += iTop; if (m_Computed.Right > 0 && m_Border.Right.Color.A > 0)
m_DrawBorders.back().Quad.V1.x -= iLeft; m_DrawBorders.back().Quad.V1.y -= iBottom; {
shape.Quad.V3.x += iLeft; shape.Quad.V3.y -= iTop; if (m_Border.Right.Style == CSS_LINE_STYLE_DASHED || m_Border.Right.Style == CSS_LINE_STYLE_DOTTED)
shape.Quad.V0.x += iLeft; shape.Quad.V0.y += iBottom; buildDashedBorder(BORDER_RIGHT);
m_DrawBorders.push_back(shape); 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() { void CSSBorderRenderer::draw() {
if (m_Dirty) updateCoords(); if (m_Dirty) updateCoords();
if (!m_Border) return; if (m_DrawBorders.empty()) return;
CViewRenderer &rVR = *CViewRenderer::getInstance(); CViewRenderer &rVR = *CViewRenderer::getInstance();
// TODO: no need for widget manager, if global color is set from parent
CRGBA globalColor; CRGBA globalColor;
if (m_ModulateGlobalColor) if (m_ModulateGlobalColor)
globalColor = CWidgetManager::getInstance()->getGlobalColor(); 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 (!dest) return;
if (value == "inherit") if (value == "inherit")
@ -513,37 +513,19 @@ namespace NLGUI
} }
else if (value == "thin") else if (value == "thin")
{ {
*dest = 1; dest->setFloatValue(1, "px");
} }
else if (value == "medium") else if (value == "medium")
{ {
*dest = 3; dest->setFloatValue(3, "px");
} }
else if (value == "thick") else if (value == "thick")
{ {
*dest = 5; dest->setFloatValue(5, "px");
}
else if (value == "0")
{
*dest = 0;
} }
else else
{ {
float tmpf; dest->parseValue(value, false, false);
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;
}
} }
} }
@ -656,18 +638,18 @@ namespace NLGUI
TStyle::const_iterator it; TStyle::const_iterator it;
for (it=style.StyleRules.begin(); it != style.StyleRules.end(); ++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); 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.BorderTopColor, current.BorderTopColor, current.TextColor); 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.BorderTopStyle, current.BorderTopStyle); 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.BorderRightWidth, current.BorderRightWidth, current.FontSize); 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.BorderRightColor, current.BorderRightColor, current.TextColor); 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.BorderRightStyle, current.BorderRightStyle); 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.BorderBottomWidth, current.BorderBottomWidth, current.FontSize); 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.BorderBottomColor, current.BorderBottomColor, current.TextColor); 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.BorderBottomStyle, current.BorderBottomStyle); 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.BorderLeftWidth, current.BorderLeftWidth, current.FontSize); 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.BorderLeftColor, current.BorderLeftColor, current.TextColor); 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.BorderLeftStyle, current.BorderLeftStyle); 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-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-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); else if (it->first == "margin-bottom") applyMarginWidth(it->second, &style.MarginBottom, current.MarginBottom, current.FontSize);

Loading…
Cancel
Save