--HG--
branch : ark
hg/ark
Ulu Kyn 5 years ago
commit c43b4b8bc0

@ -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();
@ -167,26 +204,27 @@ namespace NLGUI
return Current.FontSize-2; return Current.FontSize-2;
} }
sint styleStackIndex = 0;
inline void pushStyle() inline void pushStyle()
{ {
styleStackIndex++;
_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();
} }
inline void popStyle() inline void popStyle()
{ {
styleStackIndex--;
if (_StyleStack.empty()) if (_StyleStack.empty())
{ {
Current = Root; Current = Root;

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

@ -321,6 +321,8 @@ namespace NLGUI
void deleteLUAEnvTable(bool recurse = false); void deleteLUAEnvTable(bool recurse = false);
// Set the LUA script to execute at checkCoords time (empty to reset) // Set the LUA script to execute at checkCoords time (empty to reset)
void setLuaScriptOnDraw(const std::string &script); void setLuaScriptOnDraw(const std::string &script);
// Get the LUA script executed at checkCoords time
inline CStringShared getLuaScriptOnDraw() { return _LUAOnDraw; }
// //
void executeLuaScriptOnDraw(); void executeLuaScriptOnDraw();
// Set the LUA script to execute when a list of DB change (of forms: "@DB1,@DB2" ....). The dbList is the key // Set the LUA script to execute when a list of DB change (of forms: "@DB1,@DB2" ....). The dbList is the key

@ -161,6 +161,7 @@ namespace NLGUI
static int luaMethodCall(lua_State *ls); static int luaMethodCall(lua_State *ls);
static int setOnDraw(CLuaState &ls); // params: CInterfaceGroup*, "script". return: none static int setOnDraw(CLuaState &ls); // params: CInterfaceGroup*, "script". return: none
static int getOnDraw(CLuaState &ls); // params: CInterfaceGroup*. return: "script" (nil if none)
static int addOnDbChange(CLuaState &ls); // params: CInterfaceGroup*, "dblist", "script". return: none static int addOnDbChange(CLuaState &ls); // params: CInterfaceGroup*, "dblist", "script". return: none
static int removeOnDbChange(CLuaState &ls);// params: CInterfaceGroup*. return: none static int removeOnDbChange(CLuaState &ls);// params: CInterfaceGroup*. return: none
static int setCaptureKeyboard(CLuaState &ls); static int setCaptureKeyboard(CLuaState &ls);

@ -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,55 +493,131 @@ namespace NLGUI
} }
} }
// apply style rules void CCssStyle::applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const
void CCssStyle::apply(CStyleParams &style, const CStyleParams &current) const
{
float tmpf;
TStyle::const_iterator it;
for (it=style.StyleRules.begin(); it != style.StyleRules.end(); ++it)
{
if (it->first == "border" || it->first == "border-width")
{ {
// TODO: border: 1px solid red; if (!dest) return;
if (it->second == "inherit") if (value == "inherit")
{ {
style.BorderWidth = current.BorderWidth; *dest = currentWidth;
} }
else if (it->second == "none") else if (value == "thin")
{ {
style.BorderWidth = 0; *dest = 1;
} }
else if (it->second == "thin") else if (value == "medium")
{ {
style.BorderWidth = 1; *dest = 3;
} }
else if (it->second == "medium") else if (value == "thick")
{ {
style.BorderWidth = 3; *dest = 5;
} }
else if (it->second == "thick") else if (value == "0")
{ {
style.BorderWidth = 5; *dest = 0;
} }
else else
{ {
float tmpf; float tmpf;
std::string unit; std::string unit;
if (getCssLength(tmpf, unit, it->second.c_str())) if (getCssLength(tmpf, unit, value.c_str()))
{ {
if (unit == "rem") if (unit == "rem")
style.BorderWidth = Root.FontSize * tmpf; *dest = fontSize * tmpf;
else if (unit == "em") else if (unit == "em")
style.BorderWidth = current.FontSize * tmpf; *dest = fontSize * tmpf;
else if (unit == "pt") else if (unit == "pt")
style.BorderWidth = tmpf / 0.75f; *dest = tmpf / 0.75f;
else if (unit == "%") else if (unit == "%")
style.BorderWidth = 0; // no support for % in border width *dest = 0; // no support for % in border width
else else
style.BorderWidth = tmpf; *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
void CCssStyle::apply(CStyleParams &style, const CStyleParams &current) const
{
float tmpf;
TStyle::const_iterator it;
for (it=style.StyleRules.begin(); it != style.StyleRules.end(); ++it)
{
if (it->first == "border-top-width") applyBorderWidth(it->second, &style.BorderTopWidth, current.BorderTopWidth, current.FontSize);
else if (it->first == "border-top-color") applyBorderColor(it->second, &style.BorderTopColor, current.BorderTopColor, current.TextColor);
else if (it->first == "border-top-style") applyLineStyle(it->second, &style.BorderTopStyle, current.BorderTopStyle);
else if (it->first == "border-right-width") applyBorderWidth(it->second, &style.BorderRightWidth, current.BorderRightWidth, current.FontSize);
else if (it->first == "border-right-color") applyBorderColor(it->second, &style.BorderRightColor, current.BorderRightColor, current.TextColor);
else if (it->first == "border-right-style") applyLineStyle(it->second, &style.BorderRightStyle, current.BorderRightStyle);
else if (it->first == "border-bottom-width") applyBorderWidth(it->second, &style.BorderBottomWidth, current.BorderBottomWidth, current.FontSize);
else if (it->first == "border-bottom-color") applyBorderColor(it->second, &style.BorderBottomColor, current.BorderBottomColor, current.TextColor);
else if (it->first == "border-bottom-style") applyLineStyle(it->second, &style.BorderBottomStyle, current.BorderBottomStyle);
else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.BorderLeftWidth, current.BorderLeftWidth, current.FontSize);
else if (it->first == "border-left-color") applyBorderColor(it->second, &style.BorderLeftColor, current.BorderLeftColor, current.TextColor);
else if (it->first == "border-left-style") applyLineStyle(it->second, &style.BorderLeftStyle, current.BorderLeftStyle);
else if (it->first == "padding-top") applyPaddingWidth(it->second, &style.PaddingTop, current.PaddingTop, current.FontSize);
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->first == "padding-left") applyPaddingWidth(it->second, &style.PaddingLeft, current.PaddingLeft, current.FontSize);
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,9 +287,10 @@ namespace NLGUI
{ {
btn->setTextureOver(file); btn->setTextureOver(file);
} }
return;
} }
else
{
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(view); CViewBitmap *btm = dynamic_cast<CViewBitmap*>(view);
if(btm) if(btm)
{ {
@ -296,9 +298,10 @@ namespace NLGUI
btm->invalidateCoords(); btm->invalidateCoords();
btm->invalidateContent(); btm->invalidateContent();
paragraphChange(); paragraphChange();
return;
} }
else
{
CGroupCell *btgc = dynamic_cast<CGroupCell*>(view); CGroupCell *btgc = dynamic_cast<CGroupCell*>(view);
if(btgc) if(btgc)
{ {
@ -306,8 +309,16 @@ namespace NLGUI
btgc->invalidateCoords(); btgc->invalidateCoords();
btgc->invalidateContent(); btgc->invalidateContent();
paragraphChange(); 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,11 +2655,21 @@ 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':
{
if (tableWhitespace)
{
keep = false;
}
else
{ {
// Get the last char // Get the last char
ucchar lastChar = lastCharParam; ucchar lastChar = lastCharParam;
@ -2607,8 +2680,15 @@ namespace NLGUI
if(!getPRE()) if(!getPRE())
input = ' '; input = ' ';
} }
}
break; break;
case ' ': case ' ':
{
if (tableWhitespace)
{
keep = false;
}
else
{ {
// Get the last char // Get the last char
ucchar lastChar = lastCharParam; ucchar lastChar = lastCharParam;
@ -2618,6 +2698,7 @@ namespace NLGUI
(lastChar != (ucchar)'\n') && (lastChar != (ucchar)'\n') &&
(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0)); (lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
} }
}
break; break;
case 0xd: case 0xd:
keep = false; keep = false;
@ -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()); {
// _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.hasNonEmptyAttribute("width")) else if (elm.hasNonEmptyAttribute("width"))
{
getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str()); getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str());
}
if (_Style.hasStyle("border") || _Style.hasStyle("border-width")) // border from css or from attribute
{ {
table->Border = _Style.Current.BorderWidth; uint32 borderWidth = 0;
} CRGBA borderColor = CRGBA::Transparent;
else if (elm.hasAttribute("border"))
if (elm.hasAttribute("border"))
{ {
std::string s = elm.getAttribute("border"); std::string s = elm.getAttribute("border");
if (s.empty()) if (s.empty())
table->Border = 1; borderWidth = 1;
else else
fromString(elm.getAttribute("border"), table->Border); fromString(elm.getAttribute("border"), borderWidth);
}
if (_Style.hasStyle("border-color")) if (elm.hasNonEmptyAttribute("bordercolor"))
{ scanHTMLColor(elm.getAttribute("bordercolor").c_str(), borderColor);
std::string s = toLower(_Style.getStyle("border-color"));
if (s == "currentcolor")
table->BorderColor = _Style.Current.TextColor;
else else
scanHTMLColor(s.c_str(), table->BorderColor); 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 if (elm.hasNonEmptyAttribute("bordercolor")) else
{
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;
}
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"))
{
// _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()); 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
col = BgColor;
sint32 oldSciX, oldSciY, oldSciW, oldSciH;
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
{
CRGBA finalColor;
finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor());
// Get the parent table if (BgColor.A > 0)
if (getParent ())
{ {
CGroupTable *table = static_cast<CGroupTable*> (getParent ()); CRGBA finalColor = BgColor;
finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8); if (_ModulateGlobalColor)
} finalColor.modulateFromColor (finalColor, CWidgetManager::getInstance()->getGlobalColor());
finalColor.A = (uint8) (((uint16) CurrentAlpha * (uint16) finalColor.A) >> 8);
//nlinfo("Blank Texture"); if (finalColor.A > 0)
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor);
flush = true;
} }
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);
// Draw the top line rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor);
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal-border+_HReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the left line flush = true;
sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)border); }
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor);
// Draw the inside borders // Draw the background
if (CellSpacing) if (CurrentAlpha > 0 && !_TextureId.empty())
{
uint i;
sint32 x, y;
for (i=0; i<_Cells.size(); i++)
{ {
CGroupCell *cell = _Cells[i]; sint32 oldSciX, oldSciY, oldSciW, oldSciH;
makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH);
x = cell->getXReal(); CRGBA col = CRGBA::White;
y = cell->getYReal() - CellSpacing; col.A = CurrentAlpha;
// 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);
}
}
if (_TextureScaled && !_TextureTiled)
{
rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col);
} }
if (Border) else
{ {
CViewRenderer &rVR = *CViewRenderer::getInstance(); if (!_TextureTiled)
rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _TextureWReal, _TextureHReal, 0, false, _TextureId, col);
else
rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col);
}
CRGBA borderColorTL; restoreClip (oldSciX, oldSciY, oldSciW, oldSciH);
CRGBA lighter = blend(BorderColor, CRGBA::White, 0.5f); flush = true;
borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); }
borderColorTL.A = CurrentAlpha;
CRGBA borderColorBR; // flush background color and image
borderColorBR.modulateFromColor (BorderColor, CWidgetManager::getInstance()->getGlobalColor()); if (flush)
borderColorBR.A = CurrentAlpha; rVR.flush();
// beveled table border if (Border)
for (sint32 i=0; i<Border; i++)
{ {
// bottom, left, top, right // TODO: monitor these in checkCoords and update when changed
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+i, _WReal-i*2, 1, 0, false, rVR.getBlankTextureId(), borderColorBR); uint8 contentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A;
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+i, 1, _HReal-i*2, 0, false, rVR.getBlankTextureId(), borderColorTL); if (contentAlpha > 0)
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+i, _YReal+_HReal-i-1, _WReal-i*2, 1, 0, false, rVR.getBlankTextureId(), borderColorTL); {
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-i-1, _YReal+i, 1, _HReal-i*2, 0, false, rVR.getBlankTextureId(), borderColorBR); Border->CurrentAlpha = CurrentAlpha;
Border->setRenderLayer(_RenderLayer);
Border->setModulateGlobalColor(_ModulateGlobalColor);
Border->draw();
} }
} }
} }
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();
}
} }
} }

@ -794,6 +794,35 @@ namespace NLGUI
return 0; return 0;
} }
// ***************************************************************************
int CLuaIHM::getOnDraw(CLuaState &ls)
{
//H_AUTO(Lua_CLuaIHM_getOnDraw
CLuaStackChecker lsc(&ls, 1);
// params: CInterfaceElement*.
// return: "script" (nil if empty)
CLuaIHM::checkArgCount(ls, "getOnDraw", 1);
CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "getOnDraw() requires a UI object in param 1");
// retrieve arguments
CInterfaceElement *pIE = CLuaIHM::getUIOnStack(ls, 1);
if (pIE)
{
// must be a group
CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(pIE);
if (group)
{
if (!group->getLuaScriptOnDraw().empty()) {
ls.push(group->getLuaScriptOnDraw());
return 1;
}
}
}
ls.pushNil();
return 1;
}
// *************************************************************************** // ***************************************************************************
int CLuaIHM::addOnDbChange(CLuaState &ls) int CLuaIHM::addOnDbChange(CLuaState &ls)
{ {
@ -1589,6 +1618,7 @@ namespace NLGUI
// *** Register Functions // *** Register Functions
ls.registerFunc("setOnDraw", setOnDraw); ls.registerFunc("setOnDraw", setOnDraw);
ls.registerFunc("getOnDraw", getOnDraw);
ls.registerFunc("setCaptureKeyboard", setCaptureKeyboard); ls.registerFunc("setCaptureKeyboard", setCaptureKeyboard);
ls.registerFunc("resetCaptureKeyboard", resetCaptureKeyboard); ls.registerFunc("resetCaptureKeyboard", resetCaptureKeyboard);
ls.registerFunc("setTopWindow", setTopWindow); ls.registerFunc("setTopWindow", setTopWindow);

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

@ -15,7 +15,7 @@ SaveConfig = 1;
Driver3D="Auto"; // Valid values are "Auto" or "0", "OpengGL" or "1" & "Direct3D" or "2" Driver3D="Auto"; // Valid values are "Auto" or "0", "OpengGL" or "1" & "Direct3D" or "2"
// "Auto" will choose the best suited driver depending on hardware // "Auto" will choose the best suited driver depending on hardware
FullScreen = 1; FullScreen = 0;
Width = 0; Width = 0;
Height = 0; Height = 0;
PositionX = 0; PositionX = 0;

@ -614,6 +614,8 @@ CClientConfig::CClientConfig()
MaxMapScale = 2.0f; MaxMapScale = 2.0f;
R2EDMaxMapScale = 8.0f; R2EDMaxMapScale = 8.0f;
TargetChangeCompass = true;
// VERBOSES // VERBOSES
VerboseVP = false; VerboseVP = false;
VerboseAnimUser = false; VerboseAnimUser = false;
@ -1495,6 +1497,9 @@ void CClientConfig::setValues()
READ_FLOAT_FV(MaxMapScale); READ_FLOAT_FV(MaxMapScale);
READ_FLOAT_FV(R2EDMaxMapScale); READ_FLOAT_FV(R2EDMaxMapScale);
// /tar to update compass or not
READ_BOOL_FV(TargetChangeCompass);
///////////// /////////////
// SHADOWS // // SHADOWS //
// Shadows : Get Shadows state // Shadows : Get Shadows state

@ -607,6 +607,9 @@ struct CClientConfig
float MaxMapScale; float MaxMapScale;
float R2EDMaxMapScale; float R2EDMaxMapScale;
// If successfull /tar command should set compass or not
bool TargetChangeCompass;
////////////// //////////////
// VERBOSES // // VERBOSES //
bool VerboseVP; bool VerboseVP;

@ -4493,6 +4493,13 @@ NLMISC_COMMAND(debugItemInfoWaiters, "log ItemInfoWaiters", "")
return true; return true;
} }
NLMISC_COMMAND(debugItemInfoCache, "log ItemInfoCache", "")
{
getInventory().debugItemInfoCache();
return true;
}
NLMISC_COMMAND(debugInfoWindows, "log info windows sheetId", "") NLMISC_COMMAND(debugInfoWindows, "log info windows sheetId", "")
{ {
CInterfaceHelp::debugOpenedInfoWindows(); CInterfaceHelp::debugOpenedInfoWindows();

@ -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,20 @@ 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());
if (ClientCfg.TargetChangeCompass)
{
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 +2499,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
@ -4609,3 +4651,17 @@ public:
}; };
REGISTER_ACTION_HANDLER( CHandlerSortTribeFame, "sort_tribefame"); REGISTER_ACTION_HANDLER( CHandlerSortTribeFame, "sort_tribefame");
// ***************************************************************************
class CHandlerTriggerIconBuffs : public IActionHandler
{
public:
void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
{
CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_ICON_BUFFS", false);
// no node - show,
// node == false - hide
CDBCtrlSheet::setShowIconBuffs(!node || node->getValueBool());
}
};
REGISTER_ACTION_HANDLER(CHandlerTriggerIconBuffs, "trigger_show_icon_buffs");

@ -73,45 +73,46 @@ REGISTER_UI_CLASS(CDBCtrlSheet)
const uint64 NOTIFY_ANIM_MS_DURATION = 1000; const uint64 NOTIFY_ANIM_MS_DURATION = 1000;
// *************************************************************************** // state kept and changed by UI:SAVE:SHOW_ICON_BUFFS
bool CDBCtrlSheet::_ShowIconBuffs = true;
// ***************************************************************************
// ********************************************************************************************************** void CControlSheetInfoWaiter::sendRequest()
class CControlSheetTooltipInfoWaiter : public IItemInfoWaiter
{ {
public: Requesting = true;
// The item used to open this window getInventory().addItemInfoWaiter(this);
CDBCtrlSheet* CtrlSheet; }
string LuaMethodName;
public:
ucstring infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName);
virtual void infoReceived();
};
static CControlSheetTooltipInfoWaiter ControlSheetTooltipUpdater;
void CControlSheetTooltipInfoWaiter::infoReceived() void CControlSheetInfoWaiter::infoReceived()
{ {
getInventory().removeItemInfoWaiter(&ControlSheetTooltipUpdater); if (!Requesting) {
infoValidated(CtrlSheet, LuaMethodName); return;
}
getInventory().removeItemInfoWaiter(this);
infoValidated();
CtrlSheet->infoReceived();
Requesting = false;
} }
ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName) ucstring CControlSheetInfoWaiter::infoValidated() const
{ {
ucstring help; ucstring help;
if (CtrlSheet && !LuaMethodName.empty())
{
// delegate setup of context he help ( & window ) to lua // delegate setup of context he help ( & window ) to lua
CInterfaceManager *im = CInterfaceManager::getInstance(); CInterfaceManager *im = CInterfaceManager::getInstance();
CLuaState *ls= CLuaManager::getInstance().getLuaState(); CLuaState *ls= CLuaManager::getInstance().getLuaState();
{ {
CLuaStackRestorer lsr(ls, 0); CLuaStackRestorer lsr(ls, 0);
CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)ctrlSheet); CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)CtrlSheet);
ls->pushGlobalTable(); ls->pushGlobalTable();
CLuaObject game(*ls); CLuaObject game(*ls);
game = game["game"]; game = game["game"];
game.callMethodByNameNoThrow(luaMethodName.c_str(), 1, 1); game.callMethodByNameNoThrow(LuaMethodName.c_str(), 1, 1);
// retrieve result from stack // retrieve result from stack
if (!ls->empty()) if (!ls->empty())
@ -120,7 +121,8 @@ ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet,
} }
else else
{ {
nlwarning(toString("Ucstring result expected when calling '%s', possible script error", luaMethodName.c_str()).c_str()); nlwarning(toString("Ucstring result expected when calling '%s', possible script error", LuaMethodName.c_str()).c_str());
}
} }
} }
@ -137,7 +139,7 @@ int CDBCtrlSheet::luaGetDraggedSheet(CLuaState &ls)
// *************************************************************************** // ***************************************************************************
int CDBCtrlSheet::luaGetItemInfo(CLuaState &ls) int CDBCtrlSheet::luaGetItemInfo(CLuaState &ls)
{ {
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet *>(this);
uint32 itemSlotId = getInventory().getItemSlotId(ctrlSheet); uint32 itemSlotId = getInventory().getItemSlotId(ctrlSheet);
CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId);
@ -237,7 +239,6 @@ int CDBCtrlSheet::luaWaitInfo(CLuaState &ls)
int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls) int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls)
{ {
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this);
uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet); uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet);
CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId);
@ -505,6 +506,7 @@ CCtrlDraggable(param)
_Useable= true; _Useable= true;
_GrayedLink= NULL; _GrayedLink= NULL;
_NeedSetup= true; _NeedSetup= true;
_ItemInfoChanged = true;
_IconW = 0; _IconW = 0;
_IconH = 0; _IconH = 0;
_SetupInit= false; _SetupInit= false;
@ -528,6 +530,11 @@ CCtrlDraggable(param)
_ItemRMClassType= NULL; _ItemRMClassType= NULL;
_ItemRMFaberStatType= NULL; _ItemRMFaberStatType= NULL;
_NotifyAnimEndTime = 0; _NotifyAnimEndTime = 0;
_HpBuffIcon = "ico_heal.tga";
_SapBuffIcon = "ico_sap.tga";
_StaBuffIcon = "ico_stamina.tga";
_FocusBuffIcon = "ico_focus.tga";
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -535,6 +542,11 @@ CDBCtrlSheet::~CDBCtrlSheet()
{ {
NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver(); NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver();
if (_ItemInfoWaiter.Requesting)
{
getInventory().removeItemInfoWaiter(&_ItemInfoWaiter);
}
if (_GuildBack) if (_GuildBack)
{ {
if (Driver) if (Driver)
@ -613,6 +625,22 @@ bool CDBCtrlSheet::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
prop = (char*) xmlGetProp( cur, (xmlChar*)"slot" ); prop = (char*) xmlGetProp( cur, (xmlChar*)"slot" );
if(prop) _DrawSlot= CInterfaceElement::convertBool(prop); if(prop) _DrawSlot= CInterfaceElement::convertBool(prop);
//
_HpBuffIcon = "ico_heal.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"hp_buff_icon" );
if (prop) _HpBuffIcon = string((const char *)prop);
_SapBuffIcon = "ico_sap.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"sap_buff_icon" );
if (prop) _SapBuffIcon = string((const char *)prop);
_StaBuffIcon = "ico_stamina.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"sta_buff_icon" );
if (prop) _StaBuffIcon = string((const char *)prop);
_FocusBuffIcon = "ico_focus.tga";
prop = (char*) xmlGetProp( cur, (xmlChar*)"focus_buff_icon" );
if (prop) _FocusBuffIcon = string((const char *)prop);
updateActualType(); updateActualType();
// Init size for Type // Init size for Type
@ -1040,6 +1068,72 @@ void CDBCtrlSheet::updateIconSize()
} }
} }
// ***************************************************************************
void CDBCtrlSheet::clearIconBuffs()
{
_EnchantIcons.clear();
_BuffIcons.clear();
}
// ***************************************************************************
void CDBCtrlSheet::infoReceived()
{
if (!_ItemSheet)
{
clearIconBuffs();
return;
}
const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime());
if (itemInfo == NULL)
{
// schedule for recheck on next draw()
_ItemInfoChanged = true;
return;
}
clearIconBuffs();
// crystallized spell
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
CSBrickManager *pBM= CSBrickManager::getInstance();
for(uint i=0; i<itemInfo->Enchantment.Bricks.size(); ++i)
{
const CSBrickSheet *brick = pBM->getBrick(itemInfo->Enchantment.Bricks[i]);
if (brick)
{
if (!brick->isRoot() && !brick->isCredit() && !brick->isParameter())
{
_EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIcon()), brick->IconColor));
rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH);
}
else if (brick->isRoot())
{
// there should be single root icon and it should be first one
_EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIconBack()), brick->IconBackColor));
rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH);
}
}
}
}
// buff icons
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (itemInfo->HpBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_HpBuffIcon)));
if (itemInfo->SapBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_SapBuffIcon)));
if (itemInfo->StaBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_StaBuffIcon)));
if (itemInfo->FocusBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_FocusBuffIcon)));
// update sizes
for(uint i = 0; i < _BuffIcons.size(); ++i)
{
rVR.getTextureSizeFromId(_BuffIcons[i].TextureId, _BuffIcons[i].IconW, _BuffIcons[i].IconH);
}
}
}
// *************************************************************************** // ***************************************************************************
void CDBCtrlSheet::setupPact() void CDBCtrlSheet::setupPact()
@ -1103,6 +1197,7 @@ void CDBCtrlSheet::setupItem ()
CInterfaceManager *pIM= CInterfaceManager::getInstance(); CInterfaceManager *pIM= CInterfaceManager::getInstance();
sint32 sheet = _SheetId.getSInt32(); sint32 sheet = _SheetId.getSInt32();
// If this is the same sheet, need to resetup // If this is the same sheet, need to resetup
if (_LastSheetId != sheet || _NeedSetup) if (_LastSheetId != sheet || _NeedSetup)
{ {
@ -1203,6 +1298,9 @@ void CDBCtrlSheet::setupItem ()
// Special Item requirement // Special Item requirement
updateItemCharacRequirement(_LastSheetId); updateItemCharacRequirement(_LastSheetId);
// update item info markers
_ItemInfoChanged = true;
} }
else else
{ {
@ -1277,6 +1375,13 @@ void CDBCtrlSheet::setupItem ()
_Useable = CSkillManager::getInstance()->checkBaseSkillMetRequirement(_ItemSheet->RequiredSkill, _ItemSheet->RequiredSkillLevel); _Useable = CSkillManager::getInstance()->checkBaseSkillMetRequirement(_ItemSheet->RequiredSkill, _ItemSheet->RequiredSkillLevel);
} }
*/ */
// at each frame, update item info icon if changed
if (_ItemInfoChanged)
{
_ItemInfoChanged = false;
setupItemInfoWaiter();
}
} }
@ -2220,6 +2325,69 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti
rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color)); rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color));
} }
if (_ShowIconBuffs && !_BuffIcons.empty())
{
// there is max 4 icons
sint32 hArea = (hSheet / 4);
sint32 xIcon = x;
sint32 yIcon = y;
for (uint i = 0; i < _BuffIcons.size(); ++i)
{
sint32 wIcon = _BuffIcons[i].IconW;
sint32 hIcon = _BuffIcons[i].IconH;
if (hIcon > hArea)
{
wIcon = wIcon * ((float)hArea / hIcon);
hIcon = hArea;
}
rVR.drawRotFlipBitmap (_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _BuffIcons[i].TextureId, fastMulRGB(curSheetColor, _BuffIcons[i].Color));
xIcon += wIcon;
// move up the row for 3rd/4th icon
if (i % 3 == 1) {
xIcon = x;
yIcon += hIcon;
}
}
}
// Is the item enchanted ?
sint32 enchant = _Enchant.getSInt32();
if (enchant > 0)
{
// Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item)
enchant--;
rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor);
drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false);
}
if (_ShowIconBuffs && !_EnchantIcons.empty())
{
// should only only 2 icons at most
// draw them in single line, top-right
sint32 hArea = (hSheet / 3);
sint32 xIcon = x + wSheet - 1;
sint32 yIcon = y + hSheet - 1/* - hArea*/;
// 0 is expected to be background
for (uint i = 1; i < _EnchantIcons.size(); ++i)
{
sint32 wIcon = _EnchantIcons[i].IconW;
sint32 hIcon = _EnchantIcons[i].IconH;
if (hIcon > hArea)
{
wIcon = wIcon * ((float)hArea / hIcon);
hIcon = hArea;
}
// need to move x before draw because of right aligned
if (i == 1)
{
xIcon -= wIcon;
}
yIcon -= hIcon;
rVR.drawRotFlipBitmap(_RenderLayer + 1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[0].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[0].Color));
rVR.drawRotFlipBitmap(_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[i].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[i].Color));
}
}
// Draw Quality. -1 for lookandfeel. Draw it with global color // Draw Quality. -1 for lookandfeel. Draw it with global color
if (_DispQuality != -1) if (_DispQuality != -1)
{ {
@ -2242,15 +2410,6 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti
} }
drawNumber(x+1+crossW, y+1, wSheet, hSheet, curSheetColor, quantity, false); drawNumber(x+1+crossW, y+1, wSheet, hSheet, curSheetColor, quantity, false);
} }
// Is the item enchanted ?
sint32 enchant = _Enchant.getSInt32();
if (enchant > 0)
{
// Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item)
enchant--;
rVR.draw11RotFlipBitmap (_RenderLayer+2, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor);
drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false);
}
// if a raw material for example, must add special icon text. // if a raw material for example, must add special icon text.
displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor); displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor);
@ -3114,6 +3273,62 @@ const COutpostBuildingSheet *CDBCtrlSheet::asOutpostBuildingSheet() const
return NULL; return NULL;
} }
// ***************************************************************************
void CDBCtrlSheet::setupItemInfoWaiter()
{
const CItemSheet *item = asItemSheet();
if(!item)
{
clearIconBuffs();
return;
}
if (!useItemInfoForFamily(item->Family))
{
clearIconBuffs();
return;
}
if (getItemSerial() == 0 || getItemCreateTime() == 0)
{
clearIconBuffs();
return;
}
string luaMethodName = ((item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip");
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this);
uint itemSlotId = getInventory().getItemSlotId(ctrlSheet);
// Prepare the waiter for tooltips
_ItemInfoWaiter.ItemSheet= ctrlSheet->getSheetId();
_ItemInfoWaiter.LuaMethodName = luaMethodName;
_ItemInfoWaiter.ItemSlotId= itemSlotId;
_ItemInfoWaiter.CtrlSheet = ctrlSheet;
// send out request only if cache is not set
const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime());
if (itemInfo)
{
infoReceived();
}
else
{
// Using isInventoryPresent/Available() will fail for packers when out of range
// Getting server item however will work correctly for packer/room/guild
const CItemImage *itemImage = getInventory().getServerItem(itemSlotId);
if (itemImage)
{
_ItemInfoWaiter.sendRequest();
}
else
{
// schedule for next draw() - if inventory should not be available (ie guild),
// but user opens it anyway, then this will loop back here on every draw()
_ItemInfoChanged = true;
}
}
}
// *************************************************************************** // ***************************************************************************
void CDBCtrlSheet::getContextHelp(ucstring &help) const void CDBCtrlSheet::getContextHelp(ucstring &help) const
{ {
@ -3177,34 +3392,21 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const
{ {
if (useItemInfoForFamily(item->Family)) if (useItemInfoForFamily(item->Family))
{ {
string luaMethodName = ( (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); // call lua function to update tooltip window
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); _ItemInfoWaiter.sendRequest();
CCtrlBase *ctrlBase = const_cast<CDBCtrlSheet*>(this); help = _ItemInfoWaiter.infoValidated();
if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet))) // its expected to get at least item name back
{ if (help.empty())
// Prepare the waiter help = getItemActualName();
ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId();
ControlSheetTooltipUpdater.LuaMethodName = luaMethodName;
ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet);
ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet;
// Add the waiter
getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater);
} }
else if (!_ContextHelp.empty())
if (!_ContextHelp.empty())
{ {
help= _ContextHelp; help = _ContextHelp;
ctrlBase->setDefaultContextHelp(ucstring());
} }
else else
help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName); {
help = getItemActualName();
} }
else
if (!_ContextHelp.empty())
help= _ContextHelp;
else
help= getItemActualName();
} }
else else
help= _ContextHelp; help= _ContextHelp;
@ -3322,21 +3524,8 @@ void CDBCtrlSheet::getContextHelpToolTip(ucstring &help) const
{ {
if (useItemInfoForFamily(item->Family)) if (useItemInfoForFamily(item->Family))
{ {
string luaMethodName = (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"; _ItemInfoWaiter.sendRequest();
CDBCtrlSheet *ctrlSheet = const_cast<CDBCtrlSheet*>(this); help = _ItemInfoWaiter.infoValidated();
if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet)))
{
// Prepare the waiter
ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId();
ControlSheetTooltipUpdater.LuaMethodName = luaMethodName;
ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet);
ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet;
// Add the waiter
getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater);
}
help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName);
return; return;
} }
} }
@ -3551,6 +3740,10 @@ void CDBCtrlSheet::resetAllTexIDs()
_Stackable= 1; _Stackable= 1;
_IconW = 0; _IconW = 0;
_IconH = 0; _IconH = 0;
_ItemInfoChanged = true;
_EnchantIcons.clear();
_BuffIcons.clear();
} }
@ -4503,7 +4696,3 @@ void CDBCtrlSheet::startNotifyAnim()
_NotifyAnimEndTime = T1 + NOTIFY_ANIM_MS_DURATION; _NotifyAnimEndTime = T1 + NOTIFY_ANIM_MS_DURATION;
} }

