Add CSSLength, CSSBackground, CSSBackgroundRenderer classes
parent
65edd9f95d
commit
dfe45029ab
@ -0,0 +1,83 @@
|
|||||||
|
// 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_BACKGROUND_H
|
||||||
|
#define CL_CSS_BACKGROUND_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 background info
|
||||||
|
* \date 2021-07-02 11:36 GMT
|
||||||
|
* \author Meelis Mägi (Nimetu)
|
||||||
|
*/
|
||||||
|
class CSSBackground
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CSSBackground()
|
||||||
|
:color(NLMISC::CRGBA::Transparent),
|
||||||
|
repeatX(CSS_VALUE_REPEAT), repeatY(CSS_VALUE_REPEAT), attachment(CSS_VALUE_SCROLL),
|
||||||
|
xAnchor(CSS_VALUE_LEFT), yAnchor(CSS_VALUE_TOP),
|
||||||
|
clip(CSS_VALUE_BORDER_BOX), origin(CSS_VALUE_PADDING_BOX), size(CSS_VALUE_AUTO)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void setImage(const std::string &value);
|
||||||
|
void setPosition(const std::string &value);
|
||||||
|
void setSize(const std::string &value);
|
||||||
|
void setRepeat(const std::string &value);
|
||||||
|
void setOrigin(const std::string &value);
|
||||||
|
void setClip(const std::string &value);
|
||||||
|
void setAttachment(const std::string &value);
|
||||||
|
void setColor(const std::string &value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// TODO: only final layer has color
|
||||||
|
NLMISC::CRGBA color;
|
||||||
|
std::string image;
|
||||||
|
|
||||||
|
CSSValueType repeatX;
|
||||||
|
CSSValueType repeatY;
|
||||||
|
CSSValueType attachment;
|
||||||
|
|
||||||
|
CSSValueType xAnchor;
|
||||||
|
CSSValueType yAnchor;
|
||||||
|
CSSLength xPosition;
|
||||||
|
CSSLength yPosition;
|
||||||
|
|
||||||
|
CSSValueType clip;
|
||||||
|
CSSValueType origin;
|
||||||
|
|
||||||
|
CSSValueType size;
|
||||||
|
CSSLength width;
|
||||||
|
CSSLength height;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void positionFromOne(const std::vector<std::string> &parts);
|
||||||
|
void positionFromTwo(const std::vector<std::string> &parts);
|
||||||
|
void positionFromThree(const std::vector<std::string> &parts);
|
||||||
|
void positionFromFour(const std::vector<std::string> &parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
}//namespace
|
||||||
|
|
||||||
|
#endif // CL_CSS_BACKGROUND_H
|
||||||
|
|
||||||
|
|
@ -0,0 +1,193 @@
|
|||||||
|
// 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 NL_CSS_BACKGROUND_RENDERER_H
|
||||||
|
#define NL_CSS_BACKGROUND_RENDERER_H
|
||||||
|
|
||||||
|
#include "nel/misc/types_nl.h"
|
||||||
|
#include "nel/misc/rgba.h"
|
||||||
|
#include "nel/misc/geom_ext.h"
|
||||||
|
#include "nel/gui/css_types.h"
|
||||||
|
#include "nel/gui/css_background.h"
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
class CInterfaceElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Border renderer for GUI classes
|
||||||
|
* \date 2021-06-29 15:17 GMT
|
||||||
|
* \author Meelis Mägi (Nimetu)
|
||||||
|
*/
|
||||||
|
class CSSBackgroundRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// alpha value from parent
|
||||||
|
uint8 CurrentAlpha;
|
||||||
|
|
||||||
|
// TODO: should be moved to CSSBackground
|
||||||
|
sint32 TextureId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSSBackgroundRenderer();
|
||||||
|
~CSSBackgroundRenderer();
|
||||||
|
|
||||||
|
// return true if no background is set
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_Background.image.empty() && m_Background.color.A == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setModulateGlobalColor(bool m) { m_ModulateGlobalColor = m; }
|
||||||
|
|
||||||
|
void updateCoords();
|
||||||
|
void invalidateCoords() { m_Dirty = true; }
|
||||||
|
void invalidateContent() { m_Dirty = true; };
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void setBackground(const CSSBackground &bg);
|
||||||
|
|
||||||
|
// helper function to change background image
|
||||||
|
void setImage(const std::string &bgtex);
|
||||||
|
void setImageRepeat(bool b);
|
||||||
|
void setImageCover(bool b);
|
||||||
|
|
||||||
|
// helper function to change background color
|
||||||
|
void setColor(const NLMISC::CRGBA &color)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_Background.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLMISC::CRGBA getColor() const
|
||||||
|
{
|
||||||
|
return m_Background.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// override painting area to be at least the size of viewport (ie, <html> background)
|
||||||
|
void setFillViewport(bool b) {
|
||||||
|
m_Dirty = true;
|
||||||
|
m_FillViewport = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setViewport(CInterfaceElement *root)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_Viewport = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBorderArea(sint32 x, sint32 y, sint32 w, sint32 h)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_BorderX = x;
|
||||||
|
m_BorderY = y;
|
||||||
|
m_BorderW = w;
|
||||||
|
m_BorderH = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPaddingArea(sint32 x, sint32 y, sint32 w, sint32 h)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_PaddingX = x;
|
||||||
|
m_PaddingY = y;
|
||||||
|
m_PaddingW = w;
|
||||||
|
m_PaddingH = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setContentArea(sint32 x, sint32 y, sint32 w, sint32 h)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_ContentX = x;
|
||||||
|
m_ContentY = y;
|
||||||
|
m_ContentW = w;
|
||||||
|
m_ContentH = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sizes for em, rem units
|
||||||
|
void setFontSize(float rootFontSize, float fontSize)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
m_RootFontSize = rootFontSize;
|
||||||
|
m_FontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
sint32 m_BorderX, m_BorderY, m_BorderW, m_BorderH;
|
||||||
|
sint32 m_PaddingX, m_PaddingY, m_PaddingW, m_PaddingH;
|
||||||
|
sint32 m_ContentX, m_ContentY, m_ContentW, m_ContentH;
|
||||||
|
|
||||||
|
// font size for 'rem'
|
||||||
|
float m_RootFontSize;
|
||||||
|
|
||||||
|
// font size for 'em'
|
||||||
|
float m_FontSize;
|
||||||
|
|
||||||
|
// viewport element for vw,wh,vmin,vmax
|
||||||
|
CInterfaceElement* m_Viewport;
|
||||||
|
|
||||||
|
struct SDrawQueue
|
||||||
|
{
|
||||||
|
sint32 TextureId;
|
||||||
|
NLMISC::CQuadUV Quad;
|
||||||
|
NLMISC::CRGBA Color;
|
||||||
|
};
|
||||||
|
std::vector<SDrawQueue> m_DrawQueue;
|
||||||
|
|
||||||
|
const sint8 m_RenderLayer;
|
||||||
|
bool m_ModulateGlobalColor;
|
||||||
|
// if true, painting area returns area at least the size of viewport (ie, <html> background)
|
||||||
|
bool m_FillViewport;
|
||||||
|
|
||||||
|
// if true, then updateCoords() is called from draw()
|
||||||
|
bool m_Dirty;
|
||||||
|
|
||||||
|
CSSBackground m_Background;
|
||||||
|
|
||||||
|
// get clip area based on background-clip
|
||||||
|
void getPaintingArea(const CSSBackground &bg, sint32 &areaX, sint32 &areaY, sint32 &areaW, sint32 &areaH) const;
|
||||||
|
|
||||||
|
// get positioning area based on background-origin
|
||||||
|
void getPositioningArea(const CSSBackground &bg, sint32 &areaX, sint32 &areaY, sint32 &areaW, sint32 &areaH) const;
|
||||||
|
|
||||||
|
// calculate image size based on background-size
|
||||||
|
void calculateSize(const CSSBackground &bg, sint32 &texW, sint32 &texH) const;
|
||||||
|
|
||||||
|
// calculate image position based on background-position
|
||||||
|
void calculatePosition(const CSSBackground &bg, sint32 &texX, sint32 &texY, sint32 &texW, sint32 &texH) const;
|
||||||
|
|
||||||
|
// calculate image tile position, size, count, and spacing based on background-repeat
|
||||||
|
void calculateTiles(const CSSBackground &bg, sint32 &texX, sint32 &texY, sint32 &texW, sint32 &texH, sint32 &tilesX, sint32 &tilesY, sint32 &spacingX, sint32 &spacingY) const;
|
||||||
|
|
||||||
|
// position, size, and count for first tile to cover an area
|
||||||
|
void getImageTile(sint32 &tilePos, sint32 &tileSize, sint32 &spacing, sint32 &tiles, sint32 areaPos, sint32 areaSize, CSSValueType repeat) const;
|
||||||
|
|
||||||
|
// push background color to draw queue
|
||||||
|
void buildColorQuads(const CSSBackground &bg);
|
||||||
|
|
||||||
|
// push background image to draw quque
|
||||||
|
void buildImageQuads(const CSSBackground &bg, sint32 textureId);
|
||||||
|
|
||||||
|
}; // CSSBackgroundRenderer
|
||||||
|
|
||||||
|
}//namespace
|
||||||
|
|
||||||
|
#endif // NL_CSS_BACKGROUND_RENDERER_H
|
||||||
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
|||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010-2021 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_LENGTH_H
|
||||||
|
#define CL_CSS_LENGTH_H
|
||||||
|
|
||||||
|
#include "nel/misc/types_nl.h"
|
||||||
|
#include "nel/gui/css_types.h"
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* \brief CSS types used in GUI classes
|
||||||
|
* \date 2021-07-02 11:36 GMT
|
||||||
|
* \author Meelis Mägi (Nimetu)
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CSSLength
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Kind {
|
||||||
|
Auto, Relative, Fixed
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSLength(float value = 0, CSSUnitType unit = CSS_UNIT_NONE, Kind kind = Auto)
|
||||||
|
: m_Value(value), m_Unit(unit), m_Kind(Auto)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void setAuto() { m_Kind = Auto; }
|
||||||
|
bool parseValue(const std::string &value, bool allowPercent = true, bool allowNegative = false);
|
||||||
|
void setFloatValue(float f, const std::string &unit);
|
||||||
|
|
||||||
|
float getValue() const;
|
||||||
|
float getFloat() const { return m_Value; }
|
||||||
|
|
||||||
|
bool isPercent() const { return m_Unit == CSS_UNIT_PERCENT; }
|
||||||
|
|
||||||
|
bool isAuto() const { return m_Kind == Auto; }
|
||||||
|
bool isRelative() const { return m_Kind == Relative; }
|
||||||
|
|
||||||
|
// % uses relValue
|
||||||
|
// em uses emSize
|
||||||
|
// rem uses remSize
|
||||||
|
// vw,vh,vi,vb,vmin,vmax uses vwSize/vhSize
|
||||||
|
float calculate(uint32 relValue, uint32 emSize, uint32 remSize, uint32 vwSize, uint32 whSize) const;
|
||||||
|
|
||||||
|
CSSUnitType getUnit() const { return m_Unit; }
|
||||||
|
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setUnit(const std::string &unit);
|
||||||
|
|
||||||
|
float m_Value;
|
||||||
|
CSSUnitType m_Unit;
|
||||||
|
Kind m_Kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
}//namespace
|
||||||
|
|
||||||
|
#endif // CL_CSS_LENGTH_H
|
||||||
|
|
||||||
|
|
@ -0,0 +1,427 @@
|
|||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010-2021 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/>.
|
||||||
|
|
||||||
|
#include "stdpch.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "nel/gui/libwww.h"
|
||||||
|
#include "nel/gui/css_length.h"
|
||||||
|
#include "nel/gui/css_background.h"
|
||||||
|
|
||||||
|
using namespace NLMISC;
|
||||||
|
|
||||||
|
#ifdef DEBUG_NEW
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
|
||||||
|
void CSSBackground::setImage(const std::string &value)
|
||||||
|
{
|
||||||
|
image = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setPosition(const std::string &value)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
splitString(toLowerAscii(value), " ", parts);
|
||||||
|
|
||||||
|
if (parts.empty() || parts.size() > 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch(parts.size())
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
positionFromOne(parts);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
positionFromTwo(parts);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
positionFromThree(parts);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
positionFromFour(parts);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setSize(const std::string &value)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
splitString(toLowerAscii(value), " ", parts);
|
||||||
|
if (parts.size() > 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parts.size() == 1 && (parts[0] == "cover" || parts[0] == "contain"))
|
||||||
|
{
|
||||||
|
if (parts[0] == "cover")
|
||||||
|
size = CSS_VALUE_COVER;
|
||||||
|
else
|
||||||
|
size = CSS_VALUE_CONTAIN;
|
||||||
|
|
||||||
|
width.setAuto();
|
||||||
|
height.setAuto();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// height will default to 'auto' if not set
|
||||||
|
if (parts.size() == 1)
|
||||||
|
parts.push_back("auto");
|
||||||
|
|
||||||
|
if (parts[0] == "auto" && parts[1] == "auto")
|
||||||
|
{
|
||||||
|
size = CSS_VALUE_AUTO;
|
||||||
|
width.setAuto();
|
||||||
|
height.setAuto();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSSLength newW, newH;
|
||||||
|
bool success = true;
|
||||||
|
if (parts[0] == "auto")
|
||||||
|
{
|
||||||
|
newW.setAuto();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
if (!getCssLength(fval, unit, parts[0]))
|
||||||
|
{
|
||||||
|
nlwarning("Failed to parse background-size[0] '%s'", parts[0].c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newW.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts[1] == "auto")
|
||||||
|
{
|
||||||
|
newH.setAuto();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
if (!getCssLength(fval, unit, parts[1]))
|
||||||
|
{
|
||||||
|
nlwarning("Failed to parse background-size[1] '%s'", parts[1].c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newH.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = CSS_VALUE_LENGTH;
|
||||||
|
width = newW;
|
||||||
|
height = newH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setRepeat(const std::string &value)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
splitString(toLowerAscii(value), " ", parts);
|
||||||
|
if (parts.size() == 0 || parts.size() > 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parts.size() == 1)
|
||||||
|
{
|
||||||
|
if (parts[0] == "repeat-x")
|
||||||
|
parts.push_back("no-repeat");
|
||||||
|
else if (parts[0] == "repeat-y")
|
||||||
|
parts.insert(parts.begin(), "no-repeat");
|
||||||
|
else //repeat, space, round, no-repeat
|
||||||
|
parts.push_back(parts[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (parts[0] == "repeat") repeatX = CSS_VALUE_REPEAT;
|
||||||
|
else if (parts[0] == "no-repeat") repeatX = CSS_VALUE_NOREPEAT;
|
||||||
|
else if (parts[0] == "space") repeatX = CSS_VALUE_SPACE;
|
||||||
|
else if (parts[0] == "round") repeatX = CSS_VALUE_ROUND;
|
||||||
|
else repeatX = CSS_VALUE_REPEAT;
|
||||||
|
|
||||||
|
if (parts[1] == "repeat") repeatY = CSS_VALUE_REPEAT;
|
||||||
|
else if (parts[1] == "no-repeat") repeatY = CSS_VALUE_NOREPEAT;
|
||||||
|
else if (parts[1] == "space") repeatY = CSS_VALUE_SPACE;
|
||||||
|
else if (parts[1] == "round") repeatY = CSS_VALUE_ROUND;
|
||||||
|
else repeatY = CSS_VALUE_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setOrigin(const std::string &value)
|
||||||
|
{
|
||||||
|
if (value == "border-box") origin = CSS_VALUE_BORDER_BOX;
|
||||||
|
else if (value == "padding-box") origin = CSS_VALUE_PADDING_BOX;
|
||||||
|
else if (value == "content-box") origin = CSS_VALUE_CONTENT_BOX;
|
||||||
|
else origin = CSS_VALUE_PADDING_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setClip(const std::string &value)
|
||||||
|
{
|
||||||
|
if (value == "border-box") clip = CSS_VALUE_BORDER_BOX;
|
||||||
|
else if (value == "padding-box") clip = CSS_VALUE_PADDING_BOX;
|
||||||
|
else if (value == "content-box") clip = CSS_VALUE_CONTENT_BOX;
|
||||||
|
//else if (value == "text") clip = CSSValueType::Text;
|
||||||
|
else clip = CSS_VALUE_PADDING_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setAttachment(const std::string &value)
|
||||||
|
{
|
||||||
|
if (value == "fixed") attachment = CSS_VALUE_FIXED;
|
||||||
|
else if (value == "local") attachment = CSS_VALUE_LOCAL;
|
||||||
|
else if (value == "scroll") attachment = CSS_VALUE_SCROLL;
|
||||||
|
else attachment = CSS_VALUE_SCROLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::setColor(const std::string &value)
|
||||||
|
{
|
||||||
|
NLMISC::CRGBA tmp;
|
||||||
|
if (scanHTMLColor(value.c_str(), tmp))
|
||||||
|
color = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHorizontalKeyword(const std::string &val)
|
||||||
|
{
|
||||||
|
return val == "left" || val == "right";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isVerticalKeyword(const std::string &val)
|
||||||
|
{
|
||||||
|
return val == "top" || val == "bottom";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::positionFromOne(const std::vector<std::string> &parts)
|
||||||
|
{
|
||||||
|
CSSValueType newH = CSS_VALUE_LEFT;
|
||||||
|
CSSValueType newV = CSS_VALUE_TOP;
|
||||||
|
CSSLength newX, newY;
|
||||||
|
newX.setFloatValue(0, "%");
|
||||||
|
newY.setFloatValue(0, "%");
|
||||||
|
|
||||||
|
uint index = 0;
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
if (isHorizontalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
newH = parts[index] == "left" ? CSS_VALUE_LEFT : CSS_VALUE_RIGHT;
|
||||||
|
newV = CSS_VALUE_CENTER;
|
||||||
|
}
|
||||||
|
else if (isVerticalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
newH = CSS_VALUE_CENTER;
|
||||||
|
newV = parts[index] == "top" ? CSS_VALUE_TOP : CSS_VALUE_BOTTOM;
|
||||||
|
}
|
||||||
|
else if (parts[index] == "center")
|
||||||
|
{
|
||||||
|
newH = CSS_VALUE_CENTER;
|
||||||
|
newV = CSS_VALUE_CENTER;
|
||||||
|
}
|
||||||
|
else if (getCssLength(fval, unit, parts[index], true))
|
||||||
|
{
|
||||||
|
newX.setFloatValue(fval, unit);
|
||||||
|
newV = CSS_VALUE_CENTER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xAnchor = newH;
|
||||||
|
yAnchor = newV;
|
||||||
|
xPosition = newX;
|
||||||
|
yPosition = newY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::positionFromTwo(const std::vector<std::string> &parts)
|
||||||
|
{
|
||||||
|
CSSValueType newH = CSS_VALUE_LEFT;
|
||||||
|
CSSValueType newV = CSS_VALUE_TOP;
|
||||||
|
CSSLength newX, newY;
|
||||||
|
newX.setFloatValue(0, "%");
|
||||||
|
newY.setFloatValue(0, "%");
|
||||||
|
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
uint index = 0;
|
||||||
|
bool hasCenter = false;
|
||||||
|
bool hasX = false;
|
||||||
|
bool hasY = false;
|
||||||
|
for (uint index = 0; index < parts.size(); index++)
|
||||||
|
{
|
||||||
|
if (parts[index] == "center")
|
||||||
|
{
|
||||||
|
hasCenter = true;
|
||||||
|
}
|
||||||
|
else if (isHorizontalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasX) return;
|
||||||
|
hasX = true;
|
||||||
|
newH = parts[index] == "left" ? CSS_VALUE_LEFT : CSS_VALUE_RIGHT;
|
||||||
|
}
|
||||||
|
else if (isVerticalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasY) return;
|
||||||
|
hasY = true;
|
||||||
|
newV = parts[index] == "top" ? CSS_VALUE_TOP : CSS_VALUE_BOTTOM;
|
||||||
|
}
|
||||||
|
else if (getCssLength(fval, unit, parts[index], true))
|
||||||
|
{
|
||||||
|
// invalid: 'top 50%';
|
||||||
|
if (hasY) return;
|
||||||
|
if (!hasX)
|
||||||
|
{
|
||||||
|
hasX = true;
|
||||||
|
newX.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hasY = true;
|
||||||
|
newY.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCenter)
|
||||||
|
{
|
||||||
|
if (!hasX)
|
||||||
|
newH = CSS_VALUE_CENTER;
|
||||||
|
if (!hasY)
|
||||||
|
newV = CSS_VALUE_CENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
xAnchor = newH;
|
||||||
|
yAnchor = newV;
|
||||||
|
xPosition = newX;
|
||||||
|
yPosition = newY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::positionFromThree(const std::vector<std::string> &parts)
|
||||||
|
{
|
||||||
|
CSSValueType newH = CSS_VALUE_LEFT;
|
||||||
|
CSSValueType newV = CSS_VALUE_TOP;
|
||||||
|
CSSLength newX, newY;
|
||||||
|
newX.setFloatValue(0, "%");
|
||||||
|
newY.setFloatValue(0, "%");
|
||||||
|
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
bool hasCenter = false;
|
||||||
|
bool hasX = false;
|
||||||
|
bool hasY = false;
|
||||||
|
for(uint index = 0; index < 3; index++)
|
||||||
|
{
|
||||||
|
if (parts[index] == "center")
|
||||||
|
{
|
||||||
|
if (hasCenter) return;
|
||||||
|
hasCenter = true;
|
||||||
|
}
|
||||||
|
else if (isHorizontalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasX) return;
|
||||||
|
hasX = true;
|
||||||
|
newH = parts[index] == "left" ? CSS_VALUE_LEFT : CSS_VALUE_RIGHT;
|
||||||
|
if ((index+1) < parts.size() && getCssLength(fval, unit, parts[index+1], true))
|
||||||
|
{
|
||||||
|
newX.setFloatValue(fval, unit);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isVerticalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasY) return;
|
||||||
|
hasY = true;
|
||||||
|
newV = parts[index] == "top" ? CSS_VALUE_TOP : CSS_VALUE_BOTTOM;
|
||||||
|
if ((index+1) < parts.size() && getCssLength(fval, unit, parts[index+1], true))
|
||||||
|
{
|
||||||
|
newY.setFloatValue(fval, unit);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCenter)
|
||||||
|
{
|
||||||
|
if (hasX && hasY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!hasX)
|
||||||
|
newH = CSS_VALUE_CENTER;
|
||||||
|
else
|
||||||
|
newV = CSS_VALUE_CENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
xAnchor = newH;
|
||||||
|
yAnchor = newV;
|
||||||
|
xPosition = newX;
|
||||||
|
yPosition = newY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSBackground::positionFromFour(const std::vector<std::string> &parts)
|
||||||
|
{
|
||||||
|
CSSValueType newH = CSS_VALUE_LEFT;
|
||||||
|
CSSValueType newV = CSS_VALUE_TOP;
|
||||||
|
CSSLength newX, newY;
|
||||||
|
newX.setFloatValue(0, "%");
|
||||||
|
newY.setFloatValue(0, "%");
|
||||||
|
|
||||||
|
float fval;
|
||||||
|
std::string unit;
|
||||||
|
bool hasX = false;
|
||||||
|
bool hasY = false;
|
||||||
|
for(uint index = 0; index<4; index+=2)
|
||||||
|
{
|
||||||
|
if (parts[index] == "center")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isHorizontalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasX) return;
|
||||||
|
hasX = true;
|
||||||
|
if (!getCssLength(fval, unit, parts[index+1], true)) return;
|
||||||
|
newH = parts[index] == "left" ? CSS_VALUE_LEFT : CSS_VALUE_RIGHT;
|
||||||
|
newX.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
else if (isVerticalKeyword(parts[index]))
|
||||||
|
{
|
||||||
|
if (hasY) return;
|
||||||
|
hasY = true;
|
||||||
|
if (!getCssLength(fval, unit, parts[index+1], true)) return;
|
||||||
|
newV = parts[index] == "top" ? CSS_VALUE_TOP : CSS_VALUE_BOTTOM;
|
||||||
|
newY.setFloatValue(fval, unit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xAnchor = newH;
|
||||||
|
yAnchor = newV;
|
||||||
|
xPosition = newX;
|
||||||
|
yPosition = newY;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
@ -0,0 +1,607 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdpch.h"
|
||||||
|
#include "nel/gui/css_background_renderer.h"
|
||||||
|
#include "nel/gui/css_border_renderer.h"
|
||||||
|
#include "nel/gui/view_renderer.h"
|
||||||
|
#include "nel/gui/widget_manager.h"
|
||||||
|
#include "nel/gui/view_bitmap.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace NLMISC;
|
||||||
|
|
||||||
|
#ifdef DEBUG_NEW
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
CSSBackgroundRenderer::CSSBackgroundRenderer()
|
||||||
|
: CurrentAlpha(255), TextureId(-1),
|
||||||
|
m_BorderX(0), m_BorderY(0), m_BorderW(0), m_BorderH(0),
|
||||||
|
m_PaddingX(0), m_PaddingY(0), m_PaddingW(0), m_PaddingH(0),
|
||||||
|
m_ContentX(0), m_ContentY(0), m_ContentW(0), m_ContentH(0),
|
||||||
|
m_RootFontSize(16.f), m_FontSize(16.f), m_Viewport(NULL),
|
||||||
|
m_RenderLayer(0), m_ModulateGlobalColor(false), m_FillViewport(false),
|
||||||
|
m_Dirty(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
CSSBackgroundRenderer::~CSSBackgroundRenderer()
|
||||||
|
{
|
||||||
|
if (TextureId != -1)
|
||||||
|
CViewRenderer::getInstance()->deleteTexture(TextureId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::clear()
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
|
||||||
|
if (TextureId != -1)
|
||||||
|
CViewRenderer::getInstance()->deleteTexture(TextureId);
|
||||||
|
|
||||||
|
TextureId = -1;
|
||||||
|
m_Background.image.clear();
|
||||||
|
m_Background.color.A = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::setBackground(const CSSBackground &bg)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
// TODO: CSSBackground should keep track of TextureId
|
||||||
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
||||||
|
if (bg.image != m_Background.image && TextureId != -1)
|
||||||
|
rVR.deleteTexture(TextureId);
|
||||||
|
|
||||||
|
m_Background = bg;
|
||||||
|
// TODO: does not accept urls
|
||||||
|
if (TextureId == -1 && !bg.image.empty())
|
||||||
|
{
|
||||||
|
// TODO: make CViewRenderer accept urls
|
||||||
|
if (bg.image.find("://") != std::string::npos)
|
||||||
|
TextureId = rVR.createTexture(bg.image, 0, 0, -1, -1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::setImage(const std::string &bgtex)
|
||||||
|
{
|
||||||
|
m_Dirty = true;
|
||||||
|
// TODO: CSSBackground should keep track of TextureId
|
||||||
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
||||||
|
if (bgtex != m_Background.image && TextureId != -1)
|
||||||
|
{
|
||||||
|
rVR.deleteTexture(TextureId);
|
||||||
|
TextureId = -1;
|
||||||
|
}
|
||||||
|
m_Background.image = bgtex;
|
||||||
|
|
||||||
|
if (TextureId == -1 && !bgtex.empty())
|
||||||
|
{
|
||||||
|
// TODO: make CViewRenderer accept urls
|
||||||
|
if (bgtex.find("://") != std::string::npos)
|
||||||
|
TextureId = rVR.createTexture(bgtex, 0, 0, -1, -1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::setImageRepeat(bool b)
|
||||||
|
{
|
||||||
|
m_Background.repeatX = b ? CSS_VALUE_REPEAT : CSS_VALUE_NOREPEAT;
|
||||||
|
m_Background.repeatY = b ? CSS_VALUE_REPEAT : CSS_VALUE_NOREPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::setImageCover(bool b)
|
||||||
|
{
|
||||||
|
m_Background.size = b ? CSS_VALUE_COVER : CSS_VALUE_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::updateCoords()
|
||||||
|
{
|
||||||
|
m_Dirty = false;
|
||||||
|
m_DrawQueue.clear();
|
||||||
|
|
||||||
|
// TODO: color from last background layer
|
||||||
|
buildColorQuads(m_Background);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// background-image
|
||||||
|
buildImageQuads(m_Background, TextureId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::draw() {
|
||||||
|
if (m_Dirty) updateCoords();
|
||||||
|
if (m_DrawQueue.empty()) return;
|
||||||
|
|
||||||
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
||||||
|
|
||||||
|
// flush draw cache to ensure correct draw order
|
||||||
|
rVR.flush();
|
||||||
|
|
||||||
|
sint32 clipX, clipY, clipW, clipH;
|
||||||
|
if (m_Viewport)
|
||||||
|
{
|
||||||
|
rVR.getClipWindow(clipX, clipY, clipW, clipH);
|
||||||
|
rVR.setClipWindow(m_Viewport->getXReal(), m_Viewport->getYReal(), m_Viewport->getWReal(), m_Viewport->getHReal());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no need for widget manager, if global color is set from parent
|
||||||
|
CRGBA globalColor;
|
||||||
|
if (m_ModulateGlobalColor)
|
||||||
|
globalColor = CWidgetManager::getInstance()->getGlobalColor();
|
||||||
|
|
||||||
|
// TODO: there might be issue on draw order IF using multiple textures
|
||||||
|
// and second (top) texture is created before first one.
|
||||||
|
for(uint i = 0; i < m_DrawQueue.size(); ++i)
|
||||||
|
{
|
||||||
|
CRGBA color = m_DrawQueue[i].Color;
|
||||||
|
if (m_ModulateGlobalColor)
|
||||||
|
color.modulateFromColor (color, globalColor);
|
||||||
|
|
||||||
|
color.A = (uint8) (((uint16) CurrentAlpha * (uint16) color.A) >> 8);
|
||||||
|
rVR.drawQuad(m_RenderLayer, m_DrawQueue[i].Quad, m_DrawQueue[i].TextureId, color, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush draw cache to ensure correct draw order
|
||||||
|
rVR.flush();
|
||||||
|
|
||||||
|
if (m_Viewport)
|
||||||
|
rVR.setClipWindow(clipX, clipY, clipW, clipH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::getPositioningArea(const CSSBackground &bg, sint32 &areaX, sint32 &areaY, sint32 &areaW, sint32 &areaH) const
|
||||||
|
{
|
||||||
|
switch(bg.origin)
|
||||||
|
{
|
||||||
|
case CSS_VALUE_PADDING_BOX:
|
||||||
|
areaX = m_PaddingX;
|
||||||
|
areaY = m_PaddingY;
|
||||||
|
areaW = m_PaddingW;
|
||||||
|
areaH = m_PaddingH;
|
||||||
|
break;
|
||||||
|
case CSS_VALUE_CONTENT_BOX:
|
||||||
|
areaX = m_ContentX;
|
||||||
|
areaY = m_ContentY;
|
||||||
|
areaW = m_ContentW;
|
||||||
|
areaH = m_ContentH;
|
||||||
|
break;
|
||||||
|
case CSS_VALUE_BORDER_BOX:
|
||||||
|
// fall thru
|
||||||
|
default:
|
||||||
|
areaX = m_BorderX;
|
||||||
|
areaY = m_BorderY;
|
||||||
|
areaW = m_BorderW;
|
||||||
|
areaH = m_BorderH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::getPaintingArea(const CSSBackground &bg, sint32 &areaX, sint32 &areaY, sint32 &areaW, sint32 &areaH) const
|
||||||
|
{
|
||||||
|
switch(bg.clip)
|
||||||
|
{
|
||||||
|
case CSS_VALUE_PADDING_BOX:
|
||||||
|
areaX = m_PaddingX;
|
||||||
|
areaY = m_PaddingY;
|
||||||
|
areaW = m_PaddingW;
|
||||||
|
areaH = m_PaddingH;
|
||||||
|
break;
|
||||||
|
case CSS_VALUE_CONTENT_BOX:
|
||||||
|
areaX = m_ContentX;
|
||||||
|
areaY = m_ContentY;
|
||||||
|
areaW = m_ContentW;
|
||||||
|
areaH = m_ContentH;
|
||||||
|
break;
|
||||||
|
case CSS_VALUE_BORDER_BOX:
|
||||||
|
// fall thru
|
||||||
|
default:
|
||||||
|
areaX = m_BorderX;
|
||||||
|
areaY = m_BorderY;
|
||||||
|
areaW = m_BorderW;
|
||||||
|
areaH = m_BorderH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_FillViewport && m_Viewport)
|
||||||
|
{
|
||||||
|
sint32 newX = std::min(areaX, m_Viewport->getXReal());
|
||||||
|
sint32 newY = std::min(areaY, m_Viewport->getYReal());
|
||||||
|
areaW = std::max(areaX + areaW, m_Viewport->getXReal() + m_Viewport->getWReal()) - newX;
|
||||||
|
areaH = std::max(areaY + areaH, m_Viewport->getYReal() + m_Viewport->getHReal()) - newY;
|
||||||
|
areaX = newX;
|
||||||
|
areaY = newY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::calculateSize(const CSSBackground &bg, sint32 &texW, sint32 &texH) const
|
||||||
|
{
|
||||||
|
sint32 areaX, areaY, areaW, areaH;
|
||||||
|
getPositioningArea(bg, areaX, areaY, areaW, areaH);
|
||||||
|
|
||||||
|
sint32 vpW=0;
|
||||||
|
sint32 vpH=0;
|
||||||
|
if (m_Viewport)
|
||||||
|
{
|
||||||
|
vpW = m_Viewport->getWReal();
|
||||||
|
vpH = m_Viewport->getHReal();
|
||||||
|
}
|
||||||
|
|
||||||
|
float whRatio = (float)texW / (float)texH;
|
||||||
|
switch(bg.size)
|
||||||
|
{
|
||||||
|
case CSS_VALUE_LENGTH:
|
||||||
|
{
|
||||||
|
if (bg.width.isAuto() && bg.height.isAuto())
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
else if (bg.width.isAuto())
|
||||||
|
{
|
||||||
|
texH = bg.height.calculate(areaH, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
texW = texH * whRatio;
|
||||||
|
}
|
||||||
|
else if (bg.height.isAuto())
|
||||||
|
{
|
||||||
|
// calculate Height
|
||||||
|
texW = bg.width.calculate(areaW, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
texH = texW / whRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texW = bg.width.calculate(areaW, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
texH = bg.height.calculate(areaH, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CSS_VALUE_AUTO:
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CSS_VALUE_COVER:
|
||||||
|
{
|
||||||
|
float canvasRatio = (float)areaW / (float)areaH;
|
||||||
|
if (whRatio < canvasRatio)
|
||||||
|
{
|
||||||
|
texW = areaW;
|
||||||
|
texH = areaW / whRatio;
|
||||||
|
} else {
|
||||||
|
texW = areaH * whRatio;
|
||||||
|
texH = areaH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CSS_VALUE_CONTAIN:
|
||||||
|
{
|
||||||
|
// same as covert, but ratio check is reversed
|
||||||
|
float canvasRatio = (float)areaW / (float)areaH;
|
||||||
|
if (whRatio > canvasRatio)
|
||||||
|
{
|
||||||
|
texW = areaW;
|
||||||
|
texH = areaW / whRatio;
|
||||||
|
} else {
|
||||||
|
texW = areaH * whRatio;
|
||||||
|
texH = areaH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::calculatePosition(const CSSBackground &bg, sint32 &texX, sint32 &texY, sint32 &texW, sint32 &texH) const
|
||||||
|
{
|
||||||
|
sint32 areaX, areaY, areaW, areaH;
|
||||||
|
getPositioningArea(bg, areaX, areaY, areaW, areaH);
|
||||||
|
|
||||||
|
sint32 vpW=0;
|
||||||
|
sint32 vpH=0;
|
||||||
|
if (m_Viewport)
|
||||||
|
{
|
||||||
|
vpW = m_Viewport->getWReal();
|
||||||
|
vpH = m_Viewport->getHReal();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ofsX = bg.xPosition.calculate(1, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
float ofsY = bg.yPosition.calculate(1, m_FontSize, m_RootFontSize, vpW, vpH);
|
||||||
|
|
||||||
|
if (bg.xPosition.isPercent() || bg.xAnchor == CSS_VALUE_CENTER)
|
||||||
|
{
|
||||||
|
if (bg.xAnchor == CSS_VALUE_RIGHT)
|
||||||
|
ofsX = 1.f - ofsX;
|
||||||
|
else if (bg.xAnchor == CSS_VALUE_CENTER)
|
||||||
|
ofsX = 0.5f;
|
||||||
|
|
||||||
|
ofsX = (float)(areaW - texW) * ofsX;
|
||||||
|
}
|
||||||
|
else if (bg.xAnchor == CSS_VALUE_RIGHT)
|
||||||
|
{
|
||||||
|
ofsX = areaW - texW - ofsX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// areaY is bottom edge, areaY+areaH is top edge
|
||||||
|
if (bg.yPosition.isPercent() || bg.yAnchor == CSS_VALUE_CENTER)
|
||||||
|
{
|
||||||
|
if (bg.yAnchor == CSS_VALUE_TOP)
|
||||||
|
ofsY = 1.f - ofsY;
|
||||||
|
else if (bg.yAnchor == CSS_VALUE_CENTER)
|
||||||
|
ofsY = 0.5f;
|
||||||
|
|
||||||
|
ofsY = (float)(areaH - texH) * ofsY;
|
||||||
|
}
|
||||||
|
else if (bg.yAnchor == CSS_VALUE_TOP)
|
||||||
|
{
|
||||||
|
ofsY = areaH - texH - ofsY;
|
||||||
|
}
|
||||||
|
|
||||||
|
texX = areaX + ofsX;
|
||||||
|
texY = areaY + ofsY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::getImageTile(sint32 &tilePos, sint32 &tileSize, sint32 &spacing, sint32 &tiles, sint32 areaPos, sint32 areaSize, CSSValueType repeat) const
|
||||||
|
{
|
||||||
|
switch(repeat)
|
||||||
|
{
|
||||||
|
case CSS_VALUE_NOREPEAT:
|
||||||
|
{
|
||||||
|
tiles = 1;
|
||||||
|
spacing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CSS_VALUE_SPACE:
|
||||||
|
{
|
||||||
|
// if no space for 2+ tiles, then show single one on calculated tilePos
|
||||||
|
if (tileSize * 2 > areaSize)
|
||||||
|
{
|
||||||
|
// set spacing large enough to only display single tile
|
||||||
|
tiles = 1;
|
||||||
|
spacing = areaSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// available for middle tiles
|
||||||
|
sint32 midSize = (areaSize - tileSize*2);
|
||||||
|
// number of middle tiles
|
||||||
|
sint32 midTiles = midSize / tileSize;
|
||||||
|
|
||||||
|
tiles = 2 + midTiles;
|
||||||
|
tilePos = areaPos;
|
||||||
|
// int div for floor()
|
||||||
|
spacing = ( midSize - tileSize * midTiles) / (midTiles + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CSS_VALUE_ROUND:
|
||||||
|
// fall-thru - size is already calculated
|
||||||
|
case CSS_VALUE_REPEAT:
|
||||||
|
// fall-thru
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
tilePos -= std::ceil(abs(tilePos - areaPos)/(float)tileSize)*tileSize;
|
||||||
|
tiles = std::ceil((std::abs(areaPos - tilePos) + areaSize) / (float)tileSize);
|
||||||
|
spacing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::calculateTiles(const CSSBackground &bg, sint32 &texX, sint32 &texY, sint32 &texW, sint32 &texH, sint32 &tilesX, sint32 &tilesY, sint32 &spacingX, sint32 &spacingY) const
|
||||||
|
{
|
||||||
|
sint32 areaX, areaY, areaW, areaH;
|
||||||
|
getPositioningArea(bg, areaX, areaY, areaW, areaH);
|
||||||
|
|
||||||
|
// texX,texY is for position area (ie content-box), but painting area can be bigger (ie border-box)
|
||||||
|
sint32 paintX, paintY, paintW, paintH;
|
||||||
|
getPaintingArea(bg, paintX, paintY, paintW, paintH);
|
||||||
|
if (paintX < areaX)
|
||||||
|
areaX -= std::ceil((areaX - paintX) / (float)texW) * texW;
|
||||||
|
if ((paintX + paintW) > (areaX + areaW))
|
||||||
|
areaW += std::ceil(((paintX + paintW) - (areaX + areaW)) / (float)texW) * texW;
|
||||||
|
if (paintY < areaY)
|
||||||
|
areaY -= std::ceil((areaY - paintY) / (float)texH) * texH;
|
||||||
|
if ((paintY + paintH) > (areaY + areaH))
|
||||||
|
areaH += std::ceil(((paintY + paintH) - (areaY + areaH)) / (float)texH) * texH;
|
||||||
|
|
||||||
|
if (texW <= 0 || texH <= 0 || areaW <= 0 || areaH <= 0)
|
||||||
|
{
|
||||||
|
tilesX = tilesY = 0;
|
||||||
|
spacingX = spacingY = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bg.repeatX == CSS_VALUE_ROUND)
|
||||||
|
{
|
||||||
|
sint numTiles = std::max(1, (sint)std::round((float)areaW / texW));
|
||||||
|
texW = areaW / numTiles;
|
||||||
|
if (bg.height.isAuto() && bg.repeatY != CSS_VALUE_ROUND)
|
||||||
|
{
|
||||||
|
float aspect = (float)areaW / (numTiles * texW);
|
||||||
|
texH = texW * aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bg.repeatY == CSS_VALUE_ROUND)
|
||||||
|
{
|
||||||
|
sint numTiles = std::max(1, (sint)std::round((float)areaH / texH));
|
||||||
|
texH = areaH / numTiles;
|
||||||
|
if (bg.width.isAuto() && bg.repeatX != CSS_VALUE_ROUND)
|
||||||
|
{
|
||||||
|
float aspect = (float)areaH / (numTiles * texH);
|
||||||
|
texW = texH * aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getImageTile(texX, texW, spacingX, tilesX, areaX, areaW, bg.repeatX);
|
||||||
|
getImageTile(texY, texH, spacingY, tilesY, areaY, areaH, bg.repeatY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::buildColorQuads(const CSSBackground &bg)
|
||||||
|
{
|
||||||
|
if (bg.color.A == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// painting area defined with background-clip
|
||||||
|
sint32 x, y, w, h;
|
||||||
|
getPaintingArea(bg, x, y, w, h);
|
||||||
|
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
||||||
|
|
||||||
|
SDrawQueue shape;
|
||||||
|
shape.Quad.Uv0.set(0.f, 1.f);
|
||||||
|
shape.Quad.Uv1.set(1.f, 1.f);
|
||||||
|
shape.Quad.Uv2.set(1.f, 0.f);
|
||||||
|
shape.Quad.Uv3.set(0.f, 0.f);
|
||||||
|
|
||||||
|
shape.Quad.V0.set(x, y, 0);
|
||||||
|
shape.Quad.V1.set(x+w, y, 0);
|
||||||
|
shape.Quad.V2.set(x+w, y+h, 0);
|
||||||
|
shape.Quad.V3.set(x, y+h, 0);
|
||||||
|
|
||||||
|
shape.Color = bg.color;
|
||||||
|
shape.TextureId = rVR.getBlankTextureId();
|
||||||
|
|
||||||
|
m_DrawQueue.push_back(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
void CSSBackgroundRenderer::buildImageQuads(const CSSBackground &bg, sint32 textureId)
|
||||||
|
{
|
||||||
|
// TODO: m_Background should have textureId and that should be "reserved" in CViewRenderer
|
||||||
|
// even before download is finished
|
||||||
|
if (textureId < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
||||||
|
|
||||||
|
sint32 texW = 0;
|
||||||
|
sint32 texH = 0;
|
||||||
|
rVR.getTextureSizeFromId(textureId, texW, texH);
|
||||||
|
if (texW <= 0 || texH <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get requested texture size
|
||||||
|
calculateSize(m_Background, texW, texH);
|
||||||
|
if(texW <= 0 || texH <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get texture left/top corner
|
||||||
|
sint32 texX, texY;
|
||||||
|
calculatePosition(m_Background, texX, texY, texW, texH);
|
||||||
|
|
||||||
|
sint32 tilesX, tilesY;
|
||||||
|
sint32 spacingX, spacingY;
|
||||||
|
calculateTiles(m_Background, texX, texY, texW, texH, tilesX, tilesY, spacingX, spacingY);
|
||||||
|
|
||||||
|
sint32 clipL, clipB, clipR, clipT;
|
||||||
|
getPaintingArea(m_Background, clipL, clipB, clipR, clipT);
|
||||||
|
clipR += clipL;
|
||||||
|
clipT += clipB;
|
||||||
|
|
||||||
|
m_DrawQueue.reserve(tilesX * tilesY + m_DrawQueue.size());
|
||||||
|
for(sint32 tileX = 0; tileX < tilesX; tileX++)
|
||||||
|
{
|
||||||
|
for(sint32 tileY = 0; tileY < tilesY; tileY++)
|
||||||
|
{
|
||||||
|
sint32 tileL = texX + tileX * (texW + spacingX);
|
||||||
|
sint32 tileB = texY + tileY * (texH + spacingY);
|
||||||
|
sint32 tileR = tileL + texW;
|
||||||
|
sint32 tileT = tileB + texH;
|
||||||
|
|
||||||
|
// tile is outside clip area
|
||||||
|
if (tileT <= clipB || tileB >= clipT || tileR <= clipL || tileL >= clipR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CUV uv0(0,1);
|
||||||
|
CUV uv1(1,1);
|
||||||
|
CUV uv2(1,0);
|
||||||
|
CUV uv3(0,0);
|
||||||
|
|
||||||
|
// clip if tile not totally inside clip area
|
||||||
|
if (!(tileL >= clipL && tileR <= clipR && tileB >= clipB && tileT <= clipT))
|
||||||
|
{
|
||||||
|
float ratio;
|
||||||
|
if (tileL < clipL)
|
||||||
|
{
|
||||||
|
ratio = ((float)(clipL - tileL))/((float)(tileR - tileL));
|
||||||
|
tileL = clipL;
|
||||||
|
uv0.U += ratio*(uv1.U-uv0.U);
|
||||||
|
uv3.U += ratio*(uv2.U-uv3.U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileB < clipB)
|
||||||
|
{
|
||||||
|
ratio = ((float)(clipB - tileB))/((float)(tileT - tileB));
|
||||||
|
tileB = clipB;
|
||||||
|
uv0.V += ratio*(uv3.V-uv0.V);
|
||||||
|
uv1.V += ratio*(uv2.V-uv1.V);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileR > clipR)
|
||||||
|
{
|
||||||
|
ratio = ((float)(clipR - tileR))/((float)(tileL - tileR));
|
||||||
|
tileR = clipR;
|
||||||
|
uv2.U += ratio*(uv3.U-uv2.U);
|
||||||
|
uv1.U += ratio*(uv0.U-uv1.U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileT > clipT)
|
||||||
|
{
|
||||||
|
ratio = ((float)(clipT - tileT))/((float)(tileB - tileT));
|
||||||
|
tileT = clipT;
|
||||||
|
uv2.V += ratio*(uv1.V-uv2.V);
|
||||||
|
uv3.V += ratio*(uv0.V-uv3.V);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDrawQueue shape;
|
||||||
|
shape.Quad.Uv0 = uv0;
|
||||||
|
shape.Quad.Uv1 = uv1;
|
||||||
|
shape.Quad.Uv2 = uv2;
|
||||||
|
shape.Quad.Uv3 = uv3;
|
||||||
|
|
||||||
|
shape.Color = CRGBA::White;
|
||||||
|
shape.TextureId = textureId;
|
||||||
|
|
||||||
|
shape.Quad.V0.set(tileL, tileB, 0);
|
||||||
|
shape.Quad.V1.set(tileR, tileB, 0);
|
||||||
|
shape.Quad.V2.set(tileR, tileT, 0);
|
||||||
|
shape.Quad.V3.set(tileL, tileT, 0);
|
||||||
|
|
||||||
|
m_DrawQueue.push_back(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}//namespace
|
||||||
|
|
@ -0,0 +1,222 @@
|
|||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010-2021 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/>.
|
||||||
|
|
||||||
|
#include "stdpch.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "nel/gui/css_length.h"
|
||||||
|
|
||||||
|
using namespace NLMISC;
|
||||||
|
|
||||||
|
#ifdef DEBUG_NEW
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
|
||||||
|
bool CSSLength::parseValue(const std::string &value, bool allowPercent, bool allowNegative)
|
||||||
|
{
|
||||||
|
static const std::set<std::string> knownUnits = {
|
||||||
|
"%", "rem", "em", "px", "pt", "vw", "vh", "vi", "vb", "vmin", "vmax"
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string::size_type pos = 0;
|
||||||
|
std::string::size_type len = value.size();
|
||||||
|
if (len == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (len == 1 && value[0] == '0')
|
||||||
|
{
|
||||||
|
m_Value = 0;
|
||||||
|
m_Kind = Auto;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +100px; -100px
|
||||||
|
if (value[0] == '+')
|
||||||
|
pos++;
|
||||||
|
else if (allowNegative && value[0] == '-')
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
while(pos < len)
|
||||||
|
{
|
||||||
|
bool isNumeric = (value[pos] >= '0' && value[pos] <= '9')
|
||||||
|
|| (pos == 0 && value[pos] == '.')
|
||||||
|
|| (pos > 0 && value[pos] == '.' && value[pos-1] >= '0' && value[pos-1] <= '9');
|
||||||
|
|
||||||
|
if (!isNumeric)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string unit = toLowerAscii(value.substr(pos));
|
||||||
|
if (knownUnits.count(unit))
|
||||||
|
{
|
||||||
|
std::string tmpstr = value.substr(0, pos);
|
||||||
|
return fromString(tmpstr, m_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CSSLength::getValue() const
|
||||||
|
{
|
||||||
|
if (m_Unit == CSS_UNIT_PERCENT)
|
||||||
|
return m_Value / 100.f;
|
||||||
|
|
||||||
|
return m_Value;
|
||||||
|
}
|
||||||
|
void CSSLength::setFloatValue(float f, const std::string &unit)
|
||||||
|
{
|
||||||
|
m_Value = f;
|
||||||
|
setUnit(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSSLength::setUnit(const std::string &unit)
|
||||||
|
{
|
||||||
|
if (unit.empty())
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_NONE;
|
||||||
|
m_Kind = Fixed;
|
||||||
|
}
|
||||||
|
else if (unit == "px")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_PX;
|
||||||
|
m_Kind = Fixed;
|
||||||
|
} else if (unit == "pt")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_PT;
|
||||||
|
m_Kind = Fixed;
|
||||||
|
} else if (unit == "%")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_PERCENT;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "em")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_EM;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "rem")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_REM;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vw")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VW;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vh")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VH;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vi")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VI;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vb")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VB;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vmin")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VMIN;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "vmax")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_VMAX;
|
||||||
|
m_Kind = Relative;
|
||||||
|
} else if (unit == "auto")
|
||||||
|
{
|
||||||
|
m_Unit = CSS_UNIT_NONE;
|
||||||
|
m_Kind = Auto;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// fallback to auto
|
||||||
|
m_Unit = CSS_UNIT_NONE;
|
||||||
|
m_Kind = Auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float CSSLength::calculate(uint32 relValue, uint32 emSize, uint32 remSize, uint32 vwSize, uint32 vhSize = 0) const
|
||||||
|
{
|
||||||
|
float value = getValue();
|
||||||
|
switch(m_Unit)
|
||||||
|
{
|
||||||
|
case CSS_UNIT_EM:
|
||||||
|
return emSize * value;
|
||||||
|
case CSS_UNIT_REM:
|
||||||
|
return remSize * value;
|
||||||
|
case CSS_UNIT_PERCENT:
|
||||||
|
return relValue * value;
|
||||||
|
case CSS_UNIT_PX:
|
||||||
|
case CSS_UNIT_PT:
|
||||||
|
return value;
|
||||||
|
case CSS_UNIT_VW:
|
||||||
|
case CSS_UNIT_VI:
|
||||||
|
// Vi for horizontal writing mode only
|
||||||
|
return (float)vwSize*0.01f;
|
||||||
|
case CSS_UNIT_VH:
|
||||||
|
case CSS_UNIT_VB:
|
||||||
|
// Vb for horizontal writing mode only
|
||||||
|
return (float)vhSize*0.01f;
|
||||||
|
case CSS_UNIT_VMIN:
|
||||||
|
return (float)std::min(vwSize, vhSize)*0.01f;
|
||||||
|
case CSS_UNIT_VMAX:
|
||||||
|
return (float)std::max(vwSize, vhSize)*0.01f;
|
||||||
|
}
|
||||||
|
|
||||||
|
nldebug("Unknown CSS unit '%s'", toString().c_str());
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CSSLength::toString() const
|
||||||
|
{
|
||||||
|
if (m_Kind == Auto)
|
||||||
|
return "auto";
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
ret += NLMISC::toString("%f", m_Value);
|
||||||
|
|
||||||
|
size_t pos = ret.find(".");
|
||||||
|
for( ; pos < ret.size(); ++pos)
|
||||||
|
{
|
||||||
|
if (ret[pos] != '0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos == ret.size())
|
||||||
|
ret = ret.substr(0, ret.find("."));
|
||||||
|
|
||||||
|
switch(m_Unit)
|
||||||
|
{
|
||||||
|
case CSS_UNIT_NONE: break;
|
||||||
|
case CSS_UNIT_EM: ret += "em"; break;
|
||||||
|
case CSS_UNIT_REM: ret += "rem"; break;
|
||||||
|
case CSS_UNIT_PERCENT: ret += "%"; break;
|
||||||
|
case CSS_UNIT_PX: ret += "px"; break;
|
||||||
|
case CSS_UNIT_PT: ret += "pt"; break;
|
||||||
|
case CSS_UNIT_VW: ret += "vw"; break;
|
||||||
|
case CSS_UNIT_VH: ret += "vh"; break;
|
||||||
|
case CSS_UNIT_VI: ret += "vi"; break;
|
||||||
|
case CSS_UNIT_VB: ret += "vb"; break;
|
||||||
|
case CSS_UNIT_VMIN: ret += "vmin"; break;
|
||||||
|
case CSS_UNIT_VMAX: ret += "vmax"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue