Merge with develop

--HG--
branch : atys
hg/atys
Nuno Gonçalves 5 years ago
commit 19789a2544

@ -0,0 +1,94 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 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_BORDER_RENDERER_H
#define NL_CSS_BORDER_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"
namespace NLGUI
{
/**
* \brief Border renderer for GUI classes
* \date 2019-09-03 10:50 GMT
* \author Meelis Mägi (Nimetu)
*/
class CSSBorderRenderer
{
private:
// parent element screen coordinates
sint32 _XReal, _YReal;
sint32 _WReal, _HReal;
NLMISC::CQuadUV _QuadT;
NLMISC::CQuadUV _QuadR;
NLMISC::CQuadUV _QuadB;
NLMISC::CQuadUV _QuadL;
uint8 _RenderLayer;
bool _ModulateGlobalColor;
// if true, then updateCoords() is called from draw()
bool _Dirty;
// if true, then at least one border is set
bool _Border;
bool _BorderTop, _BorderRight, _BorderBottom, _BorderLeft;
public:
uint32 TopWidth, RightWidth, BottomWidth, LeftWidth;
NLMISC::CRGBA TopColor, RightColor, BottomColor, LeftColor;
CSSLineStyle TopStyle, RightStyle, BottomStyle, LeftStyle;
// alpha value from parent
uint8 CurrentAlpha;
public:
CSSBorderRenderer();
void setRenderLayer(sint layer);
void setModulateGlobalColor(bool m);
void setRect(sint32 x, sint32 y, sint32 w, sint32 h);
void setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left);
void setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left);
void setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left);
void updateCoords();
void invalidateCoords() { _Dirty = _Border = true; }
void invalidateContent() { _Dirty = _Border = true; };
uint32 getTopWidth() const;
uint32 getRightWidth() const;
uint32 getBottomWidth() const;
uint32 getLeftWidth() const;
uint32 getLeftRightWidth() const;
uint32 getTopBottomWidth() const;
void draw();
}; // CSSBorderRenderer
}//namespace
#endif // NL_CSS_BORDER_RENDERER_H

@ -31,7 +31,7 @@ namespace NLGUI
class CCssParser { class CCssParser {
public: public:
// parse style declaration, eg "color: red; font-size: 10px;" // parse style declaration, eg "color: red; font-size: 10px;"
static TStyle parseDecls(const std::string &styleString); static TStyleVec parseDecls(const std::string &styleString);
// parse css stylesheet // parse css stylesheet
void parseStylesheet(const std::string &cssString, std::vector<CCssStyle::SStyleRule> &rules); void parseStylesheet(const std::string &cssString, std::vector<CCssStyle::SStyleRule> &rules);

@ -20,12 +20,15 @@
#include "nel/misc/types_nl.h" #include "nel/misc/types_nl.h"
#include "nel/misc/rgba.h" #include "nel/misc/rgba.h"
#include "nel/gui/css_selector.h" #include "nel/gui/css_selector.h"
#include "nel/gui/css_types.h"
namespace NLGUI namespace NLGUI
{ {
class CHtmlElement; class CHtmlElement;
typedef std::map<std::string, std::string> TStyle; typedef std::map<std::string, std::string> TStyle;
typedef std::pair<std::string, std::string> TStylePair;
typedef std::vector<TStylePair> TStyleVec;
/** /**
* \brief CSS style rules * \brief CSS style rules
@ -62,9 +65,14 @@ namespace NLGUI
Height=-1; Height=-1;
MaxWidth=-1; MaxWidth=-1;
MaxHeight=-1; MaxHeight=-1;
BorderWidth=-1; // border style
BorderTopWidth = BorderRightWidth = BorderBottomWidth = BorderLeftWidth = CSSLineWidth::MEDIUM;
BorderTopStyle = BorderRightStyle = BorderBottomStyle = BorderLeftStyle = CSSLineStyle::NONE;
BorderTopColor = BorderRightColor = BorderBottomColor = BorderLeftColor = NLMISC::CRGBA::Transparent;
// background
BackgroundColor=NLMISC::CRGBA::Black; BackgroundColor=NLMISC::CRGBA::Black;
BackgroundColorOver=NLMISC::CRGBA::Black; BackgroundColorOver=NLMISC::CRGBA::Black;
PaddingTop = PaddingRight = PaddingBottom = PaddingLeft = 0;
} }
bool hasStyle(const std::string &key) const bool hasStyle(const std::string &key) const
@ -93,9 +101,12 @@ namespace NLGUI
sint32 Height; sint32 Height;
sint32 MaxWidth; sint32 MaxWidth;
sint32 MaxHeight; sint32 MaxHeight;
sint32 BorderWidth; uint32 BorderTopWidth, BorderRightWidth, BorderBottomWidth, BorderLeftWidth;
CSSLineStyle BorderTopStyle, BorderRightStyle, BorderBottomStyle, BorderLeftStyle;
NLMISC::CRGBA BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor;
NLMISC::CRGBA BackgroundColor; NLMISC::CRGBA BackgroundColor;
NLMISC::CRGBA BackgroundColorOver; NLMISC::CRGBA BackgroundColorOver;
uint32 PaddingTop, PaddingRight, PaddingBottom, PaddingLeft;
std::string WhiteSpace; std::string WhiteSpace;
std::string TextAlign; std::string TextAlign;
@ -106,9 +117,10 @@ namespace NLGUI
class CCssStyle { class CCssStyle {
public: public:
struct SStyleRule { struct SStyleRule {
std::vector<CCssSelector> Selector; std::vector<CCssSelector> Selector;
TStyle Properties; TStyleVec Properties;
// pseudo element like ':before' // pseudo element like ':before'
std::string PseudoElement; std::string PseudoElement;
@ -132,6 +144,9 @@ namespace NLGUI
// test if str is one of "thin/medium/thick" and return its pixel value // test if str is one of "thin/medium/thick" and return its pixel value
bool scanCssLength(const std::string& str, uint32 &px) const; bool scanCssLength(const std::string& str, uint32 &px) const;
// split css properties string, ie '1px solid rgb(100, 100, 100)' split by ' ' returns 3 parts.
void splitParams(const std::string &str, char sep, std::vector<std::string> &result) const;
// read style attribute // read style attribute
void getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams &current) const; void getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams &current) const;
void getStyleParams(const TStyle &styleRules, CStyleParams &style, const CStyleParams &current) const; void getStyleParams(const TStyle &styleRules, CStyleParams &style, const CStyleParams &current) const;
@ -143,13 +158,35 @@ namespace NLGUI
void apply(CStyleParams &style, const CStyleParams &current) const; void apply(CStyleParams &style, const CStyleParams &current) const;
// merge src into dest by overwriting key in dest // merge src into dest by overwriting key in dest
void merge(TStyle &dst, const TStyle &src) const; void merge(TStyle &dst, const TStyleVec &src) const;
// match selector to dom path // match selector to dom path
bool match(const std::vector<CCssSelector> &selector, const CHtmlElement &elm) const; bool match(const std::vector<CCssSelector> &selector, const CHtmlElement &elm) const;
// get shorthang 'top right bottom left' index values based size, ie 'padding' syntax
bool getShorthandIndices(const uint32 size, uint8 &t, uint8 &r, uint8 &b, uint8 &l) const;
// break 'border' into 'border-top-color', 'border-top-style', etc rules
bool tryBorderWidthShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
bool tryBorderStyleShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
bool tryBorderColorShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
void expandBorderShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
// parse 'background' into 'background-color', 'background-image', etc // parse 'background' into 'background-color', 'background-image', etc
void parseBackgroundShorthand(const std::string &value, CStyleParams &style) const; void expandBackgroundShorthand(const std::string &value, TStyle &style) const;
// parse 'padding' into 'padding-top', 'padding-left', etc
void expandPaddingShorthand(const std::string &value, TStyle &style) const;
// expand shorthand rule, ie "border", into longhand names, ie "border-top-width"
// if shorthand is present in style, then its removed
void expandShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
// parse string value into corresponding value
void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const;
void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA &currentColor, const NLMISC::CRGBA &textColor) const;
void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle &currentStyle) const;
void applyPaddingWidth(const std::string &value, uint32 *dest, const uint32 currentPadding, uint32 fontSize) const;
public: public:
void reset(); void reset();
@ -171,12 +208,17 @@ namespace NLGUI
{ {
_StyleStack.push_back(Current); _StyleStack.push_back(Current);
Current.GlobalColor = false;
Current.DisplayBlock = false; Current.DisplayBlock = false;
Current.Width=-1; Current.Width=-1;
Current.Height=-1; Current.Height=-1;
Current.MaxWidth=-1; Current.MaxWidth=-1;
Current.MaxHeight=-1; Current.MaxHeight=-1;
Current.BorderWidth=-1;
Current.BorderTopWidth = Current.BorderRightWidth = Current.BorderBottomWidth = Current.BorderLeftWidth = CSSLineWidth::MEDIUM;
Current.BorderTopStyle = Current.BorderRightStyle = Current.BorderBottomStyle = Current.BorderLeftStyle = CSSLineStyle::NONE;
Current.BorderTopColor = Current.BorderRightColor = Current.BorderBottomColor = Current.BorderLeftColor = Current.TextColor;
Current.PaddingTop = Current.PaddingRight = Current.PaddingBottom = Current.PaddingLeft = 0;
Current.StyleRules.clear(); Current.StyleRules.clear();
} }

@ -0,0 +1,39 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 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_TYPES_H
#define CL_CSS_TYPES_H
#include "nel/misc/types_nl.h"
namespace NLGUI
{
/**
* \brief CSS types used in GUI classes
* \date 2019-09-03 10:50 GMT
* \author Meelis Mägi (Nimetu)
*/
// ie. border-style
enum CSSLineStyle { NONE = 0, HIDDEN, SOLID, INSET, OUTSET };
// ie, border-width (px)
enum CSSLineWidth { THIN = 1, MEDIUM = 3, THICK = 5 };
}//namespace
#endif // CL_CSS_TYPES_H

@ -124,7 +124,7 @@ namespace NLGUI
void endParagraph(); void endParagraph();
// add image download (used by view_bitmap.cpp to load web images) // add image download (used by view_bitmap.cpp to load web images)
void addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage); void addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage, const std::string &placeholder = "web_del.tga");
// remove image from download list if present // remove image from download list if present
void removeImageDownload(CViewBase *img); void removeImageDownload(CViewBase *img);
std::string localImageName(const std::string &url); std::string localImageName(const std::string &url);
@ -546,6 +546,11 @@ namespace NLGUI
// IL mode // IL mode
bool _LI; bool _LI;
// style from browser.css
CCssStyle _BrowserStyle;
// local file for browser.css
std::string _BrowserCssFile;
// Keep track of current element style // Keep track of current element style
CCssStyle _Style; CCssStyle _Style;
CHtmlElement _HtmlDOM; CHtmlElement _HtmlDOM;
@ -702,6 +707,7 @@ namespace NLGUI
VAlign = CGroupCell::Middle; VAlign = CGroupCell::Middle;
LeftMargin = 0; LeftMargin = 0;
NoWrap = false; NoWrap = false;
Height = 0;
} }
NLMISC::CRGBA BgColor; NLMISC::CRGBA BgColor;
std::string Style; std::string Style;
@ -709,6 +715,7 @@ namespace NLGUI
CGroupCell::TVAlign VAlign; CGroupCell::TVAlign VAlign;
sint32 LeftMargin; sint32 LeftMargin;
bool NoWrap; bool NoWrap;
sint32 Height;
}; };
std::vector<CCellParams> _CellParams; std::vector<CCellParams> _CellParams;

@ -136,9 +136,13 @@ namespace NLGUI
void removeLine(uint index); void removeLine(uint index);
const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandler(uint lineIndex) const;
const std::string getActionHandlerParam(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const;
const std::string getRightClickHandler(uint lineIndex) const;
const std::string getRightClickHandlerParam(uint lineIndex) const;
void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandler(uint lineIndex, const std::string &ah = "");
void setActionHandlerParam(uint lineIndex, const std::string &params = ""); void setActionHandlerParam(uint lineIndex, const std::string &params = "");
void setRightClickHandler(uint lineIndex, const std::string &ah = "");
void setRightClickHandlerParam(uint lineIndex, const std::string &params = "");
void openSubMenu (sint32 nb); void openSubMenu (sint32 nb);
@ -235,6 +239,8 @@ namespace NLGUI
CInterfaceGroup *Separator; CInterfaceGroup *Separator;
std::string AHName; std::string AHName;
std::string AHParams; std::string AHParams;
std::string AHRightClick;
std::string AHRightClickParams;
std::string Id; std::string Id;
std::string Cond; // condition to know if the entry is grayed std::string Cond; // condition to know if the entry is grayed
CViewBitmap *CheckBox; CViewBitmap *CheckBox;
@ -332,9 +338,13 @@ namespace NLGUI
void deleteLine(uint index); void deleteLine(uint index);
const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandler(uint lineIndex) const;
const std::string getActionHandlerParam(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const;
const std::string getRightClickHandler(uint lineIndex) const;
const std::string getRightClickHandlerParam(uint lineIndex) const;
void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandler(uint lineIndex, const std::string &ah = "");
void setActionHandlerParam(uint lineIndex, const std::string &params = ""); void setActionHandlerParam(uint lineIndex, const std::string &params = "");
void setRightClickHandler(uint lineIndex, const std::string &ah = "");
void setRightClickHandlerParam(uint lineIndex, const std::string &params = "");
void addLine (const ucstring &name, const std::string &ah = "", const std::string &params = "", void addLine (const ucstring &name, const std::string &ah = "", const std::string &params = "",
const std::string &id = std::string(), const std::string &id = std::string(),
@ -357,7 +367,7 @@ namespace NLGUI
void setMinH(sint32 minH); void setMinH(sint32 minH);
// change fontsize for new menu items // change fontsize for new menu items
void setFontSize(uint32 fontSize); void setFontSize(uint32 fontSize, bool coef = true);
// Gray a line on the RootMenu // Gray a line on the RootMenu
void setGrayedLine(uint line, bool g); void setGrayedLine(uint line, bool g);
@ -397,6 +407,7 @@ namespace NLGUI
bool _Formatted; bool _Formatted;
uint8 _Space; uint8 _Space;
sint32 _FontSize; sint32 _FontSize;
bool _FontSizeCoef;
NLMISC::CRGBA _ColorOver; // Color of the text when the mouse is over it NLMISC::CRGBA _ColorOver; // Color of the text when the mouse is over it
NLMISC::CRGBA _ShadowColorOver; // Color of the shadow when the mouse is over it NLMISC::CRGBA _ShadowColorOver; // Color of the shadow when the mouse is over it

@ -23,9 +23,11 @@
#include "nel/gui/group_frame.h" #include "nel/gui/group_frame.h"
#include "nel/gui/view_text.h" #include "nel/gui/view_text.h"
#include "nel/gui/ctrl_button.h" #include "nel/gui/ctrl_button.h"
#include "nel/gui/css_types.h"
namespace NLGUI namespace NLGUI
{ {
class CSSBorderRenderer;
/** /**
* This group is used to simulate HTML cells. * This group is used to simulate HTML cells.
@ -39,6 +41,7 @@ namespace NLGUI
DECLARE_UI_CLASS( CGroupCell ) DECLARE_UI_CLASS( CGroupCell )
CGroupCell(const TCtorParam &param); CGroupCell(const TCtorParam &param);
~CGroupCell();
enum TAlign enum TAlign
{ {
@ -91,11 +94,18 @@ namespace NLGUI
// The cell color // The cell color
NLMISC::CRGBA BgColor; NLMISC::CRGBA BgColor;
CSSBorderRenderer* Border;
uint32 PaddingTop, PaddingRight, PaddingBottom, PaddingLeft;
// Texture // Texture
CViewRenderer::CTextureId _TextureId; /// Accelerator CViewRenderer::CTextureId _TextureId;
bool _UserTexture;
bool _TextureTiled; bool _TextureTiled;
bool _TextureScaled; bool _TextureScaled;
// cached absolute coords for background texture
sint32 _TextureXReal;
sint32 _TextureYReal;
sint32 _TextureWReal;
sint32 _TextureHReal;
// Alignment // Alignment
TAlign Align; TAlign Align;
@ -112,10 +122,17 @@ namespace NLGUI
void setTextureTile(bool tiled); void setTextureTile(bool tiled);
void setTextureScale(bool scaled); void setTextureScale(bool scaled);
uint32 getPaddingLeftRight() const { return PaddingLeft + PaddingRight; };
uint32 getPaddingTopBottom() const { return PaddingTop + PaddingBottom; };
virtual void updateCoords();
static void setDebugUICell( bool d ){ DebugUICell = d; } static void setDebugUICell( bool d ){ DebugUICell = d; }
static bool getDebugUICell(){ return DebugUICell; } static bool getDebugUICell(){ return DebugUICell; }
private: private:
void updateTextureCoords();
void setEnclosedGroupDefaultParams(); void setEnclosedGroupDefaultParams();
static bool DebugUICell; static bool DebugUICell;
}; };
@ -143,9 +160,10 @@ namespace NLGUI
// The Width you want in pixel. This is the <table width="100"> parameter // The Width you want in pixel. This is the <table width="100"> parameter
sint32 ForceWidthMin; sint32 ForceWidthMin;
// Table borders CSSBorderRenderer* Border;
sint32 Border;
NLMISC::CRGBA BorderColor; // Cell has 1px solid border when <table> has 'border' attribute with width > 0
bool CellBorder;
sint32 CellPadding; sint32 CellPadding;
sint32 CellSpacing; sint32 CellSpacing;
@ -155,6 +173,10 @@ namespace NLGUI
bool ContinuousUpdate; bool ContinuousUpdate;
void setTexture(const std::string & TxName);
void setTextureTile(bool tiled);
void setTextureScale(bool scaled);
std::string getProperties( const std::string &name ) const; std::string getProperties( const std::string &name ) const;
void setProperty( const std::string &name, const std::string &value ); void setProperty( const std::string &name, const std::string &value );
xmlNodePtr serialize( xmlNodePtr parentNode, const char *type ) const; xmlNodePtr serialize( xmlNodePtr parentNode, const char *type ) const;
@ -176,6 +198,18 @@ namespace NLGUI
virtual bool parse (xmlNodePtr cur, CInterfaceGroup * parentGroup); virtual bool parse (xmlNodePtr cur, CInterfaceGroup * parentGroup);
// Texture
CViewRenderer::CTextureId _TextureId;
bool _TextureTiled;
bool _TextureScaled;
// cached absolute coords for background texture
sint32 _TextureXReal;
sint32 _TextureYReal;
sint32 _TextureWReal;
sint32 _TextureHReal;
void updateTextureCoords();
// Content validated // Content validated
bool _ContentValidated; bool _ContentValidated;

@ -101,6 +101,12 @@ namespace NLGUI
return _TextureId; return _TextureId;
} }
// Return true if TextureId is not set
bool empty() const { return _TextureId < 0; };
// delete TextureId if set
void clear();
void serial(NLMISC::IStream &f); void serial(NLMISC::IStream &f);
private: private:

@ -26,6 +26,7 @@
#include "nel/misc/types_nl.h" #include "nel/misc/types_nl.h"
#include "nel/gui/interface_common.h" #include "nel/gui/interface_common.h"
#include "nel/gui/interface_options.h" #include "nel/gui/interface_options.h"
#include "nel/gui/interface_group.h"
#include "nel/gui/event_descriptor.h" #include "nel/gui/event_descriptor.h"
#include "nel/3d/u_camera.h" #include "nel/3d/u_camera.h"
#include "nel/gui/parser.h" #include "nel/gui/parser.h"

@ -119,6 +119,11 @@ public: // Advanced Usage.
// return a string separated by \n or eof, used to parsing text file // return a string separated by \n or eof, used to parsing text file
void getline (char *buffer, uint32 bufferSize); void getline (char *buffer, uint32 bufferSize);
// read whole file into a string. resulting buffer may contain NULL chars.
// internal read position is modified.
// return true on success, false on failure.
bool readAll(std::string &buffer);
// return the size of the file // return the size of the file
uint32 getFileSize () const { return _FileSize; } uint32 getFileSize () const { return _FileSize; }

@ -377,6 +377,7 @@ public:
static const CRGBA Magenta ; static const CRGBA Magenta ;
static const CRGBA Cyan ; static const CRGBA Cyan ;
static const CRGBA White ; static const CRGBA White ;
static const CRGBA Transparent ;
}; };

@ -0,0 +1,320 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 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_border_renderer.h"
#include "nel/gui/view_renderer.h"
#include "nel/gui/widget_manager.h"
using namespace std;
using namespace NLMISC;
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
namespace NLGUI
{
// ----------------------------------------------------------------------------
CSSBorderRenderer::CSSBorderRenderer()
{
TopWidth = RightWidth = BottomWidth = LeftWidth = 0;
TopColor = RightColor = BottomColor = LeftColor = CRGBA(128, 128, 128, 255);
TopStyle = RightStyle = BottomStyle = LeftStyle = CSSLineStyle::SOLID;
CurrentAlpha = 255;
_RenderLayer = 0;
_ModulateGlobalColor = false;
_Border = true;
_Dirty = true;
_BorderTop = _BorderRight = _BorderBottom = _BorderLeft = false;
//
_QuadT.Uv0.set(0.f, 0.f);
_QuadT.Uv1.set(0.f, 0.f);
_QuadT.Uv2.set(1.f, 1.f);
_QuadT.Uv3.set(0.f, 1.f);
//
_QuadR.Uv0.set(0.f, 0.f);
_QuadR.Uv1.set(0.f, 0.f);
_QuadR.Uv2.set(1.f, 1.f);
_QuadR.Uv3.set(0.f, 1.f);
//
_QuadB.Uv0.set(0.f, 0.f);
_QuadB.Uv1.set(0.f, 0.f);
_QuadB.Uv2.set(1.f, 1.f);
_QuadB.Uv3.set(0.f, 1.f);
//
_QuadL.Uv0.set(0.f, 0.f);
_QuadL.Uv1.set(0.f, 0.f);
_QuadL.Uv2.set(1.f, 1.f);
_QuadL.Uv3.set(0.f, 1.f);
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setRenderLayer(sint layer)
{
_RenderLayer = layer;
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setModulateGlobalColor(bool s)
{
_ModulateGlobalColor = s;
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setRect(sint32 x, sint32 y, sint32 w, sint32 h)
{
_XReal = x;
_YReal = y;
_WReal = w;
_HReal = h;
_Dirty = _Border = (w > 0 && h > 0);
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left)
{
TopWidth = top;
RightWidth = right;
BottomWidth = bottom;
LeftWidth = left;
_Dirty = _Border = (top > 0 || right > 0 || bottom > 0 || left > 0);
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left)
{
TopStyle = top;
RightStyle = right;
BottomStyle = bottom;
LeftStyle = left;
_Dirty = _Border = true;
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left)
{
TopColor = top;
RightColor = right;
BottomColor = bottom;
LeftColor = left;
_Dirty = true;
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getTopWidth() const
{
if (TopStyle == CSSLineStyle::NONE || TopStyle == CSSLineStyle::HIDDEN)
return 0;
return TopWidth;
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getRightWidth() const
{
if (RightStyle == CSSLineStyle::NONE || RightStyle == CSSLineStyle::HIDDEN)
return 0;
return RightWidth;
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getBottomWidth() const
{
if (BottomStyle == CSSLineStyle::NONE || BottomStyle == CSSLineStyle::HIDDEN)
return 0;
return BottomWidth;
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getLeftWidth() const
{
if (LeftStyle == CSSLineStyle::NONE || LeftStyle == CSSLineStyle::HIDDEN)
return 0;
return LeftWidth;
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getLeftRightWidth() const
{
return getLeftWidth() + getRightWidth();
}
// ----------------------------------------------------------------------------
uint32 CSSBorderRenderer::getTopBottomWidth() const
{
return getTopWidth() + getBottomWidth();
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::updateCoords()
{
_Dirty = false;
if (!_Border) return;
sint dTop = getTopWidth(); _BorderTop = dTop > 0;
sint dRight = getRightWidth(); _BorderRight = dRight > 0;
sint dBottom = getBottomWidth(); _BorderBottom = dBottom > 0;
sint dLeft = getLeftWidth(); _BorderLeft = dLeft > 0;
_Border = _BorderTop || _BorderRight || _BorderBottom || _BorderLeft;
if (!_Border) return;
if (_BorderTop)
{
// top-left
_QuadT.V3.x = _XReal;
_QuadT.V3.y = _YReal + _HReal;
// top-right
_QuadT.V2.x = _XReal + _WReal;
_QuadT.V2.y = _YReal + _HReal;
// bottom-right
_QuadT.V1.x = _XReal + _WReal - dRight;
_QuadT.V1.y = _YReal + _HReal - dTop;
// bottom-left
_QuadT.V0.x = _XReal + dLeft;
_QuadT.V0.y = _YReal + _HReal - dTop;
}
if (_BorderRight)
{
// top-left
_QuadR.V3.x = _XReal + _WReal - dRight;
_QuadR.V3.y = _YReal + _HReal - dTop;
// top-right
_QuadR.V2.x = _XReal + _WReal;
_QuadR.V2.y = _YReal + _HReal;
// bottom-right
_QuadR.V1.x = _XReal + _WReal;
_QuadR.V1.y = _YReal;
// bottom-left
_QuadR.V0.x = _XReal + _WReal - dRight;
_QuadR.V0.y = _YReal + dBottom;
}
if (_BorderBottom)
{
// top-left
_QuadB.V3.x = _XReal + dLeft;
_QuadB.V3.y = _YReal + dBottom;
// top-right
_QuadB.V2.x = _XReal + _WReal - dRight;
_QuadB.V2.y = _YReal + dBottom;
// bottom-right
_QuadB.V1.x = _XReal + _WReal;
_QuadB.V1.y = _YReal;
// bottom-left
_QuadB.V0.x = _XReal;
_QuadB.V0.y = _YReal;
}
if (_BorderLeft)
{
// top-left
_QuadL.V3.x = _XReal;
_QuadL.V3.y = _YReal + _HReal;
// top-right
_QuadL.V2.x = _XReal + dLeft;
_QuadL.V2.y = _YReal + _HReal - dTop;
// bottom-right
_QuadL.V1.x = _XReal + dLeft;
_QuadL.V1.y = _YReal + dBottom;
// bottom-left
_QuadL.V0.x = _XReal;
_QuadL.V0.y = _YReal;
}
}
// ----------------------------------------------------------------------------
void CSSBorderRenderer::draw() {
if (_Dirty) updateCoords();
if (!_Border) return;
CViewRenderer &rVR = *CViewRenderer::getInstance();
// TODO: no need for widget manager, if global color is set from parent
CRGBA globalColor;
if (_ModulateGlobalColor)
globalColor = CWidgetManager::getInstance()->getGlobalColor();
// TODO: monitor ModulateGlobalColor and CurrentAlpha in table checkCoords and recalculate colors on change only
// OUTSET - bottom/right darker than normal (default table style)
// INSET - top/left darker than normal
if (_BorderTop)
{
CRGBA borderColorT = TopColor;
if (TopStyle == CSSLineStyle::INSET)
borderColorT = blend(borderColorT, CRGBA::Black, 0.5f);
if (_ModulateGlobalColor)
borderColorT.modulateFromColor (borderColorT, globalColor);
borderColorT.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorT.A) >> 8);
rVR.drawQuad(_RenderLayer, _QuadT, rVR.getBlankTextureId(), borderColorT, false);
}
if (_BorderRight)
{
CRGBA borderColorR = RightColor;
if (RightStyle == CSSLineStyle::OUTSET)
borderColorR = blend(borderColorR, CRGBA::Black, 0.5f);
if (_ModulateGlobalColor)
borderColorR.modulateFromColor (borderColorR, globalColor);
borderColorR.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorR.A) >> 8);
rVR.drawQuad(_RenderLayer, _QuadR, rVR.getBlankTextureId(), borderColorR, false);
}
if (_BorderBottom)
{
CRGBA borderColorB = BottomColor;
if (BottomStyle == CSSLineStyle::OUTSET)
borderColorB = blend(borderColorB, CRGBA::Black, 0.5f);
if (_ModulateGlobalColor)
borderColorB.modulateFromColor (borderColorB, globalColor);
borderColorB.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorB.A) >> 8);
rVR.drawQuad(_RenderLayer, _QuadB, rVR.getBlankTextureId(), borderColorB, false);
}
if (_BorderLeft)
{
CRGBA borderColorL = LeftColor;
if (LeftStyle == CSSLineStyle::INSET)
borderColorL = blend(borderColorL, CRGBA::Black, 0.5f);
if (_ModulateGlobalColor)
borderColorL.modulateFromColor (borderColorL, globalColor);
borderColorL.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorL.A) >> 8);
rVR.drawQuad(_RenderLayer, _QuadL, rVR.getBlankTextureId(), borderColorL, false);
}
}
}//namespace

@ -35,9 +35,9 @@ namespace NLGUI
// //
// key is converted to lowercase // key is converted to lowercase
// value is left as is // value is left as is
TStyle CCssParser::parseDecls(const std::string &styleString) TStyleVec CCssParser::parseDecls(const std::string &styleString)
{ {
TStyle styles; TStyleVec styles;
std::vector<std::string> elements; std::vector<std::string> elements;
NLMISC::splitString(styleString, ";", elements); NLMISC::splitString(styleString, ";", elements);
@ -49,7 +49,7 @@ namespace NLGUI
{ {
std::string key = trim(toLower(elements[i].substr(0, pos))); std::string key = trim(toLower(elements[i].substr(0, pos)));
std::string value = trim(elements[i].substr(pos+1)); std::string value = trim(elements[i].substr(pos+1));
styles[key] = value; styles.push_back(TStylePair(key, value));
} }
} }
@ -94,7 +94,7 @@ namespace NLGUI
std::vector<ucstring> selectors; std::vector<ucstring> selectors;
NLMISC::explode(selectorString, ucstring(","), selectors); NLMISC::explode(selectorString, ucstring(","), selectors);
TStyle props; TStyleVec props;
props = parseDecls(styleString.toUtf8()); props = parseDecls(styleString.toUtf8());
// duplicate props to each selector in selector list, // duplicate props to each selector in selector list,

@ -102,7 +102,9 @@ namespace NLGUI
} }
else else
{ {
elm.setPseudo(i->PseudoElement, i->Properties); TStyle props;
merge(props, i->Properties);
elm.setPseudo(i->PseudoElement, props);
} }
} }
} }
@ -110,17 +112,18 @@ namespace NLGUI
// style from "style" attribute overrides <style> // style from "style" attribute overrides <style>
if (elm.hasNonEmptyAttribute("style")) if (elm.hasNonEmptyAttribute("style"))
{ {
TStyle styles = CCssParser::parseDecls(elm.getAttribute("style")); TStyleVec styles = CCssParser::parseDecls(elm.getAttribute("style"));
merge(elm.Style, styles); merge(elm.Style, styles);
} }
} }
void CCssStyle::merge(TStyle &dst, const TStyle &src) const void CCssStyle::merge(TStyle &dst, const TStyleVec &src) const
{ {
// TODO: does not use '!important' flag // TODO: does not use '!important' flag
for(TStyle::const_iterator it = src.begin(); it != src.end(); ++it) for(TStyleVec::const_iterator it = src.begin(); it != src.end(); ++it)
{ {
dst[it->first] = it->second; dst[it->first] = it->second;
expandShorthand(it->first, it->second, dst);
} }
} }
@ -304,6 +307,48 @@ namespace NLGUI
return false; return false;
} }
// ***************************************************************************
void CCssStyle::splitParams(const std::string &str, char sep, std::vector<std::string> &result) const
{
// TODO: does not handle utf8
uint32 pos = 0;
for(uint i = 0; i< str.size(); i++)
{
// split by separator first, then check if string or function
if (str[i] == sep)
{
std::string sub = trim(str.substr(pos, i - pos));
if (!sub.empty())
result.push_back(str.substr(pos, i - pos));
// skip sep
pos = i + 1;
}
else if (str[i] == '"' || str[i] == '(')
{
// string "this is string", or function rgb(1, 2, 3)
char endChar;
if (str[i] == '"')
endChar = '"';
else if (str[i] == '\'')
endChar = '\'';
else
endChar = ')';
// skip start
i++;
while(i < str.size() && str[i] != endChar)
{
if (str[i] == '\\')
i++;
i++;
}
}
}
if (pos < str.size())
result.push_back(str.substr(pos).c_str());
}
// *************************************************************************** // ***************************************************************************
// CStyleParams style; // CStyleParams style;
// style.FontSize; // font-size: 10px; // style.FontSize; // font-size: 10px;
@ -312,7 +357,10 @@ namespace NLGUI
// style.StrikeThrough; // text-decoration: line-through; text-decoration-line: line-through; // style.StrikeThrough; // text-decoration: line-through; text-decoration-line: line-through;
void CCssStyle::getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams &current) const void CCssStyle::getStyleParams(const std::string &styleString, CStyleParams &style, const CStyleParams &current) const
{ {
TStyle styles = CCssParser::parseDecls(styleString); TStyleVec stylevec = CCssParser::parseDecls(styleString);
TStyle styles;
merge(styles, stylevec);
getStyleParams(styles, style, current); getStyleParams(styles, style, current);
} }
@ -428,11 +476,6 @@ namespace NLGUI
} }
} }
else else
if (it->first == "background")
{
parseBackgroundShorthand(it->second, style);
}
else
if (it->first == "background-repeat") if (it->first == "background-repeat")
{ {
// old ryzom specific value // old ryzom specific value
@ -440,23 +483,6 @@ namespace NLGUI
style.StyleRules[it->first] = "repeat"; style.StyleRules[it->first] = "repeat";
} }
else else
if (it->first == "background-scale")
{
// replace old ryzom specific rule with background-size
if (it->second != "1")
{
style.StyleRules["background-size"] = "auto";
}
else
{
style.StyleRules["background-size"] = "100%";
}
TStyle::iterator pos = style.StyleRules.find(it->first);
if (pos != style.StyleRules.end())
style.StyleRules.erase(pos);
}
else
if (it->first == "display") if (it->first == "display")
{ {
if (it->second == "inherit") if (it->second == "inherit")
@ -467,6 +493,108 @@ namespace NLGUI
} }
} }
void CCssStyle::applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const
{
if (!dest) return;
if (value == "inherit")
{
*dest = currentWidth;
}
else if (value == "thin")
{
*dest = 1;
}
else if (value == "medium")
{
*dest = 3;
}
else if (value == "thick")
{
*dest = 5;
}
else if (value == "0")
{
*dest = 0;
}
else
{
float tmpf;
std::string unit;
if (getCssLength(tmpf, unit, value.c_str()))
{
if (unit == "rem")
*dest = fontSize * tmpf;
else if (unit == "em")
*dest = fontSize * tmpf;
else if (unit == "pt")
*dest = tmpf / 0.75f;
else if (unit == "%")
*dest = 0; // no support for % in border width
else
*dest = tmpf;
}
}
}
void CCssStyle::applyBorderColor(const std::string &value, CRGBA *dest, const CRGBA &currentColor, const CRGBA &textColor) const
{
if (!dest) return;
if (value == "inherit")
*dest = currentColor;
else if (value == "transparent")
*dest = CRGBA::Transparent;
else if (value == "currentcolor")
*dest = textColor;
else
scanHTMLColor(value.c_str(), *dest);
}
void CCssStyle::applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle &currentStyle) const
{
if (!dest) return;
if (value == "inherit")
*dest = currentStyle;
else if (value == "none")
*dest = CSSLineStyle::NONE;
else if (value == "hidden")
*dest = CSSLineStyle::HIDDEN;
else if (value == "inset")
*dest = CSSLineStyle::INSET;
else if (value == "outset")
*dest = CSSLineStyle::OUTSET;
else if (value == "solid")
*dest = CSSLineStyle::SOLID;
}
void CCssStyle::applyPaddingWidth(const std::string &value, uint32 *dest, const uint32 currentPadding, uint32 fontSize) const
{
if (!dest) return;
if (value == "inherit")
{
*dest = currentPadding;
return;
}
float tmpf;
std::string unit;
if (getCssLength(tmpf, unit, value.c_str()))
{
if (unit == "rem")
*dest = fontSize * tmpf;
else if (unit == "em")
*dest = fontSize * tmpf;
else if (unit == "pt")
*dest = tmpf / 0.75f;
else if (unit == "%")
*dest = 0; // TODO: requires content width, must remember 'unit' type
else
*dest = tmpf;
}
}
// apply style rules // apply style rules
void CCssStyle::apply(CStyleParams &style, const CStyleParams &current) const void CCssStyle::apply(CStyleParams &style, const CStyleParams &current) const
{ {
@ -474,48 +602,22 @@ 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" || it->first == "border-width") if (it->first == "border-top-width") applyBorderWidth(it->second, &style.BorderTopWidth, current.BorderTopWidth, current.FontSize);
{ else if (it->first == "border-top-color") applyBorderColor(it->second, &style.BorderTopColor, current.BorderTopColor, current.TextColor);
// TODO: border: 1px solid red; else if (it->first == "border-top-style") applyLineStyle(it->second, &style.BorderTopStyle, current.BorderTopStyle);
if (it->second == "inherit") else if (it->first == "border-right-width") applyBorderWidth(it->second, &style.BorderRightWidth, current.BorderRightWidth, current.FontSize);
{ else if (it->first == "border-right-color") applyBorderColor(it->second, &style.BorderRightColor, current.BorderRightColor, current.TextColor);
style.BorderWidth = current.BorderWidth; else if (it->first == "border-right-style") applyLineStyle(it->second, &style.BorderRightStyle, current.BorderRightStyle);
} else if (it->first == "border-bottom-width") applyBorderWidth(it->second, &style.BorderBottomWidth, current.BorderBottomWidth, current.FontSize);
else if (it->second == "none") else if (it->first == "border-bottom-color") applyBorderColor(it->second, &style.BorderBottomColor, current.BorderBottomColor, current.TextColor);
{ else if (it->first == "border-bottom-style") applyLineStyle(it->second, &style.BorderBottomStyle, current.BorderBottomStyle);
style.BorderWidth = 0; else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.BorderLeftWidth, current.BorderLeftWidth, current.FontSize);
} else if (it->first == "border-left-color") applyBorderColor(it->second, &style.BorderLeftColor, current.BorderLeftColor, current.TextColor);
else if (it->second == "thin") else if (it->first == "border-left-style") applyLineStyle(it->second, &style.BorderLeftStyle, current.BorderLeftStyle);
{ else if (it->first == "padding-top") applyPaddingWidth(it->second, &style.PaddingTop, current.PaddingTop, current.FontSize);
style.BorderWidth = 1; else if (it->first == "padding-right") applyPaddingWidth(it->second, &style.PaddingRight, current.PaddingRight, current.FontSize);
} else if (it->first == "padding-bottom") applyPaddingWidth(it->second, &style.PaddingBottom, current.PaddingBottom, current.FontSize);
else if (it->second == "medium") else if (it->first == "padding-left") applyPaddingWidth(it->second, &style.PaddingLeft, current.PaddingLeft, current.FontSize);
{
style.BorderWidth = 3;
}
else if (it->second == "thick")
{
style.BorderWidth = 5;
}
else
{
float tmpf;
std::string unit;
if (getCssLength(tmpf, unit, it->second.c_str()))
{
if (unit == "rem")
style.BorderWidth = Root.FontSize * tmpf;
else if (unit == "em")
style.BorderWidth = current.FontSize * tmpf;
else if (unit == "pt")
style.BorderWidth = tmpf / 0.75f;
else if (unit == "%")
style.BorderWidth = 0; // no support for % in border width
else
style.BorderWidth = tmpf;
}
}
}
else else
if (it->first == "font-style") if (it->first == "font-style")
{ {
@ -586,7 +688,7 @@ namespace NLGUI
uint px = 0; uint px = 0;
CRGBA color; CRGBA color;
std::vector<std::string> parts; std::vector<std::string> parts;
NLMISC::splitString(it->second, " ", parts); splitParams(it->second, ' ', parts);
if (parts.size() == 1) if (parts.size() == 1)
{ {
success = scanCssLength(parts[0], px); success = scanCssLength(parts[0], px);
@ -635,7 +737,7 @@ namespace NLGUI
prop = prop.substr(0, pos); prop = prop.substr(0, pos);
std::vector<std::string> parts; std::vector<std::string> parts;
NLMISC::splitString(prop, " ", parts); splitParams(prop, ' ', parts);
switch(parts.size()) switch(parts.size())
{ {
case 1: case 1:
@ -723,6 +825,8 @@ namespace NLGUI
style.Width = tmpf * style.FontSize; style.Width = tmpf * style.FontSize;
else if (unit == "pt") else if (unit == "pt")
style.FontSize = tmpf / 0.75f; style.FontSize = tmpf / 0.75f;
else if (unit == "%")
style.Width = 0; // TODO: style.WidthRatio
else else
style.Width = tmpf; style.Width = tmpf;
} }
@ -739,6 +843,8 @@ namespace NLGUI
style.Height = tmpf * style.FontSize; style.Height = tmpf * style.FontSize;
else if (unit == "pt") else if (unit == "pt")
style.FontSize = tmpf / 0.75f; style.FontSize = tmpf / 0.75f;
else if (unit == "%")
style.Height = 0; // TODO: style.HeightRatio
else else
style.Height = tmpf; style.Height = tmpf;
} }
@ -755,6 +861,8 @@ namespace NLGUI
style.MaxWidth = tmpf * style.FontSize; style.MaxWidth = tmpf * style.FontSize;
else if (unit == "pt") else if (unit == "pt")
style.FontSize = tmpf / 0.75f; style.FontSize = tmpf / 0.75f;
else if (unit == "%")
style.MaxWidth = 0; // TODO: style.MaxWidthRatio
else else
style.MaxWidth = tmpf; style.MaxWidth = tmpf;
} }
@ -771,6 +879,8 @@ namespace NLGUI
style.MaxHeight = tmpf * style.FontSize; style.MaxHeight = tmpf * style.FontSize;
else if (unit == "pt") else if (unit == "pt")
style.FontSize = tmpf / 0.75f; style.FontSize = tmpf / 0.75f;
else if (unit == "%")
style.MaxHeight = 0; // TODO: style.MaxHeightRatio
else else
style.MaxHeight = tmpf; style.MaxHeight = tmpf;
} }
@ -826,7 +936,7 @@ namespace NLGUI
// normalize // normalize
std::string val = toLower(trim(it->second)); std::string val = toLower(trim(it->second));
std::vector<std::string> parts; std::vector<std::string> parts;
NLMISC::splitString(val, " ", parts); splitParams(val, ' ', parts);
// check for "repeat repeat" // check for "repeat repeat"
if (parts.size() == 2 && parts[0] == parts[1]) if (parts.size() == 2 && parts[0] == parts[1])
val = parts[0]; val = parts[0];
@ -839,7 +949,7 @@ namespace NLGUI
// normalize // normalize
std::string val = toLower(trim(it->second)); std::string val = toLower(trim(it->second));
std::vector<std::string> parts; std::vector<std::string> parts;
NLMISC::splitString(val, " ", parts); splitParams(val, ' ', parts);
if (parts.size() == 2 && parts[0] == parts[1]) if (parts.size() == 2 && parts[0] == parts[1])
val = parts[0]; val = parts[0];
@ -856,7 +966,8 @@ namespace NLGUI
style.StrikeThrough = current.StrikeThrough; style.StrikeThrough = current.StrikeThrough;
} }
void CCssStyle::parseBackgroundShorthand(const std::string &value, CStyleParams &style) const // ***************************************************************************
void CCssStyle::expandBackgroundShorthand(const std::string &value, TStyle &style) const
{ {
// background: url(image.jpg) top center / 200px 200px no-repeat fixed padding-box content-box red; // background: url(image.jpg) top center / 200px 200px no-repeat fixed padding-box content-box red;
// background-image : url(image.jpg) // background-image : url(image.jpg)
@ -881,9 +992,7 @@ namespace NLGUI
uint partIndex = 0; uint partIndex = 0;
std::vector<std::string> parts; std::vector<std::string> parts;
std::vector<std::string>::iterator it; std::vector<std::string>::iterator it;
// FIXME: this will fail if url() contains ' ' chars splitParams(value, ' ', parts);
// FIXME: this will also fail on 'background: rgb(255, 0, 0)'
NLMISC::splitString(value, " ", parts);
bool failed = false; bool failed = false;
bool allowSize = false; bool allowSize = false;
@ -1134,16 +1243,16 @@ namespace NLGUI
{ {
if (props[i] == "background-position") if (props[i] == "background-position")
{ {
style.StyleRules["background-position-x"] = bgPositionX; style["background-position-x"] = bgPositionX;
style.StyleRules["background-position-y"] = bgPositionY; style["background-position-y"] = bgPositionY;
} }
else if (props[i] == "background-clip") else if (props[i] == "background-clip")
{ {
style.StyleRules["background-clip"] = bgClipValue; style["background-clip"] = bgClipValue;
} }
else else
{ {
style.StyleRules[props[i]] = values[i]; style[props[i]] = values[i];
} }
} }
else else
@ -1151,42 +1260,343 @@ namespace NLGUI
// fill in default if one is set // fill in default if one is set
if (props[i] == "background-image") if (props[i] == "background-image")
{ {
style.StyleRules[props[i]] = "none"; style[props[i]] = "none";
} }
else if (props[i] == "background-position") else if (props[i] == "background-position")
{ {
style.StyleRules[props[i]] = "0% 0%"; style[props[i]] = "0% 0%";
style.StyleRules["background-position-x"] = "left 0%"; style["background-position-x"] = "left 0%";
style.StyleRules["background-position-y"] = "top 0%"; style["background-position-y"] = "top 0%";
} }
else if (props[i] == "background-size") else if (props[i] == "background-size")
{ {
style.StyleRules[props[i]] = "auto auto"; style[props[i]] = "auto auto";
} }
else if (props[i] == "background-repeat") else if (props[i] == "background-repeat")
{ {
style.StyleRules[props[i]] = "repeat"; style[props[i]] = "repeat";
} }
else if(props[i] == "background-attachment") else if(props[i] == "background-attachment")
{ {
style.StyleRules[props[i]] = "scroll"; style[props[i]] = "scroll";
} }
else if(props[i] == "background-origin") else if(props[i] == "background-origin")
{ {
style.StyleRules[props[i]] = "padding-box"; style[props[i]] = "padding-box";
} }
else if (props[i] == "background-clip") else if (props[i] == "background-clip")
{ {
if (bgClipFound) if (bgClipFound)
style.StyleRules[props[i]] = bgClipValue; style[props[i]] = bgClipValue;
else else
style.StyleRules[props[i]] = "border-box"; style[props[i]] = "border-box";
} }
else if (props[i] == "background-color") else if (props[i] == "background-color")
{ {
style.StyleRules[props[i]] = "transparent"; style[props[i]] = "transparent";
}
}
}
}
// ***************************************************************************
bool CCssStyle::getShorthandIndices(const uint32 size, uint8 &t, uint8 &r, uint8 &b, uint8 &l) const
{
if (size == 0 || size > 4) return false;
if (size == 1)
{
t = r = b = l = 0;
}
else if (size == 2)
{
t = b = 0;
r = l = 1;
}
else if (size == 3)
{
t = 0;
r = l = 1;
b = 2;
}
else // size == 4
{
t = 0;
r = 1;
b = 2;
l = 3;
}
return true;
}
// ***************************************************************************
bool CCssStyle::tryBorderWidthShorthand(const std::string &prop, const std::string &value, TStyle &style) const
{
std::vector<std::string> parts;
splitParams(toLower(value), ' ', parts);
float tmpf;
std::string unit;
// verify that parts are valid
uint8 maxSize = (prop == "border" || prop == "border-width") ? 4 : 1;
bool hasTop = (prop == "border" || prop == "border-width" || prop == "border-top" || prop == "border-top-width");
bool hasRight = (prop == "border" || prop == "border-width" || prop == "border-right" || prop == "border-right-width");
bool hasBottom = (prop == "border" || prop == "border-width" || prop == "border-bottom" || prop == "border-bottom-width");
bool hasLeft = (prop == "border" || prop == "border-width" || prop == "border-left" || prop == "border-left-width");
if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft))
{
return false;
}
for(uint i = 0; i< parts.size(); ++i)
{
if (parts[i] != "inherit" && parts[i] != "thin" && parts[i] != "medium" && parts[i] != "thick"
&& !getCssLength(tmpf, unit, parts[i].c_str()))
{
return false;
}
}
uint8 t, r, b, l;
if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
if (hasTop) style["border-top-width"] = parts[t];
if (hasRight) style["border-right-width"] = parts[r];
if (hasBottom) style["border-bottom-width"] = parts[b];
if (hasLeft) style["border-left-width"] = parts[l];
return true;
}
// ***************************************************************************
bool CCssStyle::tryBorderStyleShorthand(const std::string &prop, const std::string &value, TStyle &style) const
{
std::vector<std::string> parts;
splitParams(toLower(value), ' ', parts);
// verify that parts are valid
uint8 maxSize = (prop == "border" || prop == "border-style") ? 4 : 1;
bool hasTop = (prop == "border" || prop == "border-style" || prop == "border-top" || prop == "border-top-style");
bool hasRight = (prop == "border" || prop == "border-style" || prop == "border-right" || prop == "border-right-style");
bool hasBottom = (prop == "border" || prop == "border-style" || prop == "border-bottom" || prop == "border-bottom-style");
bool hasLeft = (prop == "border" || prop == "border-style" || prop == "border-left" || prop == "border-left-style");
if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft))
{
return false;
}
const uint nbValues = 10;
std::string values[nbValues] = {"none", "hidden", "dotted", "dashed",
"solid", "double", "groove", "ridge", "inset", "outset"};
for(uint i = 0; i < parts.size(); ++i)
{
bool found = false;
for(uint iValue = 0; iValue < nbValues; ++iValue)
{
if (parts[i] == values[iValue])
{
found = true;
break;
} }
} }
if (!found)
{
// invalid rule
return false;
}
}
uint8 t, r, b, l;
if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
if (hasTop) style["border-top-style"] = parts[t];
if (hasRight) style["border-right-style"] = parts[r];
if (hasBottom) style["border-bottom-style"] = parts[b];
if (hasLeft) style["border-left-style"] = parts[l];
return true;
}
// ***************************************************************************
bool CCssStyle::tryBorderColorShorthand(const std::string &prop, const std::string &value, TStyle &style) const
{
std::vector<std::string> parts;
splitParams(toLower(value), ' ', parts);
CRGBA color;
// verify that parts are valid
uint8 maxSize = (prop == "border" || prop == "border-color") ? 4 : 1;
bool hasTop = (prop == "border" || prop == "border-color" || prop == "border-top" || prop == "border-top-color");
bool hasRight = (prop == "border" || prop == "border-color" || prop == "border-right" || prop == "border-right-color");
bool hasBottom = (prop == "border" || prop == "border-color" || prop == "border-bottom" || prop == "border-bottom-color");
bool hasLeft = (prop == "border" || prop == "border-color" || prop == "border-left" || prop == "border-left-color");
if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft))
{
return false;
}
for(uint i = 0; i< parts.size(); ++i)
{
if (!scanHTMLColor(parts[i].c_str(), color) && parts[i] != "currentcolor" && parts[i] != "inherit")
return false;
}
uint8 t, r, b, l;
if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
if (hasTop) style["border-top-color"] = parts[t];
if (hasRight) style["border-right-color"] = parts[r];
if (hasBottom) style["border-bottom-color"] = parts[b];
if (hasLeft) style["border-left-color"] = parts[l];
return true;
}
// ***************************************************************************
void CCssStyle::expandBorderShorthand(const std::string &prop, const std::string &value, TStyle &style) const
{
// border: 1px solid #000;
bool hasTop = (prop == "border" || prop == "border-top");
bool hasRight = (prop == "border" || prop == "border-right");
bool hasBottom = (prop == "border" || prop == "border-bottom");
bool hasLeft = (prop == "border" || prop == "border-left");
bool foundWidth = false;
bool foundStyle = false;
bool foundColor = false;
TStyle borderStyle;
std::vector<std::string> parts;
splitParams(toLower(value), ' ', parts);
for(uint index = 0; index < parts.size(); ++index)
{
bool matched = false;
if (!foundWidth)
{
matched = foundWidth = tryBorderWidthShorthand(prop, parts[index], borderStyle);
}
if (!matched && !foundStyle)
{
matched = foundStyle = tryBorderStyleShorthand(prop, parts[index], borderStyle);
}
if (!matched && !foundColor)
{
matched = foundColor = tryBorderColorShorthand(prop, parts[index], borderStyle);
}
// invalid rule if nothing gets matched
if (!matched)
{
return;
}
}
// apply rules that are present
TStyle::const_iterator it = borderStyle.begin();
while(it != borderStyle.end())
{
style[it->first] = it->second;
++it;
}
// reset those not present
if (!foundWidth)
{
if (hasTop) style["border-top-width"] = "medium";
if (hasRight) style["border-right-width"] = "medium";
if (hasBottom) style["border-bottom-width"] = "medium";
if (hasLeft) style["border-left-width"] = "medium";
}
//
if (!foundStyle)
{
if (hasTop) style["border-top-style"] = "none";
if (hasRight) style["border-right-style"] = "none";
if (hasBottom) style["border-bottom-style"] = "none";
if (hasLeft) style["border-left-style"] = "none";
}
//
if (!foundColor)
{
if (hasTop) style["border-top-color"] = "currentcolor";
if (hasRight) style["border-right-color"] = "currentcolor";
if (hasBottom) style["border-bottom-color"] = "currentcolor";
if (hasLeft) style["border-left-color"] = "currentcolor";
}
}
// ***************************************************************************
void CCssStyle::expandPaddingShorthand(const std::string &value, TStyle &style) const
{
std::vector<std::string> parts;
splitParams(toLower(value), ' ', parts);
uint8 t, r, b, l;
if (!getShorthandIndices(parts.size(), t, r, b, l))
return;
style["padding-top"] = parts[t];
style["padding-right"] = parts[r];
style["padding-bottom"] = parts[b];
style["padding-left"] = parts[l];
}
// ***************************************************************************
void CCssStyle::expandShorthand(const std::string &prop, const std::string &value, TStyle &style) const
{
// if shorthand matches, then remove it after expansion
bool keep = false;
if (prop == "background")
{
expandBackgroundShorthand(value, style);
}
else if (prop == "background-scale")
{
// replace old ryzom specific rule with background-size
if (value != "1")
{
style["background-size"] = "auto";
}
else
{
style["background-size"] = "100%";
}
}
else if (prop == "border"
|| prop == "border-top" || prop == "border-right"
|| prop == "border-bottom" || prop == "border-left")
{
// TODO: use enum or bitmap constant instead of passing a string name (prop)
expandBorderShorthand(prop, value, style);
}
else if (prop == "border-width")
{
tryBorderWidthShorthand(prop, value, style);
}
else if (prop == "border-style")
{
tryBorderStyleShorthand(prop, value, style);
}
else if (prop == "border-color")
{
tryBorderColorShorthand(prop, value, style);
}
else if (prop == "padding")
{
expandPaddingShorthand(value, style);
}
else
{
keep = true;
}
if (!keep)
{
TStyle::iterator pos = style.find(prop);
if (pos != style.end())
style.erase(pos);
} }
} }

@ -52,6 +52,7 @@
#include "nel/gui/html_element.h" #include "nel/gui/html_element.h"
#include "nel/gui/css_style.h" #include "nel/gui/css_style.h"
#include "nel/gui/css_parser.h" #include "nel/gui/css_parser.h"
#include "nel/gui/css_border_renderer.h"
#include <curl/curl.h> #include <curl/curl.h>
@ -286,28 +287,38 @@ namespace NLGUI
{ {
btn->setTextureOver(file); btn->setTextureOver(file);
} }
return;
} }
else
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(view);
if(btm)
{ {
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(view); btm->setTexture (file);
if(btm) btm->invalidateCoords();
{ btm->invalidateContent();
btm->setTexture (file); paragraphChange();
btm->invalidateCoords();
btm->invalidateContent(); return;
paragraphChange(); }
}
else CGroupCell *btgc = dynamic_cast<CGroupCell*>(view);
{ if(btgc)
CGroupCell *btgc = dynamic_cast<CGroupCell*>(view); {
if(btgc) btgc->setTexture (file);
{ btgc->invalidateCoords();
btgc->setTexture (file); btgc->invalidateContent();
btgc->invalidateCoords(); paragraphChange();
btgc->invalidateContent();
paragraphChange(); return;
} }
}
CGroupTable *table = dynamic_cast<CGroupTable*>(view);
if (table)
{
table->setTexture(file);
return;
} }
} }
@ -433,10 +444,9 @@ namespace NLGUI
{ {
if (pVT) if (pVT)
{ {
pVT->setFontSize(style.FontSize);
pVT->setColor(style.TextColor); pVT->setColor(style.TextColor);
pVT->setFontName(style.FontFamily); pVT->setFontName(style.FontFamily);
pVT->setFontSize(style.FontSize); pVT->setFontSize(style.FontSize, false);
pVT->setEmbolden(style.FontWeight >= FONT_WEIGHT_BOLD); pVT->setEmbolden(style.FontWeight >= FONT_WEIGHT_BOLD);
pVT->setOblique(style.FontOblique); pVT->setOblique(style.FontOblique);
pVT->setUnderlined(style.Underlined); pVT->setUnderlined(style.Underlined);
@ -697,7 +707,7 @@ namespace NLGUI
} }
// Add a image download request in the multi_curl // Add a image download request in the multi_curl
void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type) void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type, const std::string &placeholder)
{ {
std::string finalUrl; std::string finalUrl;
img->setModulateGlobalColor(style.GlobalColor); img->setModulateGlobalColor(style.GlobalColor);
@ -711,7 +721,6 @@ namespace NLGUI
return; return;
} }
// TODO: if no image in cache, nothing is visible
finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url)); finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url));
// use requested url for local name (cache) // use requested url for local name (cache)
@ -719,9 +728,14 @@ namespace NLGUI
LOG_DL("add to download '%s' dest '%s' img %p", finalUrl.c_str(), dest.c_str(), img); LOG_DL("add to download '%s' dest '%s' img %p", finalUrl.c_str(), dest.c_str(), img);
// Display cached image while downloading new // Display cached image while downloading new
if (type != OverImage && CFile::fileExists(dest)) if (type != OverImage)
{ {
setImage(img, dest, type); std::string temp = dest;
if (!CFile::fileExists(temp))
{
temp = placeholder;
}
setImage(img, temp, type);
setImageSize(img, style); setImageSize(img, style);
} }
@ -1139,8 +1153,10 @@ namespace NLGUI
case HTML_STRONG: renderPseudoElement(":before", elm); break; case HTML_STRONG: renderPseudoElement(":before", elm); break;
case HTML_STYLE: htmlSTYLE(elm); break; case HTML_STYLE: htmlSTYLE(elm); break;
case HTML_TABLE: htmlTABLE(elm); break; case HTML_TABLE: htmlTABLE(elm); break;
case HTML_TBODY: renderPseudoElement(":before", elm); break;
case HTML_TD: htmlTD(elm); break; case HTML_TD: htmlTD(elm); break;
case HTML_TEXTAREA: htmlTEXTAREA(elm); break; case HTML_TEXTAREA: htmlTEXTAREA(elm); break;
case HTML_TFOOT: renderPseudoElement(":before", elm); break;
case HTML_TH: htmlTH(elm); break; case HTML_TH: htmlTH(elm); break;
case HTML_TITLE: htmlTITLE(elm); break; case HTML_TITLE: htmlTITLE(elm); break;
case HTML_TR: htmlTR(elm); break; case HTML_TR: htmlTR(elm); break;
@ -1201,7 +1217,9 @@ namespace NLGUI
case HTML_STYLE: htmlSTYLEend(elm); break; case HTML_STYLE: htmlSTYLEend(elm); break;
case HTML_TABLE: htmlTABLEend(elm); break; case HTML_TABLE: htmlTABLEend(elm); break;
case HTML_TD: htmlTDend(elm); break; case HTML_TD: htmlTDend(elm); break;
case HTML_TBODY: renderPseudoElement(":after", elm); break;
case HTML_TEXTAREA: htmlTEXTAREAend(elm); break; case HTML_TEXTAREA: htmlTEXTAREAend(elm); break;
case HTML_TFOOT: renderPseudoElement(":after", elm); break;
case HTML_TH: htmlTHend(elm); break; case HTML_TH: htmlTHend(elm); break;
case HTML_TITLE: htmlTITLEend(elm); break; case HTML_TITLE: htmlTITLEend(elm); break;
case HTML_TR: htmlTRend(elm); break; case HTML_TR: htmlTRend(elm); break;
@ -1488,6 +1506,9 @@ namespace NLGUI
initImageDownload(); initImageDownload();
initBnpDownload(); initBnpDownload();
// setup default browser style
setProperty("browser_css_file", "browser.css");
} }
// *************************************************************************** // ***************************************************************************
@ -1766,6 +1787,11 @@ namespace NLGUI
{ {
return toString( _TimeoutValue ); return toString( _TimeoutValue );
} }
else
if( name == "browser_css_file" )
{
return _BrowserCssFile;
}
else else
return CGroupScrollText::getProperty( name ); return CGroupScrollText::getProperty( name );
} }
@ -2139,6 +2165,36 @@ namespace NLGUI
_TimeoutValue = d; _TimeoutValue = d;
return; return;
} }
else
if( name == "browser_css_file")
{
_BrowserStyle.reset();
_BrowserCssFile = value;
if (!_BrowserCssFile.empty())
{
std::string filename = CPath::lookup(_BrowserCssFile, false, true, true);
if (!filename.empty())
{
CIFile in;
if (in.open(filename))
{
std::string css;
if (in.readAll(css))
_BrowserStyle.parseStylesheet(css);
else
nlwarning("Failed to read browser css from '%s'", filename.c_str());
}
else
{
nlwarning("Failed to open browser css file '%s'", filename.c_str());
}
}
else
{
nlwarning("Browser css file '%s' not found", _BrowserCssFile.c_str());
}
}
}
else else
CGroupScrollText::setProperty( name, value ); CGroupScrollText::setProperty( name, value );
} }
@ -2212,6 +2268,7 @@ namespace NLGUI
xmlSetProp( node, BAD_CAST "browse_redo", BAD_CAST _BrowseRedoButton.c_str() ); xmlSetProp( node, BAD_CAST "browse_redo", BAD_CAST _BrowseRedoButton.c_str() );
xmlSetProp( node, BAD_CAST "browse_refresh", BAD_CAST _BrowseRefreshButton.c_str() ); xmlSetProp( node, BAD_CAST "browse_refresh", BAD_CAST _BrowseRefreshButton.c_str() );
xmlSetProp( node, BAD_CAST "timeout", BAD_CAST toString( _TimeoutValue ).c_str() ); xmlSetProp( node, BAD_CAST "timeout", BAD_CAST toString( _TimeoutValue ).c_str() );
xmlSetProp( node, BAD_CAST "browser_css_file", BAD_CAST _BrowserCssFile.c_str() );
return node; return node;
} }
@ -2395,6 +2452,12 @@ namespace NLGUI
if(ptr) if(ptr)
fromString((const char*)ptr, _TimeoutValue); fromString((const char*)ptr, _TimeoutValue);
ptr = xmlGetProp (cur, (xmlChar*)"browser_css_file");
if (ptr)
{
setProperty("browser_css_file", (const char *)ptr);
}
return true; return true;
} }
@ -2592,31 +2655,49 @@ namespace NLGUI
// Keep this char ? // Keep this char ?
bool keep = true; bool keep = true;
// char is between table elements
// TODO: only whitespace is handled, text is added to either TD, or after TABLE (should be before)
bool tableWhitespace = getTable() && (_Cells.empty() || _Cells.back() == NULL);
switch (input) switch (input)
{ {
// Return / tab only in <PRE> mode // Return / tab only in <PRE> mode
case '\t': case '\t':
case '\n': case '\n':
{ {
// Get the last char if (tableWhitespace)
ucchar lastChar = lastCharParam; {
if (lastChar == 0) keep = false;
lastChar = getLastChar(); }
keep = ((lastChar != (ucchar)' ') && else
(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0)); {
if(!getPRE()) // Get the last char
input = ' '; ucchar lastChar = lastCharParam;
if (lastChar == 0)
lastChar = getLastChar();
keep = ((lastChar != (ucchar)' ') &&
(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
if(!getPRE())
input = ' ';
}
} }
break; break;
case ' ': case ' ':
{ {
// Get the last char if (tableWhitespace)
ucchar lastChar = lastCharParam; {
if (lastChar == 0) keep = false;
lastChar = getLastChar(); }
keep = ((lastChar != (ucchar)' ') && else
(lastChar != (ucchar)'\n') && {
(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0)); // Get the last char
ucchar lastChar = lastCharParam;
if (lastChar == 0)
lastChar = getLastChar();
keep = ((lastChar != (ucchar)' ') &&
(lastChar != (ucchar)'\n') &&
(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
}
} }
break; break;
case 0xd: case 0xd:
@ -3402,6 +3483,7 @@ namespace NLGUI
CViewBitmap *bitmap = dynamic_cast<CViewBitmap*> (view); CViewBitmap *bitmap = dynamic_cast<CViewBitmap*> (view);
if (bitmap) if (bitmap)
{ {
// TODO: background color should have separate bitmap from background texture
// Change the background color // Change the background color
bitmap->setColor (bgcolor); bitmap->setColor (bgcolor);
bitmap->setModulateGlobalColor(false); bitmap->setModulateGlobalColor(false);
@ -3424,6 +3506,7 @@ namespace NLGUI
bitmap->setPosRef(Hotspot_TL); bitmap->setPosRef(Hotspot_TL);
bitmap->setX(0); bitmap->setX(0);
bitmap->setY(0); bitmap->setY(0);
// FIXME: renders behind container background
bitmap->setRenderLayer(-2); bitmap->setRenderLayer(-2);
bitmap->setScale(scale); bitmap->setScale(scale);
bitmap->setTile(tile); bitmap->setTile(tile);
@ -3434,7 +3517,7 @@ namespace NLGUI
else else
bitmap->setSizeRef(""); bitmap->setSizeRef("");
addImageDownload(bgtex, view); addImageDownload(bgtex, view, CStyleParams(), TImageType::NormalImage, "");
} }
} }
} }
@ -4919,49 +5002,7 @@ namespace NLGUI
_WaitingForStylesheet = false; _WaitingForStylesheet = false;
_StylesheetQueue.clear(); _StylesheetQueue.clear();
_Style.reset(); _Style.reset();
_Style = _BrowserStyle;
std::string css;
// TODO: browser css
css += "html { background-color: " + getRGBAString(BgColor) + "; color: " + getRGBAString(TextColor) + "; font-size: " + toString(TextFontSize) + "px;}";
css += "a { color: " + getRGBAString(LinkColor) + "; text-decoration: underline; -ryzom-modulate-color: "+toString(LinkColorGlobalColor)+";}";
css += "h1 { color: " + getRGBAString(H1Color) + "; font-size: "+ toString("%d", H1FontSize) + "px; -ryzom-modulate-color: "+toString(H1ColorGlobalColor)+";}";
css += "h2 { color: " + getRGBAString(H2Color) + "; font-size: "+ toString("%d", H2FontSize) + "px; -ryzom-modulate-color: "+toString(H2ColorGlobalColor)+";}";
css += "h3 { color: " + getRGBAString(H3Color) + "; font-size: "+ toString("%d", H3FontSize) + "px; -ryzom-modulate-color: "+toString(H3ColorGlobalColor)+";}";
css += "h4 { color: " + getRGBAString(H4Color) + "; font-size: "+ toString("%d", H4FontSize) + "px; -ryzom-modulate-color: "+toString(H4ColorGlobalColor)+";}";
css += "h5 { color: " + getRGBAString(H5Color) + "; font-size: "+ toString("%d", H5FontSize) + "px; -ryzom-modulate-color: "+toString(H5ColorGlobalColor)+";}";
css += "h6 { color: " + getRGBAString(H6Color) + "; font-size: "+ toString("%d", H6FontSize) + "px; -ryzom-modulate-color: "+toString(H6ColorGlobalColor)+";}";
css += "input[type=\"text\"] { color: " + getRGBAString(TextColor) + "; font-size: " + toString("%d", TextFontSize) + "px; font-weight: normal; text-shadow: 1px 1px #000;}";
css += "pre { font-family: monospace;}";
// th { text-align: center; } - overwrites align property
css += "th { font-weight: bold; }";
css += "textarea { color: " + getRGBAString(TextColor) + "; font-weight: normal; font-size: " + toString("%d", TextFontSize) + "px; text-shadow: 1px 1px #000;}";
css += "del { text-decoration: line-through;}";
css += "u { text-decoration: underline;}";
css += "em { font-style: italic; }";
css += "strong { font-weight: bold; }";
css += "small { font-size: smaller;}";
css += "dt { font-weight: bold; }";
css += "hr { color: rgb(120, 120, 120);}";
// block level elements
css += "address, article, aside, blockquote, details, dialog, dd, div, dl, dt, fieldset, figcaption, figure,";
css += "footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, li, main, nav, ol, p, pre, section, table,";
css += "ul { display: block; }";
css += "table { display: table; }";
// td { padding: 1px;} - overwrites cellpadding attribute
// table { border-spacing: 2px;} - overwrites cellspacing attribute
css += "table { border-collapse: separate;}";
// webkit pseudo elements
css += "meter::-webkit-meter-bar, meter::-webkit-optimum-value, meter::-webkit-suboptimum-value, meter::-webkit-even-less-good-value { background: none; }";
css += "meter::-webkit-meter-bar { background-color: rgb(100, 100, 100); width: 5em; height: 1em;}";
css += "meter::-webkit-meter-optimum-value { background-color: rgb(80, 220, 80); }";
css += "meter::-webkit-meter-suboptimum-value { background-color: rgb(220, 220, 80); }";
css += "meter::-webkit-meter-even-less-good-value { background-color: rgb(220, 80, 80); }";
// webkit pseudo elements
css += "progress::-webkit-progress-bar, progress::-webkit-progress-value { background: none; }";
css += "progress::-webkit-progress-bar { background-color: rgb(230, 230, 230); width: 10em; height: 1em; }";
css += "progress::-webkit-progress-value { background-color: rgb(0, 100, 180);}";
_Style.parseStylesheet(css);
} }
// *************************************************************************** // ***************************************************************************
@ -5240,9 +5281,7 @@ namespace NLGUI
{ {
CGroupHTML::CCellParams cellParams; CGroupHTML::CCellParams cellParams;
if (!_CellParams.empty() && inherit) if (!_CellParams.empty() && inherit)
{
cellParams = _CellParams.back(); cellParams = _CellParams.back();
}
if (_Style.hasStyle("background-color")) if (_Style.hasStyle("background-color"))
cellParams.BgColor = _Style.Current.BackgroundColor; cellParams.BgColor = _Style.Current.BackgroundColor;
@ -5255,6 +5294,11 @@ namespace NLGUI
if (elm.hasNonEmptyAttribute("l_margin")) if (elm.hasNonEmptyAttribute("l_margin"))
fromString(elm.getAttribute("l_margin"), cellParams.LeftMargin); fromString(elm.getAttribute("l_margin"), cellParams.LeftMargin);
if (_Style.hasStyle("height"))
cellParams.Height = _Style.Current.Height;
else if (elm.hasNonEmptyAttribute("height"))
fromString(elm.getAttribute("height"), cellParams.Height);
{ {
std::string align; std::string align;
// having text-align on table/tr should not override td align attribute // having text-align on table/tr should not override td align attribute
@ -5984,16 +6028,20 @@ namespace NLGUI
ucstring ucValue; ucstring ucValue;
ucValue.fromUtf8(elm.getAttribute("value")); ucValue.fromUtf8(elm.getAttribute("value"));
uint size = 120; uint size = 20;
uint maxlength = 1024; uint maxlength = 1024;
if (elm.hasNonEmptyAttribute("size")) if (elm.hasNonEmptyAttribute("size"))
fromString(elm.getAttribute("size"), size); fromString(elm.getAttribute("size"), size);
if (elm.hasNonEmptyAttribute("maxlength")) if (elm.hasNonEmptyAttribute("maxlength"))
fromString(elm.getAttribute("maxlength"), maxlength); fromString(elm.getAttribute("maxlength"), maxlength);
// ryzom client used to have 'size' attribute in pixels, (12 == was default font size)
if (_Style.hasStyle("-ryzom-input-size-px") && _Style.getStyle("-ryzom-input-size-px") == "true")
size = size / 12;
string textTemplate(!templateName.empty() ? templateName : DefaultFormTextGroup); string textTemplate(!templateName.empty() ? templateName : DefaultFormTextGroup);
// Add the editbox // Add the editbox
CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size/12, false, ucValue, maxlength); CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size, false, ucValue, maxlength);
if (textArea) if (textArea)
{ {
// Add the text area to the form // Add the text area to the form
@ -6208,7 +6256,8 @@ namespace NLGUI
// width: 5em, height: 1em // width: 5em, height: 1em
uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 5; uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 5;
uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize; uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize;
uint32 border = _Style.Current.BorderWidth > -1 ? _Style.Current.BorderWidth : 0; // FIXME: only using border-top
uint32 border = _Style.Current.BorderTopWidth > -1 ? _Style.Current.BorderTopWidth : 0;
uint barw = (uint) (width * meter.getValueRatio()); uint barw = (uint) (width * meter.getValueRatio());
CRGBA bgColor = meter.getBarColor(elm, _Style); CRGBA bgColor = meter.getBarColor(elm, _Style);
@ -6423,7 +6472,8 @@ namespace NLGUI
// width: 10em, height: 1em // width: 10em, height: 1em
uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 10; uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 10;
uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize; uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize;
uint32 border = _Style.Current.BorderWidth > -1 ? _Style.Current.BorderWidth : 0; // FIXME: only using border-top
uint32 border = _Style.Current.BorderTopWidth > -1 ? _Style.Current.BorderTopWidth : 0;
uint barw = (uint) (width * progress.getValueRatio()); uint barw = (uint) (width * progress.getValueRatio());
CRGBA bgColor = progress.getBarColor(elm, _Style); CRGBA bgColor = progress.getBarColor(elm, _Style);
@ -6498,7 +6548,7 @@ namespace NLGUI
sb->setMinH(_Style.Current.Height); sb->setMinH(_Style.Current.Height);
sb->setMaxVisibleLine(size); sb->setMaxVisibleLine(size);
sb->setFontSize(_Style.Current.FontSize); sb->setFontSize(_Style.Current.FontSize, false);
} }
entry.SelectBox = sb; entry.SelectBox = sb;
@ -6571,36 +6621,82 @@ namespace NLGUI
fromString(elm.getAttribute("cellpadding"), table->CellPadding); fromString(elm.getAttribute("cellpadding"), table->CellPadding);
if (_Style.hasStyle("width")) if (_Style.hasStyle("width"))
getPercentage(table->ForceWidthMin, table->TableRatio, _Style.getStyle("width").c_str());
else if (elm.hasNonEmptyAttribute("width"))
getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str());
if (_Style.hasStyle("border") || _Style.hasStyle("border-width"))
{ {
table->Border = _Style.Current.BorderWidth; // _Style.Width does not handle '%' unit currently
if (_Style.Current.Width > 0)
{
table->ForceWidthMin = _Style.Current.Width;
table->TableRatio = 0;
}
else
{
getPercentage (table->ForceWidthMin, table->TableRatio, _Style.getStyle("width").c_str());
}
} }
else if (elm.hasAttribute("border")) else if (elm.hasNonEmptyAttribute("width"))
{ {
std::string s = elm.getAttribute("border"); getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str());
if (s.empty())
table->Border = 1;
else
fromString(elm.getAttribute("border"), table->Border);
} }
if (_Style.hasStyle("border-color")) // border from css or from attribute
{ {
std::string s = toLower(_Style.getStyle("border-color")); uint32 borderWidth = 0;
if (s == "currentcolor") CRGBA borderColor = CRGBA::Transparent;
table->BorderColor = _Style.Current.TextColor;
if (elm.hasAttribute("border"))
{
std::string s = elm.getAttribute("border");
if (s.empty())
borderWidth = 1;
else
fromString(elm.getAttribute("border"), borderWidth);
if (elm.hasNonEmptyAttribute("bordercolor"))
scanHTMLColor(elm.getAttribute("bordercolor").c_str(), borderColor);
else
borderColor = CRGBA(128, 128, 128, 255);
table->CellBorder = (borderWidth > 0);
table->Border->setWidth(borderWidth, borderWidth, borderWidth, borderWidth);
table->Border->setColor(borderColor, borderColor, borderColor, borderColor);
table->Border->setStyle(CSSLineStyle::OUTSET, CSSLineStyle::OUTSET, CSSLineStyle::OUTSET, CSSLineStyle::OUTSET);
}
else else
scanHTMLColor(s.c_str(), table->BorderColor); {
table->CellBorder = false;
}
if (_Style.hasStyle("border-top-width")) table->Border->TopWidth = _Style.Current.BorderTopWidth;
if (_Style.hasStyle("border-right-width")) table->Border->RightWidth = _Style.Current.BorderRightWidth;
if (_Style.hasStyle("border-bottom-width")) table->Border->BottomWidth = _Style.Current.BorderBottomWidth;
if (_Style.hasStyle("border-left-width")) table->Border->LeftWidth = _Style.Current.BorderLeftWidth;
if (_Style.hasStyle("border-top-color")) table->Border->TopColor = _Style.Current.BorderTopColor;
if (_Style.hasStyle("border-right-color")) table->Border->RightColor = _Style.Current.BorderRightColor;
if (_Style.hasStyle("border-bottom-color")) table->Border->BottomColor = _Style.Current.BorderBottomColor;
if (_Style.hasStyle("border-left-color")) table->Border->LeftColor = _Style.Current.BorderLeftColor;
if (_Style.hasStyle("border-top-style")) table->Border->TopStyle = _Style.Current.BorderTopStyle;
if (_Style.hasStyle("border-right-style")) table->Border->RightStyle = _Style.Current.BorderRightStyle;
if (_Style.hasStyle("border-bottom-style")) table->Border->BottomStyle = _Style.Current.BorderBottomStyle;
if (_Style.hasStyle("border-left-style")) table->Border->LeftStyle = _Style.Current.BorderLeftStyle;
} }
else if (elm.hasNonEmptyAttribute("bordercolor"))
if (_Style.hasStyle("background-image"))
{ {
scanHTMLColor(elm.getAttribute("bordercolor").c_str(), table->BorderColor); if (_Style.checkStyle("background-repeat", "repeat"))
table->setTextureTile(true);
if (_Style.checkStyle("background-size", "100%"))
table->setTextureScale(true);
string image = _Style.getStyle("background-image");
addImageDownload(image, table, CStyleParams(), TImageType::NormalImage, "");
} }
// setting ModulateGlobalColor must be after addImageDownload
if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true"))
table->setModulateGlobalColor(true);
table->setMarginLeft(getIndent()); table->setMarginLeft(getIndent());
addHtmlGroup (table, 0); addHtmlGroup (table, 0);
@ -6628,9 +6724,21 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
void CGroupHTML::htmlTD(const CHtmlElement &elm) void CGroupHTML::htmlTD(const CHtmlElement &elm)
{ {
CRGBA rowColor = CRGBA::Transparent;
// remember row color so we can blend it with cell color
if (!_CellParams.empty())
rowColor = _CellParams.back().BgColor;
// Get cells parameters // Get cells parameters
getCellsParameters(elm, true); getCellsParameters(elm, true);
// if cell has own background,then it must be blended with row
if (rowColor.A > 0 && (elm.hasNonEmptyAttribute("bgcolor") || _Style.hasStyle("background-color")))
{
if (_CellParams.back().BgColor.A < 255)
_CellParams.back().BgColor.blendFromui(rowColor, _CellParams.back().BgColor, _CellParams.back().BgColor.A);
}
if (elm.ID == HTML_TH) if (elm.ID == HTML_TH)
{ {
if (!_Style.hasStyle("font-weight")) if (!_Style.hasStyle("font-weight"))
@ -6653,14 +6761,6 @@ namespace NLGUI
return; return;
} }
if (_Style.hasStyle("padding"))
{
uint32 a;
// TODO: cssLength
if (fromString(_Style.getStyle("padding"), a))
table->CellPadding = a;
}
_Cells.back() = new CGroupCell(CViewBase::TCtorParam()); _Cells.back() = new CGroupCell(CViewBase::TCtorParam());
if (_Style.checkStyle("background-repeat", "repeat")) if (_Style.checkStyle("background-repeat", "repeat"))
@ -6672,7 +6772,7 @@ namespace NLGUI
if (_Style.hasStyle("background-image")) if (_Style.hasStyle("background-image"))
{ {
string image = _Style.getStyle("background-image"); string image = _Style.getStyle("background-image");
addImageDownload(image, _Cells.back()); addImageDownload(image, _Cells.back(), CStyleParams(), TImageType::NormalImage, "");
} }
if (elm.hasNonEmptyAttribute("colspan")) if (elm.hasNonEmptyAttribute("colspan"))
@ -6687,19 +6787,70 @@ namespace NLGUI
_Cells.back()->NoWrap = _CellParams.back().NoWrap; _Cells.back()->NoWrap = _CellParams.back().NoWrap;
_Cells.back()->ColSpan = std::max(1, _Cells.back()->ColSpan); _Cells.back()->ColSpan = std::max(1, _Cells.back()->ColSpan);
_Cells.back()->RowSpan = std::max(1, _Cells.back()->RowSpan); _Cells.back()->RowSpan = std::max(1, _Cells.back()->RowSpan);
_Cells.back()->Height = _CellParams.back().Height;
float temp; float temp;
if (_Style.hasStyle("width")) if (_Style.hasStyle("width"))
getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, _Style.getStyle("width").c_str()); {
// _Style.Width does not handle '%' unit currently
if (_Style.Current.Width > 0)
{
_Cells.back()->WidthWanted = _Style.Current.Width;
_Cells.back()->TableRatio = 0;
}
else
{
getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, _Style.getStyle("width").c_str());
}
}
else if (elm.hasNonEmptyAttribute("width")) else if (elm.hasNonEmptyAttribute("width"))
{
getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, elm.getAttribute("width").c_str()); getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, elm.getAttribute("width").c_str());
}
if (_Style.hasStyle("height"))
getPercentage (_Cells.back()->Height, temp, _Style.getStyle("height").c_str());
else if (elm.hasNonEmptyAttribute("height"))
getPercentage (_Cells.back()->Height, temp, elm.getAttribute("height").c_str());
_Cells.back()->NewLine = getTR(); _Cells.back()->NewLine = getTR();
// setting ModulateGlobalColor must be after addImageDownload
if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true"))
_Cells.back()->setModulateGlobalColor(true);
// border from <table border="1">
if (table->CellBorder)
{
_Cells.back()->Border->setWidth(1, 1, 1, 1);
_Cells.back()->Border->setColor(table->Border->TopColor, table->Border->RightColor, table->Border->BottomColor, table->Border->LeftColor);
_Cells.back()->Border->setStyle(CSSLineStyle::INSET, CSSLineStyle::INSET, CSSLineStyle::INSET, CSSLineStyle::INSET);
}
if (_Style.hasStyle("border-top-width")) _Cells.back()->Border->TopWidth = _Style.Current.BorderTopWidth;
if (_Style.hasStyle("border-right-width")) _Cells.back()->Border->RightWidth = _Style.Current.BorderRightWidth;
if (_Style.hasStyle("border-bottom-width")) _Cells.back()->Border->BottomWidth = _Style.Current.BorderBottomWidth;
if (_Style.hasStyle("border-left-width")) _Cells.back()->Border->LeftWidth = _Style.Current.BorderLeftWidth;
if (_Style.hasStyle("border-top-color")) _Cells.back()->Border->TopColor = _Style.Current.BorderTopColor;
if (_Style.hasStyle("border-right-color")) _Cells.back()->Border->RightColor = _Style.Current.BorderRightColor;
if (_Style.hasStyle("border-bottom-color")) _Cells.back()->Border->BottomColor = _Style.Current.BorderBottomColor;
if (_Style.hasStyle("border-left-color")) _Cells.back()->Border->LeftColor = _Style.Current.BorderLeftColor;
if (_Style.hasStyle("border-top-style")) _Cells.back()->Border->TopStyle = _Style.Current.BorderTopStyle;
if (_Style.hasStyle("border-right-style")) _Cells.back()->Border->RightStyle = _Style.Current.BorderRightStyle;
if (_Style.hasStyle("border-bottom-style")) _Cells.back()->Border->BottomStyle = _Style.Current.BorderBottomStyle;
if (_Style.hasStyle("border-left-style")) _Cells.back()->Border->LeftStyle = _Style.Current.BorderLeftStyle;
// padding from <table cellpadding="1">
if (table->CellPadding)
{
_Cells.back()->PaddingTop = table->CellPadding;
_Cells.back()->PaddingRight = table->CellPadding;
_Cells.back()->PaddingBottom = table->CellPadding;
_Cells.back()->PaddingLeft = table->CellPadding;
}
if (_Style.hasStyle("padding-top")) _Cells.back()->PaddingTop = _Style.Current.PaddingTop;
if (_Style.hasStyle("padding-right")) _Cells.back()->PaddingRight = _Style.Current.PaddingRight;
if (_Style.hasStyle("padding-bottom")) _Cells.back()->PaddingBottom = _Style.Current.PaddingBottom;
if (_Style.hasStyle("padding-left")) _Cells.back()->PaddingLeft = _Style.Current.PaddingLeft;
table->addChild (_Cells.back()); table->addChild (_Cells.back());
// reusing indent pushed by table // reusing indent pushed by table
@ -6808,6 +6959,13 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
void CGroupHTML::htmlTR(const CHtmlElement &elm) void CGroupHTML::htmlTR(const CHtmlElement &elm)
{ {
// prevent inheriting from table
if (!_CellParams.empty())
{
_CellParams.back().BgColor = CRGBA::Transparent;
_CellParams.back().Height = 0;
}
// Get cells parameters // Get cells parameters
getCellsParameters(elm, true); getCellsParameters(elm, true);

@ -1038,6 +1038,18 @@ namespace NLGUI
} }
} }
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup)
{
// If a line is selected and the line is not grayed and has right click action handler
if ((_Selected != -1) && (!_Lines[i].ViewText->getGrayed()) && !_Lines[_Selected].AHRightClick.empty())
{
CAHManager::getInstance()->runActionHandler ( _Lines[_Selected].AHRightClick,
CWidgetManager::getInstance()->getCtrlLaunchingModal(),
_Lines[_Selected].AHRightClickParams );
return true;
}
}
if (event.getType() == NLGUI::CEventDescriptor::mouse) if (event.getType() == NLGUI::CEventDescriptor::mouse)
{ {
const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event; const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
@ -1221,7 +1233,7 @@ namespace NLGUI
pV->setText (name); pV->setText (name);
} }
pV->setColor (_GroupMenu->_Color); pV->setColor (_GroupMenu->_Color);
pV->setFontSize (_GroupMenu->_FontSize); pV->setFontSize (_GroupMenu->_FontSize, _GroupMenu->_FontSizeCoef);
pV->setShadow (_GroupMenu->_Shadow); pV->setShadow (_GroupMenu->_Shadow);
pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setShadowOutline (_GroupMenu->_ShadowOutline);
pV->setCheckable(checkable); pV->setCheckable(checkable);
@ -1310,7 +1322,7 @@ namespace NLGUI
} }
pV->setColor (_GroupMenu->_Color); pV->setColor (_GroupMenu->_Color);
pV->setFontSize (_GroupMenu->_FontSize); pV->setFontSize (_GroupMenu->_FontSize, _GroupMenu->_FontSizeCoef);
pV->setShadow (_GroupMenu->_Shadow); pV->setShadow (_GroupMenu->_Shadow);
pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setShadowOutline (_GroupMenu->_ShadowOutline);
pV->setCheckable(checkable); pV->setCheckable(checkable);
@ -1685,6 +1697,28 @@ namespace NLGUI
_Lines[lineIndex].AHParams = params; _Lines[lineIndex].AHParams = params;
} }
// ------------------------------------------------------------------------------------------------
void CGroupSubMenu::setRightClickHandler(uint lineIndex, const std::string &ah)
{
if (lineIndex > _Lines.size())
{
nlwarning("Bad index");
return;
}
_Lines[lineIndex].AHRightClick = ah;
}
// ------------------------------------------------------------------------------------------------
void CGroupSubMenu::setRightClickHandlerParam(uint lineIndex, const std::string &params)
{
if (lineIndex > _Lines.size())
{
nlwarning("Bad index");
return;
}
_Lines[lineIndex].AHRightClickParams = params;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void CGroupSubMenu::setSelectable(uint lineIndex, bool selectable) void CGroupSubMenu::setSelectable(uint lineIndex, bool selectable)
{ {
@ -1990,6 +2024,7 @@ namespace NLGUI
_ShadowColorGrayed = CRGBA::Black; _ShadowColorGrayed = CRGBA::Black;
_HighLightOver.set(128, 0, 0, 255); _HighLightOver.set(128, 0, 0, 255);
_FontSize = 12; _FontSize = 12;
_FontSizeCoef = true;
_Shadow = false; _Shadow = false;
_ShadowOutline = false; _ShadowOutline = false;
_ResizeFromChildH = _ResizeFromChildW = true; _ResizeFromChildH = _ResizeFromChildW = true;
@ -2584,9 +2619,10 @@ namespace NLGUI
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void CGroupMenu::setFontSize(uint fontSize) void CGroupMenu::setFontSize(uint fontSize, bool coef)
{ {
_FontSize = fontSize; _FontSize = fontSize;
_FontSizeCoef = coef;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -2632,6 +2668,20 @@ namespace NLGUI
_RootMenu->setActionHandlerParam(lineIndex, params); _RootMenu->setActionHandlerParam(lineIndex, params);
} }
// ------------------------------------------------------------------------------------------------
void CGroupMenu::setRightClickHandler(uint lineIndex, const std::string &ah)
{
if (_RootMenu)
_RootMenu->setRightClickHandler(lineIndex, ah);
}
// ------------------------------------------------------------------------------------------------
void CGroupMenu::setRightClickHandlerParam(uint lineIndex, const std::string &params)
{
if (_RootMenu)
_RootMenu->setRightClickHandlerParam(lineIndex, params);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void CGroupMenu::setUserGroupRight(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/) void CGroupMenu::setUserGroupRight(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/)
{ {

@ -25,6 +25,7 @@
#include "nel/misc/i_xml.h" #include "nel/misc/i_xml.h"
#include "nel/misc/i18n.h" #include "nel/misc/i18n.h"
#include "nel/misc/xml_auto_ptr.h" #include "nel/misc/xml_auto_ptr.h"
#include "nel/gui/css_border_renderer.h"
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
@ -52,6 +53,9 @@ namespace NLGUI
RowSpan = 1; RowSpan = 1;
TableColumnIndex = 0; TableColumnIndex = 0;
Group = new CInterfaceGroup(CViewBase::TCtorParam()); Group = new CInterfaceGroup(CViewBase::TCtorParam());
// TODO: only initialize if border is set
Border = new CSSBorderRenderer();
PaddingTop = PaddingRight = PaddingBottom = PaddingLeft = 0;
Align = Left; Align = Left;
VAlign = Middle; VAlign = Middle;
LeftMargin = 0; LeftMargin = 0;
@ -59,13 +63,26 @@ namespace NLGUI
IgnoreMaxWidth = false; IgnoreMaxWidth = false;
IgnoreMinWidth = false; IgnoreMinWidth = false;
AddChildW = false; AddChildW = false;
_UserTexture = false;
_TextureTiled = false; _TextureTiled = false;
_TextureScaled = false; _TextureScaled = false;
_TextureXReal = 0;
_TextureYReal = 0;
_TextureWReal = 0;
_TextureHReal = 0;
setEnclosedGroupDefaultParams(); setEnclosedGroupDefaultParams();
addGroup (Group); addGroup (Group);
} }
// ----------------------------------------------------------------------------
CGroupCell::~CGroupCell()
{
if (Border)
{
delete Border;
Border = NULL;
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CGroupCell::setEnclosedGroupDefaultParams() void CGroupCell::setEnclosedGroupDefaultParams()
{ {
@ -481,85 +498,72 @@ namespace NLGUI
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0,255,255,255) ); rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0,255,255,255) );
} }
uint8 CurrentAlpha = 255;
CGroupTable *table = NULL;
if (getParent ())
{
table = static_cast<CGroupTable*> (getParent ());
CurrentAlpha = table->CurrentAlpha;
}
// Draw the background // Draw the background
if (_UserTexture || BgColor.A != 0) if (BgColor.A > 0 || !_TextureId.empty())
{ {
CViewRenderer &rVR = *CViewRenderer::getInstance(); CViewRenderer &rVR = *CViewRenderer::getInstance();
if (_UserTexture)
bool flush = false;
if (CurrentAlpha > 0 && !_TextureId.empty())
{ {
CRGBA col; CRGBA col = CRGBA::White;
if (BgColor.A == 0 ) col.A = CurrentAlpha;
col = CRGBA(255,255,255,255);
else sint32 oldSciX, oldSciY, oldSciW, oldSciH;
col = BgColor; makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH);
if (_TextureScaled && !_TextureTiled) if (_TextureScaled && !_TextureTiled)
{ {
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col);
_WReal, _HReal,
0, false,
_TextureId,
col );
} }
else else
{ {
if (!_TextureTiled) if (!_TextureTiled)
{ rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _TextureWReal, _TextureHReal, 0, false, _TextureId, col);
rVR.draw11RotFlipBitmap (_RenderLayer, _XReal, _YReal,
0, false,
_TextureId,
col);
}
else else
{ rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col);
rVR.drawRotFlipBitmapTiled(_RenderLayer, _XReal, _YReal,
_WReal, _HReal,
0, false,
_TextureId,
0,
col);
}
} }
restoreClip (oldSciX, oldSciY, oldSciW, oldSciH);
flush = true;
} }
else
if (BgColor.A > 0)
{ {
CRGBA finalColor; CRGBA finalColor = BgColor;
finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor()); if (_ModulateGlobalColor)
finalColor.modulateFromColor (finalColor, CWidgetManager::getInstance()->getGlobalColor());
finalColor.A = (uint8) (((uint16) CurrentAlpha * (uint16) finalColor.A) >> 8);
// Get the parent table if (finalColor.A > 0)
if (getParent ()) rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor);
{
CGroupTable *table = static_cast<CGroupTable*> (getParent ()); flush = true;
finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8);
}
//nlinfo("Blank Texture");
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor);
} }
if (flush)
rVR.flush();
} }
// Get the parent table if (Border)
if (getParent ())
{ {
CGroupTable *table = static_cast<CGroupTable*> (getParent ()); // TODO: monitor these in checkCoords and update when changed
if (table->Border) { uint8 contentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A;
CRGBA lighter = blend(table->BorderColor, CRGBA::White, 0.5f); if (contentAlpha > 0)
{
CRGBA borderColorTL; Border->CurrentAlpha = contentAlpha;
borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); Border->setRenderLayer(_RenderLayer);
borderColorTL.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorTL.A) >> 8); Border->setModulateGlobalColor(_ModulateGlobalColor);
Border->draw();
CRGBA borderColorBR;
borderColorBR.modulateFromColor (table->BorderColor, CWidgetManager::getInstance()->getGlobalColor());
borderColorBR.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorBR.A) >> 8);
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorTL );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorBR );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_HReal-1, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorBR );
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorTL );
} }
} }
@ -569,13 +573,19 @@ namespace NLGUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
sint32 CGroupCell::getMaxUsedW() const sint32 CGroupCell::getMaxUsedW() const
{ {
return Group->getMaxUsedW(); sint32 result = getPaddingLeftRight() + Group->getMaxUsedW();
if (Border)
result += Border->getLeftRightWidth();
return result;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
sint32 CGroupCell::getMinUsedW() const sint32 CGroupCell::getMinUsedW() const
{ {
return Group->getMinUsedW(); sint32 result = getPaddingLeftRight() + Group->getMinUsedW();
if (Border)
result += Border->getLeftRightWidth();
return result;
} }
@ -584,14 +594,13 @@ namespace NLGUI
{ {
if (TxName.empty() || TxName == "none") if (TxName.empty() || TxName == "none")
{ {
_UserTexture = false; _TextureId.clear();
nlinfo("Set no texture");
} }
else else
{ {
nlinfo("Set texture to cell : %s", TxName.c_str());
_UserTexture = true;
_TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false); _TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false);
updateTextureCoords();
} }
} }
@ -611,6 +620,31 @@ namespace NLGUI
_TextureScaled = scaled; _TextureScaled = scaled;
} }
// ----------------------------------------------------------------------------
void CGroupCell::updateTextureCoords()
{
if (_TextureId.empty()) return;
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal);
_TextureXReal = _XReal;
_TextureYReal = _YReal + _HReal - _TextureHReal;
if (_TextureTiled && _TextureHReal > 0)
{
sint diff = (_HReal / _TextureHReal) * _TextureHReal;
_TextureYReal -= diff;
_TextureHReal += diff;
}
}
// ----------------------------------------------------------------------------
void CGroupCell::updateCoords()
{
CInterfaceGroup::updateCoords();
updateTextureCoords();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
NLMISC_REGISTER_OBJECT(CViewBase, CGroupTable, std::string, "table"); NLMISC_REGISTER_OBJECT(CViewBase, CGroupTable, std::string, "table");
@ -622,11 +656,21 @@ namespace NLGUI
_ContentValidated = false; _ContentValidated = false;
TableRatio = 0.f; TableRatio = 0.f;
ForceWidthMin = 0; ForceWidthMin = 0;
Border=0;
BorderColor = CRGBA(32, 32, 32, 255); // TODO: only initialize when needed
Border = new CSSBorderRenderer();
CellBorder = false;
CellPadding=1; CellPadding=1;
CellSpacing=2; CellSpacing=2;
ContinuousUpdate = false; ContinuousUpdate = false;
_TextureTiled = false;
_TextureScaled = false;
_TextureXReal = 0;
_TextureYReal = 0;
_TextureWReal = 0;
_TextureHReal = 0;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -688,13 +732,62 @@ namespace NLGUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
CGroupTable::~CGroupTable() CGroupTable::~CGroupTable()
{ {
if (Border)
{
delete Border;
Border = NULL;
}
/* uint i; /* uint i;
for (i=0; i<_Cells.size(); i++) for (i=0; i<_Cells.size(); i++)
delete _Cells[i]; delete _Cells[i];
_Cells.clear ();*/ _Cells.clear ();*/
} }
// ----------------------------------------------------------------------------
void CGroupTable::setTexture(const std::string & TxName)
{
if (TxName.empty() || TxName == "none")
{
_TextureId.clear();
}
else
{
_TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false);
updateTextureCoords();
}
}
// ----------------------------------------------------------------------------
void CGroupTable::setTextureTile(bool tiled)
{
_TextureTiled = tiled;
}
// ----------------------------------------------------------------------------
void CGroupTable::setTextureScale(bool scaled)
{
_TextureScaled = scaled;
}
// ----------------------------------------------------------------------------
void CGroupTable::updateTextureCoords()
{
if (_TextureId.empty()) return;
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal);
_TextureXReal = _XReal;
_TextureYReal = _YReal + _HReal - _TextureHReal;
if (_TextureTiled && _TextureHReal > 0)
{
sint diff = (_HReal / _TextureHReal) * _TextureHReal;
_TextureYReal -= diff;
_TextureHReal += diff;
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CGroupTable::updateCoords() void CGroupTable::updateCoords()
@ -738,21 +831,22 @@ namespace NLGUI
// Get width min and max // Get width min and max
if( !cell->IgnoreMaxWidth) if( !cell->IgnoreMaxWidth)
{
cell->WidthMax = cell->getMaxUsedW() + cell->LeftMargin; cell->WidthMax = cell->getMaxUsedW() + cell->LeftMargin;
}
else else
{
cell->WidthMax = cell->WidthWanted + additionnalWidth + cell->LeftMargin; cell->WidthMax = cell->WidthWanted + additionnalWidth + cell->LeftMargin;
}
sint32 cellWidth; sint32 cellWidth;
if(!cell->IgnoreMinWidth) if(!cell->IgnoreMinWidth)
{
cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin; cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin;
}
else else
{
cellWidth = cell->NoWrap ? cell->WidthMax : cell->LeftMargin; cellWidth = cell->NoWrap ? cell->WidthMax : cell->LeftMargin;
{
sint32 cellBorderPadding = cell->getPaddingLeftRight();
if (cell->Border)
cellBorderPadding += cell->Border->getLeftRightWidth();
if (cellWidth < cellBorderPadding)
cellWidth = cellBorderPadding;
} }
// New cell ? // New cell ?
@ -795,11 +889,11 @@ namespace NLGUI
_Columns[column].WidthMax = (sint32)(cell->WidthMax*colspan); _Columns[column].WidthMax = (sint32)(cell->WidthMax*colspan);
if (cell->TableRatio*colspan > _Columns[column].TableRatio) if (cell->TableRatio*colspan > _Columns[column].TableRatio)
_Columns[column].TableRatio = cell->TableRatio*colspan; _Columns[column].TableRatio = cell->TableRatio*colspan;
if (cell->WidthWanted*colspan + additionnalWidth > _Columns[column].WidthWanted) if ((cell->WidthWanted + additionnalWidth)*colspan > _Columns[column].WidthWanted)
_Columns[column].WidthWanted = (sint32)(cell->WidthWanted*colspan) + additionnalWidth; _Columns[column].WidthWanted = (sint32)((cell->WidthWanted + additionnalWidth)*colspan);
if (_Columns[column].WidthWanted + additionnalWidth) if (_Columns[column].WidthWanted > _Columns[column].WidthMax)
_Columns[column].WidthMax = _Columns[column].WidthWanted + additionnalWidth; _Columns[column].WidthMax = _Columns[column].WidthWanted;
if (_Columns[column].WidthWanted > _Columns[column].Width) if (_Columns[column].WidthWanted > _Columns[column].Width)
_Columns[column].Width = _Columns[column].WidthWanted; _Columns[column].Width = _Columns[column].WidthWanted;
@ -821,15 +915,23 @@ namespace NLGUI
column++; column++;
} }
// Width of cells and table borders // Additional space contributing to table width
sint32 padding = CellPadding + (Border ? 1 : 0); sint32 tableBorderSpacing = 0;
sint32 borderWidth = 2*Border + ((sint32)_Columns.size()+1) * CellSpacing + ((sint32)_Columns.size()*2) * padding; if (Border)
tableBorderSpacing += Border->getLeftRightWidth();
tableBorderSpacing += ((sint32)_Columns.size()+1) * CellSpacing;;
sint32 innerForceWidthMin = ForceWidthMin;
if (innerForceWidthMin < tableBorderSpacing)
innerForceWidthMin = 0;
else
innerForceWidthMin -= tableBorderSpacing;
// Get the width // Get the width
sint32 tableWidthMax = ForceWidthMin?ForceWidthMin:_LastParentW; // getWReal(); sint32 tableWidthMax = innerForceWidthMin ? innerForceWidthMin : _LastParentW - tableBorderSpacing; // getWReal();
sint32 tableWidthMin = std::max(ForceWidthMin, (sint32)((float)tableWidthMax*TableRatio)); sint32 tableWidthMin = std::max(innerForceWidthMin, (sint32)((float)tableWidthMax*TableRatio));
tableWidthMax = std::max ((sint32)0, tableWidthMax-borderWidth); tableWidthMax = std::max ((sint32)0, tableWidthMax);
tableWidthMin = std::max ((sint32)0, tableWidthMin-borderWidth); tableWidthMin = std::max ((sint32)0, tableWidthMin);
// Get the width of the table and normalize percent of the cell (sum of TableRatio must == 1) // Get the width of the table and normalize percent of the cell (sum of TableRatio must == 1)
sint32 tableWidth = 0; sint32 tableWidth = 0;
@ -845,10 +947,10 @@ namespace NLGUI
// force table width to fit all columns // force table width to fit all columns
// if width is set, then use column min width // if width is set, then use column min width
if (ForceWidthMin > 0) if (innerForceWidthMin > 0)
tableWidthMax = std::min(_LastParentW - borderWidth, std::max(tableWidthMax, tableWidth)); tableWidthMax = std::min(_LastParentW - tableBorderSpacing, std::max(tableWidthMax, tableWidth));
else else
tableWidthMax = std::min(_LastParentW - borderWidth, std::max(tableWidthMax, tableMaxContentWidth)); tableWidthMax = std::min(_LastParentW - tableBorderSpacing, std::max(tableWidthMax, tableMaxContentWidth));
if (tableWidthMax < 0) if (tableWidthMax < 0)
tableWidthMax = 0; tableWidthMax = 0;
@ -857,6 +959,7 @@ namespace NLGUI
std::swap(tableWidthMin, tableWidthMax); std::swap(tableWidthMin, tableWidthMax);
// Eval table size with all percent cells resized // Eval table size with all percent cells resized
// TODO: _Columns[i].TableRatio is for outer width
sint32 tableWidthSizeAfterPercent = tableWidth; sint32 tableWidthSizeAfterPercent = tableWidth;
for (i=0; i<_Columns.size(); i++) for (i=0; i<_Columns.size(); i++)
{ {
@ -1029,7 +1132,7 @@ namespace NLGUI
column = 0; column = 0;
sint32 row = 0; sint32 row = 0;
sint32 currentX = Border + CellSpacing + padding; sint32 currentX = 0;
_Rows.clear (); _Rows.clear ();
for (i=0; i<_Cells.size(); i++) for (i=0; i<_Cells.size(); i++)
@ -1039,7 +1142,9 @@ namespace NLGUI
if (cell->NewLine) if (cell->NewLine)
{ {
column = 0; column = 0;
currentX = Border + CellSpacing + padding; currentX = CellSpacing;
if (Border)
currentX += Border->getLeftWidth();
_Rows.push_back(CRow()); _Rows.push_back(CRow());
} }
@ -1048,7 +1153,7 @@ namespace NLGUI
{ {
// we have active rowspan, must add up 'skipped' columns // we have active rowspan, must add up 'skipped' columns
for( ; column < (uint)cell->TableColumnIndex; ++column) for( ; column < (uint)cell->TableColumnIndex; ++column)
currentX += _Columns[column].Width + padding*2 + CellSpacing; currentX += _Columns[column].Width + CellSpacing;
} }
// Set the x and width // Set the x and width
@ -1057,11 +1162,19 @@ namespace NLGUI
sint32 alignmentX = 0; sint32 alignmentX = 0;
sint32 widthReduceX = 0; sint32 widthReduceX = 0;
sint32 columnWidth = _Columns[column].Width; sint32 columnWidth = _Columns[column].Width;
sint32 cellBorderPaddingLeft = cell->PaddingLeft;
sint32 cellBorderPaddingRight = cell->PaddingRight;
if (cell->Border)
{
cellBorderPaddingLeft += cell->Border->getLeftWidth();
cellBorderPaddingRight += cell->Border->getRightWidth();
}
if (cell->ColSpan > 1) if (cell->ColSpan > 1)
{ {
// scan ahead and add up column widths as they might be different // scan ahead and add up column widths as they might be different
for(int j = 1; j<cell->ColSpan; j++) for(int j = 1; j<cell->ColSpan; j++)
columnWidth += CellSpacing + padding*2 + _Columns[column+j].Width; columnWidth += CellSpacing + _Columns[column+j].Width;
} }
if (cell->WidthMax < columnWidth) if (cell->WidthMax < columnWidth)
@ -1081,11 +1194,13 @@ namespace NLGUI
} }
} }
cell->setX(currentX - padding); // outer
cell->setW(columnWidth + padding*2); cell->setX(currentX);
cell->setW(columnWidth);
cell->Group->setX(alignmentX + cell->LeftMargin + padding); // inner
cell->Group->setW(columnWidth - widthReduceX); cell->Group->setX(cellBorderPaddingLeft + alignmentX + cell->LeftMargin);
cell->Group->setW(columnWidth - widthReduceX - cellBorderPaddingLeft - cellBorderPaddingRight);
cell->Group->CInterfaceElement::updateCoords(); cell->Group->CInterfaceElement::updateCoords();
// Update coords to get H // Update coords to get H
@ -1094,16 +1209,23 @@ namespace NLGUI
// Resize the row array // Resize the row array
float rowspan = 1.f / (float)cell->RowSpan; float rowspan = 1.f / (float)cell->RowSpan;
_Rows.back().Height = std::max((sint32)(cell->Height*rowspan), std::max(_Rows.back().Height, (sint32)(cell->Group->getH()*rowspan))); uint cellBorderPadding = cell->getPaddingTopBottom();
if (cell->Border)
cellBorderPadding += cell->Border->getTopBottomWidth();
sint32 cellHeight = std::max((sint32)(cell->Height*rowspan), (sint32)(cell->Group->getH()*rowspan + cellBorderPadding));
_Rows.back().Height = std::max(_Rows.back().Height, (sint32)cellHeight);
// Next column // Next column
currentX += columnWidth + 2*padding + CellSpacing; currentX += columnWidth + CellSpacing;
column += cell->ColSpan; column += cell->ColSpan;
} }
// Set cell Y // Set cell Y
row = 0; row = 0;
sint32 currentY = -(Border + CellSpacing + padding); sint32 currentY = -CellSpacing;
if (Border)
currentY -= Border->getTopWidth();
for (i=0; i<_Cells.size(); i++) for (i=0; i<_Cells.size(); i++)
{ {
// New cell ? // New cell ?
@ -1112,7 +1234,7 @@ namespace NLGUI
{ {
if (_Rows[row].Height != 0) if (_Rows[row].Height != 0)
{ {
currentY -= _Rows[row].Height + 2*padding + CellSpacing; currentY -= _Rows[row].Height + CellSpacing;
} }
row++; row++;
} }
@ -1120,12 +1242,19 @@ namespace NLGUI
// Check align // Check align
sint32 alignmentY = 0; sint32 alignmentY = 0;
sint32 rowHeight = _Rows[row].Height; sint32 rowHeight = _Rows[row].Height;
sint32 cellBorderPaddingTop = cell->PaddingTop;
sint32 cellBorderPaddingBottom = cell->PaddingBottom;
if (cell->Border)
{
cellBorderPaddingTop += cell->Border->getTopWidth();
cellBorderPaddingBottom += cell->Border->getBottomWidth();
}
if (cell->RowSpan > 1) if (cell->RowSpan > 1)
{ {
// we need to scan down and add up row heights // we need to scan down and add up row heights
int k = std::min((sint32)_Rows.size(), row + cell->RowSpan); int k = std::min((sint32)_Rows.size(), row + cell->RowSpan);
for(int j=row+1; j<k; j++) for(int j=row+1; j<k; j++)
rowHeight += CellSpacing + padding*2 + _Rows[j].Height; rowHeight += CellSpacing + _Rows[j].Height;
} }
if ((sint32)cell->Group->getH() < rowHeight) if ((sint32)cell->Group->getH() < rowHeight)
{ {
@ -1142,15 +1271,26 @@ namespace NLGUI
} }
} }
cell->setY(currentY + padding); // outer
cell->setH (rowHeight + 2*padding); cell->setY(currentY);
cell->Group->setY(-(alignmentY + padding)); cell->setH (rowHeight);
// inner
cell->Group->setY(-(alignmentY + cellBorderPaddingTop - cellBorderPaddingBottom));
} }
// Resize the table // final row
setW(finalWidth+borderWidth-_LastParentW);
if (!_Rows.empty()) if (!_Rows.empty())
currentY -= _Rows[row].Height + padding + CellSpacing + Border; currentY -= _Rows.back().Height;
currentY -= CellSpacing;
finalWidth += ((sint)_Columns.size() + 1) * CellSpacing;
if (Border)
{
currentY -= Border->getBottomWidth();
finalWidth += Border->getLeftRightWidth();
}
// Resize the table
setW(finalWidth-_LastParentW);
setH(-currentY); setH(-currentY);
// All done // All done
@ -1160,8 +1300,22 @@ namespace NLGUI
CInterfaceGroup::updateCoords(); CInterfaceGroup::updateCoords();
updateTextureCoords();
// update borders if present
if (Border)
{
Border->setRect(_XReal + _MarginLeft, _YReal, _WReal, _HReal);
}
// update cell borders if present
for (uint32 i=0; i<_Cells.size(); i++)
{
if (_Cells[i]->Border)
{
_Cells[i]->Border->setRect(_Cells[i]->_XReal, _Cells[i]->_YReal, _Cells[i]->_WReal, _Cells[i]->_HReal);
}
}
// Validated // Validated
_ContentValidated = true; _ContentValidated = true;
@ -1267,7 +1421,9 @@ namespace NLGUI
for (i=0; i<columns.size(); i++) for (i=0; i<columns.size(); i++)
maxWidth += columns[i]; maxWidth += columns[i];
maxWidth += 2*Border + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding; maxWidth += ((sint32)columns.size()+1) * CellSpacing;
if (Border)
maxWidth += Border->getLeftRightWidth();
return maxWidth; return maxWidth;
} }
@ -1312,7 +1468,9 @@ namespace NLGUI
for (i=0; i<columns.size(); i++) for (i=0; i<columns.size(); i++)
maxWidth += columns[i]; maxWidth += columns[i];
maxWidth += 2*Border + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding; maxWidth += ((sint32)columns.size()+1) * CellSpacing;
if (Border)
maxWidth += Border->getLeftRightWidth();
return maxWidth; return maxWidth;
} }
@ -1342,64 +1500,62 @@ namespace NLGUI
if (!_Columns.empty() && !_Rows.empty()) if (!_Columns.empty() && !_Rows.empty())
{ {
sint32 border = Border + CellSpacing; bool flush = false;
if (border && BgColor.A) CViewRenderer &rVR = *CViewRenderer::getInstance();
if (BgColor.A > 0)
{ {
CRGBA finalColor; CRGBA finalColor = BgColor;
finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor()); if (_ModulateGlobalColor)
finalColor.A = CurrentAlpha; finalColor.modulateFromColor (finalColor, CWidgetManager::getInstance()->getGlobalColor());
finalColor.A = (uint8) (((uint16) CurrentAlpha * (uint16) finalColor.A) >> 8);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the top line flush = true;
CViewRenderer &rVR = *CViewRenderer::getInstance(); }
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal-border+_HReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the left line // Draw the background
sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)border); if (CurrentAlpha > 0 && !_TextureId.empty())
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); {
sint32 oldSciX, oldSciY, oldSciW, oldSciH;
makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH);
// Draw the inside borders CRGBA col = CRGBA::White;
if (CellSpacing) col.A = CurrentAlpha;
if (_TextureScaled && !_TextureTiled)
{ {
uint i; rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col);
sint32 x, y; }
for (i=0; i<_Cells.size(); i++) else
{ {
CGroupCell *cell = _Cells[i]; if (!_TextureTiled)
rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _TextureWReal, _TextureHReal, 0, false, _TextureId, col);
x = cell->getXReal(); else
y = cell->getYReal() - CellSpacing; rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col);
// right
rVR.drawRotFlipBitmap (_RenderLayer, x + cell->getW(), y, CellSpacing, cell->getH() + CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor);
// bottom
rVR.drawRotFlipBitmap (_RenderLayer, x, y, cell->getW(), CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor);
}
} }
restoreClip (oldSciX, oldSciY, oldSciW, oldSciH);
flush = true;
} }
if (Border)
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
CRGBA borderColorTL; // flush background color and image
CRGBA lighter = blend(BorderColor, CRGBA::White, 0.5f); if (flush)
borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); rVR.flush();
borderColorTL.A = CurrentAlpha;
CRGBA borderColorBR; if (Border)
borderColorBR.modulateFromColor (BorderColor, CWidgetManager::getInstance()->getGlobalColor()); {
borderColorBR.A = CurrentAlpha; // TODO: monitor these in checkCoords and update when changed
uint8 contentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A;
// beveled table border if (contentAlpha > 0)
for (sint32 i=0; i<Border; i++)
{ {
// bottom, left, top, right Border->CurrentAlpha = CurrentAlpha;
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+i, _WReal-i*2, 1, 0, false, rVR.getBlankTextureId(), borderColorBR); Border->setRenderLayer(_RenderLayer);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+i, 1, _HReal-i*2, 0, false, rVR.getBlankTextureId(), borderColorTL); Border->setModulateGlobalColor(_ModulateGlobalColor);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+_HReal-i-1, _WReal-i*2, 1, 0, false, rVR.getBlankTextureId(), borderColorTL); Border->draw();
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-i-1, _YReal+i, 1, _HReal-i*2, 0, false, rVR.getBlankTextureId(), borderColorBR);
} }
} }
} }
CInterfaceGroup::draw (); CInterfaceGroup::draw ();
@ -1412,12 +1568,16 @@ namespace NLGUI
{ {
if( name == "border" ) if( name == "border" )
{ {
return toString( Border ); if (Border)
return toString( Border->TopWidth );
return "0";
} }
else else
if( name == "bordercolor" ) if( name == "bordercolor" )
{ {
return toString( BorderColor ); if (Border)
return toString( Border->TopColor );
return toString(CRGBA::Transparent);
} }
else else
if( name == "cellpadding" ) if( name == "cellpadding" )
@ -1452,7 +1612,14 @@ namespace NLGUI
{ {
sint32 i; sint32 i;
if( fromString( value, i ) ) if( fromString( value, i ) )
Border = i; {
if (!Border)
Border = new CSSBorderRenderer();
Border->TopWidth = i;
Border->RightWidth = i;
Border->BottomWidth = i;
Border->LeftWidth = i;
}
return; return;
} }
else else
@ -1460,7 +1627,14 @@ namespace NLGUI
{ {
CRGBA c; CRGBA c;
if( fromString( value, c ) ) if( fromString( value, c ) )
BorderColor = c; {
if (!Border)
Border = new CSSBorderRenderer();
Border->TopColor = c;
Border->RightColor = c;
Border->BottomColor = c;
Border->LeftColor = c;
}
return; return;
} }
else else
@ -1505,8 +1679,11 @@ namespace NLGUI
return NULL; return NULL;
xmlSetProp( node, BAD_CAST "type", BAD_CAST "table" ); xmlSetProp( node, BAD_CAST "type", BAD_CAST "table" );
xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border ).c_str() ); if (Border)
xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( BorderColor ).c_str() ); {
xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border->TopWidth ).c_str() );
xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( Border->TopColor ).c_str() );
}
xmlSetProp( node, BAD_CAST "cellpadding", BAD_CAST toString( CellPadding ).c_str() ); xmlSetProp( node, BAD_CAST "cellpadding", BAD_CAST toString( CellPadding ).c_str() );
xmlSetProp( node, BAD_CAST "cellspacing", BAD_CAST toString( CellSpacing ).c_str() ); xmlSetProp( node, BAD_CAST "cellspacing", BAD_CAST toString( CellSpacing ).c_str() );
xmlSetProp( node, BAD_CAST "bgcolor", BAD_CAST toString( BgColor ).c_str() ); xmlSetProp( node, BAD_CAST "bgcolor", BAD_CAST toString( BgColor ).c_str() );
@ -1528,13 +1705,20 @@ namespace NLGUI
ptr = (char*) xmlGetProp( cur, (xmlChar*)"border" ); ptr = (char*) xmlGetProp( cur, (xmlChar*)"border" );
if (ptr) if (ptr)
{ {
fromString((const char*)ptr, Border); uint32 w;
fromString((const char*)ptr, w);
if (!Border)
Border = new CSSBorderRenderer();
Border->setWidth(w, w, w, w);
} }
// //
ptr = (char*) xmlGetProp( cur, (xmlChar*)"bordercolor" ); ptr = (char*) xmlGetProp( cur, (xmlChar*)"bordercolor" );
if (ptr) if (ptr)
{ {
BorderColor = convertColor((const char*)ptr); CRGBA c = convertColor((const char*)ptr);
if (!Border)
Border = new CSSBorderRenderer();
Border->setColor(c, c, c, c);
} }
// //
ptr = (char*) xmlGetProp( cur, (xmlChar*)"cellpadding" ); ptr = (char*) xmlGetProp( cur, (xmlChar*)"cellpadding" );

@ -190,6 +190,35 @@ namespace NLGUI
elm.reindexChilds(); elm.reindexChilds();
parent.reindexChilds(); parent.reindexChilds();
} }
// move all <tr> directly under <table> to its own <tbody> ("table > tbody > tr" selector).
// TODO: move first real <thead> to front, move first real <tfoot> at the end
if (elm.ID == HTML_TABLE)
{
std::list<CHtmlElement>::iterator it = elm.Children.begin();
std::list<CHtmlElement>::iterator tbody = elm.Children.end();
for(it = elm.Children.begin(); it != elm.Children.end(); ++it)
{
if (it->ID == HTML_TR)
{
if (tbody == elm.Children.end())
{
tbody = elm.Children.insert(it, CHtmlElement(CHtmlElement::ELEMENT_NODE, "tbody"));
tbody->ID = HTML_TBODY;
tbody->parent = &elm;
}
tbody->Children.splice(tbody->Children.end(), elm.Children, it);
it = tbody;
}
else if (tbody != elm.Children.end())
{
tbody->reindexChilds();
tbody = elm.Children.end();
}
}
elm.reindexChilds();
}
} }
} }

@ -1932,6 +1932,16 @@ namespace NLGUI
return _TextureId >= 0; return _TextureId >= 0;
} }
// ***************************************************************************
void CViewRenderer::CTextureId::clear()
{
if (_TextureId >= 0)
{
CViewRenderer::getInstance()->deleteTexture(_TextureId);
_TextureId = -1;
}
}
// *************************************************************************** // ***************************************************************************
void CViewRenderer::CTextureId::serial(NLMISC::IStream &f) void CViewRenderer::CTextureId::serial(NLMISC::IStream &f)
{ {

@ -361,6 +361,37 @@ void CIFile::flush()
} }
} }
// ======================================================================================================
bool CIFile::readAll(std::string &buffer)
{
try
{
uint32 remaining = _FileSize;
buffer.clear();
buffer.reserve(_FileSize);
while(!eof() && remaining > 0)
{
const static uint bufsize = 1024;
char buf[bufsize];
uint32 readnow = bufsize;
if (readnow > remaining)
readnow = remaining;
serialBuffer((uint8 *)&buf[0], readnow);
buffer.append(buf, readnow);
remaining -= readnow;
}
}
catch (const EFile &)
{
// buffer state is unknown
return false;
}
return true;
}
// ====================================================================================================== // ======================================================================================================
void CIFile::getline (char *buffer, uint32 bufferSize) void CIFile::getline (char *buffer, uint32 bufferSize)
{ {

@ -48,6 +48,7 @@ const CRGBA CRGBA::Blue(0, 0, 255) ;
const CRGBA CRGBA::Magenta(255, 0, 255) ; const CRGBA CRGBA::Magenta(255, 0, 255) ;
const CRGBA CRGBA::Cyan(0, 255, 255) ; const CRGBA CRGBA::Cyan(0, 255, 255) ;
const CRGBA CRGBA::White(255, 255, 255) ; const CRGBA CRGBA::White(255, 255, 255) ;
const CRGBA CRGBA::Transparent(0, 0, 0, 0);
// *************************************************************************** // ***************************************************************************
void CRGBA::serial(NLMISC::IStream &f) void CRGBA::serial(NLMISC::IStream &f)

@ -23,6 +23,7 @@
#include "nel/gui/group_container.h" #include "nel/gui/group_container.h"
#include "nel/gui/group_editbox.h" #include "nel/gui/group_editbox.h"
#include "nel/gui/group_menu.h"
#include "dbctrl_sheet.h" #include "dbctrl_sheet.h"
#include "interface_3d_scene.h" #include "interface_3d_scene.h"
#include "character_3d.h" #include "character_3d.h"
@ -74,7 +75,31 @@ class CAHActiveMenu : public IActionHandler
// open the menu // open the menu
if (CDBCtrlSheet::getDraggedSheet() == NULL) if (CDBCtrlSheet::getDraggedSheet() == NULL)
{ {
CWidgetManager::getInstance()->enableModalWindow (pCaller, getParam(Params, "menu")); std::string menuId = getParam(Params, "menu");
CGroupMenu *groupMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId(menuId));
if (groupMenu)
{
bool pushModal;
// default = false
fromString(getParam(Params, "pushmodal"), pushModal);
if (pushModal)
{
// if false, then close all modal window when groupMenu deactivates
bool popModal;
if (!fromString(getParam(Params, "popmodal"), popModal))
{
popModal = true;
}
groupMenu->setCloseSubMenuUsingPopModal(popModal);
CWidgetManager::getInstance()->pushModalWindow(pCaller, groupMenu);
}
else
{
groupMenu->setCloseSubMenuUsingPopModal(false);
CWidgetManager::getInstance()->enableModalWindow(pCaller, groupMenu);
}
}
} }
} }
}; };

@ -53,6 +53,7 @@
#include "action_handler_tools.h" #include "action_handler_tools.h"
#include "../connection.h" #include "../connection.h"
#include "../client_chat_manager.h" #include "../client_chat_manager.h"
#include "group_compas.h"
// Game specific includes // Game specific includes
#include "../motion/user_controls.h" #include "../motion/user_controls.h"
@ -2475,6 +2476,17 @@ class CAHTarget : public IActionHandler
if (entity && entity->properties().selectable() && !entity->getDisplayName().empty()) if (entity && entity->properties().selectable() && !entity->getDisplayName().empty())
{ {
UserEntity->selection(entity->slot()); UserEntity->selection(entity->slot());
CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass"));
if (gc)
{
CCompassTarget ct;
ct.setType(CCompassTarget::Selection);
gc->setActive(true);
gc->setTarget(ct);
gc->blink();
CWidgetManager::getInstance()->setTopWindow(gc);
}
} }
else if (!quiet) else if (!quiet)
{ {
@ -2484,6 +2496,33 @@ class CAHTarget : public IActionHandler
}; };
REGISTER_ACTION_HANDLER (CAHTarget, "target"); REGISTER_ACTION_HANDLER (CAHTarget, "target");
// ***************************************************************************
class CAHTargetLandmark : public IActionHandler
{
virtual void execute (CCtrlBase * /* pCaller */, const string &Params)
{
string search = getParam(Params, "search");
if (search.empty()) return;
bool startsWith = false;
if (search.size() > 0 && (search[0] == '\'' || search[0] == '"') && search[0] == search[search.size()-1])
{
startsWith = true;
search = trimQuotes(search);
}
const std::string mapid = "ui:interface:map:content:map_content:actual_map";
CGroupMap* cgMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId(mapid));
if (cgMap)
{
if (!cgMap->targetLandmarkByName(search, startsWith))
{
CInterfaceManager::getInstance()->displaySystemInfo(CI18N::get("uiTargetErrorCmd"));
}
}
}
};
REGISTER_ACTION_HANDLER (CAHTargetLandmark, "target_landmark");
class CAHAddShape : public IActionHandler class CAHAddShape : public IActionHandler

@ -101,6 +101,12 @@ const uint32 ISLAND_PIXEL_PER_METER = 2;
static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel); static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel);
// calculate distance (squared) between two points
static float distsqr(const CVector2f a, const CVector2f b)
{
return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}
// popup the landmark name dialog // popup the landmark name dialog
static void popupLandMarkNameDialog() static void popupLandMarkNameDialog()
@ -2654,6 +2660,9 @@ static void hideTeleportButtonsInPopupMenuIfNotEnoughPriv()
ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu:lmteleport"); ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu:lmteleport");
if(ie) ie->setActive(showTeleport); if(ie) ie->setActive(showTeleport);
ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu_base:lmteleport");
if(ie) ie->setActive(showTeleport);
} }
//============================================================================================================ //============================================================================================================
@ -2717,8 +2726,8 @@ CGroupMap::CLandMarkButton *CGroupMap::createLandMarkButton(const CLandMarkOptio
lmb->setModulateGlobalColorAll(false); lmb->setModulateGlobalColorAll(false);
if (!options.LandMarkMenu.empty()) if (!options.LandMarkMenu.empty())
{ {
lmb->setActionOnRightClick("active_menu"); lmb->setActionOnRightClick("world_map_right_click");
lmb->setParamsOnRightClick(NLMISC::toString("menu=%s", options.LandMarkMenu.c_str())); lmb->setParamsOnRightClick(NLMISC::toString("map=%s|menu=%s", _Id.c_str(), options.LandMarkMenu.c_str()));
} }
lmb->setPosRef(Hotspot_MM); lmb->setPosRef(Hotspot_MM);
return lmb; return lmb;
@ -2760,21 +2769,38 @@ void CGroupMap::updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOption
} }
//============================================================================================================ //============================================================================================================
bool CGroupMap::filterLandmark(const ucstring &title) const bool CGroupMap::filterLandmark(const ucstring &title, const std::vector<ucstring> filter, bool startsWith) const
{ {
if (_LandmarkFilter.size() > 0) if (filter.size() > 0)
{ {
ucstring lcTitle = toLower(title); ucstring lcTitle = toLower(title);
for(uint i = 0; i< _LandmarkFilter.size(); ++i) { if (startsWith)
if (lcTitle.find(_LandmarkFilter[i]) == ucstring::npos) { {
if (lcTitle.find(filter[0]) != 0)
{
return false; return false;
} }
} }
else
{
for(uint i = 0; i< filter.size(); ++i)
{
if (lcTitle.find(filter[i]) == ucstring::npos)
{
return false;
}
}
}
} }
return true; return true;
} }
//============================================================================================================
bool CGroupMap::filterLandmark(const ucstring &title) const
{
return filterLandmark(title, _LandmarkFilter);
}
//============================================================================================================ //============================================================================================================
void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options) void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options)
{ {
@ -2853,6 +2879,23 @@ CCtrlButton *CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucst
return _UserLM.back(); return _UserLM.back();
} }
//============================================================================================================
CCtrlButton* CGroupMap::getLandmarkCtrl(const std::string &lmType, uint lmIndex) const
{
CCtrlButton *ctrl = NULL;
if (lmType == "user")
{
if (lmIndex < _UserLM.size())
{
ctrl = _UserLM[lmIndex];
}
else nlwarning("_UserLM index out of bounds (size:%u, index:%u)", (uint)_UserLM.size(), lmIndex);
}
else nlwarning("unsupported landmark type '%s'", lmType.c_str());
return ctrl;
}
//============================================================================================================ //============================================================================================================
void CGroupMap::removeUserLandMark(CCtrlButton *button) void CGroupMap::removeUserLandMark(CCtrlButton *button)
{ {
@ -3319,6 +3362,129 @@ void CGroupMap::targetLandmarkResult(uint32 index)
} }
} }
//=========================================================================================================
CGroupMap::CLandMarkButton* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const
{
CLandMarkButton *ret = NULL;
std::vector<ucstring> keywords;
if (startsWith)
keywords.push_back(search);
else
splitUCString(toLower(search), ucstring(" "), keywords);
closest = std::numeric_limits<float>::max();
for(TLandMarkButtonVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
{
ucstring lc;
(*it)->getContextHelp(lc);
if(filterLandmark(lc, keywords, startsWith)) {
CVector2f pos;
mapToWorld(pos, (*it)->Pos);
float dist = distsqr(center, pos);
if (dist < closest)
{
ret = (*it);
closest = dist;
}
}
}
return ret;
}
//=========================================================================================================
CGroupMap::CLandMarkText* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const
{
CLandMarkText *ret = NULL;
std::vector<ucstring> keywords;
if (startsWith)
keywords.push_back(search);
else
splitUCString(toLower(search), ucstring(" "), keywords);
closest = std::numeric_limits<float>::max();
for(TLandMarkTextVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
{
ucstring lc;
lc = (*it)->getText();
if(filterLandmark(lc, keywords, startsWith)) {
CVector2f pos;
mapToWorld(pos, (*it)->Pos);
float dist = distsqr(center, pos);
if (dist < closest)
{
ret = (*it);
closest = dist;
}
}
}
return ret;
}
bool CGroupMap::targetLandmarkByName(const ucstring &search, bool startsWith) const
{
CCompassTarget ct;
CLandMarkButton* lm;
float dist;
float closest = std::numeric_limits<float>::max();
bool found = false;
CVector2f center;
mapToWorld(center, _PlayerPos);
lm = findClosestLandmark(center, search, startsWith, _UserLM, dist);
if (lm && dist < closest)
{
ct.setType(CCompassTarget::UserLandMark);
mapToWorld(ct.Pos, lm->Pos);
lm->getContextHelp(ct.Name);
closest = dist;
found = true;
}
// only check other types if user landmark was not found
if (!found)
{
lm = findClosestLandmark(center, search, startsWith, _ContinentLM, dist);
if (lm && dist < closest)
{
ct.setType(CCompassTarget::ContinentLandMark);
mapToWorld(ct.Pos, lm->Pos);
lm->getContextHelp(ct.Name);
closest = dist;
found = true;
}
CLandMarkText* lmt;
lmt = findClosestLandmark(center, search, startsWith, _ContinentText, dist);
if (lmt && dist < closest)
{
ct.setType(CCompassTarget::ContinentLandMark);
mapToWorld(ct.Pos, lmt->Pos);
ct.Name = lmt->getText();
closest = dist;
found = true;
}
}
if (found)
{
CInterfaceManager *im = CInterfaceManager::getInstance();
CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId(_CompassId));
if (gc)
{
gc->setActive(true);
gc->setTarget(ct);
gc->blink();
CWidgetManager::getInstance()->setTopWindow(gc);
}
}
return found;
}
//========================================================================================================= //=========================================================================================================
void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos) void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos)
{ {
@ -3575,6 +3741,126 @@ int CGroupMap::luaIsIsland(CLuaState &ls)
// ACTION HANDLERS // // ACTION HANDLERS //
///////////////////// /////////////////////
//=========================================================================================================
void CGroupMap::updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const
{
static uint nbShowLandmarks = 5;
static uint nbShowLandmarksMax = 5;
const CGroupMenu *pMenu = dynamic_cast<CGroupMenu *>(CWidgetManager::getInstance()->getElementFromId(menu));
if (!pMenu) return;
CGroupSubMenu *rootMenu = pMenu->getRootMenu();
if (!rootMenu) return;
// remove previous markers from menu
for(uint i = 0; i < nbShowLandmarksMax; ++i)
{
std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i);
sint index = rootMenu->getLineFromId(lineId);
if (index < 0) break;
rootMenu->removeLine(index);
}
// no continent selected (ie world map view)
if (!_CurContinent) return;
// sort landmarks, keep indices
typedef std::pair<uint, float> TSortedDistPair;
std::vector<TSortedDistPair> sortedIndices;
for(uint i = 0; i < _CurContinent->UserLandMarks.size(); ++i)
{
float dist = distsqr(pos, _CurContinent->UserLandMarks[i].Pos);
if (sortedIndices.empty())
{
sortedIndices.push_back(TSortedDistPair(i, dist));
}
else
{
bool found = false;
for(uint j = 0; j< sortedIndices.size(); j++)
{
if (dist < sortedIndices[j].second)
{
sortedIndices.insert(sortedIndices.begin() + j, TSortedDistPair(i, dist));
found = true;
if (sortedIndices.size() > nbShowLandmarks)
{
sortedIndices.pop_back();
}
break;
}
}
if (!found && sortedIndices.size() < nbShowLandmarks)
{
sortedIndices.push_back(TSortedDistPair(i, dist));
}
}
}
// add landmarks to menu
uint lineIndex = rootMenu->getNumLines();
for(uint i = 0; i< sortedIndices.size(); ++i)
{
uint32 index = sortedIndices[i].first;
ucstring name = ucstring(toString("%.2fm ", sqrt(sortedIndices[i].second))) + _CurContinent->UserLandMarks[index].Title;
std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i);
std::string ahParams = toString("type=user|map=%s|index=%d", _Id.c_str(), index);
CViewTextMenu* vt = rootMenu->addLine(ucstring(""), "map_landmark_by_index", ahParams, lineId.c_str(), "", "", false, false, false);
if (!vt) break;
vt->setSingleLineTextFormatTaged(name);
// TODO: should calculate from mouse pos and client width
vt->setLineMaxW(800);
CLandMarkOptions options = getUserLandMarkOptions(index);
typedef std::pair<std::string, std::string> TTmplParams;
std::vector<TTmplParams> vparams;
vparams.push_back(TTmplParams("id", toString("lmicon%d", i)));
vparams.push_back(TTmplParams("sizeref", ""));
vparams.push_back(TTmplParams("icon_texture", options.LandMarkTexNormal));
vparams.push_back(TTmplParams("icon_color", options.ColorNormal.toString()));
CInterfaceGroup *pUGLeft = CWidgetManager::getInstance()->getParser()->createGroupInstance("landmark_row_icon", lineId, vparams);
if (pUGLeft)
rootMenu->setUserGroupLeft(lineIndex, pUGLeft, true);
rootMenu->setRightClickHandler(lineIndex, "map_landmark_by_index");
rootMenu->setRightClickHandlerParam(lineIndex, toString("%s|menu=%s_base", ahParams.c_str(), options.LandMarkMenu.c_str()));
lineIndex++;
}
}
//=========================================================================================================
// remap caller with landmark using index/type and call popup menu or set compass target if no menu is set
class CAHMapLandmarkByIndex : public IActionHandler
{
virtual void execute (CCtrlBase* pCaller, const string &params )
{
const std::string mapName = getParam(params, "map");
const std::string lmType = getParam(params, "type");
const std::string menuId = getParam(params, "menu");
uint index;
if (!fromString(getParam(params, "index"), index)) return;
CGroupMap *map = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(mapName));
if (!map) return;
// remap caller to landmark from menu row
CCtrlButton* pButton = map->getLandmarkCtrl(lmType, index);
if (!pButton) return;
if (menuId.empty())
map->targetLandmark(pButton);
else
CAHManager::getInstance()->runActionHandler("active_menu", pButton, toString("pushmodal=true|popmodal=false|menu=%s", menuId.c_str()));
}
};
REGISTER_ACTION_HANDLER(CAHMapLandmarkByIndex, "map_landmark_by_index");
//========================================================================================================= //=========================================================================================================
// Set landmark filter // Set landmark filter
class CAHLandMarkFilter : public IActionHandler class CAHLandMarkFilter : public IActionHandler
@ -3879,23 +4165,41 @@ class CAHWorldMapRightClick : public IActionHandler
virtual void execute (CCtrlBase *pCaller, const string &params) virtual void execute (CCtrlBase *pCaller, const string &params)
{ {
std::string map = getParam(params, "map"); std::string map = getParam(params, "map");
CInterfaceManager *im = CInterfaceManager::getInstance(); std::string menu = getParam(params, "menu");
hideTeleportButtonsInPopupMenuIfNotEnoughPriv(); hideTeleportButtonsInPopupMenuIfNotEnoughPriv();
CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map)); CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
if (!gm) return; if (!gm) return;
if (!gm->isIsland())
if (gm->isIsland())
{ {
CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu"); if (gm->getArkPowoMode() == "editor")
menu = gm->getArkPowoMapMenu();
else
menu = "ui:interface:map_menu_island";
} }
else else
{ {
if (gm->getArkPowoMode() == "editor") if (menu.empty())
CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu="+gm->getArkPowoMapMenu()); menu = "ui:interface:map_menu";
else
CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu_island"); // update menu with closest landmarks
NLMISC::CVector2f pos(NLMISC::CVector2f::Null);
CCtrlButton *button = dynamic_cast<CCtrlButton *>(pCaller);
if (button)
gm->getLandmarkPosition(button, pos);
if(pos == NLMISC::CVector2f::Null)
{
pos = gm->getRightClickLastPos();
gm->mapToWorld(pos, pos);
}
gm->updateClosestLandMarkMenu(menu, pos);
} }
CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=" + menu);
} }
}; };
REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click") REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click")