@ -37,7 +37,7 @@
#include "game_share/item_family.h" #include "game_share/item_family.h"
// //
#include "../time_client.h" #include "../time_client.h"
#include "item_info_waiter.h"
class CItemSheet; class CItemSheet;
class CPactSheet; class CPactSheet;
@ -53,6 +53,25 @@ namespace NLGUI
class CViewRenderer; class CViewRenderer;
} }
class CDBCtrlSheet;
// ***************************************************************************
// Item info request from server
class CControlSheetInfoWaiter : public IItemInfoWaiter
{
public:
CDBCtrlSheet* CtrlSheet;
string LuaMethodName;
bool Requesting;
CControlSheetInfoWaiter()
: IItemInfoWaiter(), Requesting(false)
{ }
public:
ucstring infoValidated() const;
void sendRequest();
virtual void infoReceived();
};
// *************************************************************************** // ***************************************************************************
/** Common info for CDBCtrlSheet and CDBGroupListSheet /** Common info for CDBCtrlSheet and CDBGroupListSheet
@ -580,8 +599,13 @@ public:
// start notify anim (at the end of regen usually) // start notify anim (at the end of regen usually)
void startNotifyAnim(); void startNotifyAnim();
protected: // callback from info waiter
void infoReceived();
// set enchant/buff marker visiblility
static void setShowIconBuffs(bool b) { _ShowIconBuffs = b; }
protected:
inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const; inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const;
void setupItem(); void setupItem();
@ -622,6 +646,7 @@ protected:
NLMISC::CCDBNodeLeaf *_ItemRMFaberStatType; NLMISC::CCDBNodeLeaf *_ItemRMFaberStatType;
mutable sint32 _LastSheetId; mutable sint32 _LastSheetId;
bool _ItemInfoChanged;
/// Display /// Display
sint32 _DispSlotBmpId; // Display slot bitmap id sint32 _DispSlotBmpId; // Display slot bitmap id
@ -632,6 +657,26 @@ protected:
sint32 _DispOverBmpId; // Over Icon sint32 _DispOverBmpId; // Over Icon
sint32 _DispOver2BmpId; // Over Icon N0 2 for bricks / items. Useful for items when _DispOverBmpId is used to paint user color on the item. sint32 _DispOver2BmpId; // Over Icon N0 2 for bricks / items. Useful for items when _DispOverBmpId is used to paint user color on the item.
std::string _HpBuffIcon;
std::string _SapBuffIcon;
std::string _StaBuffIcon;
std::string _FocusBuffIcon;
// texture ids to show
struct SBuffIcon
{
SBuffIcon(sint32 txid, NLMISC::CRGBA col=NLMISC::CRGBA::White)
:TextureId(txid), Color(col), IconW(0), IconH(0)
{ }
sint32 TextureId;
NLMISC::CRGBA Color;
sint32 IconW;
sint32 IconH;
};
std::vector<SBuffIcon> _BuffIcons;
std::vector<SBuffIcon> _EnchantIcons;
// Level Brick or Quality // Level Brick or Quality
union union
{ {
@ -751,16 +796,21 @@ protected:
sint64 _NotifyAnimEndTime; sint64 _NotifyAnimEndTime;
mutable CControlSheetInfoWaiter _ItemInfoWaiter;
private: private:
mutable TSheetType _ActualType; mutable TSheetType _ActualType;
static CDBCtrlSheet *_CurrSelection; static CDBCtrlSheet *_CurrSelection;
static CDBCtrlSheet *_CurrMenuSheet; static CDBCtrlSheet *_CurrMenuSheet;
static bool _ShowIconBuffs;
private: private:
void updateActualType() const; void updateActualType() const;
void updateIconSize(); void updateIconSize();
void resetAllTexIDs(); void resetAllTexIDs();
void setupInit(); void setupInit();
// remove enchant and buff markers from item icon
void clearIconBuffs();
void setupCharBitmaps(sint32 maxW, sint32 maxLine, sint32 maxWChar= 1000, bool topDown= false); void setupCharBitmaps(sint32 maxW, sint32 maxLine, sint32 maxWChar= 1000, bool topDown= false);
void resetCharBitmaps(); void resetCharBitmaps();
@ -769,6 +819,9 @@ private:
// special for items // special for items
void updateItemCharacRequirement(sint32 sheetId); void updateItemCharacRequirement(sint32 sheetId);
// Send ITEM_INFO:GET request to server to fetch Buffs, Enchant info
void setupItemInfoWaiter();
// update armour color, and cache // update armour color, and cache
void updateArmourColor(sint8 col); void updateArmourColor(sint8 col);

@ -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;
}
}
else
{
for(uint i = 0; i< filter.size(); ++i)
{
if (lcTitle.find(filter[i]) == ucstring::npos)
{
return false; 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();

@ -58,6 +58,8 @@
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
extern TSessionId CharacterHomeSessionId;
extern NLMISC::CLog g_log; extern NLMISC::CLog g_log;
// Context help // Context help
extern void contextHelp (const std::string &help); extern void contextHelp (const std::string &help);
@ -127,6 +129,8 @@ CItemImage::CItemImage()
Sheet = NULL; Sheet = NULL;
Quality = NULL; Quality = NULL;
Quantity = NULL; Quantity = NULL;
CreateTime = NULL;
Serial = NULL;
UserColor = NULL; UserColor = NULL;
Price = NULL; Price = NULL;
Weight= NULL; Weight= NULL;
@ -141,6 +145,8 @@ void CItemImage::build(CCDBNodeBranch *branch)
Sheet = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SHEET"), false)); Sheet = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SHEET"), false));
Quality = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUALITY"), false)); Quality = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUALITY"), false));
Quantity = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUANTITY"), false)); Quantity = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("QUANTITY"), false));
CreateTime = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("CREATE_TIME"), false));
Serial = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("SERIAL"), false));
UserColor = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false)); UserColor = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false));
Price = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("PRICE"), false)); Price = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("PRICE"), false));
Weight = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("WEIGHT"), false)); Weight = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("WEIGHT"), false));
@ -149,7 +155,145 @@ void CItemImage::build(CCDBNodeBranch *branch)
ResaleFlag = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false)); ResaleFlag = dynamic_cast<CCDBNodeLeaf *>(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false));
// Should always have at least those one:(ie all but Price) // Should always have at least those one:(ie all but Price)
nlassert(Sheet && Quality && Quantity && UserColor && Weight && NameId && InfoVersion); nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion);
}
uint64 CItemImage::getItemId() const
{
return ((uint64)getSerial() << 32) | getCreateTime();
}
// *************************************************************************************************
void CItemInfoCache::load(const std::string &filename)
{
try
{
CIFile f;
if (f.open(filename))
{
serial(f);
}
} catch(...)
{ }
}
void CItemInfoCache::save(const std::string &filename)
{
try
{
COFile f;
if (f.open(filename))
{
serial(f);
}
}catch(...)
{ }
}
void CItemInfoCache::serial(NLMISC::IStream &s)
{
s.serialCheck(NELID("METI"));
uint ver = 1;
s.serialVersion(ver);
uint8 byte = 1;
if (s.isReading())
{
_ItemInfoCacheMap.clear();
while(true)
{
uint64 key;
s.serial(byte);
if (byte == 0)
{
break;
}
s.serial(key);
s.serial(_ItemInfoCacheMap[key].CacheCycle);
_ItemInfoCacheMap[key].serial(s);
// these are not used in item info cache
_ItemInfoCacheMap[key].InfoVersionFromMsg = 0;
_ItemInfoCacheMap[key].InfoVersionFromSlot = 0;
_ItemInfoCacheMap[key].InfoVersionSlotServerWaiting = 0;
}
}
else
{
byte = 1;
TItemInfoCacheMap::iterator it = _ItemInfoCacheMap.begin();
while (it != _ItemInfoCacheMap.end())
{
// purge item from cache if not encountered in X save
if (it->second.CacheCycle < 10000)
{
// 'record exists' byte
s.serial(byte);
// item id (serial << 32 | createTime)
uint64 key = it->first;
s.serial(key);
uint32 cycle = it->second.CacheCycle+1;
s.serial(cycle);
// item info
it->second.serial(s);
}
++it;
}
// eof of records byte
byte = 0;
s.serial(byte);
}
}
const CClientItemInfo *CItemInfoCache::getItemInfo(uint32 serial, uint32 createTime) const
{
if (serial > 0 && createTime > 0)
{
uint64 itemId = ((uint64)serial << 32) | createTime;
return getItemInfo(itemId);
}
return NULL;
}
const CClientItemInfo *CItemInfoCache::getItemInfo(uint64 itemId) const
{
if (itemId > 0)
{
TItemInfoCacheMap::const_iterator it = _ItemInfoCacheMap.find(itemId);
if (it != _ItemInfoCacheMap.end())
return &(it->second);
}
return NULL;
}
void CItemInfoCache::readFromImpulse(uint64 itemId, CItemInfos itemInfo)
{
if (itemId > 0)
{
_ItemInfoCacheMap[itemId].readFromImpulse(itemInfo);
_ItemInfoCacheMap[itemId].CacheCycle = 0;
}
}
void CItemInfoCache::debugItemInfoCache() const
{
nlinfo("ItemInfoCache: %d entries", _ItemInfoCacheMap.size());
uint count = 0;
for (auto it = _ItemInfoCacheMap.begin(); it != _ItemInfoCacheMap.end(); ++it)
{
uint32 serial = (it->first >> 32) & 0xFFFFFFFF;
uint32 created = it->first & 0xFFFFFFFF;
nlinfo("[%-4d] cacheCycle:%d, serial:%d, createTime:%d", count++, it->second.CacheCycle, serial, created);
}
CInterfaceManager *pIM= CInterfaceManager::getInstance();
pIM->displaySystemInfo(toString("ItemInfoCache: %d entries written to client.log", _ItemInfoCacheMap.size()));
} }
// ************************************************************************************************* // *************************************************************************************************
@ -180,12 +324,16 @@ CInventoryManager::CInventoryManager()
BagItemEquipped[i]= false; BagItemEquipped[i]= false;
} }
_ItemInfoCacheFilename = toString("save/item_infos_%d.cache", CharacterHomeSessionId.asInt());
_ItemInfoCache.load(_ItemInfoCacheFilename);
nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0])); nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0]));
} }
// *************************************************************************** // ***************************************************************************
CInventoryManager::~CInventoryManager() CInventoryManager::~CInventoryManager()
{ {
_ItemInfoCache.save(_ItemInfoCacheFilename);
} }
// ************************************************************************************************* // *************************************************************************************************
@ -257,6 +405,11 @@ CItemImage &CInventoryManager::getServerBagItem(uint index)
nlassert(index < MAX_BAGINV_ENTRIES); nlassert(index < MAX_BAGINV_ENTRIES);
return ServerBag[index]; return ServerBag[index];
} }
const CItemImage &CInventoryManager::getServerBagItem(uint index) const
{
nlassert(index < MAX_BAGINV_ENTRIES);
return ServerBag[index];
}
// ************************************************************************************************* // *************************************************************************************************
CItemImage &CInventoryManager::getServerTempItem(uint index) CItemImage &CInventoryManager::getServerTempItem(uint index)
@ -264,6 +417,11 @@ CItemImage &CInventoryManager::getServerTempItem(uint index)
nlassert(index < MAX_TEMPINV_ENTRIES); nlassert(index < MAX_TEMPINV_ENTRIES);
return ServerTempInv[index]; return ServerTempInv[index];
} }
const CItemImage &CInventoryManager::getServerTempItem(uint index) const
{
nlassert(index < MAX_TEMPINV_ENTRIES);
return ServerTempInv[index];
}
// ************************************************************************************************* // *************************************************************************************************
CItemImage *CInventoryManager::getServerHandItem(uint index) CItemImage *CInventoryManager::getServerHandItem(uint index)
@ -3262,22 +3420,53 @@ uint CInventoryManager::getItemSheetForSlotId(uint slotId) const
return 0; return 0;
} }
// ***************************************************************************
const CClientItemInfo *CInventoryManager::getItemInfoCache(uint32 serial, uint32 createTime) const
{
return _ItemInfoCache.getItemInfo(serial, createTime);
}
// *************************************************************************** // ***************************************************************************
const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const
{ {
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId); TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
static CClientItemInfo empty; static CClientItemInfo empty;
if(it==_ItemInfoMap.end()) if (it == _ItemInfoMap.end() || !isItemInfoUpToDate(slotId))
{
// if slot has not been populated yet or out of date, then return info from cache if possible
const CItemImage *item = getServerItem(slotId);
if (item && item->getItemId() > 0) {
const CClientItemInfo *ret = _ItemInfoCache.getItemInfo(item->getItemId());
if (ret != NULL)
{
return *ret;
}
}
}
if (it == _ItemInfoMap.end())
{
return empty; return empty;
else }
return it->second; return it->second;
} }
// *************************************************************************** // ***************************************************************************
bool CInventoryManager::isItemInfoUpToDate(uint slotId) bool CInventoryManager::isItemInfoAvailable(uint slotId) const
{ {
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
return it != _ItemInfoMap.end();
}
// ***************************************************************************
bool CInventoryManager::isItemInfoUpToDate(uint slotId) const
{
TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId);
if (it == _ItemInfoMap.end())
return true;
// true if the version already matches // true if the version already matches
return getItemInfo(slotId).InfoVersionFromMsg == getItemInfo(slotId).InfoVersionFromSlot; return it->second.InfoVersionFromMsg == it->second.InfoVersionFromSlot;
} }
// *************************************************************************** // ***************************************************************************
@ -3314,8 +3503,10 @@ void CInventoryManager::removeItemInfoWaiter(IItemInfoWaiter *waiter)
void CInventoryManager::updateItemInfoWaiters(uint itemSlotId) void CInventoryManager::updateItemInfoWaiters(uint itemSlotId)
{ {
// First verify if the versions matches. If differ, no need to update waiters since not good. // First verify if the versions matches. If differ, no need to update waiters since not good.
if(getItemInfo(itemSlotId).InfoVersionFromMsg != getItemInfo(itemSlotId).InfoVersionFromSlot) if (!isItemInfoUpToDate(itemSlotId))
{
return; return;
}
bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading; bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading;
@ -3409,10 +3600,15 @@ void CInventoryManager::onReceiveItemSheet(ICDBNode* node)
// *************************************************************************** // ***************************************************************************
void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo) void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo)
{ {
uint itemSlotId;
// update the Info // update the Info
itemSlotId= itemInfo.slotId; uint itemSlotId = itemInfo.slotId;
const CItemImage *item = getServerItem(itemSlotId);
if (item && item->getItemId() > 0)
{
_ItemInfoCache.readFromImpulse(item->getItemId(), itemInfo);
}
// write in map, from DB. // write in map, from DB.
_ItemInfoMap[itemSlotId].readFromImpulse(itemInfo); _ItemInfoMap[itemSlotId].readFromImpulse(itemInfo);
@ -3426,7 +3622,7 @@ void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo)
// *************************************************************************** // ***************************************************************************
void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion) void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion)
{ {
_ItemInfoMap[slotId].refreshInfoVersion( infoVersion ); _ItemInfoMap[slotId].refreshInfoVersion(infoVersion);
} }
// *************************************************************************** // ***************************************************************************
@ -3522,6 +3718,12 @@ void CInventoryManager::debugItemInfoWaiters()
} }
} }
// ***************************************************************************
void CInventoryManager::debugItemInfoCache() const
{
_ItemInfoCache.debugItemInfoCache();
}
// *************************************************************************** // ***************************************************************************
void CInventoryManager::sortBag() void CInventoryManager::sortBag()
{ {
@ -3677,6 +3879,14 @@ CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index)
return ServerPAInv[beastIndex][index]; return ServerPAInv[beastIndex][index];
} }
const CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index) const
{
nlassert(beastIndex < MAX_INVENTORY_ANIMAL);
nlassert(index < MAX_ANIMALINV_ENTRIES);
return ServerPAInv[beastIndex][index];
}
// *************************************************************************** // ***************************************************************************
CItemImage &CInventoryManager::getLocalItem(uint inv, uint index) CItemImage &CInventoryManager::getLocalItem(uint inv, uint index)
{ {
@ -3703,6 +3913,93 @@ CItemImage &CInventoryManager::getServerItem(uint inv, uint index)
return dummy; return dummy;
} }
// ***************************************************************************
const CItemImage *CInventoryManager::getServerItem(uint slotId) const
{
uint inv, index;
getSlotInvIndex(slotId, inv, index);
if (inv == INVENTORIES::bag)
{
return &getServerBagItem(index);
}
else if (inv >= INVENTORIES::pet_animal && inv <INVENTORIES::pet_animal+MAX_INVENTORY_ANIMAL)
{
return &getServerPAItem(inv-INVENTORIES::pet_animal, index);
}
else if (inv == INVENTORIES::temporary)
{
return &getServerTempItem(index);
}
else if (inv == INVENTORIES::guild)
{
// player is in guild outpost or in guild hall
if (getInventory().isInventoryAvailable(INVENTORIES::guild))
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("SERVER:GUILD:INVENTORY:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
return NULL;
}
else if (inv == INVENTORIES::player_room)
{
// player is in their room
if (getInventory().isInventoryAvailable(INVENTORIES::player_room))
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
return NULL;
}
else if (inv == INVENTORIES::trading)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:TRADING:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else if (inv == INVENTORIES::exchange)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:GIVE:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else if (inv == INVENTORIES::exchange_proposition)
{
CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:RECEIVE:" + toString(index));
if (itemBranch)
{
static CItemImage image;
image.build(itemBranch);
return &image;
}
}
else
{
nlwarning("getServerItem: invalid inventory %d for slotId %d", inv, slotId);
}
// invalid inventory
return NULL;
}
// *************************************************************************** // ***************************************************************************
CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str) CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str)
{ {
@ -3719,3 +4016,11 @@ CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &s
if (sTmp == "inv_room") return InvRoom; if (sTmp == "inv_room") return InvRoom;
return InvUnknown; return InvUnknown;
} }
// ***************************************************************************
void CInventoryManager::getSlotInvIndex(uint slotId, uint &inv, uint &index) const
{
inv = slotId >> CItemInfos::SlotIdIndexBitSize;
index = slotId & CItemInfos::SlotIdIndexBitMask;
}

@ -31,7 +31,7 @@ namespace NLMISC{
class CCDBNodeBranch; class CCDBNodeBranch;
} }
class CDBCtrlSheet; class CDBCtrlSheet;
class IItermInfoWaiter;
const uint MAX_TEMPINV_ENTRIES = INVENTORIES::NbTempInvSlots; const uint MAX_TEMPINV_ENTRIES = INVENTORIES::NbTempInvSlots;
const uint MAX_BAGINV_ENTRIES = INVENTORIES::NbBagSlots; const uint MAX_BAGINV_ENTRIES = INVENTORIES::NbBagSlots;
@ -60,6 +60,8 @@ public:
NLMISC::CCDBNodeLeaf *Sheet; NLMISC::CCDBNodeLeaf *Sheet;
NLMISC::CCDBNodeLeaf *Quality; NLMISC::CCDBNodeLeaf *Quality;
NLMISC::CCDBNodeLeaf *Quantity; NLMISC::CCDBNodeLeaf *Quantity;
NLMISC::CCDBNodeLeaf *CreateTime;
NLMISC::CCDBNodeLeaf *Serial;
NLMISC::CCDBNodeLeaf *UserColor; NLMISC::CCDBNodeLeaf *UserColor;
NLMISC::CCDBNodeLeaf *Price; NLMISC::CCDBNodeLeaf *Price;
NLMISC::CCDBNodeLeaf *Weight; NLMISC::CCDBNodeLeaf *Weight;
@ -72,10 +74,13 @@ public:
CItemImage(); CItemImage();
// build from a branch // build from a branch
void build(NLMISC::CCDBNodeBranch *branch); void build(NLMISC::CCDBNodeBranch *branch);
uint64 getItemId() const;
// shortcuts to avoid NULL pointer tests // shortcuts to avoid NULL pointer tests
uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); } uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); }
uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); } uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); }
uint16 getQuantity() const { return (uint16) (Quantity ? Quantity->getValue16() : 0); } uint16 getQuantity() const { return (uint16) (Quantity ? Quantity->getValue16() : 0); }
uint32 getCreateTime() const { return (uint32) (CreateTime ? CreateTime->getValue32() : 0); }
uint32 getSerial() const { return (uint32) (Serial ? Serial->getValue32() : 0); }
uint8 getUserColor() const { return (uint8) (UserColor ? UserColor->getValue16() : 0); } uint8 getUserColor() const { return (uint8) (UserColor ? UserColor->getValue16() : 0); }
uint32 getPrice() const { return (uint32) (Price ? Price->getValue32() : 0); } uint32 getPrice() const { return (uint32) (Price ? Price->getValue32() : 0); }
uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); } uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); }
@ -87,6 +92,8 @@ public:
void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); } void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); }
void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); } void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); }
void setQuantity(uint16 quantity) { if (Quantity) Quantity->setValue16((sint16) quantity); } void setQuantity(uint16 quantity) { if (Quantity) Quantity->setValue16((sint16) quantity); }
void setCreateTime(uint32 create_time) { if (CreateTime) CreateTime->setValue32((sint32) create_time); }
void setSerial(uint32 serial) { if (Serial) Serial->setValue32((sint32) serial); }
void setUserColor(uint8 uc) { if (UserColor) UserColor->setValue8((sint8) uc); } void setUserColor(uint8 uc) { if (UserColor) UserColor->setValue8((sint8) uc); }
void setPrice(uint32 price) { if (Price) Price->setValue32((sint32) price); } void setPrice(uint32 price) { if (Price) Price->setValue32((sint32) price); }
void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); } void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); }
@ -108,11 +115,15 @@ public:
// This is the InfoVersionFromSlot when last request was sent to server // This is the InfoVersionFromSlot when last request was sent to server
uint16 InfoVersionSlotServerWaiting; uint16 InfoVersionSlotServerWaiting;
// Used to track cache age (reset on use, +1 on every save)
uint32 CacheCycle;
CClientItemInfo() CClientItemInfo()
{ {
InfoVersionFromMsg= 0; InfoVersionFromMsg= 0;
InfoVersionFromSlot= 0; InfoVersionFromSlot= 0;
InfoVersionSlotServerWaiting= 0; InfoVersionSlotServerWaiting= 0;
CacheCycle= 0;
} }
/// Set InfoVersion from Info message (info requested by the player) /// Set InfoVersion from Info message (info requested by the player)
@ -122,21 +133,25 @@ public:
void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; } void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; }
}; };
class CItemInfoCache
class IItemInfoWaiter
{ {
public: public:
IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;} void load(const std::string &filename);
virtual ~IItemInfoWaiter() {} void save(const std::string &filename);
// The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested void serial(NLMISC::IStream &s);
uint ItemSheet;
// The item SlotId to retrieve info. // retrieve pointer to item info or null if error
uint ItemSlotId; const CClientItemInfo *getItemInfo(uint32 serial, uint32 createTime) const;
const CClientItemInfo *getItemInfo(uint64 itemId) const;
// Called when the info is received for this slot.
virtual void infoReceived() =0;
};
// set/update item info in cache
void readFromImpulse(uint64 itemId, CItemInfos itemInfo);
void debugItemInfoCache() const;
private:
typedef std::map<uint64, CClientItemInfo> TItemInfoCacheMap;
TItemInfoCacheMap _ItemInfoCacheMap;
};
// *************************************************************************** // ***************************************************************************
/** This manager gives direct access to inventory slots (bag, temporary inventory, hands, and equip inventory) /** This manager gives direct access to inventory slots (bag, temporary inventory, hands, and equip inventory)
@ -189,8 +204,10 @@ public:
// SERVER INVENTORY // SERVER INVENTORY
// get item of bag (local inventory) // get item of bag (local inventory)
CItemImage &getServerBagItem(uint index); CItemImage &getServerBagItem(uint index);
const CItemImage &getServerBagItem(uint index) const;
// get temporary item (local inventory) // get temporary item (local inventory)
CItemImage &getServerTempItem(uint index); CItemImage &getServerTempItem(uint index);
const CItemImage &getServerTempItem(uint index) const;
// get hand item (local inventory) // get hand item (local inventory)
CItemImage *getServerHandItem(uint index); CItemImage *getServerHandItem(uint index);
// get equip item (local inventory) // get equip item (local inventory)
@ -200,8 +217,11 @@ public:
void setServerMoney(uint64 value); void setServerMoney(uint64 value);
// get item of pack animal (server inventory). beastIndex ranges from 0 to MAX_INVENTORY_ANIMAL-1 // get item of pack animal (server inventory). beastIndex ranges from 0 to MAX_INVENTORY_ANIMAL-1
CItemImage &getServerPAItem(uint beastIndex, uint index); CItemImage &getServerPAItem(uint beastIndex, uint index);
const CItemImage &getServerPAItem(uint beastIndex, uint index) const;
// get the item Image for the given inventory. assert if bad inventory // get the item Image for the given inventory. assert if bad inventory
CItemImage &getServerItem(uint inv, uint index); CItemImage &getServerItem(uint inv, uint index);
// get the item Image for the given slotId or NULL if bad
const CItemImage *getServerItem(uint slotId) const;
// Drag'n'Drop Management // Drag'n'Drop Management
enum TFrom { Slot, TextList, IconList, Nowhere }; enum TFrom { Slot, TextList, IconList, Nowhere };
@ -267,9 +287,13 @@ public:
uint16 getItemSlotId(CDBCtrlSheet *ctrl); uint16 getItemSlotId(CDBCtrlSheet *ctrl);
uint16 getItemSlotId(const std::string &itemDb, uint slotIndex); uint16 getItemSlotId(const std::string &itemDb, uint slotIndex);
const CClientItemInfo &getItemInfo(uint slotId) const; const CClientItemInfo &getItemInfo(uint slotId) const;
// get item info from cache
const CClientItemInfo *getItemInfoCache(uint32 serial, uint32 createTime) const;
uint getItemSheetForSlotId(uint slotId) const; uint getItemSheetForSlotId(uint slotId) const;
// Returns true if the item info is already in slot cache
bool isItemInfoAvailable(uint slotId) const;
// Returns true if the item info version already matches // Returns true if the item info version already matches
bool isItemInfoUpToDate(uint slotId); bool isItemInfoUpToDate(uint slotId) const;
// Add a Waiter on ItemInfo (ItemHelp opening). no-op if here, but reorder (returns true if the version already matches or if waiter is NULL) // Add a Waiter on ItemInfo (ItemHelp opening). no-op if here, but reorder (returns true if the version already matches or if waiter is NULL)
void addItemInfoWaiter(IItemInfoWaiter *waiter); void addItemInfoWaiter(IItemInfoWaiter *waiter);
// remove a Waiter on ItemInfo (ItemHelp closing). no-op if not here. NB: no delete // remove a Waiter on ItemInfo (ItemHelp closing). no-op if not here. NB: no delete
@ -279,6 +303,7 @@ public:
void onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion); void onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion);
// Log for debug // Log for debug
void debugItemInfoWaiters(); void debugItemInfoWaiters();
void debugItemInfoCache() const;
void sortBag(); void sortBag();
@ -294,6 +319,9 @@ public:
enum TInvType { InvBag, InvPA0, InvPA1, InvPA2, InvPA3, InvPA4, InvPA5, InvPA6, InvGuild, InvRoom, InvUnknown }; enum TInvType { InvBag, InvPA0, InvPA1, InvPA2, InvPA3, InvPA4, InvPA5, InvPA6, InvGuild, InvRoom, InvUnknown };
static TInvType invTypeFromString(const std::string &str); static TInvType invTypeFromString(const std::string &str);
// inventory and slot from slotId
void getSlotInvIndex(uint slotId, uint &inv, uint &index) const;
private: private:
// LOCAL INVENTORY // LOCAL INVENTORY
@ -318,6 +346,8 @@ private:
CDBCtrlSheet *DNDCurrentItem; CDBCtrlSheet *DNDCurrentItem;
// ItemExtraInfo management. // ItemExtraInfo management.
std::string _ItemInfoCacheFilename;
CItemInfoCache _ItemInfoCache;
typedef std::map<uint, CClientItemInfo> TItemInfoMap; typedef std::map<uint, CClientItemInfo> TItemInfoMap;
TItemInfoMap _ItemInfoMap; TItemInfoMap _ItemInfoMap;
typedef std::list<IItemInfoWaiter*> TItemInfoWaiters; typedef std::list<IItemInfoWaiter*> TItemInfoWaiters;

@ -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 RZ_ITEM_INFO_WAITER_H
#define RZ_ITEM_INFO_WAITER_H
class IItemInfoWaiter
{
public:
IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;}
virtual ~IItemInfoWaiter() {}
// The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested
uint ItemSheet;
// The item SlotId to retrieve info.
uint ItemSlotId;
// Called when the info is received for this slot.
virtual void infoReceived() =0;
};
#endif // RZ_DBCTRL_SHEET_INFO_WAITER_H
/* End of item_info_waiter.h */