@ -199,6 +199,8 @@ public:
float getScale() const { return _UserScale; } float getScale() const { return _UserScale; }
/// add a user landmark (returns a pointer on its button).Coordinate are in the current map (not world coordinates) /// add a user landmark (returns a pointer on its button).Coordinate are in the current map (not world coordinates)
CCtrlButton *addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType); CCtrlButton *addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType);
/// return current continent landmark by its index and type
CCtrlButton* getLandmarkCtrl(const std::string &lmType, uint lmIndex) const;
// remove a user landmark from a pointer on its button // remove a user landmark from a pointer on its button
void removeUserLandMark(CCtrlButton *button); void removeUserLandMark(CCtrlButton *button);
// update a user landmark from a pointer on its button // update a user landmark from a pointer on its button
@ -214,6 +216,8 @@ public:
// target the given landmark // target the given landmark
void targetLandmark(CCtrlButton *lm); void targetLandmark(CCtrlButton *lm);
void targetLandmarkResult(uint32 index); void targetLandmarkResult(uint32 index);
// search matching landmark and target it. return true if landmark was targeted
bool targetLandmarkByName(const ucstring &search, bool startsWith) const;
// get the world position of a landmark or return vector Null if not found // get the world position of a landmark or return vector Null if not found
void getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos); void getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos);
@ -293,6 +297,8 @@ public:
bool isIsland() const { return _IsIsland; } bool isIsland() const { return _IsIsland; }
void updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private: private:
// A non rectangular button to click on zone of the map // A non rectangular button to click on zone of the map
@ -592,6 +598,12 @@ private:
// Test title against landmark filter // Test title against landmark filter
bool filterLandmark(const ucstring &title) const; bool filterLandmark(const ucstring &title) const;
bool filterLandmark(const ucstring &title, const std::vector<ucstring> filter, bool startsWith = false) const;
// return closest landmark which matches (case insensitive) search string
// center position must be in world coordindates
CLandMarkButton* findClosestLandmark(const NLMISC::CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const;
CLandMarkText* findClosestLandmark(const NLMISC::CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const;
// update the scale depending on the window size and the user scale // update the scale depending on the window size and the user scale
void updateScale(); void updateScale();

Loading…
Cancel
Save