@ -497,6 +497,7 @@ void CLuaIHMRyzom::RegisterRyzomFunctions(NLGUI::CLuaState &ls)
ls.registerFunc("saveUserChannels", saveUserChannels); ls.registerFunc("saveUserChannels", saveUserChannels);
ls.registerFunc("readUserChannels", readUserChannels); ls.registerFunc("readUserChannels", readUserChannels);
ls.registerFunc("getMaxDynChan", getMaxDynChan); ls.registerFunc("getMaxDynChan", getMaxDynChan);
ls.registerFunc("scrollElement", scrollElement);
lua_State *L = ls.getStatePointer(); lua_State *L = ls.getStatePointer();
@ -4020,7 +4021,7 @@ int CLuaIHMRyzom::setArkPowoOptions(CLuaState &ls)
// *************************************************************************** // ***************************************************************************
int CLuaIHMRyzom::readUserChannels(CLuaState &ls) int CLuaIHMRyzom::readUserChannels(CLuaState &ls)
{ {
std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml");
try try
{ {
CIFile fd; CIFile fd;
@ -4031,37 +4032,43 @@ int CLuaIHMRyzom::readUserChannels(CLuaState &ls)
xmlKeepBlanksDefault(0); xmlKeepBlanksDefault(0);
xmlNodePtr root = stream.getRootNode(); xmlNodePtr root = stream.getRootNode();
if (!root)
return 0; if (!root) return 0;
CXMLAutoPtr prop; CXMLAutoPtr prop;
// table
ls.newTable(); ls.newTable();
CLuaObject output(ls); CLuaObject output(ls);
uint nb = 0; std::vector< string > tags;
// allowed tags
tags.push_back("id");
tags.push_back("name");
tags.push_back("rgba");
tags.push_back("passwd");
xmlNodePtr node = root->children; xmlNodePtr node = root->children;
uint nb = 0;
while (node) while (node)
{ {
prop = xmlGetProp(node, (xmlChar*)"name"); ls.newTable();
if (!prop) CLuaObject nodeTable(ls);
return 0;
std::string name = (const char*)prop;
prop = xmlGetProp(node, (xmlChar*)"passwd"); for (uint i = 0; i < tags.size(); i++)
if (!prop) {
return 0; prop = xmlGetProp(node, (xmlChar*)tags[i].c_str());
std::string pass = (const char*)prop; if (!prop) return 0;
output.setValue(name.c_str(), pass.c_str()); nodeTable.setValue(tags[i].c_str(), (const char *)prop);
}
output.setValue(toString("%i", nb).c_str(), nodeTable);
node = node->next; node = node->next;
nb++; nb++;
} }
output.push();
// no exception // no exception
fd.close(); fd.close();
// release lua table
output.push();
} }
nlinfo("parse %s", filename.c_str()); nlinfo("parse %s", filename.c_str());
} }
@ -4091,7 +4098,7 @@ int CLuaIHMRyzom::saveUserChannels(CLuaState &ls)
CLuaObject params; CLuaObject params;
params.pop(ls); params.pop(ls);
std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml");
try try
{ {
COFile fd; COFile fd;
@ -4104,27 +4111,38 @@ int CLuaIHMRyzom::saveUserChannels(CLuaState &ls)
xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL); xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
xmlDocSetRootElement(doc, node); xmlDocSetRootElement(doc, node);
std::string key, value;
ENUM_LUA_TABLE(params, it) ENUM_LUA_TABLE(params, it)
{ {
if (!it.nextKey().isString()) if (it.nextKey().type() == LUA_TSTRING)
{
xmlNodePtr newNode = xmlNewChild(node, NULL, (const xmlChar*)"channels", NULL);
if (it.nextValue().type() == LUA_TTABLE)
{
xmlSetProp(newNode, (const xmlChar*)"id", (const xmlChar*)it.nextKey().toString().c_str());
ENUM_LUA_TABLE(it.nextValue(), itt)
{
if (!itt.nextKey().isString())
continue; continue;
if (!it.nextValue().isString()) if (!itt.nextValue().isString())
continue; continue;
std::string name = it.nextKey().toString(); key = itt.nextKey().toString();
std::string pass = it.nextValue().toString(); value = itt.nextValue().toString();
xmlNodePtr newNode = xmlNewChild(node, NULL, (const xmlChar*)"channels", NULL); xmlSetProp(newNode, (const xmlChar*)key.c_str(), (const xmlChar*)value.c_str());
xmlSetProp(newNode, (const xmlChar*)"name", (const xmlChar*)name.c_str()); }
xmlSetProp(newNode, (const xmlChar*)"passwd", (const xmlChar*)pass.c_str()); }
}
} }
stream.flush(); stream.flush();
// no exception
fd.close(); fd.close();
} }
nlinfo("save %s", filename.c_str()); nlinfo("save %s", filename.c_str());
if (verbose) if (verbose)
CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename); CInterfaceManager::getInstance()->displaySystemInfo("Save " + filename);
} }
catch (const Exception &e) catch (const Exception &e)
{ {
@ -4257,3 +4275,47 @@ int CLuaIHMRyzom::displayChatMessage(CLuaState &ls)
} }
return 1; return 1;
} }
// ***************************************************************************
int CLuaIHMRyzom::scrollElement(CLuaState &ls)
{
const char *funcName = "scrollElement";
// scrollElement(object, vertical, direction, offset_multiplier)
CLuaIHM::checkArgMin(ls, funcName, 3);
CLuaIHM::check(ls, ls.getTop() > 2, funcName);
CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), toString("%s requires a UI object in param 1", funcName));
CLuaIHM::check(ls, ls.type(2)==LUA_TBOOLEAN, toString("%s requires a boolean in param 2", funcName));
CLuaIHM::check(ls, ls.isInteger(3), toString("%s requires a number in param 3", funcName));
if (ls.getTop() > 3)
CLuaIHM::check(ls, ls.isInteger(4), toString("%s requires a number in param 4", funcName));
CInterfaceElement *pIE = CLuaIHM::getUIOnStack(ls, 1);
if (pIE)
{
// must be a scroll element
CCtrlScroll *pCS = dynamic_cast<CCtrlScroll*>(pIE);
if (pCS)
{
sint32 direction = 0;
sint32 multiplier = 16;
direction = (ls.toInteger(3) > 0) ? 1 : -1;
if (ls.getTop() > 3)
multiplier = (ls.toInteger(4) > 0) ? ls.toInteger(4) : 1;
const bool vertical = ls.toBoolean(2);
if (vertical)
pCS->moveTrackY(-(direction * multiplier));
else
pCS->moveTrackX(-(direction * multiplier));
return 0;
}
}
ls.pushNil();
return 1;
}

@ -273,6 +273,9 @@ private:
static bool isPlayerInPVPMode(); static bool isPlayerInPVPMode();
static bool isTargetInPVPMode(); static bool isTargetInPVPMode();
// vertical and horizontal scrolling
// do not require element to be focused
static int scrollElement(CLuaState &ls); // return none (nil if error)
public: public:

@ -161,6 +161,8 @@ bool CHugeListObs::init()
case Trading: case Trading:
_Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false);
_Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false);
_Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false);
_Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false);
_Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false);
_Items[k].Price = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:PRICE").c_str(), (int) k), false); _Items[k].Price = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:PRICE").c_str(), (int) k), false);
_Items[k].Weight = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:WEIGHT").c_str(), (int) k), false); _Items[k].Weight = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:WEIGHT").c_str(), (int) k), false);
@ -181,6 +183,7 @@ bool CHugeListObs::init()
if ((_Items[k].SlotType == NULL) || (_Items[k].Quality == NULL) || (_Items[k].SheetIDOrSkill == NULL) || if ((_Items[k].SlotType == NULL) || (_Items[k].Quality == NULL) || (_Items[k].SheetIDOrSkill == NULL) ||
(_Items[k].Price == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].Price == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) ||
(_Items[k].UserColor==NULL) || (_Items[k].NameId==NULL) || (_Items[k].Quantity==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].NameId==NULL) || (_Items[k].Quantity==NULL) ||
(_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL) ||
(_Items[k].PriceRetire==NULL) || (_Items[k].SellerType==NULL) || (_Items[k].ResaleTimeLeft==NULL) || (_Items[k].PriceRetire==NULL) || (_Items[k].SellerType==NULL) || (_Items[k].ResaleTimeLeft==NULL) ||
(_Items[k].VendorNameId==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].VendorNameId==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) ||
(_Items[k].RMFaberStatType == NULL) || (_Items[k].PrerequisitValid == NULL) || (_Items[k].RMFaberStatType == NULL) || (_Items[k].PrerequisitValid == NULL) ||
@ -191,6 +194,8 @@ bool CHugeListObs::init()
case ItemForMissions: case ItemForMissions:
_Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false);
_Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false);
_Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false);
_Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false);
_Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false);
_Items[k].LogicTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:LOGIC_TEXT_ID").c_str(), (int) k), false); _Items[k].LogicTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:LOGIC_TEXT_ID").c_str(), (int) k), false);
_Items[k].DescTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:DESC_TEXT_ID").c_str(), (int) k), false); _Items[k].DescTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:DESC_TEXT_ID").c_str(), (int) k), false);
@ -205,7 +210,7 @@ bool CHugeListObs::init()
(_Items[k].LogicTextID == NULL) || (_Items[k].DescTextID == NULL) || (_Items[k].LogicTextID == NULL) || (_Items[k].DescTextID == NULL) ||
(_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) ||
(_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) ||
(_Items[k].NameId==NULL) (_Items[k].NameId==NULL) || (_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL)
) )
return false; return false;
break; break;
@ -383,6 +388,8 @@ void CHugeListObs::update(ICDBNode * /* node */)
{ {
page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32();
page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16();
page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32();
page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32();
page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32();
page.Items[k].Price = (uint32) _Items[k].Price->getValue32(); page.Items[k].Price = (uint32) _Items[k].Price->getValue32();
page.Items[k].Weight= (uint16) _Items[k].Weight->getValue16(); page.Items[k].Weight= (uint16) _Items[k].Weight->getValue16();
@ -420,6 +427,8 @@ void CHugeListObs::update(ICDBNode * /* node */)
case ItemForMissions: case ItemForMissions:
page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32();
page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16();
page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32();
page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32();
page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32();
page.Items[k].LogicTextID = (uint32) _Items[k].LogicTextID->getValue32(); page.Items[k].LogicTextID = (uint32) _Items[k].LogicTextID->getValue32();
page.Items[k].DescTextID = (uint32) _Items[k].DescTextID->getValue32(); page.Items[k].DescTextID = (uint32) _Items[k].DescTextID->getValue32();
@ -569,6 +578,10 @@ void CHugeListObs::updateUIItemPage(uint index)
case Trading: case Trading:
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false);
if (leaf) leaf->setValue32(currItem.Quality); if (leaf) leaf->setValue32(currItem.Quality);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false);
if (leaf) leaf->setValue32(currItem.Serial);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false);
if (leaf) leaf->setValue32(currItem.CreateTime);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false);
if (leaf) leaf->setValue32(currItem.SlotType); if (leaf) leaf->setValue32(currItem.SlotType);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false);
@ -610,6 +623,10 @@ void CHugeListObs::updateUIItemPage(uint index)
case ItemForMissions: case ItemForMissions:
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false);
if (leaf) leaf->setValue32(currItem.Quality); if (leaf) leaf->setValue32(currItem.Quality);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false);
if (leaf) leaf->setValue32(currItem.Serial);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false);
if (leaf) leaf->setValue32(currItem.CreateTime);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false);
if (leaf) leaf->setValue32(currItem.SlotType); if (leaf) leaf->setValue32(currItem.SlotType);
leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false);

@ -124,6 +124,8 @@ private:
// //
NLMISC::CCDBNodeLeaf *SlotType; NLMISC::CCDBNodeLeaf *SlotType;
NLMISC::CCDBNodeLeaf *Quality; NLMISC::CCDBNodeLeaf *Quality;
NLMISC::CCDBNodeLeaf *Serial;
NLMISC::CCDBNodeLeaf *CreateTime;
NLMISC::CCDBNodeLeaf *SheetIDOrSkill; NLMISC::CCDBNodeLeaf *SheetIDOrSkill;
// //
NLMISC::CCDBNodeLeaf *LogicTextID; // valid if the item is to be obtained for a mission NLMISC::CCDBNodeLeaf *LogicTextID; // valid if the item is to be obtained for a mission
@ -157,6 +159,8 @@ private:
GuildName(NULL), GuildName(NULL),
SlotType(NULL), SlotType(NULL),
Quality(NULL), Quality(NULL),
Serial(NULL),
CreateTime(NULL),
SheetIDOrSkill(NULL), SheetIDOrSkill(NULL),
LogicTextID(NULL), LogicTextID(NULL),
DescTextID(NULL), DescTextID(NULL),
@ -216,6 +220,8 @@ private:
TRADE_SLOT_TYPE::TTradeSlotType SlotType; TRADE_SLOT_TYPE::TTradeSlotType SlotType;
uint16 Quality; uint16 Quality;
uint32 Serial;
uint32 CreateTime;
uint32 SheetIDOrSkill; uint32 SheetIDOrSkill;
uint32 LogicTextID; // Valid if the item is to be obtained as a mission reward uint32 LogicTextID; // Valid if the item is to be obtained as a mission reward
uint32 DescTextID; // Valid if the item is to be obtained as a mission reward uint32 DescTextID; // Valid if the item is to be obtained as a mission reward

Loading…
Cancel
Save