diff --git a/code/nel/include/nel/gui/view_text.h b/code/nel/include/nel/gui/view_text.h
new file mode 100644
index 000000000..5c22f7110
--- /dev/null
+++ b/code/nel/include/nel/gui/view_text.h
@@ -0,0 +1,413 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+
+
+#ifndef NL_VIEW_TEXT_H
+#define NL_VIEW_TEXT_H
+
+#include "nel/gui/view_base.h"
+#include "nel/gui/string_case.h"
+#include "nel/3d/u_text_context.h"
+
+namespace NLGUI
+{
+ class CCtrlToolTip;
+
+ /**
+ * class implementing a text view
+ * \author Matthieu 'TrapII' Besson
+ * \author Nicolas Vizerie
+ * \author Nevrax France
+ * \date 2002
+ */
+ class CViewText : public CViewBase
+ {
+ public:
+ enum TTextMode { ClipWord, DontClipWord, Justified };
+ public:
+
+ DECLARE_UI_CLASS(CViewText)
+
+
+ /// Constructor
+ CViewText (const TCtorParam ¶m);
+
+ /// Constructor
+ CViewText (const std::string& id, const std::string Text="", sint FontSize=12,
+ NLMISC::CRGBA Color=NLMISC::CRGBA(255,255,255), bool Shadow=false);
+
+ virtual ~CViewText();
+
+ CViewText &operator=(const CViewText &vt);
+
+ void parseTextOptions (xmlNodePtr cur);
+ bool parse (xmlNodePtr cur, CInterfaceGroup * parentGroup);
+ virtual uint32 getMemory() { return (uint32)(sizeof(*this)+_Id.size()); }
+
+ /// Updating
+ virtual void draw ();
+ void updateTextContext ();
+ virtual void checkCoords();
+ virtual void updateCoords();
+ virtual void onAddToGroup();
+
+ /// From CInterfaceElement
+ sint32 getMaxUsedW() const;
+ sint32 getMinUsedW() const;
+
+ /// Accessors
+
+ /// Set
+
+ void setText (const ucstring &text);
+ void setFontSize (sint nFontSize);
+ void setColor (const NLMISC::CRGBA &color);
+ void setShadow (bool bShadow);
+ void setShadowColor (const NLMISC::CRGBA &color);
+ void setLineMaxW (sint nMaxW, bool invalidate=true);
+ void setMultiLine (bool bMultiLine);
+ void setMultiLineSpace (sint nMultiLineSpace);
+ void setMultiLineMaxWOnly (bool state);
+ void setMultiLineClipEndSpace (bool state); // use it for multiline edit box for instance
+ void setFirstLineX (uint firstLineX);
+ void setMultiMaxLine(uint l) { _MultiMaxLine = l; }
+
+ // Force only a subset of letter to be displayed. Default is 0/0xFFFFFFFF
+ void enableStringSelection(uint start, uint end);
+ void disableStringSelection();
+
+ /// Get
+
+ ucstring getText() const { return _Text; }
+ sint getFontSize() const;
+ NLMISC::CRGBA getColor() { return _Color; }
+ bool getShadow() { return _Shadow; }
+ NLMISC::CRGBA getShadowColor() { return _ShadowColor; }
+ sint getLineMaxW() const { return _LineMaxW; }
+ bool getMultiLine() const { return _MultiLine; }
+ sint getMultiLineSpace() const { return _MultiLineSpace; }
+ bool getMultiLineMaxWOnly() const { return _MultiLineMaxWOnly; }
+ uint32 getMultiMaxLine() const { return _MultiMaxLine; }
+
+ // get current Hint font width, in pixels
+ uint getFontWidth() const;
+ // get current font height, in pixels
+ uint getFontHeight() const;
+ // get current font leg height, in pixels
+ uint getFontLegHeight() const;
+ // Set the display mode (supported with multiline only for now)
+ void setTextMode(TTextMode mode);
+ TTextMode getTextMode() const { return _TextMode; }
+ uint getNumLine() const;
+ uint getFirstLineX() const;
+ uint getLastLineW () const;
+ void setUnderlined (bool underlined) { _Underlined = underlined; }
+ bool getUnderlined () const { return _Underlined; }
+ // true if the viewText is a single line clamped.
+ bool isSingleLineTextClamped() const {return _SingleLineTextClamped;}
+
+ // Character positions
+
+ /** Get position of the ith character, position are relative to the BR corner of the text.
+ * \param lineEnd. When set to true, return the coordinate of the previous line if the index is at the start of a line.
+ * When looking at standard edit box, we see that if a line is split accross to line with no
+ * This also returns the height of the line
+ */
+ void getCharacterPositionFromIndex(sint index, bool lineEnd, sint &x, sint &y, sint &height) const;
+ /** From a coordinate relative to the BR BR corner of the text, return the index of a character.
+ * If no character is found at the given position, the closest character is returned (first or last character, for the line or the whole text)
+ */
+ void getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &lineEnd) const;
+ /** From a character index, get the index of the line it belongs to, or -1 if the index is invalid
+ * \param cursorDisplayedAtEndOfPreviousLine true if the cursor is displayed at the end of the previous line that match its index
+ */
+ sint getLineFromIndex(uint index, bool cursorDisplayedAtEndOfPreviousLine = true) const;
+ /// From a line number, get the character at which it starts, or -1 if invalid
+ sint getLineStartIndex(uint line) const;
+ /// From a line number, get the character at which it ends (not including any '\n' ), or -1 if invalid
+ void getLineEndIndex(uint line, sint &index, bool &endOfPreviousLine) const;
+
+ std::string getHardText() const { std::string result; _Text.toString (result); return result; }
+ void setHardText (const std::string &ht);
+
+ std::string getColorAsString() const;
+ void setColorAsString(const std::string &ht);
+
+ NLMISC::CRGBA getColorRGBA() const;
+ void setColorRGBA(NLMISC::CRGBA col);
+
+ virtual sint32 getAlpha() const { return _Color.A; }
+ virtual void setAlpha (sint32 a) { _ShadowColor.A = _Color.A = (uint8)a; }
+
+ /** Setup a Text with Format Tags. Text is store without color/format tags, and special array is allocated for Format association
+ */
+ void setTextFormatTaged(const ucstring &text);
+
+ void setSingleLineTextFormatTaged(const ucstring &text);
+
+ // Remove end space
+ void removeEndSpaces();
+
+ // Reset the text index because the text context has changed
+ void resetTextIndex();
+
+ // Case mode
+ void setCaseMode (TCaseMode caseMode);
+ TCaseMode getCaseMode () const;
+
+ // OverExtendViewText
+ void setOverExtendViewText(bool state) {_OverExtendViewText= state;}
+ bool getOverExtendViewText() const {return _OverExtendViewText;}
+
+ // OverExtendViewTextUseParentRect
+ void setOverExtendViewTextUseParentRect(bool state) {_OverExtendViewTextUseParentRect= state;}
+ bool getOverExtendViewTextUseParentRect() const {return _OverExtendViewTextUseParentRect;}
+
+ // see if text ellipsis if done at right side of the text
+ bool isClampRight() const { return _ClampRight; }
+
+ int luaSetLineMaxW(CLuaState &ls);
+
+ REFLECT_EXPORT_START(CViewText, CViewBase)
+ REFLECT_STRING("hardtext", getHardText, setHardText);
+ REFLECT_UCSTRING("uc_hardtext", getText, setText);
+ REFLECT_UCSTRING("uc_hardtext_format", getText, setTextFormatTaged);
+ REFLECT_UCSTRING("uc_hardtext_single_line_format", getText, setSingleLineTextFormatTaged);
+ REFLECT_STRING ("color", getColorAsString, setColorAsString);
+ REFLECT_RGBA ("color_rgba", getColorRGBA, setColorRGBA);
+ REFLECT_SINT32 ("alpha", getAlpha, setAlpha);
+ REFLECT_BOOL ("overExtendViewText", getOverExtendViewText, setOverExtendViewText);
+ REFLECT_BOOL ("overExtendViewTextUseParentRect", getOverExtendViewTextUseParentRect, setOverExtendViewTextUseParentRect);
+ REFLECT_LUA_METHOD("setLineMaxW", luaSetLineMaxW);
+ REFLECT_EXPORT_END
+
+
+ virtual void serial(NLMISC::IStream &f);
+
+ protected:
+
+ /// Text to display.
+ ucstring _Text;
+ /// index of the computed String associated to this text control
+ uint _Index;
+ /// info on the computed String associated to this text control
+ NL3D::UTextContext::CStringInfo _Info;
+ /// the font size
+ sint _FontSize;
+ // width of the font in pixel. Just a Hint for tabing format (computed with '_')
+ uint _FontWidth;
+ // height of the font in pixel.
+ // use getFontHeight
+ uint _FontHeight;
+ uint _FontLegHeight;
+ float _SpaceWidth;
+ /// the text color
+ NLMISC::CRGBA _Color;
+ /// the shadow mode
+ bool _Shadow;
+ /// the case mode
+ TCaseMode _CaseMode;
+ /// the text shadow color
+ NLMISC::CRGBA _ShadowColor;
+ /// Is the line (under p loop) should be considered at bottom (if false bottom is under p leg)
+ /// maxw for the line/multiline
+ sint32 _LineMaxW;
+ /// For single line, true if the text is clamped (ie displayed with "...")
+ bool _SingleLineTextClamped;
+
+ /// Multiple lines handling
+ bool _MultiLine;
+ bool _MultiLineMaxWOnly;
+ bool _MultiLineClipEndSpace;
+ uint8 _AutoClampOffset;
+ TTextMode _TextMode;
+ sint _MultiLineSpace;
+ sint _LastMultiLineMaxW;
+ uint32 _MultiMaxLine;
+
+
+ /// FormatTag handling
+ struct CFormatInfo
+ {
+ // The color to change
+ NLMISC::CRGBA Color;
+ // The Tabulation to apply, in number of "_" characters.
+ uint TabX;
+ // Index in vector
+ sint IndexTt;
+
+ CFormatInfo()
+ {
+ Color= NLMISC::CRGBA::White;
+ TabX= 0;
+ IndexTt = -1;
+ }
+
+ bool operator==(const CFormatInfo &o) const {return Color==o.Color && TabX==o.TabX && IndexTt==o.IndexTt;}
+ bool operator!=(const CFormatInfo &o) const {return !operator==(o);}
+ };
+ struct CFormatTag : public CFormatInfo
+ {
+ uint Index;
+
+ // compare 2 tags, not a tag and a CFormatInfo
+ bool sameTag(const CFormatTag &o) const
+ {
+ return CFormatInfo::operator==(o) && Index==o.Index;
+ }
+ };
+ std::vector _FormatTags;
+
+ /// Get the current maxW for multiline, accordgin to parent and _MultiLineOptionMaxW
+ sint getCurrentMultiLineMaxW() const;
+
+
+
+
+ NL3D::ULetterColors * _LetterColors;
+
+ private:
+ // A word in a line
+ class CWord
+ {
+ public:
+ // default ctor
+ CWord(uint numSpaces = 0) : Index(0), NumSpaces(numSpaces) {}
+ ucstring Text;
+ uint Index; // index of the info for this word
+ NL3D::UTextContext::CStringInfo Info;
+ uint NumSpaces; // number of spaces before this word
+ // The specialized color/format of this word. White if none
+ CFormatInfo Format;
+ public:
+ // build from a string, using the current text context
+ void build(const ucstring &text, uint numSpaces= 0);
+ };
+ typedef std::vector TWordVect;
+
+ // A line of text (which is made of one word with space, or of several words with no spaces in them)
+ class CLine : public NLMISC::CRefCount
+ {
+ public:
+ // ctor
+ CLine();
+ // Clear the line & remove text contexts
+ void clear();
+ // Add a new word (and its context) in the line + a number of spaces to append at the end of the line
+ void addWord(const ucstring &word, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth);
+ void addWord(const CWord &word, uint fontWidth);
+ uint getNumWords() const { return (uint)_Words.size(); }
+ CWord &getWord(uint index) { return _Words[index]; }
+ float getSpaceWidth() const { return _SpaceWidth; }
+ void setSpaceWidth(float width) { _SpaceWidth = width; }
+ // Get the number of chars in the line, not counting the end spaces, but couting the spaces in words
+ uint getNumChars() const { return _NumChars; }
+ // Get the total number of spaces between words (not including those in words, but there should not be if text is justified)
+ uint getNumSpaces() const { return _NumSpaces; }
+ float getStringLine() const { return _StringLine; }
+ float getWidthWithoutSpaces() const { return _WidthWithoutSpaces; }
+ // get total width including spaces, but not including end spaces
+ float getWidth() const { return _WidthWithoutSpaces + _SpaceWidth * _NumSpaces; }
+ // Get the number of spaces at the end of the line
+ void setEndSpaces(uint numSpaces) { _EndSpaces = numSpaces; }
+ // Set the number of spaces at the end of the line
+ uint getEndSpaces() const { return _EndSpaces; }
+ // Test if there's a line feed at the end of the line
+ bool getLF() const { return _HasLF; }
+ void setLF(bool lf) { _HasLF = lf; }
+ void resetTextIndex();
+ private:
+ TWordVect _Words;
+ uint _NumChars;
+ uint _NumSpaces;
+ float _SpaceWidth; // width of a space, in pixels (used with multispace alignment)
+ float _StringLine;
+ float _WidthWithoutSpaces; // width without space (see the Field NumSpaces in the CWord class).
+ // NB : space inserted inside a word are counted, however!
+ uint _EndSpaces; // spaces at the end of the line
+ bool _HasLF; // a linefeed is at end of line (no breaking due to line full)
+ };
+ /// NB : we keep pointers on lines (each line contains a vector, that we don't want to be copied, and this occurs as the vector of lines grows..)
+
+ typedef NLMISC::CSmartPtr TLineSPtr;
+ typedef std::vector TLinePtVect;
+ private:
+ /** Data of the updated text for multiline. It is built from the _Text field in the updateTextContext member function,
+ * and is used to perform the draw
+ */
+ TLinePtVect _Lines;
+
+ /// if true, and if the view text is isSingleLineTextClamped(), then an over will be drawn, with the text
+ bool _OverExtendViewText : 1;
+ /// if true and _OverExtendViewText true too, use the parent rectangle to know if must display the over or not
+ bool _OverExtendViewTextUseParentRect : 1;
+ /// Letter selection handling
+ bool _AutoClamp : 1;
+ bool _ClampRight : 1;
+ bool _TextSelection : 1;
+ bool _InvalidTextContext : 1;
+ bool _Underlined : 1;
+ bool _ContinuousUpdate : 1;
+ bool _Setuped : 1;
+
+ uint _TextSelectionStart;
+ uint _TextSelectionEnd;
+
+ // First line X coordinate
+ uint _FirstLineX;
+
+ /// Dynamic tooltips
+ std::vector _Tooltips;
+
+
+ private:
+ void setup ();
+ void setupDefault ();
+
+ void setStringSelectionSkipingSpace(uint stringId, const ucstring &text, sint charStart, sint charEnd);
+
+ // void pushString(const ucstring &str, bool deleteSpaceAtStart = false);
+
+ /// \from CInterfaceElement
+ void onInvalidateContent();
+
+ // may append a new line, and append a word to the last line (no spaces)
+ void flushWordInLine(ucstring &ucCurrentWord, bool &linePushed, const CFormatInfo &wordFormat);
+ // Clear all the lines and free their datas
+ void clearLines();
+ // Update in the case of a multiline text
+ void updateTextContextMultiLine(uint nMaxWidth);
+ // Update in the case of a multiline text with justification
+ void updateTextContextMultiLineJustified(uint nMaxWidth, bool expandSpaces);
+ // Recompute font size info
+ void computeFontSize ();
+
+ // used for "donctClipWord" case in updateTextContextMultiLineJustified(). currLine is reseted
+ void addDontClipWordLine(std::vector &currLine);
+
+ // FormatTag build.
+ static void buildFormatTagText(const ucstring &text, ucstring &textBuild, std::vector &formatTags, std::vector &tooltips);
+ // FormatTag parsing.
+ bool isFormatTagChange(uint textIndex, uint ctIndex) const;
+ void getFormatTagChange(uint textIndex, uint &ctIndex, CFormatInfo &wordFormat) const;
+ };
+
+}
+
+#endif // NL_VIEW_TEXT_H
+
+/* End of view_text.h */
diff --git a/code/nel/src/gui/view_text.cpp b/code/nel/src/gui/view_text.cpp
new file mode 100644
index 000000000..4c29b5146
--- /dev/null
+++ b/code/nel/src/gui/view_text.cpp
@@ -0,0 +1,2603 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#include "nel/misc/bit_mem_stream.h"
+#include "nel/misc/i18n.h"
+
+#include "nel/gui/view_text.h"
+#include "nel/gui/view_renderer.h"
+#include "nel/gui/widget_manager.h"
+#include "nel/gui/group_container_base.h"
+#include "nel/gui/ctrl_tooltip.h"
+#include "nel/misc/xml_auto_ptr.h"
+#include "nel/gui/lua_ihm.h"
+#include "nel/gui/view_pointer_base.h"
+
+using namespace std;
+using namespace NLMISC;
+using namespace NL3D;
+
+typedef std::string::size_type TCharPos; // index of a chracter in a string
+
+REGISTER_UI_CLASS(CViewText)
+
+namespace NLGUI
+{
+
+ // ***************************************************************************
+ void CViewText::setupDefault ()
+ {
+ _CaseMode = CaseNormal;
+ _Underlined = false;
+ _ContinuousUpdate = false;
+ _Active = true;
+ _X = 0;
+ _Y = 0;
+ _W = 0;;
+ _H = 0;
+ _SizeRef = 0;
+ _SizeDivW = 10;
+ _SizeDivH = 10;
+ _ParentPosRef = Hotspot_BL;
+ _PosRef = Hotspot_BL;
+
+ _FontSize = 12 +
+ CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont ).getValSInt32();
+ _Color = CRGBA(255,255,255,255);
+ _Shadow = false;
+ _ShadowColor = CRGBA(0,0,0,255);
+
+ _MultiLine = false;
+ _TextMode = DontClipWord;
+ _MultiLineSpace = 8;
+ _LineMaxW = 16384;
+ _MultiLineMaxWOnly = false;
+ _MultiLineClipEndSpace = false;
+ _LastMultiLineMaxW = 0;
+ _MultiMaxLine = 0;
+ _Index = 0xFFFFFFFF;
+
+ _FontWidth= 0;
+ _FontHeight = 0;
+ _FontLegHeight = 0;
+
+ _TextSelection= false;
+ _TextSelectionStart= 0;
+ _TextSelectionEnd= std::numeric_limits::max();
+
+ _InvalidTextContext= true;
+ _FirstLineX = 0;
+ computeFontSize ();
+
+ _SingleLineTextClamped= false;
+ _OverExtendViewText= false;
+ _OverExtendViewTextUseParentRect= false;
+
+ _AutoClamp = false;
+ _ClampRight = true; // clamp on the right of the text
+
+ _LetterColors = NULL;
+ _Setuped= false;
+ _AutoClampOffset = 0;
+ }
+
+ // ***************************************************************************
+
+ NLMISC_REGISTER_OBJECT(CViewBase, CViewText, std::string, "text");
+
+ CViewText::CViewText(const TCtorParam ¶m)
+ :CViewBase(param)
+ {
+ setupDefault ();
+ }
+
+ ///constructor
+ // ***************************************************************************
+ CViewText:: CViewText (const std::string& id, const std::string Text, sint FontSize,
+ NLMISC::CRGBA Color, bool Shadow)
+ :CViewBase(TCtorParam())
+ {
+ _Id = id;
+ setupDefault ();
+
+ _FontSize = FontSize + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
+ _Color = Color;
+ _Shadow = Shadow;
+ setText(Text);
+ computeFontSize ();
+ }
+
+ // ***************************************************************************
+ CViewText::~CViewText()
+ {
+ if (_Index != 0xFFFFFFFF)
+ CViewRenderer::getTextContext()->erase (_Index);
+ clearLines();
+
+ if (!_Setuped)
+ for (uint i=0 ; i<_Tooltips.size() ; ++i)
+ delete _Tooltips[i];
+
+ _Tooltips.clear();
+ }
+
+ // ***************************************************************************
+ CViewText &CViewText::operator=(const CViewText &vt)
+ {
+ if (_Index != 0xFFFFFFFF)
+ CViewRenderer::getTextContext()->erase (_Index);
+
+ // Create database entries
+ _Active = vt._Active;
+ _X = vt._X;
+ _Y = vt._Y;
+ _W = vt._W;
+ _H = vt._H;
+ _SizeRef = vt._SizeRef;
+ _SizeDivW = vt._SizeDivW;
+ _SizeDivH = vt._SizeDivH;
+ _ParentPosRef = vt._ParentPosRef;
+ _PosRef = vt._PosRef;
+
+ _FontSize = vt._FontSize;
+ _Color = vt._Color;
+ _Shadow = vt._Shadow;
+ _ShadowColor = vt._ShadowColor;
+
+ _MultiLine = false;
+ _MultiLineSpace = 8;
+ _LineMaxW= 16384;
+ _MultiLineMaxWOnly = false;
+ _MultiLineClipEndSpace = false;
+ _LastMultiLineMaxW = 0;
+ _Index = 0xFFFFFFFF;
+
+ _ModulateGlobalColor= vt._ModulateGlobalColor;
+
+
+ // remove previous lines
+ clearLines();
+ _InvalidTextContext = true;
+ computeFontSize ();
+
+ return *this;
+ }
+
+ // ***************************************************************************
+ void CViewText::parseTextOptions (xmlNodePtr cur)
+ {
+ CXMLAutoPtr prop;
+
+ prop= (char*) xmlGetProp( cur, (xmlChar*)"color" );
+ _Color = CRGBA(255,255,255,255);
+ if (prop)
+ _Color = convertColor(prop);
+
+ prop= (char*) xmlGetProp (cur, (xmlChar*)"global_color");
+ if(prop)
+ _ModulateGlobalColor= convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"fontsize" );
+ _FontSize = 12 + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
+ if (prop)
+ {
+ fromString((const char*)prop, _FontSize);
+ _FontSize += CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
+ }
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"shadow" );
+ _Shadow = false;
+ if (prop)
+ _Shadow = convertBool(prop);
+
+ prop= (char*) xmlGetProp( cur, (xmlChar*)"shadow_color" );
+ _ShadowColor = CRGBA(0,0,0,255);
+ if (prop)
+ _ShadowColor = convertColor(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line" );
+ _MultiLine = false;
+ if (prop)
+ _MultiLine = convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"justification" );
+ if (prop)
+ {
+ if (nlstricmp("clip_word", (const char *) prop) == 0) _TextMode = ClipWord;
+ else if (nlstricmp("dont_clip_word", (const char *) prop) == 0) _TextMode = DontClipWord;
+ else if (nlstricmp("justified", (const char *) prop) == 0) _TextMode = Justified;
+ else nlwarning(" bad text mode");
+ }
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"line_maxw" );
+ _LineMaxW = 16384;
+ if (prop)
+ fromString((const char*)prop, _LineMaxW);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line_space" );
+ _MultiLineSpace = 8;
+ if (prop)
+ fromString((const char*)prop, _MultiLineSpace);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line_maxw_only" );
+ _MultiLineMaxWOnly = false;
+ if (prop)
+ _MultiLineMaxWOnly = convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_max_line" );
+ _MultiMaxLine = 0;
+ if (prop)
+ fromString((const char*)prop, _MultiMaxLine);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"underlined" );
+ _Underlined = false;
+ if (prop)
+ _Underlined = convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"case_mode" );
+ _CaseMode = CaseNormal;
+ if (prop)
+ {
+ sint32 caseMode;
+ fromString((const char*)prop, caseMode);
+ _CaseMode = (TCaseMode)caseMode;
+ }
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"over_extend_view_text" );
+ _OverExtendViewText= false;
+ if(prop)
+ _OverExtendViewText= convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"over_extend_parent_rect" );
+ _OverExtendViewTextUseParentRect= false;
+ if(prop)
+ _OverExtendViewTextUseParentRect= convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"auto_clamp" );
+ _AutoClamp = false;
+ if (prop)
+ _AutoClamp = convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"clamp_right" );
+ _ClampRight = true;
+ if (prop)
+ _ClampRight = convertBool(prop);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"auto_clamp_offset" );
+ _AutoClampOffset = 0;
+ if (prop)
+ fromString((const char*)prop, _AutoClampOffset);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"continuous_update" );
+ if (prop)
+ {
+ _ContinuousUpdate = convertBool(prop);
+ }
+
+
+ computeFontSize ();
+ }
+
+ /*
+ * parse an xml node and initialize the base view mambers. Must call CViewBase::parse
+ * \param cur : pointer to the xml node to be parsed
+ * \param parentGroup : the parent group of the view
+ * \partam id : a refence to the string that will receive the view ID
+ * \return true if success
+ */
+ // ***************************************************************************
+ bool CViewText::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
+ {
+
+ // const ucstring* tmp;
+ CXMLAutoPtr prop;
+ //try to get props that can be inherited from groups
+ //if a property is not defined, try to find it in the parent group.
+ //if it is undefined, set it to zero
+
+ if (! CViewBase::parse(cur,parentGroup) )
+ return false;
+
+ //set w and h to 0 : they depend on the string contained
+ _W = 0;
+ _H = 0;
+
+ //try to get the NEEDED specific props
+ parseTextOptions(cur);
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"hardtext" );
+ if (prop)
+ {
+ const char *propPtr = prop;
+ _Text = ucstring(propPtr);
+
+ if ((strlen(propPtr)>2) && (propPtr[0] == 'u') && (propPtr[1] == 'i'))
+ _Text = CI18N::get (propPtr);
+ setCase (_Text, _CaseMode);
+ }
+
+ prop = (char*) xmlGetProp( cur, (xmlChar*)"hardtext_format" );
+ if (prop)
+ {
+ const char *propPtr = prop;
+ if (_MultiLine)
+ {
+ setTextFormatTaged(CI18N::get(propPtr));
+ }
+ else
+ {
+ setSingleLineTextFormatTaged(CI18N::get(propPtr));
+ }
+ }
+
+ invalidateContent ();
+
+ return true;
+ }
+
+ // ***************************************************************************
+ sint CViewText::getCurrentMultiLineMaxW() const
+ {
+ if(_MultiLineMaxWOnly)
+ return _LineMaxW;
+ else
+ {
+ sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
+ return std::min(parentWidth-(sint)(_XReal-_Parent->getXReal()), (sint)_LineMaxW);
+ }
+ }
+
+
+ // ***************************************************************************
+ void CViewText::checkCoords ()
+ {
+ if ((_MultiLine)&&(_Parent != NULL))
+ {
+ // If never setuped, and if text is not empty
+ if (_Lines.size() == 0 && !_Text.empty())
+ invalidateContent ();
+
+ sint currentMaxW= getCurrentMultiLineMaxW();
+ if ( _LastMultiLineMaxW != currentMaxW )
+ {
+ if (_ContinuousUpdate)
+ {
+ _LastMultiLineMaxW = currentMaxW;
+ invalidateContent();
+ }
+ else
+ {
+ CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
+ if (pCB != NULL)
+ {
+ if( pCB->isResizer() )
+ {
+ // We are resizing !!!!
+ }
+ else
+ {
+ _LastMultiLineMaxW = currentMaxW;
+ invalidateContent();
+ }
+ }
+ else
+ {
+ _LastMultiLineMaxW = currentMaxW;
+ invalidateContent();
+ }
+ }
+ }
+ }
+ else
+ {
+ if (_Index == 0xFFFFFFFF)
+ invalidateContent ();
+ }
+ }
+ /*
+ * draw the view
+ */
+ // ***************************************************************************
+ void CViewText::draw ()
+ {
+ H_AUTO( RZ_Interface_CViewText_draw )
+
+ CViewRenderer &rVR = *CViewRenderer::getInstance();
+
+ // *** Out Of Clip?
+ sint32 ClipX, ClipY, ClipW, ClipH;
+ rVR.getClipWindow (ClipX, ClipY, ClipW, ClipH);
+ if (((_XReal) > (ClipX+ClipW)) || ((_XReal+_WReal) < ClipX) ||
+ ((_YReal) > (ClipY+ClipH)) || ((_YReal+_HReal) < ClipY))
+ return;
+
+ // *** Screen Minimized?
+ uint32 w, h;
+ float oow, ooh;
+ rVR.getScreenSize (w, h);
+ if (rVR.isMinimized())
+ return;
+ rVR.getScreenOOSize (oow, ooh);
+
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+
+
+ // *** get current color
+ CRGBA col, shcol;
+ if(getModulateGlobalColor())
+ {
+ CRGBA gcfc = CWidgetManager::getInstance()->getGlobalColorForContent();
+ col.modulateFromColor (_Color, gcfc);
+ shcol.modulateFromColor (_ShadowColor, gcfc);
+ }
+ else
+ {
+ col = _Color;
+ shcol = _ShadowColor;
+ col.A = (uint8)(((sint)col.A*((sint)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
+ shcol.A = (uint8)(((sint)shcol.A*((sint)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
+ }
+
+
+ // *** Draw multiline
+ if ((_MultiLine)&&(_Parent != NULL))
+ {
+ if (_Lines.size() == 0) return;
+
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setShadeColor (shcol);
+ TextContext->setFontSize (_FontSize);
+
+ float y = (float)(_YReal) * ooh; // y is expressed in scree, coordinates [0..1]
+ //y += _LinesInfos[_LinesInfos.size()-1].StringLine / h;
+
+ // Y is the base line of the string, so it must be grown up.
+ y += (float)_FontLegHeight * ooh;
+
+ sint y_line = _YReal+_FontLegHeight-2;
+
+ // special selection code
+ if(_TextSelection)
+ {
+ sint charIndex = 0;
+ for (sint i = 0; i<(sint)_Lines.size(); i++)
+ {
+ CLine &currLine = *_Lines[i];
+ for(uint k = 0; k < currLine.getNumWords(); ++k)
+ {
+ CWord &currWord = currLine.getWord(k);
+ charIndex += currWord.NumSpaces;
+ sint cStart= max(charIndex, (sint)_TextSelectionStart);
+ sint cEnd= min(charIndex+(sint)currWord.Text.length(), (sint)_TextSelectionEnd);
+
+ // range must be valid
+ if(cStartsetStringSelection(currWord.Index, 0, 0);
+ }
+
+ // next word
+ charIndex+= (sint)currWord.Text.length();
+ }
+ charIndex += currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
+ }
+ }
+
+ // draw
+ for (sint i = (sint)_Lines.size()-1; i >= 0; --i)
+ {
+ CLine &currLine = *_Lines[i];
+ // current x position
+ float px = (float) (_XReal + ((i==0) ? (sint)_FirstLineX : 0));
+ // draw each words of the line
+ for(uint k = 0; k < currLine.getNumWords(); ++k)
+ {
+ CWord &currWord = currLine.getWord(k);
+
+ // Change the current color
+ if(currWord.Format.Color==CRGBA::White)
+ TextContext->setStringColor(currWord.Index, col);
+ else
+ {
+ CRGBA mCol;
+ mCol.modulateFromColor(col, currWord.Format.Color);
+ TextContext->setStringColor(currWord.Index, mCol);
+ }
+
+ // skip spaces before current word
+ float firstSpace = currWord.NumSpaces * currLine.getSpaceWidth();
+ sint line_width = 0;
+ if (_Underlined)
+ {
+ line_width = (sint)floorf(currLine.getWidthWithoutSpaces() + currLine.getSpaceWidth());
+ line_width -= (sint)floorf(firstSpace);
+ }
+ px += firstSpace;
+ // skip tabulation before current word
+ if(currWord.Format.TabX)
+ px= max(px, (float)(_XReal + currWord.Format.TabX*_FontWidth));
+
+ // draw. We take floorf px to avoid filtering of letters that are not located on a pixel boundary
+ rVR.drawText (_RenderLayer, floorf(px) * oow, y, currWord.Index, (float)ClipX * oow, (float)ClipY * ooh,
+ (float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
+
+ // Draw a line
+ if (_Underlined)
+ rVR.drawRotFlipBitmap (_RenderLayer, (sint)floorf(px), y_line, line_width, 1, 0, false, rVR.getBlankTextureId(), col);
+
+ // skip word
+ px += currWord.Info.StringWidth;
+ }
+ // go one line up
+ y += (_FontHeight + _MultiLineSpace) * ooh;
+ y_line += _FontHeight+_MultiLineSpace;
+ }
+
+ // reset selection
+ if(_TextSelection)
+ {
+ for (sint i = 0; i<(sint)_Lines.size(); i++)
+ {
+ CLine &currLine = *_Lines[i];
+ for(uint k = 0; k < currLine.getNumWords(); ++k)
+ {
+ TextContext->resetStringSelection(currLine.getWord(k).Index);
+ }
+ }
+ }
+ }
+ // *** Single Line Version (currently no support for text justification)
+ else
+ {
+ nlassert(_Index != 0xFFFFFFFF);
+
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setShadeColor (shcol);
+ TextContext->setFontSize (_FontSize);
+
+
+ if(_LetterColors!=NULL && !TextContext->isSameLetterColors(_LetterColors, _Index))
+ {
+ TextContext->setLetterColors(_LetterColors, _Index);
+ }
+
+
+ float x = (float)(_XReal) * oow;
+ float y = (float)(_YReal) * ooh;
+
+ // Y is the base line of the string, so it must be grown up.
+ y += (float)_FontLegHeight * ooh;
+
+ // special selection code
+ if(_TextSelection)
+ // select subset. Arg, must skip spaces because not inserted in VertexBuffer.
+ setStringSelectionSkipingSpace(_Index, _Text, _TextSelectionStart, _TextSelectionEnd);
+
+ // Change the current color
+ TextContext->setStringColor(_Index, col);
+
+ // draw
+ rVR.drawText (_RenderLayer, x, y, _Index, (float)ClipX * oow, (float)ClipY * ooh,
+ (float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
+
+ // Draw a line
+ if (_Underlined)
+ rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_FontLegHeight-2, _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
+
+ // reset selection
+ if(_TextSelection)
+ TextContext->resetStringSelection(_Index);
+
+ // if single line clamped, may allow to draw an over
+ if(isSingleLineTextClamped() && _OverExtendViewText && CWidgetManager::getInstance()->getPointer())
+ {
+ // but must check first if mouse is over
+ sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
+ sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
+ bool mouseIn;
+ // use parent clip or self clip?
+ if(_OverExtendViewTextUseParentRect)
+ mouseIn= _Parent && _Parent->isIn(x,y);
+ else
+ mouseIn= isIn(x,y);
+ // if the mouse cursor is in the clip area
+ if(mouseIn)
+ {
+ // check the window under the mouse is the root window
+ CInterfaceGroup *pIG = CWidgetManager::getInstance()->getWindowUnder(x,y);
+ CInterfaceElement *pParent = this;
+ bool bFound = false;
+ while (pParent != NULL)
+ {
+ if (pParent == pIG)
+ {
+ bFound = true;
+ break;
+ }
+ pParent = pParent->getParent();
+ }
+
+ // ok => let this view text be the extend over one
+ if(bFound)
+ {
+ // last check: the window must not be currently moved
+ CGroupContainerBase *gc= dynamic_cast(pIG);
+ if(!gc || !gc->isMoving())
+ {
+ CRGBA col= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionViewTextOverBackColor).getValColor();
+ CWidgetManager::getInstance()->setOverExtendViewText(this, col);
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ // ***************************************************************************
+ void CViewText::onAddToGroup()
+ {
+ // Add tooltips if not done
+ if(!_Setuped)
+ setup();
+ }
+
+ // ***************************************************************************
+ void CViewText::setTextMode(TTextMode mode)
+ {
+ if (mode != _TextMode)
+ {
+ _TextMode = mode;
+ invalidateContent ();
+ }
+ }
+
+ // ***************************************************************************
+ void CViewText::setText(const ucstring & text)
+ {
+ // common case: no special format, no case mode => easy cache test
+ if (_FormatTags.empty() && _CaseMode==CaseNormal)
+ {
+ if (text != _Text)
+ {
+ _Text = text;
+ // no need to call "setCase (_Text, _CaseMode);" since CaseNormal:
+ invalidateContent ();
+ }
+ }
+ else
+ {
+ // if the view text had some format before, no choice, must recompute all
+ if(!_FormatTags.empty())
+ {
+ _Text = text;
+ setCase (_Text, _CaseMode);
+ invalidateContent ();
+ }
+ // else test if after the case change the cache succeed
+ else
+ {
+ // compute the temp cased text
+ ucstring tempText= text;
+ setCase(tempText, _CaseMode);
+ if(tempText!=_Text)
+ {
+ _Text = tempText;
+ invalidateContent ();
+ }
+ }
+ }
+
+ // clear format tags if any
+ _FormatTags.clear();
+ }
+
+ // ***************************************************************************
+ void CViewText::setFontSize (sint nFontSize)
+ {
+ _FontSize = nFontSize + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
+ computeFontSize ();
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ sint CViewText::getFontSize() const
+ {
+ return _FontSize - CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
+ }
+
+ // ***************************************************************************
+ void CViewText::setColor(const NLMISC::CRGBA & color)
+ {
+ _Color = color;
+ }
+
+ // ***************************************************************************
+ void CViewText::setShadow (bool bShadow)
+ {
+ _Shadow = bShadow;
+ computeFontSize ();
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ void CViewText::setShadowColor(const NLMISC::CRGBA & color)
+ {
+ _ShadowColor = color;
+ }
+
+ // ***************************************************************************
+ void CViewText::setLineMaxW (sint nMaxW, bool invalidate)
+ {
+ if(_LineMaxW!=nMaxW)
+ {
+ _LineMaxW = nMaxW;
+ if (invalidate)
+ invalidateContent();
+ }
+ }
+
+ // ***************************************************************************
+ int CViewText::luaSetLineMaxW(CLuaState &ls)
+ {
+ CLuaIHM::checkArgCount(ls, "setLineMaxW", 1);
+ sint32 value;
+ if(CLuaIHM::popSINT32(ls, value))
+ {
+ setLineMaxW(value);
+ }
+ return 0;
+ }
+
+ // ***************************************************************************
+ void CViewText::setMultiLine (bool bMultiLine)
+ {
+ _MultiLine = bMultiLine;
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ void CViewText::setMultiLineSpace (sint nMultiLineSpace)
+ {
+ _MultiLineSpace = nMultiLineSpace;
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ void CViewText::setMultiLineMaxWOnly (bool state)
+ {
+ _MultiLineMaxWOnly = state;
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ void CViewText::setMultiLineClipEndSpace (bool state)
+ {
+ _MultiLineClipEndSpace= state;
+ invalidateContent();
+ }
+
+ // ***************************************************************************
+ uint CViewText::getFontWidth() const
+ {
+ return _FontWidth;
+ }
+
+ // ***************************************************************************
+ uint CViewText::getFontHeight() const
+ {
+ return _FontHeight;
+ }
+
+ // ***************************************************************************
+ uint CViewText::getFontLegHeight() const
+ {
+ return _FontLegHeight;
+ }
+
+ // ***************************************************************************
+ void CViewText::flushWordInLine(ucstring &ucCurrentWord, bool &linePushed, const CFormatInfo &wordFormat)
+ {
+ // create a new line?
+ if(!linePushed)
+ {
+ _Lines.push_back(TLineSPtr(new CLine));
+ linePushed= true;
+ }
+ // Append to the last line
+ _Lines.back()->addWord(ucCurrentWord, 0, wordFormat, _FontWidth);
+ // reset the word
+ ucCurrentWord = ucstring("");
+ }
+
+
+ // ***************************************************************************
+ void CViewText::updateTextContextMultiLine(uint nMaxWidth)
+ {
+ ucchar ucLetter;
+ UTextContext::CStringInfo si;
+ uint i;
+ // word state
+ ucstring ucCurrentWord;
+ CFormatInfo wordFormat;
+ // line state
+ float rWidthCurrentLine = 0, rWidthLetter;
+ bool linePushed= false;
+ // for all the text
+ uint textSize= (uint)_Text.size();
+ uint formatTagIndex= 0;
+ for (i = 0; i < textSize; ++i)
+ {
+ if(isFormatTagChange(i, formatTagIndex))
+ {
+ // If the word was not empty before this color tag
+ if(!ucCurrentWord.empty())
+ flushWordInLine(ucCurrentWord, linePushed, wordFormat);
+
+ // get new color and skip ctIndex.
+ getFormatTagChange(i, formatTagIndex, wordFormat);
+
+ // Ensure the line witdh count the tab
+ rWidthCurrentLine= max(rWidthCurrentLine, (float)wordFormat.TabX*_FontWidth);
+ }
+
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+
+ // Parse the letter
+ {
+ ucLetter = _Text[i];
+ if (ucLetter == ucchar('\n'))
+ {
+ flushWordInLine(ucCurrentWord, linePushed, wordFormat);
+ // reset line state
+ linePushed= false;
+ rWidthCurrentLine = 0;
+ }
+ else
+ {
+ ucstring ucStrLetter;
+ ucStrLetter= ucLetter;
+ si = TextContext->getStringInfo (ucStrLetter);
+ rWidthLetter = (si.StringWidth);
+ if ((rWidthCurrentLine + rWidthLetter) > nMaxWidth)
+ {
+ flushWordInLine(ucCurrentWord, linePushed, wordFormat);
+
+ // reset line state, and begin with the cut letter
+ linePushed= false;
+ rWidthCurrentLine = rWidthLetter;
+ ucCurrentWord = ucLetter;
+ }
+ else
+ {
+ // Grow the current word
+ ucCurrentWord += ucLetter;
+ rWidthCurrentLine += rWidthLetter;
+ }
+ }
+ }
+ }
+ if (ucCurrentWord.length())
+ {
+ flushWordInLine(ucCurrentWord, linePushed, wordFormat);
+ }
+ }
+
+
+ // ***************************************************************************
+ void CViewText::addDontClipWordLine(std::vector &currLine)
+ {
+ // create a new line
+ _Lines.push_back(TLineSPtr(new CLine));
+
+ // Fill it with words. if all words of same color, create only one CWord
+ if (!currLine.empty())
+ {
+ CFormatInfo lineWordFormat= currLine[0].Format;
+ ucstring lineWord;
+ for(uint i=0;iaddWord(lineWord, 0, lineWordFormat, _FontWidth);
+ // get new lineWordFormat
+ lineWordFormat= currLine[i].Format;
+ // and clear
+ lineWord.clear();
+ }
+
+ // Append the word with space to the lineWord.
+ ucstring blank;
+ blank.resize(currLine[i].NumSpaces, (ucchar) ' ');
+ lineWord += blank;
+ lineWord += currLine[i].Text;
+ }
+
+ if(!lineWord.empty())
+ _Lines.back()->addWord(lineWord, 0, lineWordFormat, _FontWidth);
+
+ // clear
+ currLine.clear();
+ }
+ }
+
+ // ***************************************************************************
+ void CViewText::updateTextContextMultiLineJustified(uint nMaxWidth, bool expandSpaces)
+ {
+ UTextContext::CStringInfo si;
+ //
+ TCharPos currPos = 0;
+ //
+ static const ucstring spaceStr(" ");
+ // precLineWidth valid only id precedent line is part of same paragraph.
+ float precLineWidth= 0;
+ float lineWidth = (float)_FirstLineX; // width of the current line
+ uint numWordsInLine = 0; // number of words in the current line
+ bool isParagraphStart = true; // A paragraph is a group of characters between 2 \n
+ bool lineFeed;
+ bool breakLine;
+ //
+ vector currLine; // if spaces are not expanded, all words of a line are inserted here (NB: index and stringInfo not filled)
+ ucstring wordValue;
+ CFormatInfo wordFormat;
+ uint formatTagIndex= 0;
+ //
+ while (currPos != _Text.length())
+ {
+ TCharPos spaceEnd;
+ TCharPos wordEnd;
+ uint numSpaces;
+ float newLineWidth;
+ breakLine = false;
+ //
+ if (_Text[currPos] == (ucchar) '\n')
+ {
+ lineFeed = true;
+ }
+ else
+ {
+ lineFeed = false;
+ // Skip spaces and count them
+ spaceEnd = _Text.find_first_not_of(spaceStr, currPos);
+ if (spaceEnd == std::string::npos)
+ {
+ spaceEnd = _Text.length();
+ }
+ numSpaces = (uint) (spaceEnd - currPos);
+ if (!isParagraphStart && numSpaces != 0 && numWordsInLine == 0) // Are these the first spaces of the line ?
+ {
+ if (!_Lines.empty())
+ {
+ /* Yoyo: I changed this (added the "cut space"), because in editBox, it is so strange when
+ the word hit the end of line, and if you add spaces just after, nothing happens because
+ cursor pos is clamped at end of line.
+ */
+ // Cannot put all of thoses spaces to the prec end of line?
+ if(_MultiLineClipEndSpace && precLineWidth + numSpaces * _SpaceWidth > nMaxWidth)
+ {
+ // put some of these spaces at the end of the previous line.
+ sint maxNumSpaces= (sint)floorf((nMaxWidth - precLineWidth) / _SpaceWidth);
+ _Lines.back()->setEndSpaces(maxNumSpaces);
+ // And start the new lines with the remaining spaces.
+ numSpaces-= maxNumSpaces;
+ currPos+= maxNumSpaces;
+ }
+ else
+ {
+ // ok, put all spaces to previous line
+ _Lines.back()->setEndSpaces(numSpaces);
+ currPos = spaceEnd;
+ numSpaces= 0;
+ }
+ if(currPos >=_Text.length())
+ break;
+ }
+ }
+
+ // Detect change of wordFormat at the begining of the word
+ if(isFormatTagChange((uint)spaceEnd, formatTagIndex))
+ {
+ getFormatTagChange((uint)spaceEnd, formatTagIndex, wordFormat);
+ }
+
+ // Get word until a space, a \n, or a FormatTagChange is encountered
+ uint i;
+ for(i= (uint)spaceEnd;i<(uint)_Text.length();i++)
+ {
+ ucchar c= _Text[i];
+ if(c==' ' || c=='\n')
+ break;
+ // If change of color tag, stop the word, but don't take the new color now.
+ if(isFormatTagChange(i, formatTagIndex))
+ break;
+ }
+ wordEnd = i;
+
+
+ // Get the word value.
+ wordValue = _Text.substr(spaceEnd, wordEnd - spaceEnd);
+ // compute width of word
+ si = CViewRenderer::getTextContext()->getStringInfo(wordValue);
+
+ // compute size of spaces/Tab + word
+ newLineWidth = lineWidth + numSpaces * _SpaceWidth;
+ newLineWidth = max(newLineWidth, (float)wordFormat.TabX*_FontWidth);
+ newLineWidth+= si.StringWidth;
+ }
+ //
+ // Does the word go beyond the end of line ?
+ if (!lineFeed && newLineWidth > (float) nMaxWidth)
+ {
+ // Have we enough room for this word on a line ?
+ bool roomForThisWord = (numWordsInLine > 0) || ( (newLineWidth - lineWidth) < (float) nMaxWidth );
+
+ // not enough room for that word
+ // If it is the only word of the line, just split it
+ // Otherwise, scale the spaces between words so that the line as the maximum width
+ if (roomForThisWord)
+ {
+ if (expandSpaces)
+ {
+ nlassert(_Lines.size() > 0);
+ nlassert(_Lines.back()->getNumWords() > 0);
+
+ // Yoyo: if the line has tab, then don't justify
+ if(wordFormat.TabX > 0)
+ _Lines.back()->setSpaceWidth(_SpaceWidth);
+ else
+ {
+ // Scale the width so that the line has the maximum width
+ float roomForSpaces = nMaxWidth - _Lines.back()->getWidthWithoutSpaces();
+ uint startNumSpaces = _Lines.back()->getNumSpaces();
+ if (startNumSpaces != 0)
+ {
+ _Lines.back()->setSpaceWidth(roomForSpaces / startNumSpaces);
+ }
+ else
+ {
+ _Lines.back()->setSpaceWidth(_SpaceWidth);
+ }
+ }
+ }
+ else
+ {
+ breakLine = true;
+ }
+ // we dont change the position in the input string so that the current will be processed on the next line
+
+ }
+ else // it is the only word on the line..
+ {
+ // .. so split it
+ // 1) Check if spaces go beyond the end of line
+ if (numSpaces * _SpaceWidth > nMaxWidth)
+ {
+ uint maxNumSpaces = std::max(1U, (uint) (nMaxWidth / _SpaceWidth));
+ CWord spaceWord; // a word with only spaces in it
+ spaceWord.build (ucstring (""), maxNumSpaces);
+ spaceWord.Format= wordFormat;
+ _Lines.push_back(TLineSPtr(new CLine));
+ _Lines.back()->addWord(spaceWord, _FontWidth);
+ if (expandSpaces)
+ {
+ _Lines.back()->setSpaceWidth(nMaxWidth / (float) maxNumSpaces);
+ }
+ else
+ {
+ _Lines.back()->setSpaceWidth(_SpaceWidth);
+ }
+ currPos = currPos + maxNumSpaces;
+ }
+ else
+ {
+ float px = numSpaces * _SpaceWidth;
+ uint currChar = 0;
+ ucstring oneChar(" ");
+ for(currChar = 0; currChar < wordValue.length(); ++currChar)
+ {
+ oneChar = wordValue[currChar];
+ si = CViewRenderer::getTextContext()->getStringInfo(oneChar);
+ if ((uint) (px + si.StringWidth) > nMaxWidth) break;
+ px += si.StringWidth;
+ }
+ currChar = std::max((uint) 1, currChar); // must fit at least one character otherwise there's an infinite loop
+ wordValue = _Text.substr(spaceEnd, currChar);
+ CWord word;
+ word.build(wordValue, numSpaces);
+ word.Format= wordFormat;
+ _Lines.push_back(TLineSPtr(new CLine));
+ float roomForSpaces = (float) nMaxWidth - word.Info.StringWidth;
+ if (expandSpaces && numSpaces != 0)
+ {
+ _Lines.back()->setSpaceWidth(roomForSpaces / (float) numSpaces);
+ }
+ else
+ {
+ _Lines.back()->setSpaceWidth(0);
+ }
+ _Lines.back()->addWord(word, _FontWidth);
+ currPos = currPos + numSpaces + currChar;
+ }
+ }
+ // reset line
+ numWordsInLine = 0;
+ precLineWidth= lineWidth;
+ lineWidth = 0;
+ isParagraphStart = false;
+ }
+ else if (!lineFeed) // the end of line hasn't been reached
+ {
+ if (expandSpaces)
+ {
+ // add in the current line (and create one if necessary)
+ if (numWordsInLine == 0)
+ {
+ _Lines.push_back(TLineSPtr(new CLine));
+ _Lines.back()->setSpaceWidth(_SpaceWidth);
+ }
+ if (!wordValue.empty() || numSpaces != 0)
+ {
+ CWord word;
+ word.build(wordValue, numSpaces);
+ word.Format= wordFormat;
+ // update line width
+ _Lines.back()->addWord(word, _FontWidth);
+ ++numWordsInLine;
+ }
+ }
+ else
+ {
+ CWord word;
+ // Don't build here, this is used as temp data.
+ word.Text= wordValue;
+ word.NumSpaces= numSpaces;
+ word.Format= wordFormat;
+ // Append to the temp Data.
+ currLine.push_back(word);
+
+ ++numWordsInLine;
+ }
+ lineWidth = newLineWidth;
+ currPos = wordEnd;
+ }
+ else
+ {
+ // '\n' was encountered
+ ++ currPos;
+ isParagraphStart = true;
+ }
+ if (lineFeed || breakLine) // '\n' was encoutered, or a linefeed has been asked
+ {
+ // !expandSpaces => insert minimum words according to word color.
+ if (!expandSpaces)
+ {
+ // Add the new line.
+ addDontClipWordLine(currLine);
+ // LineFeed?
+ if (lineFeed)
+ {
+ _Lines.back()->setLF(true);
+ }
+ }
+ // expandSpaces => just add a empty line.
+ else
+ {
+ if (numWordsInLine == 0)
+ {
+ // if nothing has been inserted in this line, create at least an empty line
+ _Lines.push_back(TLineSPtr(new CLine));
+ }
+ if (lineFeed)
+ {
+ _Lines.back()->setLF(true);
+ }
+ }
+ lineWidth = 0.f;
+ numWordsInLine = 0;
+ }
+ }
+
+ // if current line hasn't been pushed, add it
+ if (!expandSpaces && !currLine.empty())
+ {
+ // Add new line
+ addDontClipWordLine(currLine);
+ }
+
+ // if the text ends with \n, must insert the last line ourself
+ if (!_Text.empty() && _Text[_Text.length() - 1] == (ucchar) '\n')
+ {
+ _Lines.push_back(TLineSPtr(new CLine));
+ }
+ }
+
+
+ // ***************************************************************************
+ void CViewText::updateTextContext ()
+ {
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+
+ // default state
+ _SingleLineTextClamped= false;
+
+ if ((_MultiLine)&&(_Parent != NULL))
+ {
+ sint nMaxWidth = getCurrentMultiLineMaxW();
+ _LastMultiLineMaxW = nMaxWidth;
+ clearLines();
+ if (nMaxWidth <= 0)
+ {
+ // parent size may not be known yet
+ return;
+ }
+ switch(_TextMode)
+ {
+ case ClipWord: updateTextContextMultiLine(nMaxWidth); break;
+ case DontClipWord: updateTextContextMultiLineJustified(nMaxWidth, false); break;
+ case Justified: updateTextContextMultiLineJustified(nMaxWidth, true); break;
+ }
+
+ // Special case for multiline limited in number of lines
+ if ((_Lines.size() > 0) && (_MultiMaxLine > 0) && (_Lines.size() > _MultiMaxLine))
+ {
+ while (_Lines.size() > _MultiMaxLine)
+ {
+ _Lines.back()->clear();
+ _Lines.pop_back();
+ }
+ _Lines.pop_back();
+ CViewText::CLine *endLine = new CViewText::CLine;
+ CViewText::CWord w;
+ w.build(string("..."));
+ endLine->addWord(w, _FontWidth);
+ _Lines.push_back(TLineSPtr(endLine));
+ }
+
+ // Calculate size
+ float rTotalW = 0;
+ for (uint i = 0; i < _Lines.size(); ++i)
+ {
+ rTotalW = std::max(_Lines[i]->getWidth() + ((i==0)?_FirstLineX:0), rTotalW);
+ }
+ _W = (sint)rTotalW;
+ _H = std::max(_FontHeight, uint(_FontHeight * _Lines.size() + std::max(0, sint(_Lines.size()) - 1) * _MultiLineSpace));
+
+ // Compute tooltips size
+ if (_Tooltips.size() > 0)
+ for (uint i=0 ; i<_Lines.size() ; ++i)
+ {
+ for (uint j=0 ; j<_Lines[i]->getNumWords() ; ++j)
+ {
+ CWord word = _Lines[i]->getWord(j);
+ // float w = _Lines[i]->getWidth();
+
+ if (word.Format.IndexTt != -1)
+ {
+ if (_Tooltips.size() > (uint)word.Format.IndexTt)
+ {
+ CCtrlToolTip *pTooltip = _Tooltips[word.Format.IndexTt];
+
+ sint y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i - 1));
+
+ pTooltip->setX(0);
+ pTooltip->setY(y);
+ pTooltip->setW(getCurrentMultiLineMaxW());
+ pTooltip->setH(_FontHeight);
+ }
+ }
+ }
+ }
+ }
+ else // Single line code
+ {
+ if (_Index != 0xFFFFFFFF)
+ TextContext->erase (_Index);
+
+ // Common case: no W clamp
+ _Index = TextContext->textPush (_Text);
+ _Info = TextContext->getStringInfo (_Index);
+ _W = (sint)(_Info.StringWidth);
+
+ // Rare case: clamp W => recompute slowly, cut letters
+ if(_W>_LineMaxW)
+ {
+ TextContext->erase (_Index);
+
+ ucchar ucLetter;
+ UTextContext::CStringInfo si;
+ ucstring ucCurrentLine;
+ ucCurrentLine.reserve(_Text.size());
+ // Append ... to the end of line
+ si = TextContext->getStringInfo (ucstring("..."));
+ float dotWidth= si.StringWidth;
+ float rWidthCurrentLine = 0, rWidthLetter;
+ // for all the text
+ if (_ClampRight)
+ {
+ for (uint i = 0; i < _Text.size(); ++i)
+ {
+ ucLetter= _Text[i];
+ ucstring ucStrLetter;
+ ucStrLetter= ucLetter;
+ si = TextContext->getStringInfo (ucStrLetter);
+ rWidthLetter = (si.StringWidth);
+ if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
+ {
+ break;
+ }
+ else
+ {
+ // Grow the current line
+ ucCurrentLine += ucLetter;
+ rWidthCurrentLine += rWidthLetter;
+ }
+ }
+
+ // Add the dots
+ ucCurrentLine+= "...";
+ }
+ else
+ {
+ for (sint i = (sint)_Text.size() - 1; i >= 0; --i)
+ {
+ ucLetter= _Text[i];
+ ucstring ucStrLetter;
+ ucStrLetter= ucLetter;
+ si = TextContext->getStringInfo (ucStrLetter);
+ rWidthLetter = (si.StringWidth);
+ if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
+ {
+ break;
+ }
+ else
+ {
+ // Grow the current line
+ ucCurrentLine = ucLetter + ucCurrentLine;
+ rWidthCurrentLine += rWidthLetter;
+ }
+ }
+
+ // Add the dots
+ ucCurrentLine = "..." + ucCurrentLine;
+ }
+
+ // And so setup this trunc text
+ _Index = TextContext->textPush (ucCurrentLine);
+ _Info = TextContext->getStringInfo (_Index);
+ _W = (sint)(_Info.StringWidth);
+
+ _SingleLineTextClamped= true;
+ }
+
+ // same height always
+ _H = _FontHeight;
+ }
+
+ _InvalidTextContext= false;
+ }
+
+ // ***************************************************************************
+ void CViewText::updateCoords()
+ {
+ if (_AutoClamp)
+ {
+ CViewBase::updateCoords ();
+ if (_Parent)
+ {
+ CInterfaceGroup *parent = _Parent;
+ // avoid resizing parents to compute the limiter
+ while (parent && (parent->getResizeFromChildW() || parent->isGroupList() ))
+ {
+ // NB nico : the dynamic_cast for CGroupList is bad!!
+ // can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
+ // ...
+ parent = parent->getParent();
+ }
+ if (parent)
+ {
+ if (_ClampRight)
+ {
+ sint32 parentRight = parent->getXReal() + parent->getWReal() - (sint32) _AutoClampOffset;
+ setLineMaxW(std::max((sint32) 0, parentRight - _XReal));
+ }
+ else
+ {
+ sint32 parentLeft = parent->getXReal() + (sint32) _AutoClampOffset;
+ setLineMaxW(std::max((sint32) 0, _XReal + _WReal - parentLeft));
+ }
+ }
+ }
+ }
+
+ if(_InvalidTextContext)
+ updateTextContext();
+
+ CViewBase::updateCoords ();
+ }
+
+ // ***************************************************************************
+ sint CViewText::getLineFromIndex(uint index, bool cursorDisplayedAtEndOfPreviousLine /* = true*/) const
+ {
+ if (index > _Text.length()) return -1;
+ if (_MultiLine)
+ {
+ uint charIndex = 0;
+ for(sint i = 0; i < (sint) _Lines.size(); ++i)
+ {
+ CLine &currLine = *_Lines[i];
+ uint newCharIndex = charIndex + currLine.getNumChars() + currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
+ if (newCharIndex > index)
+ {
+ if (i != 0 && cursorDisplayedAtEndOfPreviousLine && charIndex == index)
+ {
+ return i - 1;
+ }
+ else
+ {
+ return i;
+ }
+ }
+ charIndex = newCharIndex;
+ }
+ return (sint)_Lines.size() - 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // ***************************************************************************
+ sint CViewText::getLineStartIndex(uint line) const
+ {
+ uint charIndex = 0;
+ if (line >= _Lines.size()) return -1;
+ for(uint i = 0; i < line; ++i)
+ {
+ CLine &currLine = *_Lines[i];
+ charIndex += currLine.getNumChars() + currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
+ }
+ // skip all spaces at start of line (unless there are only spaces in the line)
+ std::string::size_type nextPos = _Text.find_first_not_of((ucchar) ' ', charIndex);
+ if (nextPos != std::string::npos)
+ {
+ if (getLineFromIndex(charIndex) == (sint) line)
+ {
+ return (sint) nextPos;
+ }
+ }
+ return charIndex;
+ }
+
+ // ***************************************************************************
+ void CViewText::getLineEndIndex(uint line, sint &index, bool &endOfPreviousLine) const
+ {
+ sint startIndex = getLineStartIndex(line);
+ if (startIndex == -1)
+ {
+ index = -1;
+ endOfPreviousLine = false;
+ return;
+ }
+ index = startIndex + _Lines[line]->getNumChars() + _Lines[line]->getEndSpaces();
+ endOfPreviousLine = !_Lines[line]->getLF();
+ }
+
+ // ***************************************************************************
+ void CViewText::setHardText (const std::string &ht)
+ {
+ // ucstring Text = ucstring(ht);
+ ucstring Text;
+ if ((ht.size()>2) && (ht[0] == 'u') && (ht[1] == 'i'))
+ Text = CI18N::get (ht);
+ else
+ Text.fromUtf8(ht);
+ setText(Text);
+ }
+
+ // ***************************************************************************
+ string CViewText::getColorAsString() const
+ {
+ return NLMISC::toString(_Color.R) + " " + NLMISC::toString(_Color.G) + " " + NLMISC::toString(_Color.B) + " " + NLMISC::toString(_Color.A);
+ }
+
+ // ***************************************************************************
+ void CViewText::setColorAsString(const string &ht)
+ {
+ _Color = convertColor (ht.c_str());
+ }
+
+ // ***************************************************************************
+ NLMISC::CRGBA CViewText::getColorRGBA() const
+ {
+ return _Color;
+ }
+
+ // ***************************************************************************
+ void CViewText::setColorRGBA(NLMISC::CRGBA col)
+ {
+ _Color = col;
+ }
+
+ // ***************************************************************************
+ void CViewText::getCharacterPositionFromIndex(sint index, bool cursorAtPreviousLineEnd, sint &x, sint &y, sint &height) const
+ {
+ NLMISC::clamp(index, 0, (sint) _Text.length());
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+ // CViewRenderer &rVR = *CViewRenderer::getInstance();
+ height = getFontHeight();
+ //
+ if (_MultiLine)
+ {
+ uint charIndex = 0;
+ // special case for end of text
+ if (index == (sint) _Text.length())
+ {
+ y = 0;
+ if (_Lines.empty())
+ {
+ x = 0;
+ }
+ else
+ {
+ CLine &lastLine = *_Lines.back();
+ x = (sint) (lastLine.getWidth() + lastLine.getEndSpaces() * lastLine.getSpaceWidth());
+ sint nMaxWidth = getCurrentMultiLineMaxW();
+ x = std::min(x, nMaxWidth);
+ }
+ return;
+ }
+ for(sint i = 0; i < (sint) _Lines.size(); ++i)
+ {
+ if (i != 0 && charIndex == (uint) index && cursorAtPreviousLineEnd)
+ {
+ // should display the character at the end of previous line
+ CLine &currLine = *_Lines[i - 1];
+ y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i));
+ x = (sint) (currLine.getWidth() + currLine.getEndSpaces() * currLine.getSpaceWidth());
+ sint nMaxWidth = getCurrentMultiLineMaxW();
+ x = std::min(x, nMaxWidth);
+ return;
+ }
+ CLine &currLine = *_Lines[i];
+ uint newCharIndex = charIndex + currLine.getNumChars() + currLine.getEndSpaces() + (_Lines[i]->getLF() ? 1 : 0);
+ if ((sint) newCharIndex > index)
+ {
+ // ok, this line contains the character, now, see which word contains it.
+ y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - 1 - i));
+ // see if the index is in the spaces at the end of line
+ if (index - charIndex >= currLine.getNumChars())
+ {
+ uint numSpaces = index - charIndex - currLine.getNumChars();
+ x = (sint) (currLine.getWidth() + numSpaces * _SpaceWidth);
+ sint nMaxWidth = getCurrentMultiLineMaxW();
+ x = std::min(x, nMaxWidth);
+ return;
+ }
+ // now, search containing word in current line
+ float px = (float)_FirstLineX;
+ for(uint k = 0; k < currLine.getNumWords(); ++k)
+ {
+ CWord &currWord = currLine.getWord(k);
+ if ((sint) (charIndex + currWord.NumSpaces + currWord.Text.length()) >= index)
+ {
+ // character is in currWord or the in spaces preceding it
+ // check if the character is in the word
+ if ((uint) (index - charIndex) > currWord.NumSpaces)
+ {
+ // get the x position
+ ucstring subStr = currWord.Text.substr(0, index - charIndex - currWord.NumSpaces);
+ // compute the size
+ UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
+ x = (sint) (px + si.StringWidth + currWord.NumSpaces * currLine.getSpaceWidth());
+ height = getFontHeight();
+ return;
+ }
+ else
+ {
+ // character is in the spaces preceding the word
+ x = (sint) (px + currLine.getSpaceWidth() * (index - charIndex));
+ height = getFontHeight();
+ return;
+ }
+ }
+ charIndex += (uint)currWord.Text.length() + currWord.NumSpaces;
+ px += currWord.NumSpaces * currLine.getSpaceWidth() + currWord.Info.StringWidth;
+ }
+ }
+ charIndex = newCharIndex;
+ }
+
+ }
+ else
+ {
+ // get the x position
+ ucstring subStr = _Text.substr(0, index);
+ // compute the size
+ UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
+ y = 0;
+ x = (sint) si.StringWidth;
+ }
+ }
+
+ // ***************************************************************************
+ // Tool fct : From a word and a x coordinate, give the matching character index
+ static uint getCharacterIndex(const ucstring &textValue, float x)
+ {
+ float px = 0.f;
+ UTextContext::CStringInfo si;
+ ucstring singleChar(" ");
+ uint i;
+ for (i = 0; i < textValue.length(); ++i)
+ {
+ // get character width
+ singleChar[0] = textValue[i];
+ si = CViewRenderer::getTextContext()->getStringInfo(singleChar);
+ px += si.StringWidth;
+ // the character is at the i - 1 position
+ if (px > x)
+ {
+ // if the half of the character is after the cursor, then prefer select the next one (like in Word)
+ if(px-si.StringWidth/2 < x)
+ i++;
+ break;
+ }
+ }
+ return i;
+ }
+
+ // ***************************************************************************
+ void CViewText::getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &cursorAtPreviousLineEnd) const
+ {
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+
+ // setup the text context
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+ // find the line where the character is
+ // CViewRenderer &rVR = *CViewRenderer::getInstance();
+ uint charPos = 0;
+ if (_MultiLine)
+ {
+ // seek the line
+ float py = 0.f;
+ if (py > y)
+ {
+ index = (uint)_Text.length();
+ cursorAtPreviousLineEnd = false;
+ return;
+ }
+ sint line;
+ for (line = (uint)_Lines.size() - 1; line >= 0; --line)
+ {
+ float newPy = py + _FontHeight + _MultiLineSpace;
+ if (newPy > y)
+ {
+ break;
+ }
+ py = newPy;
+ }
+ if (line == -1)
+ {
+ index = 0;
+ cursorAtPreviousLineEnd = false;
+ return; // above the first line, so take character 0
+ }
+ // compute character index at start of line
+ sint i;
+ for (i = 0; i < line; ++i)
+ {
+ charPos += _Lines[i]->getNumChars() + _Lines[i]->getEndSpaces() + (_Lines[i]->getLF() ? 1 : 0);
+ }
+ // seek word that contains the character
+ CLine &currLine = *_Lines[line];
+ // See if character is in the ending spaces
+ if (x >= (sint) currLine.getWidth())
+ {
+ // Add _SpaceWidth/2 to select between chars
+ sint numSpaces = _SpaceWidth != 0 ? (sint) (((float) x + _SpaceWidth/2 - currLine.getWidth()) / _SpaceWidth)
+ : 0;
+ clamp(numSpaces, 0, (sint)currLine.getEndSpaces());
+ index = charPos + currLine.getNumChars() + numSpaces;
+ cursorAtPreviousLineEnd = !_Lines[i]->getLF();
+ return;
+ }
+
+ float px = (float)_FirstLineX;
+ for(uint k = 0; k < currLine.getNumWords(); ++k)
+ {
+ CWord &currWord = currLine.getWord(k);
+ float spacesWidth = currLine.getSpaceWidth() * currWord.NumSpaces;
+ float newPx = px + currWord.Info.StringWidth + spacesWidth;
+ if (newPx >= x) // if the word contains the x position..
+ {
+ if (x < (px + spacesWidth))
+ {
+ // the coords x is in the spaces that are preceding the word
+ // Add spaceWidth/2 to select between chars
+ sint numSpaces = currLine.getSpaceWidth() != 0 ? (sint) ((x + currLine.getSpaceWidth()/2 - px) / currLine.getSpaceWidth())
+ : 0;
+ clamp(numSpaces, 0, (sint)currWord.NumSpaces);
+ index = numSpaces + charPos;
+ cursorAtPreviousLineEnd = false;
+ return;
+ }
+ else
+ {
+ // the coord is in the word itself
+ index = charPos + currWord.NumSpaces + getCharacterIndex(currWord.Text, (float) x - (px + spacesWidth));
+ cursorAtPreviousLineEnd = false;
+ return;
+ }
+ }
+ px = newPx;
+ charPos += (uint)currWord.Text.length() + currWord.NumSpaces;
+ }
+ index = charPos;
+ cursorAtPreviousLineEnd = false;
+ return;
+ }
+ else
+ {
+ cursorAtPreviousLineEnd = false;
+ if (y < 0)
+ {
+ index = (uint)_Text.length();
+ return;
+ }
+ if (y > (sint) _FontHeight)
+ {
+ index = 0;
+ return;
+ }
+ index = getCharacterIndex(_Text, (float) x);
+ return;
+ }
+ }
+
+ // ***************************************************************************
+ void CViewText::enableStringSelection(uint start, uint end)
+ {
+ _TextSelection= true;
+ _TextSelectionStart= start;
+ _TextSelectionEnd= end;
+ }
+
+ // ***************************************************************************
+ void CViewText::disableStringSelection()
+ {
+ _TextSelection= false;
+ _TextSelectionStart= 0;
+ _TextSelectionEnd= std::numeric_limits::max();
+ }
+
+ // ***************************************************************************
+ void CViewText::setStringSelectionSkipingSpace(uint stringId, const ucstring &text, sint charStart, sint charEnd)
+ {
+ sint quadStart= charStart;
+ sint quadSize= charEnd-charStart;
+ sint j;
+ for(j=0;jsetStringSelection(stringId, quadStart, quadSize);
+ }
+
+ // ***************************************************************************
+ void CViewText::clearLines()
+ {
+ for(uint k = 0; k < _Lines.size(); ++k)
+ {
+ _Lines[k]->clear();
+ }
+ _Lines.clear();
+ }
+
+ // ***************************************************************************
+ uint CViewText::getNumLine() const
+ {
+ if (_MultiLine)
+ {
+ return (uint)_Lines.size();
+ }
+ else
+ {
+ return _Text.empty() ? 0 : 1;
+ }
+ }
+
+ // ***************************************************************************
+ uint CViewText::getFirstLineX() const
+ {
+ return _FirstLineX;
+ }
+
+ // ***************************************************************************
+ uint CViewText::getLastLineW () const
+ {
+ if (!_Lines.empty())
+ return (uint)_Lines.back()->getWidth();
+ return 0;
+ }
+
+ // ***************************************************************************
+ void CViewText::setFirstLineX(uint firstLineX)
+ {
+ _FirstLineX = firstLineX;
+ }
+
+ /////////////////////////////////////
+ // CViewText::CLine implementation //
+ /////////////////////////////////////
+
+ // ***************************************************************************
+ CViewText::CLine::CLine() : _NumChars(0),
+ _NumSpaces(0),
+ _SpaceWidth(0.f),
+ _StringLine(0),
+ _WidthWithoutSpaces(0.f),
+ _EndSpaces(0),
+ _HasLF(false)
+ {
+ }
+
+ // ***************************************************************************
+ void CViewText::CLine::addWord(const ucstring &text, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth)
+ {
+ CWord word;
+ word.build(text, numSpaces);
+ word.Format= wordFormat;
+ addWord(word, fontWidth);
+ }
+
+ // ***************************************************************************
+ void CViewText::CLine::addWord(const CWord &word, uint fontWidth)
+ {
+ _Words.push_back(word);
+ _NumChars += word.NumSpaces + uint(word.Text.length());
+ _NumSpaces += word.NumSpaces;
+ if (fabsf(word.Info.StringLine) > fabsf(_StringLine))
+ {
+ _StringLine = word.Info.StringLine;
+ }
+ // the width of the line must reach at least the Tab
+ _WidthWithoutSpaces= max(_WidthWithoutSpaces, word.Format.TabX * float(fontWidth));
+ // append the text space
+ _WidthWithoutSpaces += word.Info.StringWidth;
+ }
+
+ // ***************************************************************************
+ void CViewText::CLine::clear()
+ {
+ for(uint k = 0; k < _Words.size(); ++k)
+ {
+ if (_Words[k].Index != 0xffffffff)
+ CViewRenderer::getTextContext()->erase(_Words[k].Index);
+ }
+ _Words.clear();
+ _NumChars = 0;
+ _SpaceWidth = 0.f;
+ }
+
+ // ***************************************************************************
+ void CViewText::CLine::resetTextIndex()
+ {
+ for(uint k = 0; k < _Words.size(); ++k)
+ {
+ _Words[k].Index = 0xffffffff;
+ }
+ }
+
+ // ***************************************************************************
+ void CViewText::CWord::build(const ucstring &text, uint numSpaces/*=0*/)
+ {
+ Text = text;
+ NumSpaces = numSpaces;
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+ Index = TextContext->textPush(text);
+ Info = TextContext->getStringInfo(Index);
+ }
+
+ // ***************************************************************************
+ void CViewText::removeEndSpaces()
+ {
+ sint i = (sint)_Text.size()-1;
+ while ((i>=0) && ((_Text[i] < 0x20) || (_Text[i] == ' ')))
+ {
+ i--;
+ }
+ _Text.resize (i+1);
+ }
+
+ // ***************************************************************************
+ sint32 CViewText::getMaxUsedW() const
+ {
+ static const ucstring spaceStr(" \t");
+ static const ucstring lineFeedStr("\n");
+ float maxWidth = 0;
+
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+
+ TCharPos linePos = 0;
+ while (linePos < _Text.length())
+ {
+ // Get the end of the line
+ float lineWidth = 0;
+ TCharPos lineEnd;
+ lineEnd = _Text.find_first_of(lineFeedStr, linePos);
+ if (lineEnd == std::string::npos)
+ {
+ lineEnd = _Text.length();
+ }
+
+ ucstring lineValue;
+ lineValue = _Text.substr(linePos, lineEnd - linePos);
+
+ TCharPos currPos = 0;
+ while (currPos != lineValue.length())
+ {
+ TCharPos spaceEnd;
+ TCharPos wordEnd;
+ uint numSpaces;
+
+ // Skip spaces and count them
+ spaceEnd = lineValue.find_first_not_of(spaceStr, currPos);
+ if (spaceEnd == std::string::npos)
+ {
+ spaceEnd = lineValue.length();
+ }
+ numSpaces = (uint) (spaceEnd - currPos);
+
+ // Get word until a space or a \n is encountered
+ wordEnd = lineValue.find_first_of(spaceStr, spaceEnd);
+ if (wordEnd == std::string::npos)
+ {
+ wordEnd = lineValue.length();
+ }
+
+ ucstring wordValue;
+ wordValue = lineValue.substr(spaceEnd, wordEnd - spaceEnd);
+
+ // compute width of word
+ UTextContext::CStringInfo si;
+ si = TextContext->getStringInfo(wordValue);
+
+ // compute size of spaces + word
+ lineWidth += numSpaces * _SpaceWidth + si.StringWidth;
+
+ currPos = wordEnd;
+ }
+
+ // Update line width
+ if (lineWidth > maxWidth)
+ maxWidth = lineWidth;
+
+ linePos = lineEnd+1;
+ }
+
+ return (sint32)maxWidth;
+ }
+
+ // ***************************************************************************
+ sint32 CViewText::getMinUsedW() const
+ {
+ static const ucstring spaceOrLineFeedStr(" \n\t");
+ sint32 maxWidth = 0;
+
+ // Not multi line ? Same size than min
+ if (!_MultiLine)
+ return getMaxUsedW();
+
+ // If we can clip word, size of the largest word
+ if (_TextMode == ClipWord)
+ {
+ // No largest font parameter, return the font height
+ return _FontHeight;
+ }
+ // If we can't clip the words, return the size of the largest word
+ else if ((_TextMode == DontClipWord) || (_TextMode == Justified))
+ {
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+
+ // Current position in text
+ TCharPos currPos = 0;
+ while (currPos < _Text.length())
+ {
+ // Current word
+ ucstring wordValue;
+ UTextContext::CStringInfo si;
+ TCharPos wordEnd;
+
+ // Get word until a space or a \n is encountered
+ currPos = _Text.find_first_not_of(spaceOrLineFeedStr, currPos);
+ if (currPos == std::string::npos)
+ break;
+ wordEnd = _Text.find_first_of(spaceOrLineFeedStr, currPos);
+ if (wordEnd == std::string::npos)
+ wordEnd = _Text.length();
+
+ // Get the word
+ wordValue = _Text.substr(currPos, wordEnd - currPos);
+
+ // Compute width of word
+ si = TextContext->getStringInfo(wordValue);
+
+ // Larger ?
+ sint32 stringWidth = (sint32)si.StringWidth;
+ if (stringWidth>maxWidth)
+ maxWidth = stringWidth;
+
+ // Next word
+ currPos = wordEnd;
+ }
+ }
+
+ return maxWidth;
+ }
+
+ // ***************************************************************************
+ void CViewText::onInvalidateContent()
+ {
+ _InvalidTextContext= true;
+ invalidateCoords();
+ }
+
+ // ***************************************************************************
+ void CViewText::computeFontSize ()
+ {
+ NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
+ TextContext->setHotSpot (UTextContext::BottomLeft);
+ TextContext->setShaded (_Shadow);
+ TextContext->setFontSize (_FontSize);
+
+ // Letter size
+ UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); // for now we can't now that directly from UTextContext
+ _FontHeight = (uint) si.StringHeight + (_Shadow?1:0);
+ _FontLegHeight = (uint) si.StringLine + (_Shadow?1:0);
+
+ // Space width
+ si = TextContext->getStringInfo(ucstring(" "));
+ _SpaceWidth = si.StringWidth;
+
+ // Font Width
+ si = TextContext->getStringInfo(ucstring("_"));
+ _FontWidth = (uint)si.StringWidth;
+ }
+
+
+ // ***************************************************************************
+ static inline bool isColorTag(const ucstring &s, uint index, uint textSize)
+ {
+ // Format is @{RGBA}
+ if(s[index]=='@')
+ {
+ if( textSize>index+1 && s[index+1]=='{')
+ {
+ // verify 1st letter is a xdigit
+ if( textSize>index+2 && isxdigit(s[index+2]))
+ {
+ // We have good chance its a color tag. Do last verification
+ if(textSize>index+6 && s[index+6]=='}')
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // ***************************************************************************
+ // isColorTag must be ok.
+ static inline CRGBA getColorTag(const ucstring &s, uint &index)
+ {
+ // extract the color string: "FABC"
+ char tmpCol[5];
+ for(uint i=0;i<4;i++)
+ tmpCol[i]= (char)s[index+2+i];
+ tmpCol[4]= 0;
+
+ // Convert to color
+ CRGBA color;
+ uint pCol;
+ sscanf(tmpCol, "%x", &pCol);
+ // Transform 4 bits to 8 bit.
+ color.R= (pCol>>12)&0xF; color.R+= color.R<<4;
+ color.G= (pCol>>8)&0xF; color.G+= color.G<<4;
+ color.B= (pCol>>4)&0xF; color.B+= color.B<<4;
+ color.A= (pCol)&0xF; color.A+= color.A<<4;
+
+ // skip tag
+ index+= 7;
+
+ return color;
+ }
+
+
+ // ***************************************************************************
+ const uint MaxTabDigit= 3;
+ static inline bool isTabTag(const ucstring &s, uint index, uint textSize)
+ {
+ // Format is @{Tvalue}, where value ,1,2,3 digit.
+ if(s[index]=='@')
+ {
+ if( textSize>index+1 && s[index+1]=='{')
+ {
+ if( textSize>index+2 && s[index+2]=='T')
+ {
+ // We have good chance its a Tab tag. Do last verification
+ for(uint i=4;i<4+MaxTabDigit;i++)
+ {
+ if(textSize>index+i && s[index+i]=='}')
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // ***************************************************************************
+ // isTabTag must be ok.
+ static inline sint getTabTag(const ucstring &s, uint &index)
+ {
+ // extract the tab min X value
+ char tmpTab[MaxTabDigit+1];
+ uint i;
+ for(i=0;iindex+1 && s[index+1]=='{')
+ {
+ if( textSize>index+2 && s[index+2]=='H')
+ {
+ uint i = 3;
+ while (textSize>index+i && s[index+i]!='}')
+ i++;
+
+ if (textSize>index+i && s[index+i]=='}')
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // ***************************************************************************
+ // isTooltipTag must be ok.
+ static inline ucstring getTooltipTag(const ucstring &s, uint &index)
+ {
+ ucstring result;
+ uint i = 3;
+ while (s[index+i] != '}')
+ {
+ result += s[index+i];
+ i++;
+ }
+
+ // skip tag
+ index += i+1;
+
+ return result;
+ }
+
+
+ // ***************************************************************************
+ void CViewText::buildFormatTagText(const ucstring &text, ucstring &textBuild, std::vector &formatTags, std::vector &tooltips)
+ {
+ formatTags.clear();
+ tooltips.clear();
+
+ // Build the text without the formatTags, and get the color tags separately
+ textBuild.reserve(text.size());
+ uint textSize= (uint)text.size();
+ // Must herit all the props from old tags.
+ CViewText::CFormatTag precTag; // set default.
+ precTag.Index = 0;
+ for (uint i = 0; i < textSize;)
+ {
+ if(isColorTag(text, i, textSize))
+ {
+ // get old tag.
+ CViewText::CFormatTag ct= precTag;
+ // get new color and skip tag.
+ ct.Color= getColorTag(text, i);
+ ct.Index= (uint)textBuild.size();
+ formatTags.push_back(ct);
+ }
+ else if(isTabTag(text, i, textSize))
+ {
+ // get old tag.
+ CViewText::CFormatTag ct= precTag;
+ // get new Tab and skip tag.
+ ct.TabX= getTabTag(text, i);
+ ct.Index= (uint)textBuild.size();
+ formatTags.push_back(ct);
+ }
+ else if(isTooltipTag(text, i, textSize))
+ {
+ // get old tag.
+ CViewText::CFormatTag ct= precTag;
+ // get new Tab and skip tag.
+ ucstring uitt = getTooltipTag(text, i);
+ if (uitt.empty())
+ {
+ ct.IndexTt= -1;
+ }
+ else
+ {
+ ct.IndexTt= (uint)tooltips.size();
+ tooltips.push_back(uitt);
+ }
+
+ ct.Index= (uint)textBuild.size();
+ formatTags.push_back(ct);
+ }
+ else
+ {
+ bool lineFeed= text[i]=='\n';
+
+ // append to textBuild
+ textBuild+= text[i];
+ ++i;
+
+ // if \n, reset tabulations
+ if(lineFeed)
+ {
+ CViewText::CFormatTag ct= precTag;
+ ct.TabX= 0;
+ ct.Index= (uint)textBuild.size();
+ formatTags.push_back(ct);
+ }
+ }
+ // bkup
+ if(!formatTags.empty())
+ precTag= formatTags.back();
+ }
+ }
+
+
+ // ***************************************************************************
+ void CViewText::setTextFormatTaged(const ucstring &text)
+ {
+
+ // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
+ ucstring tempText;
+ // static to avoid reallocation
+ static std::vector tempFormatTags;
+ static std::vector tempTooltips;
+ buildFormatTagText(text, tempText, tempFormatTags, tempTooltips);
+ setCase (tempText, _CaseMode);
+
+ // compare Tag arrays
+ bool sameTagArray= false;
+ if(_FormatTags.size()==tempFormatTags.size())
+ {
+ sameTagArray= true;
+ for(uint i=0;i<_FormatTags.size();i++)
+ {
+ if(!_FormatTags[i].sameTag(tempFormatTags[i]))
+ {
+ sameTagArray= false;
+ break;
+ }
+ }
+ }
+
+ // test transformed text with current one
+ if(tempText!=_Text || !sameTagArray )
+ {
+ // copy tags
+ _FormatTags= tempFormatTags;
+ // Copy to Text (preserve Memory)
+ contReset(_Text);
+ _Text= tempText;
+
+ CInterfaceGroup *parent = getParent();
+
+ // Delete old dynamic tooltips
+ for (uint i=0 ; i<_Tooltips.size() ; ++i)
+ {
+ if (parent)
+ parent->delCtrl(_Tooltips[i]);
+ else
+ delete _Tooltips[i];
+ }
+ _Tooltips.clear();
+
+ // Add new dynamic tooltips
+ for (uint i=0 ; isetId(_Id+"_tt"+toString(i));
+ pTooltip->setAvoidResizeParent(avoidResizeParent());
+ pTooltip->setRenderLayer(getRenderLayer());
+ pTooltip->setDefaultContextHelp(CI18N::get(tempTooltips[i].toString()));
+ pTooltip->setParentPos(this);
+ pTooltip->setParentPosRef(Hotspot_BR);
+ pTooltip->setPosRef(Hotspot_BR);
+ pTooltip->setToolTipParent(CCtrlBase::TTWindow);
+ pTooltip->setToolTipParentPosRef(Hotspot_TTAuto);
+ pTooltip->setToolTipPosRef(Hotspot_TTAuto);
+ pTooltip->setActive(true);
+
+ _Tooltips.push_back(pTooltip);
+
+ if (parent)
+ {
+ pTooltip->setParent(parent);
+ parent->addCtrl(_Tooltips.back());
+ }
+ }
+
+ if (parent)
+ _Setuped = true;
+ else
+ _Setuped = false;
+
+ invalidateContent ();
+ }
+
+ // color format is available only if multilined
+ if (!_MultiLine)
+ nlwarning( toString("ViewText isn't multilined : uc_hardtext_format will not act as wanted !\n%s", text.toString().c_str()).c_str() );
+ }
+
+
+ void CViewText::setSingleLineTextFormatTaged(const ucstring &text)
+ {
+ // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
+ ucstring tempText;
+ static std::vector tempLetterColors;
+ static std::vector tempTooltips;
+
+ // parse text
+ buildFormatTagText(text, tempText, tempLetterColors, tempTooltips);
+ setCase (tempText, _CaseMode);
+
+ // decal for spaces (not inserted in VertexBuffer)
+ uint textIndex = 0;
+ uint spacesNb = 0;
+ for(uint i=0; icreateLetterColors();
+ for(uint i=0; ipushLetterColor(formatTag.Index, formatTag.Color);
+ }
+
+ // test transformed text with current one
+ if(tempText!=_Text || !_LetterColors || !_LetterColors->isSameLetterColors(letterColors))
+ {
+ _LetterColors = letterColors;
+
+ TextContext->setLetterColors(letterColors, _Index);
+
+ // Copy to Text (preserve Memory)
+ contReset(_Text);
+ _Text= tempText;
+ invalidateContent ();
+ }
+
+ // this color format is available only if not multilined
+ if (_MultiLine)
+ nlwarning( toString("ViewText is multilined : uc_hardtext_single_line_format will not act as wanted !\n%s", text.toString().c_str()).c_str() );
+ }
+
+
+ // ***************************************************************************
+ bool CViewText::isFormatTagChange(uint textIndex, uint ctIndex) const
+ {
+ if(ctIndex>=_FormatTags.size())
+ return false;
+ // return true if the textIndex is > (eg if some skip with spaces) or = (common case)
+ return _FormatTags[ctIndex].Index <= textIndex;
+ }
+
+ // ***************************************************************************
+ void CViewText::getFormatTagChange(uint textIndex, uint &ctIndex, CFormatInfo &wordFormat) const
+ {
+ // support the possible case with multiple color tags with same textIndex.
+ while(ctIndex<_FormatTags.size() && _FormatTags[ctIndex].Index<=textIndex)
+ {
+ // Take the last tag.
+ wordFormat.Color= _FormatTags[ctIndex].Color;
+ wordFormat.TabX= _FormatTags[ctIndex].TabX;
+ wordFormat.IndexTt= _FormatTags[ctIndex].IndexTt;
+ // skip it.
+ ctIndex++;
+ }
+ }
+
+
+ // ***************************************************************************
+
+ void CViewText::setCaseMode (TCaseMode caseMode)
+ {
+ _CaseMode = caseMode;
+ setCase (_Text, _CaseMode);
+ }
+
+ // ***************************************************************************
+
+ TCaseMode CViewText::getCaseMode () const
+ {
+ return _CaseMode;
+ }
+
+ // ***************************************************************************
+
+ void CViewText::resetTextIndex()
+ {
+ _Index = 0xffffffff;
+ for(uint k = 0; k < _Lines.size(); ++k)
+ _Lines[k]->resetTextIndex();
+ }
+
+ // ***************************************************************************
+ void CViewText::setup()
+ {
+ _Setuped= true;
+
+ // Add dynamic tooltips
+ for (uint i=0 ; i<_Tooltips.size() ; ++i)
+ {
+ CInterfaceGroup *parent = getParent();
+ if (parent)
+ {
+ _Tooltips[i]->setParent(parent);
+ parent->addCtrl(_Tooltips.back());
+ }
+ }
+ }
+
+ // ***************************************************************************
+ void CViewText::serial(NLMISC::IStream &f)
+ {
+ #define SERIAL_UINT(val) { uint32 tmp = (uint32) val; f.serial(tmp); val = (uint) tmp; }
+ #define SERIAL_SINT(val) { sint32 tmp = (sint32) val; f.serial(tmp); val = (sint) tmp; }
+ CViewBase::serial(f);
+ SERIAL_SINT(_FontSize);
+ SERIAL_UINT(_FontWidth);
+ SERIAL_UINT(_FontHeight);
+ SERIAL_UINT(_FontLegHeight);
+ f.serial(_SpaceWidth);
+ f.serial(_Color);
+ f.serial(_Shadow);
+ f.serialEnum(_CaseMode);
+ f.serial(_ShadowColor);
+ f.serial(_LineMaxW);
+ f.serial(_SingleLineTextClamped);
+ f.serial(_MultiLine);
+ f.serial(_MultiLineMaxWOnly);
+ f.serial(_MultiLineClipEndSpace);
+ f.serial(_AutoClampOffset);
+ f.serialEnum(_TextMode);
+ SERIAL_SINT(_MultiLineSpace);
+ SERIAL_SINT(_LastMultiLineMaxW);
+ f.serial(_MultiMaxLine);
+
+ bool hasTag = !_FormatTags.empty();
+ f.serial(hasTag);
+ if (f.isReading())
+ {
+ ucstring text;
+ f.serial(text);
+ if (hasTag)
+ {
+ if (_MultiLine)
+ {
+ setTextFormatTaged(text);
+ }
+ else
+ {
+ setSingleLineTextFormatTaged(text);
+ }
+ }
+ else
+ {
+ setText(text);
+ }
+ }
+ else
+ {
+ f.serial(_Text);
+ }
+
+ #undef SERIAL_UINT
+ #undef SERIAL_SINT
+ }
+
+
+ // ***************************************************************************
+
+}
+
diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp
index 8bf79b805..3b212af7e 100644
--- a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp
+++ b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp
@@ -19,7 +19,7 @@
#include "stdpch.h"
// client
#include "chat_text_manager.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "interface_manager.h"
using namespace std;
diff --git a/code/ryzom/client/src/interface_v3/chat_window.h b/code/ryzom/client/src/interface_v3/chat_window.h
index 8e5da91c2..285116998 100644
--- a/code/ryzom/client/src/interface_v3/chat_window.h
+++ b/code/ryzom/client/src/interface_v3/chat_window.h
@@ -28,12 +28,12 @@
namespace NLGUI
{
class CCtrlBase;
+ class CViewText;
}
class CChatWindow;
class CGroupContainer;
class CGroupEditBox;
-class CViewText;
/** Interface to react to a chat box entry
* Derivers should define the msgEntered member function to handle entry event.
diff --git a/code/ryzom/client/src/interface_v3/ctrl_text_button.cpp b/code/ryzom/client/src/interface_v3/ctrl_text_button.cpp
index efa54d33c..62a82831b 100644
--- a/code/ryzom/client/src/interface_v3/ctrl_text_button.cpp
+++ b/code/ryzom/client/src/interface_v3/ctrl_text_button.cpp
@@ -23,7 +23,7 @@
#include "ctrl_text_button.h"
#include "interface_manager.h"
#include "nel/misc/xml_auto_ptr.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_text_id.h"
#include "group_container.h"
#include "nel/gui/lua_ihm.h"
diff --git a/code/ryzom/client/src/interface_v3/ctrl_text_button.h b/code/ryzom/client/src/interface_v3/ctrl_text_button.h
index 34a93520e..fd90e2d7e 100644
--- a/code/ryzom/client/src/interface_v3/ctrl_text_button.h
+++ b/code/ryzom/client/src/interface_v3/ctrl_text_button.h
@@ -26,10 +26,9 @@
namespace NLGUI
{
class CEventDescriptor;
+ class CViewText;
}
class CInterfaceManager;
-class CViewText;
-
// ***************************************************************************
/**
diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp
index c02b21caf..3f1e81378 100644
--- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp
+++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp
@@ -20,7 +20,7 @@
#include "dbctrl_sheet.h"
#include "interface_manager.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "../sheet_manager.h"
#include "../client_sheets/entity_sheet.h"
#include "../client_sheets/pact_sheet.h"
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.cpp b/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.cpp
index 521fd3605..bfe7e06fe 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.cpp
+++ b/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.cpp
@@ -26,7 +26,7 @@
#include "nel/gui/ctrl_button.h"
#include "group_editbox.h"
#include "../client_cfg.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "skill_manager.h"
#include "../string_manager_client.h"
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.h b/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.h
index 75a162dd5..94af94de9 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.h
+++ b/code/ryzom/client/src/interface_v3/dbgroup_build_phrase.h
@@ -29,6 +29,7 @@
namespace NLGUI
{
class CCtrlBaseButton;
+ class CViewText;
}
@@ -36,7 +37,6 @@ namespace NLGUI
class CDBCtrlSheet;
class CSBrickSheet;
class CViewBitmap;
-class CViewText;
class CGroupEditBox;
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_combo_box.h b/code/ryzom/client/src/interface_v3/dbgroup_combo_box.h
index 90e1a2036..4429c6a13 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_combo_box.h
+++ b/code/ryzom/client/src/interface_v3/dbgroup_combo_box.h
@@ -25,10 +25,10 @@
namespace NLGUI
{
class CCtrlBaseButton;
+ class CViewText;
}
// ***************************************************************************
-class CViewText;
class CGroupMenu;
// ***************************************************************************
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp
index b76ef53fb..fd98d08b9 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp
+++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp
@@ -23,7 +23,7 @@
#include "nel/misc/xml_auto_ptr.h"
#include "../sheet_manager.h"
#include "nel/gui/ctrl_button.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "nel/gui/action_handler.h"
#include "../time_client.h"
#include "game_share/animal_status.h"
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.h b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.h
index f11faabbf..f5d5fdb67 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.h
+++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.h
@@ -25,7 +25,7 @@
#include "nel/misc/types_nl.h"
#include "list_sheet_base.h"
#include "dbctrl_sheet.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
namespace NLGUI
{
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp
index defdeff6c..de7711f69 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp
+++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp
@@ -23,7 +23,7 @@
#include "nel/misc/xml_auto_ptr.h"
#include "../sheet_manager.h"
#include "nel/gui/ctrl_button.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "nel/gui/action_handler.h"
#include "sphrase_manager.h"
#include "game_share/time_weather_season/time_and_season.h"
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_select_number.cpp b/code/ryzom/client/src/interface_v3/dbgroup_select_number.cpp
index 02e44236e..4889fa367 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_select_number.cpp
+++ b/code/ryzom/client/src/interface_v3/dbgroup_select_number.cpp
@@ -21,7 +21,7 @@
#include "dbgroup_select_number.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_bitmap.h"
#include "nel/gui/ctrl_button.h"
#include "nel/gui/interface_property.h"
diff --git a/code/ryzom/client/src/interface_v3/dbgroup_select_number.h b/code/ryzom/client/src/interface_v3/dbgroup_select_number.h
index a02708e87..d6446ee33 100644
--- a/code/ryzom/client/src/interface_v3/dbgroup_select_number.h
+++ b/code/ryzom/client/src/interface_v3/dbgroup_select_number.h
@@ -26,12 +26,12 @@
namespace NLGUI
{
class CCtrlBaseButton;
+ class CViewText;
}
// ***************************************************************************
class CViewBitmap;
-class CViewText;
// ***************************************************************************
diff --git a/code/ryzom/client/src/interface_v3/dbview_number.h b/code/ryzom/client/src/interface_v3/dbview_number.h
index 1c7079f06..602f0e3b9 100644
--- a/code/ryzom/client/src/interface_v3/dbview_number.h
+++ b/code/ryzom/client/src/interface_v3/dbview_number.h
@@ -21,7 +21,7 @@
#include "nel/misc/types_nl.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
// ***************************************************************************
diff --git a/code/ryzom/client/src/interface_v3/dbview_quantity.h b/code/ryzom/client/src/interface_v3/dbview_quantity.h
index 65a12086d..a693a46d3 100644
--- a/code/ryzom/client/src/interface_v3/dbview_quantity.h
+++ b/code/ryzom/client/src/interface_v3/dbview_quantity.h
@@ -21,7 +21,7 @@
#include "nel/misc/types_nl.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
// ***************************************************************************
diff --git a/code/ryzom/client/src/interface_v3/flying_text_manager.cpp b/code/ryzom/client/src/interface_v3/flying_text_manager.cpp
index f8ef9e29c..54b910564 100644
--- a/code/ryzom/client/src/interface_v3/flying_text_manager.cpp
+++ b/code/ryzom/client/src/interface_v3/flying_text_manager.cpp
@@ -20,7 +20,7 @@
#include "flying_text_manager.h"
#include "interface_manager.h"
#include "group_in_scene.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
using namespace std;
diff --git a/code/ryzom/client/src/interface_v3/group_container.cpp b/code/ryzom/client/src/interface_v3/group_container.cpp
index ee6379722..c1efb9c0d 100644
--- a/code/ryzom/client/src/interface_v3/group_container.cpp
+++ b/code/ryzom/client/src/interface_v3/group_container.cpp
@@ -34,7 +34,7 @@
#include "group_list.h"
#include "nel/gui/ctrl_button.h"
#include "nel/gui/ctrl_scroll.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_bitmap.h"
#include "../time_client.h"
diff --git a/code/ryzom/client/src/interface_v3/group_container.h b/code/ryzom/client/src/interface_v3/group_container.h
index 0a79f0931..35c5a851e 100644
--- a/code/ryzom/client/src/interface_v3/group_container.h
+++ b/code/ryzom/client/src/interface_v3/group_container.h
@@ -28,10 +28,10 @@ namespace NLGUI
class CEventDescriptorLocalised;
class CCtrlButton;
class CCtrlScroll;
+ class CViewText;
}
class CInterfaceList;
-class CViewText;
class COptionsContainerInsertion;
class COptionsContainerMove;
class CGroupContainer;
diff --git a/code/ryzom/client/src/interface_v3/group_editbox.cpp b/code/ryzom/client/src/interface_v3/group_editbox.cpp
index 7d51be171..529642288 100644
--- a/code/ryzom/client/src/interface_v3/group_editbox.cpp
+++ b/code/ryzom/client/src/interface_v3/group_editbox.cpp
@@ -22,7 +22,7 @@
#include "interface_manager.h"
#include "input_handler_manager.h"
#include "nel/misc/command.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "nel/misc/xml_auto_ptr.h"
#include "nel/gui/interface_options.h"
#include "dbctrl_sheet.h"
diff --git a/code/ryzom/client/src/interface_v3/group_editbox.h b/code/ryzom/client/src/interface_v3/group_editbox.h
index 99a07c093..1c0a02e68 100644
--- a/code/ryzom/client/src/interface_v3/group_editbox.h
+++ b/code/ryzom/client/src/interface_v3/group_editbox.h
@@ -26,8 +26,8 @@
namespace NLGUI
{
class CEventDescriptor;
+ class CViewText;
}
-class CViewText;
// ----------------------------------------------------------------------------
class CGroupEditBox : public CGroupEditBoxBase
diff --git a/code/ryzom/client/src/interface_v3/group_list.h b/code/ryzom/client/src/interface_v3/group_list.h
index b7fe975d2..94b5d5b7f 100644
--- a/code/ryzom/client/src/interface_v3/group_list.h
+++ b/code/ryzom/client/src/interface_v3/group_list.h
@@ -21,7 +21,7 @@
#include "nel/misc/types_nl.h"
#include "nel/gui/group_frame.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
// ----------------------------------------------------------------------------
diff --git a/code/ryzom/client/src/interface_v3/group_map.h b/code/ryzom/client/src/interface_v3/group_map.h
index d2fa808b7..0521ede20 100644
--- a/code/ryzom/client/src/interface_v3/group_map.h
+++ b/code/ryzom/client/src/interface_v3/group_map.h
@@ -28,7 +28,7 @@
#include "nel/gui/interface_group.h"
#include "nel/gui/ctrl_button.h"
#include "view_bitmap.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "animal_position_state.h"
#include "../continent.h"
//
diff --git a/code/ryzom/client/src/interface_v3/group_menu.h b/code/ryzom/client/src/interface_v3/group_menu.h
index 41bcae76a..8f87f09a6 100644
--- a/code/ryzom/client/src/interface_v3/group_menu.h
+++ b/code/ryzom/client/src/interface_v3/group_menu.h
@@ -22,7 +22,7 @@
#include "nel/gui/interface_group.h"
#include "nel/gui/group_modal.h"
#include "nel/gui/group_submenu_base.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "ctrl_text_button.h"
namespace NLGUI
diff --git a/code/ryzom/client/src/interface_v3/group_paragraph.h b/code/ryzom/client/src/interface_v3/group_paragraph.h
index d73174a90..1366e21a2 100644
--- a/code/ryzom/client/src/interface_v3/group_paragraph.h
+++ b/code/ryzom/client/src/interface_v3/group_paragraph.h
@@ -21,7 +21,7 @@
#include "nel/misc/types_nl.h"
#include "nel/gui/group_frame.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_link.h"
#include "nel/gui/ctrl_button.h"
diff --git a/code/ryzom/client/src/interface_v3/group_phrase_skill_filter.cpp b/code/ryzom/client/src/interface_v3/group_phrase_skill_filter.cpp
index 10f23bb9a..4417509a7 100644
--- a/code/ryzom/client/src/interface_v3/group_phrase_skill_filter.cpp
+++ b/code/ryzom/client/src/interface_v3/group_phrase_skill_filter.cpp
@@ -22,7 +22,7 @@
#include "interface_manager.h"
#include "nel/gui/interface_expr.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "game_share/skills.h"
#include "game_share/brick_families.h"
diff --git a/code/ryzom/client/src/interface_v3/group_scrolltext.cpp b/code/ryzom/client/src/interface_v3/group_scrolltext.cpp
index 89e556870..ea8409475 100644
--- a/code/ryzom/client/src/interface_v3/group_scrolltext.cpp
+++ b/code/ryzom/client/src/interface_v3/group_scrolltext.cpp
@@ -22,7 +22,7 @@
#include "stdpch.h"
#include "group_scrolltext.h"
#include "group_list.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "nel/gui/ctrl_scroll.h"
#include "nel/gui/ctrl_button.h"
#include "nel/gui/action_handler.h"
diff --git a/code/ryzom/client/src/interface_v3/group_skills.cpp b/code/ryzom/client/src/interface_v3/group_skills.cpp
index a4ede0d59..d866a8c5a 100644
--- a/code/ryzom/client/src/interface_v3/group_skills.cpp
+++ b/code/ryzom/client/src/interface_v3/group_skills.cpp
@@ -23,7 +23,7 @@
#include "interface_manager.h"
#include "nel/gui/interface_expr.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_bitmap.h"
#include "dbview_number.h"
#include "dbview_bar.h"
diff --git a/code/ryzom/client/src/interface_v3/group_table.h b/code/ryzom/client/src/interface_v3/group_table.h
index 7c7ac640e..ba14e7039 100644
--- a/code/ryzom/client/src/interface_v3/group_table.h
+++ b/code/ryzom/client/src/interface_v3/group_table.h
@@ -21,7 +21,7 @@
#include "nel/misc/types_nl.h"
#include "nel/gui/group_frame.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_link.h"
#include "nel/gui/ctrl_button.h"
diff --git a/code/ryzom/client/src/interface_v3/group_tree.cpp b/code/ryzom/client/src/interface_v3/group_tree.cpp
index 17c0bff09..4c6d48bb6 100644
--- a/code/ryzom/client/src/interface_v3/group_tree.cpp
+++ b/code/ryzom/client/src/interface_v3/group_tree.cpp
@@ -22,7 +22,7 @@
#include "interface_manager.h"
#include "nel/gui/interface_element.h"
#include "view_bitmap.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "group_container.h"
#include "nel/gui/action_handler.h"
#include "nel/gui/lua_ihm.h"
diff --git a/code/ryzom/client/src/interface_v3/group_tree.h b/code/ryzom/client/src/interface_v3/group_tree.h
index 038db0cf0..5b158f67b 100644
--- a/code/ryzom/client/src/interface_v3/group_tree.h
+++ b/code/ryzom/client/src/interface_v3/group_tree.h
@@ -23,8 +23,12 @@
#include "nel/gui/group_frame.h"
#include "nel/misc/smart_ptr.h"
+namespace NLGUI
+{
+ class CViewText;
+}
+
class CViewBitmap;
-class CViewText;
// ----------------------------------------------------------------------------
class CGroupTree : public CInterfaceGroup
diff --git a/code/ryzom/client/src/interface_v3/guild_manager.cpp b/code/ryzom/client/src/interface_v3/guild_manager.cpp
index ae93f7778..a89387a82 100644
--- a/code/ryzom/client/src/interface_v3/guild_manager.cpp
+++ b/code/ryzom/client/src/interface_v3/guild_manager.cpp
@@ -22,7 +22,7 @@
#include "interface_manager.h"
#include "../string_manager_client.h"
#include "nel/gui/action_handler.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "dbctrl_sheet.h"
#include "group_container.h"
#include "group_menu.h"
diff --git a/code/ryzom/client/src/interface_v3/interface_manager.cpp b/code/ryzom/client/src/interface_v3/interface_manager.cpp
index 1e9ebb20e..9624e1074 100644
--- a/code/ryzom/client/src/interface_v3/interface_manager.cpp
+++ b/code/ryzom/client/src/interface_v3/interface_manager.cpp
@@ -49,7 +49,7 @@
//#include "view_bitmap_progress.h"
#include "view_bitmap_faber_mp.h"
#include "view_bitmap_combo.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
// Ctrl
#include "nel/gui/ctrl_scroll.h"
#include "nel/gui/ctrl_button.h"
diff --git a/code/ryzom/client/src/interface_v3/interface_parser.cpp b/code/ryzom/client/src/interface_v3/interface_parser.cpp
index be1f38175..cec1aeac6 100644
--- a/code/ryzom/client/src/interface_v3/interface_parser.cpp
+++ b/code/ryzom/client/src/interface_v3/interface_parser.cpp
@@ -39,7 +39,7 @@
#include "view_bitmap.h"
#include "view_bitmap_faber_mp.h"
#include "view_bitmap_combo.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_text_formated.h"
#include "view_text_id.h"
#include "view_text_id_formated.h"
diff --git a/code/ryzom/client/src/interface_v3/interface_pointer.h b/code/ryzom/client/src/interface_v3/interface_pointer.h
index e0e193baa..62605d6e3 100644
--- a/code/ryzom/client/src/interface_v3/interface_pointer.h
+++ b/code/ryzom/client/src/interface_v3/interface_pointer.h
@@ -27,6 +27,7 @@ namespace NLGUI
class CCtrlBase;
class CCtrlBaseButton;
class CInterfaceGroup;
+ class CViewText;
}
using namespace NLGUI;
@@ -60,7 +61,7 @@ public:
typedef CInterfacePtr::TInterfacePtr CInterfaceElementPtr;
typedef CInterfacePtr::TInterfacePtr CInterfaceGroupPtr;
typedef CInterfacePtr::TInterfacePtr CCtrlTextButtonPtr;
-typedef CInterfacePtr::TInterfacePtr CViewTextPtr;
+typedef CInterfacePtr::TInterfacePtr CViewTextPtr;
typedef CInterfacePtr::TInterfacePtr CViewTextMenuPtr;
typedef CInterfacePtr::TInterfacePtr CCtrlBasePtr;
typedef CInterfacePtr::TInterfacePtr CCtrlBaseButtonPtr;
diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp
index e1e73deed..3f363258c 100644
--- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp
+++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp
@@ -49,7 +49,7 @@
#include "action_handler_tools.h"
#include "interface_manager.h"
#include "nel/gui/interface_group.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "game_share/people_pd.h"
#include "group_tree.h"
#include "nel/gui/interface_link.h"
diff --git a/code/ryzom/client/src/interface_v3/register_interface_elements.cpp b/code/ryzom/client/src/interface_v3/register_interface_elements.cpp
index d9ac41023..299ff3f4b 100644
--- a/code/ryzom/client/src/interface_v3/register_interface_elements.cpp
+++ b/code/ryzom/client/src/interface_v3/register_interface_elements.cpp
@@ -20,7 +20,7 @@
#include "nel/gui/interface_element.h"
#include "interface_3d_scene.h"
#include "nel/gui/view_base.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
#include "view_text_id.h"
#include "view_bitmap.h"
#include "view_radar.h"
diff --git a/code/ryzom/client/src/interface_v3/view_bitmap_faber_mp.h b/code/ryzom/client/src/interface_v3/view_bitmap_faber_mp.h
index 839286c78..22c7b3e0b 100644
--- a/code/ryzom/client/src/interface_v3/view_bitmap_faber_mp.h
+++ b/code/ryzom/client/src/interface_v3/view_bitmap_faber_mp.h
@@ -24,7 +24,7 @@
///\todo nico : do the real display when item icons are available
-#include "view_text.h"
+#include "nel/gui/view_text.h"
/**
* class used to display mps for faber interface
diff --git a/code/ryzom/client/src/interface_v3/view_link.h b/code/ryzom/client/src/interface_v3/view_link.h
index ba30fafd2..169487a1d 100644
--- a/code/ryzom/client/src/interface_v3/view_link.h
+++ b/code/ryzom/client/src/interface_v3/view_link.h
@@ -19,7 +19,7 @@
#ifndef NL_VIEW_LINK_H
#define NL_VIEW_LINK_H
-#include "view_text.h"
+#include "nel/gui/view_text.h"
/**
* class implementing a link view
diff --git a/code/ryzom/client/src/interface_v3/view_text.cpp b/code/ryzom/client/src/interface_v3/view_text.cpp
deleted file mode 100644
index fc50c1b76..000000000
--- a/code/ryzom/client/src/interface_v3/view_text.cpp
+++ /dev/null
@@ -1,2597 +0,0 @@
-// Ryzom - MMORPG Framework
-// 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 .
-
-#include "nel/misc/bit_mem_stream.h"
-#include "nel/misc/i18n.h"
-
-#include "view_text.h"
-#include "nel/gui/view_renderer.h"
-#include "nel/gui/widget_manager.h"
-#include "nel/gui/group_container_base.h"
-#include "nel/gui/ctrl_tooltip.h"
-#include "nel/misc/xml_auto_ptr.h"
-#include "nel/gui/lua_ihm.h"
-#include "nel/gui/view_pointer_base.h"
-
-using namespace std;
-using namespace NLMISC;
-using namespace NL3D;
-
-typedef std::string::size_type TCharPos; // index of a chracter in a string
-
-REGISTER_UI_CLASS(CViewText)
-
-// ***************************************************************************
-void CViewText::setupDefault ()
-{
- _CaseMode = CaseNormal;
- _Underlined = false;
- _ContinuousUpdate = false;
- _Active = true;
- _X = 0;
- _Y = 0;
- _W = 0;;
- _H = 0;
- _SizeRef = 0;
- _SizeDivW = 10;
- _SizeDivH = 10;
- _ParentPosRef = Hotspot_BL;
- _PosRef = Hotspot_BL;
-
- _FontSize = 12 +
- CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont ).getValSInt32();
- _Color = CRGBA(255,255,255,255);
- _Shadow = false;
- _ShadowColor = CRGBA(0,0,0,255);
-
- _MultiLine = false;
- _TextMode = DontClipWord;
- _MultiLineSpace = 8;
- _LineMaxW = 16384;
- _MultiLineMaxWOnly = false;
- _MultiLineClipEndSpace = false;
- _LastMultiLineMaxW = 0;
- _MultiMaxLine = 0;
- _Index = 0xFFFFFFFF;
-
- _FontWidth= 0;
- _FontHeight = 0;
- _FontLegHeight = 0;
-
- _TextSelection= false;
- _TextSelectionStart= 0;
- _TextSelectionEnd= std::numeric_limits::max();
-
- _InvalidTextContext= true;
- _FirstLineX = 0;
- computeFontSize ();
-
- _SingleLineTextClamped= false;
- _OverExtendViewText= false;
- _OverExtendViewTextUseParentRect= false;
-
- _AutoClamp = false;
- _ClampRight = true; // clamp on the right of the text
-
- _LetterColors = NULL;
- _Setuped= false;
- _AutoClampOffset = 0;
-}
-
-// ***************************************************************************
-
-NLMISC_REGISTER_OBJECT(CViewBase, CViewText, std::string, "text");
-
-CViewText::CViewText(const TCtorParam ¶m)
-:CViewBase(param)
-{
- setupDefault ();
-}
-
-///constructor
-// ***************************************************************************
-CViewText:: CViewText (const std::string& id, const std::string Text, sint FontSize,
- NLMISC::CRGBA Color, bool Shadow)
- :CViewBase(TCtorParam())
-{
- _Id = id;
- setupDefault ();
-
- _FontSize = FontSize + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
- _Color = Color;
- _Shadow = Shadow;
- setText(Text);
- computeFontSize ();
-}
-
-// ***************************************************************************
-CViewText::~CViewText()
-{
- if (_Index != 0xFFFFFFFF)
- CViewRenderer::getTextContext()->erase (_Index);
- clearLines();
-
- if (!_Setuped)
- for (uint i=0 ; i<_Tooltips.size() ; ++i)
- delete _Tooltips[i];
-
- _Tooltips.clear();
-}
-
-// ***************************************************************************
-CViewText &CViewText::operator=(const CViewText &vt)
-{
- if (_Index != 0xFFFFFFFF)
- CViewRenderer::getTextContext()->erase (_Index);
-
- // Create database entries
- _Active = vt._Active;
- _X = vt._X;
- _Y = vt._Y;
- _W = vt._W;
- _H = vt._H;
- _SizeRef = vt._SizeRef;
- _SizeDivW = vt._SizeDivW;
- _SizeDivH = vt._SizeDivH;
- _ParentPosRef = vt._ParentPosRef;
- _PosRef = vt._PosRef;
-
- _FontSize = vt._FontSize;
- _Color = vt._Color;
- _Shadow = vt._Shadow;
- _ShadowColor = vt._ShadowColor;
-
- _MultiLine = false;
- _MultiLineSpace = 8;
- _LineMaxW= 16384;
- _MultiLineMaxWOnly = false;
- _MultiLineClipEndSpace = false;
- _LastMultiLineMaxW = 0;
- _Index = 0xFFFFFFFF;
-
- _ModulateGlobalColor= vt._ModulateGlobalColor;
-
-
- // remove previous lines
- clearLines();
- _InvalidTextContext = true;
- computeFontSize ();
-
- return *this;
-}
-
-// ***************************************************************************
-void CViewText::parseTextOptions (xmlNodePtr cur)
-{
- CXMLAutoPtr prop;
-
- prop= (char*) xmlGetProp( cur, (xmlChar*)"color" );
- _Color = CRGBA(255,255,255,255);
- if (prop)
- _Color = convertColor(prop);
-
- prop= (char*) xmlGetProp (cur, (xmlChar*)"global_color");
- if(prop)
- _ModulateGlobalColor= convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"fontsize" );
- _FontSize = 12 + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
- if (prop)
- {
- fromString((const char*)prop, _FontSize);
- _FontSize += CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
- }
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"shadow" );
- _Shadow = false;
- if (prop)
- _Shadow = convertBool(prop);
-
- prop= (char*) xmlGetProp( cur, (xmlChar*)"shadow_color" );
- _ShadowColor = CRGBA(0,0,0,255);
- if (prop)
- _ShadowColor = convertColor(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line" );
- _MultiLine = false;
- if (prop)
- _MultiLine = convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"justification" );
- if (prop)
- {
- if (nlstricmp("clip_word", (const char *) prop) == 0) _TextMode = ClipWord;
- else if (nlstricmp("dont_clip_word", (const char *) prop) == 0) _TextMode = DontClipWord;
- else if (nlstricmp("justified", (const char *) prop) == 0) _TextMode = Justified;
- else nlwarning(" bad text mode");
- }
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"line_maxw" );
- _LineMaxW = 16384;
- if (prop)
- fromString((const char*)prop, _LineMaxW);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line_space" );
- _MultiLineSpace = 8;
- if (prop)
- fromString((const char*)prop, _MultiLineSpace);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_line_maxw_only" );
- _MultiLineMaxWOnly = false;
- if (prop)
- _MultiLineMaxWOnly = convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"multi_max_line" );
- _MultiMaxLine = 0;
- if (prop)
- fromString((const char*)prop, _MultiMaxLine);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"underlined" );
- _Underlined = false;
- if (prop)
- _Underlined = convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"case_mode" );
- _CaseMode = CaseNormal;
- if (prop)
- {
- sint32 caseMode;
- fromString((const char*)prop, caseMode);
- _CaseMode = (TCaseMode)caseMode;
- }
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"over_extend_view_text" );
- _OverExtendViewText= false;
- if(prop)
- _OverExtendViewText= convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"over_extend_parent_rect" );
- _OverExtendViewTextUseParentRect= false;
- if(prop)
- _OverExtendViewTextUseParentRect= convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"auto_clamp" );
- _AutoClamp = false;
- if (prop)
- _AutoClamp = convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"clamp_right" );
- _ClampRight = true;
- if (prop)
- _ClampRight = convertBool(prop);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"auto_clamp_offset" );
- _AutoClampOffset = 0;
- if (prop)
- fromString((const char*)prop, _AutoClampOffset);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"continuous_update" );
- if (prop)
- {
- _ContinuousUpdate = convertBool(prop);
- }
-
-
- computeFontSize ();
-}
-
-/*
-* parse an xml node and initialize the base view mambers. Must call CViewBase::parse
-* \param cur : pointer to the xml node to be parsed
-* \param parentGroup : the parent group of the view
-* \partam id : a refence to the string that will receive the view ID
-* \return true if success
-*/
-// ***************************************************************************
-bool CViewText::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
-{
-
-// const ucstring* tmp;
- CXMLAutoPtr prop;
- //try to get props that can be inherited from groups
- //if a property is not defined, try to find it in the parent group.
- //if it is undefined, set it to zero
-
- if (! CViewBase::parse(cur,parentGroup) )
- return false;
-
- //set w and h to 0 : they depend on the string contained
- _W = 0;
- _H = 0;
-
- //try to get the NEEDED specific props
- parseTextOptions(cur);
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"hardtext" );
- if (prop)
- {
- const char *propPtr = prop;
- _Text = ucstring(propPtr);
-
- if ((strlen(propPtr)>2) && (propPtr[0] == 'u') && (propPtr[1] == 'i'))
- _Text = CI18N::get (propPtr);
- setCase (_Text, _CaseMode);
- }
-
- prop = (char*) xmlGetProp( cur, (xmlChar*)"hardtext_format" );
- if (prop)
- {
- const char *propPtr = prop;
- if (_MultiLine)
- {
- setTextFormatTaged(CI18N::get(propPtr));
- }
- else
- {
- setSingleLineTextFormatTaged(CI18N::get(propPtr));
- }
- }
-
- invalidateContent ();
-
- return true;
-}
-
-// ***************************************************************************
-sint CViewText::getCurrentMultiLineMaxW() const
-{
- if(_MultiLineMaxWOnly)
- return _LineMaxW;
- else
- {
- sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
- return std::min(parentWidth-(sint)(_XReal-_Parent->getXReal()), (sint)_LineMaxW);
- }
-}
-
-
-// ***************************************************************************
-void CViewText::checkCoords ()
-{
- if ((_MultiLine)&&(_Parent != NULL))
- {
- // If never setuped, and if text is not empty
- if (_Lines.size() == 0 && !_Text.empty())
- invalidateContent ();
-
- sint currentMaxW= getCurrentMultiLineMaxW();
- if ( _LastMultiLineMaxW != currentMaxW )
- {
- if (_ContinuousUpdate)
- {
- _LastMultiLineMaxW = currentMaxW;
- invalidateContent();
- }
- else
- {
- CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
- if (pCB != NULL)
- {
- if( pCB->isResizer() )
- {
- // We are resizing !!!!
- }
- else
- {
- _LastMultiLineMaxW = currentMaxW;
- invalidateContent();
- }
- }
- else
- {
- _LastMultiLineMaxW = currentMaxW;
- invalidateContent();
- }
- }
- }
- }
- else
- {
- if (_Index == 0xFFFFFFFF)
- invalidateContent ();
- }
-}
-/*
-* draw the view
-*/
-// ***************************************************************************
-void CViewText::draw ()
-{
- H_AUTO( RZ_Interface_CViewText_draw )
-
- CViewRenderer &rVR = *CViewRenderer::getInstance();
-
- // *** Out Of Clip?
- sint32 ClipX, ClipY, ClipW, ClipH;
- rVR.getClipWindow (ClipX, ClipY, ClipW, ClipH);
- if (((_XReal) > (ClipX+ClipW)) || ((_XReal+_WReal) < ClipX) ||
- ((_YReal) > (ClipY+ClipH)) || ((_YReal+_HReal) < ClipY))
- return;
-
- // *** Screen Minimized?
- uint32 w, h;
- float oow, ooh;
- rVR.getScreenSize (w, h);
- if (rVR.isMinimized())
- return;
- rVR.getScreenOOSize (oow, ooh);
-
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
-
-
- // *** get current color
- CRGBA col, shcol;
- if(getModulateGlobalColor())
- {
- CRGBA gcfc = CWidgetManager::getInstance()->getGlobalColorForContent();
- col.modulateFromColor (_Color, gcfc);
- shcol.modulateFromColor (_ShadowColor, gcfc);
- }
- else
- {
- col = _Color;
- shcol = _ShadowColor;
- col.A = (uint8)(((sint)col.A*((sint)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
- shcol.A = (uint8)(((sint)shcol.A*((sint)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
- }
-
-
- // *** Draw multiline
- if ((_MultiLine)&&(_Parent != NULL))
- {
- if (_Lines.size() == 0) return;
-
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
-
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setShadeColor (shcol);
- TextContext->setFontSize (_FontSize);
-
- float y = (float)(_YReal) * ooh; // y is expressed in scree, coordinates [0..1]
- //y += _LinesInfos[_LinesInfos.size()-1].StringLine / h;
-
- // Y is the base line of the string, so it must be grown up.
- y += (float)_FontLegHeight * ooh;
-
- sint y_line = _YReal+_FontLegHeight-2;
-
- // special selection code
- if(_TextSelection)
- {
- sint charIndex = 0;
- for (sint i = 0; i<(sint)_Lines.size(); i++)
- {
- CLine &currLine = *_Lines[i];
- for(uint k = 0; k < currLine.getNumWords(); ++k)
- {
- CWord &currWord = currLine.getWord(k);
- charIndex += currWord.NumSpaces;
- sint cStart= max(charIndex, (sint)_TextSelectionStart);
- sint cEnd= min(charIndex+(sint)currWord.Text.length(), (sint)_TextSelectionEnd);
-
- // range must be valid
- if(cStartsetStringSelection(currWord.Index, 0, 0);
- }
-
- // next word
- charIndex+= (sint)currWord.Text.length();
- }
- charIndex += currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
- }
- }
-
- // draw
- for (sint i = (sint)_Lines.size()-1; i >= 0; --i)
- {
- CLine &currLine = *_Lines[i];
- // current x position
- float px = (float) (_XReal + ((i==0) ? (sint)_FirstLineX : 0));
- // draw each words of the line
- for(uint k = 0; k < currLine.getNumWords(); ++k)
- {
- CWord &currWord = currLine.getWord(k);
-
- // Change the current color
- if(currWord.Format.Color==CRGBA::White)
- TextContext->setStringColor(currWord.Index, col);
- else
- {
- CRGBA mCol;
- mCol.modulateFromColor(col, currWord.Format.Color);
- TextContext->setStringColor(currWord.Index, mCol);
- }
-
- // skip spaces before current word
- float firstSpace = currWord.NumSpaces * currLine.getSpaceWidth();
- sint line_width = 0;
- if (_Underlined)
- {
- line_width = (sint)floorf(currLine.getWidthWithoutSpaces() + currLine.getSpaceWidth());
- line_width -= (sint)floorf(firstSpace);
- }
- px += firstSpace;
- // skip tabulation before current word
- if(currWord.Format.TabX)
- px= max(px, (float)(_XReal + currWord.Format.TabX*_FontWidth));
-
- // draw. We take floorf px to avoid filtering of letters that are not located on a pixel boundary
- rVR.drawText (_RenderLayer, floorf(px) * oow, y, currWord.Index, (float)ClipX * oow, (float)ClipY * ooh,
- (float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
-
- // Draw a line
- if (_Underlined)
- rVR.drawRotFlipBitmap (_RenderLayer, (sint)floorf(px), y_line, line_width, 1, 0, false, rVR.getBlankTextureId(), col);
-
- // skip word
- px += currWord.Info.StringWidth;
- }
- // go one line up
- y += (_FontHeight + _MultiLineSpace) * ooh;
- y_line += _FontHeight+_MultiLineSpace;
- }
-
- // reset selection
- if(_TextSelection)
- {
- for (sint i = 0; i<(sint)_Lines.size(); i++)
- {
- CLine &currLine = *_Lines[i];
- for(uint k = 0; k < currLine.getNumWords(); ++k)
- {
- TextContext->resetStringSelection(currLine.getWord(k).Index);
- }
- }
- }
- }
- // *** Single Line Version (currently no support for text justification)
- else
- {
- nlassert(_Index != 0xFFFFFFFF);
-
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setShadeColor (shcol);
- TextContext->setFontSize (_FontSize);
-
-
- if(_LetterColors!=NULL && !TextContext->isSameLetterColors(_LetterColors, _Index))
- {
- TextContext->setLetterColors(_LetterColors, _Index);
- }
-
-
- float x = (float)(_XReal) * oow;
- float y = (float)(_YReal) * ooh;
-
- // Y is the base line of the string, so it must be grown up.
- y += (float)_FontLegHeight * ooh;
-
- // special selection code
- if(_TextSelection)
- // select subset. Arg, must skip spaces because not inserted in VertexBuffer.
- setStringSelectionSkipingSpace(_Index, _Text, _TextSelectionStart, _TextSelectionEnd);
-
- // Change the current color
- TextContext->setStringColor(_Index, col);
-
- // draw
- rVR.drawText (_RenderLayer, x, y, _Index, (float)ClipX * oow, (float)ClipY * ooh,
- (float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
-
- // Draw a line
- if (_Underlined)
- rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_FontLegHeight-2, _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
-
- // reset selection
- if(_TextSelection)
- TextContext->resetStringSelection(_Index);
-
- // if single line clamped, may allow to draw an over
- if(isSingleLineTextClamped() && _OverExtendViewText && CWidgetManager::getInstance()->getPointer())
- {
- // but must check first if mouse is over
- sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
- sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
- bool mouseIn;
- // use parent clip or self clip?
- if(_OverExtendViewTextUseParentRect)
- mouseIn= _Parent && _Parent->isIn(x,y);
- else
- mouseIn= isIn(x,y);
- // if the mouse cursor is in the clip area
- if(mouseIn)
- {
- // check the window under the mouse is the root window
- CInterfaceGroup *pIG = CWidgetManager::getInstance()->getWindowUnder(x,y);
- CInterfaceElement *pParent = this;
- bool bFound = false;
- while (pParent != NULL)
- {
- if (pParent == pIG)
- {
- bFound = true;
- break;
- }
- pParent = pParent->getParent();
- }
-
- // ok => let this view text be the extend over one
- if(bFound)
- {
- // last check: the window must not be currently moved
- CGroupContainerBase *gc= dynamic_cast(pIG);
- if(!gc || !gc->isMoving())
- {
- CRGBA col= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionViewTextOverBackColor).getValColor();
- CWidgetManager::getInstance()->setOverExtendViewText(this, col);
- }
- }
- }
- }
- }
-
-}
-
-// ***************************************************************************
-void CViewText::onAddToGroup()
-{
- // Add tooltips if not done
- if(!_Setuped)
- setup();
-}
-
-// ***************************************************************************
-void CViewText::setTextMode(TTextMode mode)
-{
- if (mode != _TextMode)
- {
- _TextMode = mode;
- invalidateContent ();
- }
-}
-
-// ***************************************************************************
-void CViewText::setText(const ucstring & text)
-{
- // common case: no special format, no case mode => easy cache test
- if (_FormatTags.empty() && _CaseMode==CaseNormal)
- {
- if (text != _Text)
- {
- _Text = text;
- // no need to call "setCase (_Text, _CaseMode);" since CaseNormal:
- invalidateContent ();
- }
- }
- else
- {
- // if the view text had some format before, no choice, must recompute all
- if(!_FormatTags.empty())
- {
- _Text = text;
- setCase (_Text, _CaseMode);
- invalidateContent ();
- }
- // else test if after the case change the cache succeed
- else
- {
- // compute the temp cased text
- ucstring tempText= text;
- setCase(tempText, _CaseMode);
- if(tempText!=_Text)
- {
- _Text = tempText;
- invalidateContent ();
- }
- }
- }
-
- // clear format tags if any
- _FormatTags.clear();
-}
-
-// ***************************************************************************
-void CViewText::setFontSize (sint nFontSize)
-{
- _FontSize = nFontSize + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
- computeFontSize ();
- invalidateContent();
-}
-
-// ***************************************************************************
-sint CViewText::getFontSize() const
-{
- return _FontSize - CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32();
-}
-
-// ***************************************************************************
-void CViewText::setColor(const NLMISC::CRGBA & color)
-{
- _Color = color;
-}
-
-// ***************************************************************************
-void CViewText::setShadow (bool bShadow)
-{
- _Shadow = bShadow;
- computeFontSize ();
- invalidateContent();
-}
-
-// ***************************************************************************
-void CViewText::setShadowColor(const NLMISC::CRGBA & color)
-{
- _ShadowColor = color;
-}
-
-// ***************************************************************************
-void CViewText::setLineMaxW (sint nMaxW, bool invalidate)
-{
- if(_LineMaxW!=nMaxW)
- {
- _LineMaxW = nMaxW;
- if (invalidate)
- invalidateContent();
- }
-}
-
-// ***************************************************************************
-int CViewText::luaSetLineMaxW(CLuaState &ls)
-{
- CLuaIHM::checkArgCount(ls, "setLineMaxW", 1);
- sint32 value;
- if(CLuaIHM::popSINT32(ls, value))
- {
- setLineMaxW(value);
- }
- return 0;
-}
-
-// ***************************************************************************
-void CViewText::setMultiLine (bool bMultiLine)
-{
- _MultiLine = bMultiLine;
- invalidateContent();
-}
-
-// ***************************************************************************
-void CViewText::setMultiLineSpace (sint nMultiLineSpace)
-{
- _MultiLineSpace = nMultiLineSpace;
- invalidateContent();
-}
-
-// ***************************************************************************
-void CViewText::setMultiLineMaxWOnly (bool state)
-{
- _MultiLineMaxWOnly = state;
- invalidateContent();
-}
-
-// ***************************************************************************
-void CViewText::setMultiLineClipEndSpace (bool state)
-{
- _MultiLineClipEndSpace= state;
- invalidateContent();
-}
-
-// ***************************************************************************
-uint CViewText::getFontWidth() const
-{
- return _FontWidth;
-}
-
-// ***************************************************************************
-uint CViewText::getFontHeight() const
-{
- return _FontHeight;
-}
-
-// ***************************************************************************
-uint CViewText::getFontLegHeight() const
-{
- return _FontLegHeight;
-}
-
-// ***************************************************************************
-void CViewText::flushWordInLine(ucstring &ucCurrentWord, bool &linePushed, const CFormatInfo &wordFormat)
-{
- // create a new line?
- if(!linePushed)
- {
- _Lines.push_back(TLineSPtr(new CLine));
- linePushed= true;
- }
- // Append to the last line
- _Lines.back()->addWord(ucCurrentWord, 0, wordFormat, _FontWidth);
- // reset the word
- ucCurrentWord = ucstring("");
-}
-
-
-// ***************************************************************************
-void CViewText::updateTextContextMultiLine(uint nMaxWidth)
-{
- ucchar ucLetter;
- UTextContext::CStringInfo si;
- uint i;
- // word state
- ucstring ucCurrentWord;
- CFormatInfo wordFormat;
- // line state
- float rWidthCurrentLine = 0, rWidthLetter;
- bool linePushed= false;
- // for all the text
- uint textSize= (uint)_Text.size();
- uint formatTagIndex= 0;
- for (i = 0; i < textSize; ++i)
- {
- if(isFormatTagChange(i, formatTagIndex))
- {
- // If the word was not empty before this color tag
- if(!ucCurrentWord.empty())
- flushWordInLine(ucCurrentWord, linePushed, wordFormat);
-
- // get new color and skip ctIndex.
- getFormatTagChange(i, formatTagIndex, wordFormat);
-
- // Ensure the line witdh count the tab
- rWidthCurrentLine= max(rWidthCurrentLine, (float)wordFormat.TabX*_FontWidth);
- }
-
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
-
- // Parse the letter
- {
- ucLetter = _Text[i];
- if (ucLetter == ucchar('\n'))
- {
- flushWordInLine(ucCurrentWord, linePushed, wordFormat);
- // reset line state
- linePushed= false;
- rWidthCurrentLine = 0;
- }
- else
- {
- ucstring ucStrLetter;
- ucStrLetter= ucLetter;
- si = TextContext->getStringInfo (ucStrLetter);
- rWidthLetter = (si.StringWidth);
- if ((rWidthCurrentLine + rWidthLetter) > nMaxWidth)
- {
- flushWordInLine(ucCurrentWord, linePushed, wordFormat);
-
- // reset line state, and begin with the cut letter
- linePushed= false;
- rWidthCurrentLine = rWidthLetter;
- ucCurrentWord = ucLetter;
- }
- else
- {
- // Grow the current word
- ucCurrentWord += ucLetter;
- rWidthCurrentLine += rWidthLetter;
- }
- }
- }
- }
- if (ucCurrentWord.length())
- {
- flushWordInLine(ucCurrentWord, linePushed, wordFormat);
- }
-}
-
-
-// ***************************************************************************
-void CViewText::addDontClipWordLine(std::vector &currLine)
-{
- // create a new line
- _Lines.push_back(TLineSPtr(new CLine));
-
- // Fill it with words. if all words of same color, create only one CWord
- if (!currLine.empty())
- {
- CFormatInfo lineWordFormat= currLine[0].Format;
- ucstring lineWord;
- for(uint i=0;iaddWord(lineWord, 0, lineWordFormat, _FontWidth);
- // get new lineWordFormat
- lineWordFormat= currLine[i].Format;
- // and clear
- lineWord.clear();
- }
-
- // Append the word with space to the lineWord.
- ucstring blank;
- blank.resize(currLine[i].NumSpaces, (ucchar) ' ');
- lineWord += blank;
- lineWord += currLine[i].Text;
- }
-
- if(!lineWord.empty())
- _Lines.back()->addWord(lineWord, 0, lineWordFormat, _FontWidth);
-
- // clear
- currLine.clear();
- }
-}
-
-// ***************************************************************************
-void CViewText::updateTextContextMultiLineJustified(uint nMaxWidth, bool expandSpaces)
-{
- UTextContext::CStringInfo si;
- //
- TCharPos currPos = 0;
- //
- static const ucstring spaceStr(" ");
- // precLineWidth valid only id precedent line is part of same paragraph.
- float precLineWidth= 0;
- float lineWidth = (float)_FirstLineX; // width of the current line
- uint numWordsInLine = 0; // number of words in the current line
- bool isParagraphStart = true; // A paragraph is a group of characters between 2 \n
- bool lineFeed;
- bool breakLine;
- //
- vector currLine; // if spaces are not expanded, all words of a line are inserted here (NB: index and stringInfo not filled)
- ucstring wordValue;
- CFormatInfo wordFormat;
- uint formatTagIndex= 0;
- //
- while (currPos != _Text.length())
- {
- TCharPos spaceEnd;
- TCharPos wordEnd;
- uint numSpaces;
- float newLineWidth;
- breakLine = false;
- //
- if (_Text[currPos] == (ucchar) '\n')
- {
- lineFeed = true;
- }
- else
- {
- lineFeed = false;
- // Skip spaces and count them
- spaceEnd = _Text.find_first_not_of(spaceStr, currPos);
- if (spaceEnd == std::string::npos)
- {
- spaceEnd = _Text.length();
- }
- numSpaces = (uint) (spaceEnd - currPos);
- if (!isParagraphStart && numSpaces != 0 && numWordsInLine == 0) // Are these the first spaces of the line ?
- {
- if (!_Lines.empty())
- {
- /* Yoyo: I changed this (added the "cut space"), because in editBox, it is so strange when
- the word hit the end of line, and if you add spaces just after, nothing happens because
- cursor pos is clamped at end of line.
- */
- // Cannot put all of thoses spaces to the prec end of line?
- if(_MultiLineClipEndSpace && precLineWidth + numSpaces * _SpaceWidth > nMaxWidth)
- {
- // put some of these spaces at the end of the previous line.
- sint maxNumSpaces= (sint)floorf((nMaxWidth - precLineWidth) / _SpaceWidth);
- _Lines.back()->setEndSpaces(maxNumSpaces);
- // And start the new lines with the remaining spaces.
- numSpaces-= maxNumSpaces;
- currPos+= maxNumSpaces;
- }
- else
- {
- // ok, put all spaces to previous line
- _Lines.back()->setEndSpaces(numSpaces);
- currPos = spaceEnd;
- numSpaces= 0;
- }
- if(currPos >=_Text.length())
- break;
- }
- }
-
- // Detect change of wordFormat at the begining of the word
- if(isFormatTagChange((uint)spaceEnd, formatTagIndex))
- {
- getFormatTagChange((uint)spaceEnd, formatTagIndex, wordFormat);
- }
-
- // Get word until a space, a \n, or a FormatTagChange is encountered
- uint i;
- for(i= (uint)spaceEnd;i<(uint)_Text.length();i++)
- {
- ucchar c= _Text[i];
- if(c==' ' || c=='\n')
- break;
- // If change of color tag, stop the word, but don't take the new color now.
- if(isFormatTagChange(i, formatTagIndex))
- break;
- }
- wordEnd = i;
-
-
- // Get the word value.
- wordValue = _Text.substr(spaceEnd, wordEnd - spaceEnd);
- // compute width of word
- si = CViewRenderer::getTextContext()->getStringInfo(wordValue);
-
- // compute size of spaces/Tab + word
- newLineWidth = lineWidth + numSpaces * _SpaceWidth;
- newLineWidth = max(newLineWidth, (float)wordFormat.TabX*_FontWidth);
- newLineWidth+= si.StringWidth;
- }
- //
- // Does the word go beyond the end of line ?
- if (!lineFeed && newLineWidth > (float) nMaxWidth)
- {
- // Have we enough room for this word on a line ?
- bool roomForThisWord = (numWordsInLine > 0) || ( (newLineWidth - lineWidth) < (float) nMaxWidth );
-
- // not enough room for that word
- // If it is the only word of the line, just split it
- // Otherwise, scale the spaces between words so that the line as the maximum width
- if (roomForThisWord)
- {
- if (expandSpaces)
- {
- nlassert(_Lines.size() > 0);
- nlassert(_Lines.back()->getNumWords() > 0);
-
- // Yoyo: if the line has tab, then don't justify
- if(wordFormat.TabX > 0)
- _Lines.back()->setSpaceWidth(_SpaceWidth);
- else
- {
- // Scale the width so that the line has the maximum width
- float roomForSpaces = nMaxWidth - _Lines.back()->getWidthWithoutSpaces();
- uint startNumSpaces = _Lines.back()->getNumSpaces();
- if (startNumSpaces != 0)
- {
- _Lines.back()->setSpaceWidth(roomForSpaces / startNumSpaces);
- }
- else
- {
- _Lines.back()->setSpaceWidth(_SpaceWidth);
- }
- }
- }
- else
- {
- breakLine = true;
- }
- // we dont change the position in the input string so that the current will be processed on the next line
-
- }
- else // it is the only word on the line..
- {
- // .. so split it
- // 1) Check if spaces go beyond the end of line
- if (numSpaces * _SpaceWidth > nMaxWidth)
- {
- uint maxNumSpaces = std::max(1U, (uint) (nMaxWidth / _SpaceWidth));
- CWord spaceWord; // a word with only spaces in it
- spaceWord.build (ucstring (""), maxNumSpaces);
- spaceWord.Format= wordFormat;
- _Lines.push_back(TLineSPtr(new CLine));
- _Lines.back()->addWord(spaceWord, _FontWidth);
- if (expandSpaces)
- {
- _Lines.back()->setSpaceWidth(nMaxWidth / (float) maxNumSpaces);
- }
- else
- {
- _Lines.back()->setSpaceWidth(_SpaceWidth);
- }
- currPos = currPos + maxNumSpaces;
- }
- else
- {
- float px = numSpaces * _SpaceWidth;
- uint currChar = 0;
- ucstring oneChar(" ");
- for(currChar = 0; currChar < wordValue.length(); ++currChar)
- {
- oneChar = wordValue[currChar];
- si = CViewRenderer::getTextContext()->getStringInfo(oneChar);
- if ((uint) (px + si.StringWidth) > nMaxWidth) break;
- px += si.StringWidth;
- }
- currChar = std::max((uint) 1, currChar); // must fit at least one character otherwise there's an infinite loop
- wordValue = _Text.substr(spaceEnd, currChar);
- CWord word;
- word.build(wordValue, numSpaces);
- word.Format= wordFormat;
- _Lines.push_back(TLineSPtr(new CLine));
- float roomForSpaces = (float) nMaxWidth - word.Info.StringWidth;
- if (expandSpaces && numSpaces != 0)
- {
- _Lines.back()->setSpaceWidth(roomForSpaces / (float) numSpaces);
- }
- else
- {
- _Lines.back()->setSpaceWidth(0);
- }
- _Lines.back()->addWord(word, _FontWidth);
- currPos = currPos + numSpaces + currChar;
- }
- }
- // reset line
- numWordsInLine = 0;
- precLineWidth= lineWidth;
- lineWidth = 0;
- isParagraphStart = false;
- }
- else if (!lineFeed) // the end of line hasn't been reached
- {
- if (expandSpaces)
- {
- // add in the current line (and create one if necessary)
- if (numWordsInLine == 0)
- {
- _Lines.push_back(TLineSPtr(new CLine));
- _Lines.back()->setSpaceWidth(_SpaceWidth);
- }
- if (!wordValue.empty() || numSpaces != 0)
- {
- CWord word;
- word.build(wordValue, numSpaces);
- word.Format= wordFormat;
- // update line width
- _Lines.back()->addWord(word, _FontWidth);
- ++numWordsInLine;
- }
- }
- else
- {
- CWord word;
- // Don't build here, this is used as temp data.
- word.Text= wordValue;
- word.NumSpaces= numSpaces;
- word.Format= wordFormat;
- // Append to the temp Data.
- currLine.push_back(word);
-
- ++numWordsInLine;
- }
- lineWidth = newLineWidth;
- currPos = wordEnd;
- }
- else
- {
- // '\n' was encountered
- ++ currPos;
- isParagraphStart = true;
- }
- if (lineFeed || breakLine) // '\n' was encoutered, or a linefeed has been asked
- {
- // !expandSpaces => insert minimum words according to word color.
- if (!expandSpaces)
- {
- // Add the new line.
- addDontClipWordLine(currLine);
- // LineFeed?
- if (lineFeed)
- {
- _Lines.back()->setLF(true);
- }
- }
- // expandSpaces => just add a empty line.
- else
- {
- if (numWordsInLine == 0)
- {
- // if nothing has been inserted in this line, create at least an empty line
- _Lines.push_back(TLineSPtr(new CLine));
- }
- if (lineFeed)
- {
- _Lines.back()->setLF(true);
- }
- }
- lineWidth = 0.f;
- numWordsInLine = 0;
- }
- }
-
- // if current line hasn't been pushed, add it
- if (!expandSpaces && !currLine.empty())
- {
- // Add new line
- addDontClipWordLine(currLine);
- }
-
- // if the text ends with \n, must insert the last line ourself
- if (!_Text.empty() && _Text[_Text.length() - 1] == (ucchar) '\n')
- {
- _Lines.push_back(TLineSPtr(new CLine));
- }
-}
-
-
-// ***************************************************************************
-void CViewText::updateTextContext ()
-{
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
-
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
-
- // default state
- _SingleLineTextClamped= false;
-
- if ((_MultiLine)&&(_Parent != NULL))
- {
- sint nMaxWidth = getCurrentMultiLineMaxW();
- _LastMultiLineMaxW = nMaxWidth;
- clearLines();
- if (nMaxWidth <= 0)
- {
- // parent size may not be known yet
- return;
- }
- switch(_TextMode)
- {
- case ClipWord: updateTextContextMultiLine(nMaxWidth); break;
- case DontClipWord: updateTextContextMultiLineJustified(nMaxWidth, false); break;
- case Justified: updateTextContextMultiLineJustified(nMaxWidth, true); break;
- }
-
- // Special case for multiline limited in number of lines
- if ((_Lines.size() > 0) && (_MultiMaxLine > 0) && (_Lines.size() > _MultiMaxLine))
- {
- while (_Lines.size() > _MultiMaxLine)
- {
- _Lines.back()->clear();
- _Lines.pop_back();
- }
- _Lines.pop_back();
- CViewText::CLine *endLine = new CViewText::CLine;
- CViewText::CWord w;
- w.build(string("..."));
- endLine->addWord(w, _FontWidth);
- _Lines.push_back(TLineSPtr(endLine));
- }
-
- // Calculate size
- float rTotalW = 0;
- for (uint i = 0; i < _Lines.size(); ++i)
- {
- rTotalW = std::max(_Lines[i]->getWidth() + ((i==0)?_FirstLineX:0), rTotalW);
- }
- _W = (sint)rTotalW;
- _H = std::max(_FontHeight, uint(_FontHeight * _Lines.size() + std::max(0, sint(_Lines.size()) - 1) * _MultiLineSpace));
-
- // Compute tooltips size
- if (_Tooltips.size() > 0)
- for (uint i=0 ; i<_Lines.size() ; ++i)
- {
- for (uint j=0 ; j<_Lines[i]->getNumWords() ; ++j)
- {
- CWord word = _Lines[i]->getWord(j);
-// float w = _Lines[i]->getWidth();
-
- if (word.Format.IndexTt != -1)
- {
- if (_Tooltips.size() > (uint)word.Format.IndexTt)
- {
- CCtrlToolTip *pTooltip = _Tooltips[word.Format.IndexTt];
-
- sint y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i - 1));
-
- pTooltip->setX(0);
- pTooltip->setY(y);
- pTooltip->setW(getCurrentMultiLineMaxW());
- pTooltip->setH(_FontHeight);
- }
- }
- }
- }
- }
- else // Single line code
- {
- if (_Index != 0xFFFFFFFF)
- TextContext->erase (_Index);
-
- // Common case: no W clamp
- _Index = TextContext->textPush (_Text);
- _Info = TextContext->getStringInfo (_Index);
- _W = (sint)(_Info.StringWidth);
-
- // Rare case: clamp W => recompute slowly, cut letters
- if(_W>_LineMaxW)
- {
- TextContext->erase (_Index);
-
- ucchar ucLetter;
- UTextContext::CStringInfo si;
- ucstring ucCurrentLine;
- ucCurrentLine.reserve(_Text.size());
- // Append ... to the end of line
- si = TextContext->getStringInfo (ucstring("..."));
- float dotWidth= si.StringWidth;
- float rWidthCurrentLine = 0, rWidthLetter;
- // for all the text
- if (_ClampRight)
- {
- for (uint i = 0; i < _Text.size(); ++i)
- {
- ucLetter= _Text[i];
- ucstring ucStrLetter;
- ucStrLetter= ucLetter;
- si = TextContext->getStringInfo (ucStrLetter);
- rWidthLetter = (si.StringWidth);
- if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
- {
- break;
- }
- else
- {
- // Grow the current line
- ucCurrentLine += ucLetter;
- rWidthCurrentLine += rWidthLetter;
- }
- }
-
- // Add the dots
- ucCurrentLine+= "...";
- }
- else
- {
- for (sint i = (sint)_Text.size() - 1; i >= 0; --i)
- {
- ucLetter= _Text[i];
- ucstring ucStrLetter;
- ucStrLetter= ucLetter;
- si = TextContext->getStringInfo (ucStrLetter);
- rWidthLetter = (si.StringWidth);
- if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
- {
- break;
- }
- else
- {
- // Grow the current line
- ucCurrentLine = ucLetter + ucCurrentLine;
- rWidthCurrentLine += rWidthLetter;
- }
- }
-
- // Add the dots
- ucCurrentLine = "..." + ucCurrentLine;
- }
-
- // And so setup this trunc text
- _Index = TextContext->textPush (ucCurrentLine);
- _Info = TextContext->getStringInfo (_Index);
- _W = (sint)(_Info.StringWidth);
-
- _SingleLineTextClamped= true;
- }
-
- // same height always
- _H = _FontHeight;
- }
-
- _InvalidTextContext= false;
-}
-
-// ***************************************************************************
-void CViewText::updateCoords()
-{
- if (_AutoClamp)
- {
- CViewBase::updateCoords ();
- if (_Parent)
- {
- CInterfaceGroup *parent = _Parent;
- // avoid resizing parents to compute the limiter
- while (parent && (parent->getResizeFromChildW() || parent->isGroupList() ))
- {
- // NB nico : the dynamic_cast for CGroupList is bad!!
- // can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
- // ...
- parent = parent->getParent();
- }
- if (parent)
- {
- if (_ClampRight)
- {
- sint32 parentRight = parent->getXReal() + parent->getWReal() - (sint32) _AutoClampOffset;
- setLineMaxW(std::max((sint32) 0, parentRight - _XReal));
- }
- else
- {
- sint32 parentLeft = parent->getXReal() + (sint32) _AutoClampOffset;
- setLineMaxW(std::max((sint32) 0, _XReal + _WReal - parentLeft));
- }
- }
- }
- }
-
- if(_InvalidTextContext)
- updateTextContext();
-
- CViewBase::updateCoords ();
-}
-
-// ***************************************************************************
-sint CViewText::getLineFromIndex(uint index, bool cursorDisplayedAtEndOfPreviousLine /* = true*/) const
-{
- if (index > _Text.length()) return -1;
- if (_MultiLine)
- {
- uint charIndex = 0;
- for(sint i = 0; i < (sint) _Lines.size(); ++i)
- {
- CLine &currLine = *_Lines[i];
- uint newCharIndex = charIndex + currLine.getNumChars() + currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
- if (newCharIndex > index)
- {
- if (i != 0 && cursorDisplayedAtEndOfPreviousLine && charIndex == index)
- {
- return i - 1;
- }
- else
- {
- return i;
- }
- }
- charIndex = newCharIndex;
- }
- return (sint)_Lines.size() - 1;
- }
- else
- {
- return 0;
- }
-}
-
-// ***************************************************************************
-sint CViewText::getLineStartIndex(uint line) const
-{
- uint charIndex = 0;
- if (line >= _Lines.size()) return -1;
- for(uint i = 0; i < line; ++i)
- {
- CLine &currLine = *_Lines[i];
- charIndex += currLine.getNumChars() + currLine.getEndSpaces() + (currLine.getLF() ? 1 : 0);
- }
- // skip all spaces at start of line (unless there are only spaces in the line)
- std::string::size_type nextPos = _Text.find_first_not_of((ucchar) ' ', charIndex);
- if (nextPos != std::string::npos)
- {
- if (getLineFromIndex(charIndex) == (sint) line)
- {
- return (sint) nextPos;
- }
- }
- return charIndex;
-}
-
-// ***************************************************************************
-void CViewText::getLineEndIndex(uint line, sint &index, bool &endOfPreviousLine) const
-{
- sint startIndex = getLineStartIndex(line);
- if (startIndex == -1)
- {
- index = -1;
- endOfPreviousLine = false;
- return;
- }
- index = startIndex + _Lines[line]->getNumChars() + _Lines[line]->getEndSpaces();
- endOfPreviousLine = !_Lines[line]->getLF();
-}
-
-// ***************************************************************************
-void CViewText::setHardText (const std::string &ht)
-{
-// ucstring Text = ucstring(ht);
- ucstring Text;
- if ((ht.size()>2) && (ht[0] == 'u') && (ht[1] == 'i'))
- Text = CI18N::get (ht);
- else
- Text.fromUtf8(ht);
- setText(Text);
-}
-
-// ***************************************************************************
-string CViewText::getColorAsString() const
-{
- return NLMISC::toString(_Color.R) + " " + NLMISC::toString(_Color.G) + " " + NLMISC::toString(_Color.B) + " " + NLMISC::toString(_Color.A);
-}
-
-// ***************************************************************************
-void CViewText::setColorAsString(const string &ht)
-{
- _Color = convertColor (ht.c_str());
-}
-
-// ***************************************************************************
-NLMISC::CRGBA CViewText::getColorRGBA() const
-{
- return _Color;
-}
-
-// ***************************************************************************
-void CViewText::setColorRGBA(NLMISC::CRGBA col)
-{
- _Color = col;
-}
-
-// ***************************************************************************
-void CViewText::getCharacterPositionFromIndex(sint index, bool cursorAtPreviousLineEnd, sint &x, sint &y, sint &height) const
-{
- NLMISC::clamp(index, 0, (sint) _Text.length());
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
-// CViewRenderer &rVR = *CViewRenderer::getInstance();
- height = getFontHeight();
- //
- if (_MultiLine)
- {
- uint charIndex = 0;
- // special case for end of text
- if (index == (sint) _Text.length())
- {
- y = 0;
- if (_Lines.empty())
- {
- x = 0;
- }
- else
- {
- CLine &lastLine = *_Lines.back();
- x = (sint) (lastLine.getWidth() + lastLine.getEndSpaces() * lastLine.getSpaceWidth());
- sint nMaxWidth = getCurrentMultiLineMaxW();
- x = std::min(x, nMaxWidth);
- }
- return;
- }
- for(sint i = 0; i < (sint) _Lines.size(); ++i)
- {
- if (i != 0 && charIndex == (uint) index && cursorAtPreviousLineEnd)
- {
- // should display the character at the end of previous line
- CLine &currLine = *_Lines[i - 1];
- y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i));
- x = (sint) (currLine.getWidth() + currLine.getEndSpaces() * currLine.getSpaceWidth());
- sint nMaxWidth = getCurrentMultiLineMaxW();
- x = std::min(x, nMaxWidth);
- return;
- }
- CLine &currLine = *_Lines[i];
- uint newCharIndex = charIndex + currLine.getNumChars() + currLine.getEndSpaces() + (_Lines[i]->getLF() ? 1 : 0);
- if ((sint) newCharIndex > index)
- {
- // ok, this line contains the character, now, see which word contains it.
- y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - 1 - i));
- // see if the index is in the spaces at the end of line
- if (index - charIndex >= currLine.getNumChars())
- {
- uint numSpaces = index - charIndex - currLine.getNumChars();
- x = (sint) (currLine.getWidth() + numSpaces * _SpaceWidth);
- sint nMaxWidth = getCurrentMultiLineMaxW();
- x = std::min(x, nMaxWidth);
- return;
- }
- // now, search containing word in current line
- float px = (float)_FirstLineX;
- for(uint k = 0; k < currLine.getNumWords(); ++k)
- {
- CWord &currWord = currLine.getWord(k);
- if ((sint) (charIndex + currWord.NumSpaces + currWord.Text.length()) >= index)
- {
- // character is in currWord or the in spaces preceding it
- // check if the character is in the word
- if ((uint) (index - charIndex) > currWord.NumSpaces)
- {
- // get the x position
- ucstring subStr = currWord.Text.substr(0, index - charIndex - currWord.NumSpaces);
- // compute the size
- UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
- x = (sint) (px + si.StringWidth + currWord.NumSpaces * currLine.getSpaceWidth());
- height = getFontHeight();
- return;
- }
- else
- {
- // character is in the spaces preceding the word
- x = (sint) (px + currLine.getSpaceWidth() * (index - charIndex));
- height = getFontHeight();
- return;
- }
- }
- charIndex += (uint)currWord.Text.length() + currWord.NumSpaces;
- px += currWord.NumSpaces * currLine.getSpaceWidth() + currWord.Info.StringWidth;
- }
- }
- charIndex = newCharIndex;
- }
-
- }
- else
- {
- // get the x position
- ucstring subStr = _Text.substr(0, index);
- // compute the size
- UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
- y = 0;
- x = (sint) si.StringWidth;
- }
-}
-
-// ***************************************************************************
-// Tool fct : From a word and a x coordinate, give the matching character index
-static uint getCharacterIndex(const ucstring &textValue, float x)
-{
- float px = 0.f;
- UTextContext::CStringInfo si;
- ucstring singleChar(" ");
- uint i;
- for (i = 0; i < textValue.length(); ++i)
- {
- // get character width
- singleChar[0] = textValue[i];
- si = CViewRenderer::getTextContext()->getStringInfo(singleChar);
- px += si.StringWidth;
- // the character is at the i - 1 position
- if (px > x)
- {
- // if the half of the character is after the cursor, then prefer select the next one (like in Word)
- if(px-si.StringWidth/2 < x)
- i++;
- break;
- }
- }
- return i;
-}
-
-// ***************************************************************************
-void CViewText::getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &cursorAtPreviousLineEnd) const
-{
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
-
- // setup the text context
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
- // find the line where the character is
-// CViewRenderer &rVR = *CViewRenderer::getInstance();
- uint charPos = 0;
- if (_MultiLine)
- {
- // seek the line
- float py = 0.f;
- if (py > y)
- {
- index = (uint)_Text.length();
- cursorAtPreviousLineEnd = false;
- return;
- }
- sint line;
- for (line = (uint)_Lines.size() - 1; line >= 0; --line)
- {
- float newPy = py + _FontHeight + _MultiLineSpace;
- if (newPy > y)
- {
- break;
- }
- py = newPy;
- }
- if (line == -1)
- {
- index = 0;
- cursorAtPreviousLineEnd = false;
- return; // above the first line, so take character 0
- }
- // compute character index at start of line
- sint i;
- for (i = 0; i < line; ++i)
- {
- charPos += _Lines[i]->getNumChars() + _Lines[i]->getEndSpaces() + (_Lines[i]->getLF() ? 1 : 0);
- }
- // seek word that contains the character
- CLine &currLine = *_Lines[line];
- // See if character is in the ending spaces
- if (x >= (sint) currLine.getWidth())
- {
- // Add _SpaceWidth/2 to select between chars
- sint numSpaces = _SpaceWidth != 0 ? (sint) (((float) x + _SpaceWidth/2 - currLine.getWidth()) / _SpaceWidth)
- : 0;
- clamp(numSpaces, 0, (sint)currLine.getEndSpaces());
- index = charPos + currLine.getNumChars() + numSpaces;
- cursorAtPreviousLineEnd = !_Lines[i]->getLF();
- return;
- }
-
- float px = (float)_FirstLineX;
- for(uint k = 0; k < currLine.getNumWords(); ++k)
- {
- CWord &currWord = currLine.getWord(k);
- float spacesWidth = currLine.getSpaceWidth() * currWord.NumSpaces;
- float newPx = px + currWord.Info.StringWidth + spacesWidth;
- if (newPx >= x) // if the word contains the x position..
- {
- if (x < (px + spacesWidth))
- {
- // the coords x is in the spaces that are preceding the word
- // Add spaceWidth/2 to select between chars
- sint numSpaces = currLine.getSpaceWidth() != 0 ? (sint) ((x + currLine.getSpaceWidth()/2 - px) / currLine.getSpaceWidth())
- : 0;
- clamp(numSpaces, 0, (sint)currWord.NumSpaces);
- index = numSpaces + charPos;
- cursorAtPreviousLineEnd = false;
- return;
- }
- else
- {
- // the coord is in the word itself
- index = charPos + currWord.NumSpaces + getCharacterIndex(currWord.Text, (float) x - (px + spacesWidth));
- cursorAtPreviousLineEnd = false;
- return;
- }
- }
- px = newPx;
- charPos += (uint)currWord.Text.length() + currWord.NumSpaces;
- }
- index = charPos;
- cursorAtPreviousLineEnd = false;
- return;
- }
- else
- {
- cursorAtPreviousLineEnd = false;
- if (y < 0)
- {
- index = (uint)_Text.length();
- return;
- }
- if (y > (sint) _FontHeight)
- {
- index = 0;
- return;
- }
- index = getCharacterIndex(_Text, (float) x);
- return;
- }
-}
-
-// ***************************************************************************
-void CViewText::enableStringSelection(uint start, uint end)
-{
- _TextSelection= true;
- _TextSelectionStart= start;
- _TextSelectionEnd= end;
-}
-
-// ***************************************************************************
-void CViewText::disableStringSelection()
-{
- _TextSelection= false;
- _TextSelectionStart= 0;
- _TextSelectionEnd= std::numeric_limits::max();
-}
-
-// ***************************************************************************
-void CViewText::setStringSelectionSkipingSpace(uint stringId, const ucstring &text, sint charStart, sint charEnd)
-{
- sint quadStart= charStart;
- sint quadSize= charEnd-charStart;
- sint j;
- for(j=0;jsetStringSelection(stringId, quadStart, quadSize);
-}
-
-// ***************************************************************************
-void CViewText::clearLines()
-{
- for(uint k = 0; k < _Lines.size(); ++k)
- {
- _Lines[k]->clear();
- }
- _Lines.clear();
-}
-
-// ***************************************************************************
-uint CViewText::getNumLine() const
-{
- if (_MultiLine)
- {
- return (uint)_Lines.size();
- }
- else
- {
- return _Text.empty() ? 0 : 1;
- }
-}
-
-// ***************************************************************************
-uint CViewText::getFirstLineX() const
-{
- return _FirstLineX;
-}
-
-// ***************************************************************************
-uint CViewText::getLastLineW () const
-{
- if (!_Lines.empty())
- return (uint)_Lines.back()->getWidth();
- return 0;
-}
-
-// ***************************************************************************
-void CViewText::setFirstLineX(uint firstLineX)
-{
- _FirstLineX = firstLineX;
-}
-
-/////////////////////////////////////
-// CViewText::CLine implementation //
-/////////////////////////////////////
-
-// ***************************************************************************
-CViewText::CLine::CLine() : _NumChars(0),
- _NumSpaces(0),
- _SpaceWidth(0.f),
- _StringLine(0),
- _WidthWithoutSpaces(0.f),
- _EndSpaces(0),
- _HasLF(false)
-{
-}
-
-// ***************************************************************************
-void CViewText::CLine::addWord(const ucstring &text, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth)
-{
- CWord word;
- word.build(text, numSpaces);
- word.Format= wordFormat;
- addWord(word, fontWidth);
-}
-
-// ***************************************************************************
-void CViewText::CLine::addWord(const CWord &word, uint fontWidth)
-{
- _Words.push_back(word);
- _NumChars += word.NumSpaces + uint(word.Text.length());
- _NumSpaces += word.NumSpaces;
- if (fabsf(word.Info.StringLine) > fabsf(_StringLine))
- {
- _StringLine = word.Info.StringLine;
- }
- // the width of the line must reach at least the Tab
- _WidthWithoutSpaces= max(_WidthWithoutSpaces, word.Format.TabX * float(fontWidth));
- // append the text space
- _WidthWithoutSpaces += word.Info.StringWidth;
-}
-
-// ***************************************************************************
-void CViewText::CLine::clear()
-{
- for(uint k = 0; k < _Words.size(); ++k)
- {
- if (_Words[k].Index != 0xffffffff)
- CViewRenderer::getTextContext()->erase(_Words[k].Index);
- }
- _Words.clear();
- _NumChars = 0;
- _SpaceWidth = 0.f;
-}
-
-// ***************************************************************************
-void CViewText::CLine::resetTextIndex()
-{
- for(uint k = 0; k < _Words.size(); ++k)
- {
- _Words[k].Index = 0xffffffff;
- }
-}
-
-// ***************************************************************************
-void CViewText::CWord::build(const ucstring &text, uint numSpaces/*=0*/)
-{
- Text = text;
- NumSpaces = numSpaces;
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
- Index = TextContext->textPush(text);
- Info = TextContext->getStringInfo(Index);
-}
-
-// ***************************************************************************
-void CViewText::removeEndSpaces()
-{
- sint i = (sint)_Text.size()-1;
- while ((i>=0) && ((_Text[i] < 0x20) || (_Text[i] == ' ')))
- {
- i--;
- }
- _Text.resize (i+1);
-}
-
-// ***************************************************************************
-sint32 CViewText::getMaxUsedW() const
-{
- static const ucstring spaceStr(" \t");
- static const ucstring lineFeedStr("\n");
- float maxWidth = 0;
-
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
-
- TCharPos linePos = 0;
- while (linePos < _Text.length())
- {
- // Get the end of the line
- float lineWidth = 0;
- TCharPos lineEnd;
- lineEnd = _Text.find_first_of(lineFeedStr, linePos);
- if (lineEnd == std::string::npos)
- {
- lineEnd = _Text.length();
- }
-
- ucstring lineValue;
- lineValue = _Text.substr(linePos, lineEnd - linePos);
-
- TCharPos currPos = 0;
- while (currPos != lineValue.length())
- {
- TCharPos spaceEnd;
- TCharPos wordEnd;
- uint numSpaces;
-
- // Skip spaces and count them
- spaceEnd = lineValue.find_first_not_of(spaceStr, currPos);
- if (spaceEnd == std::string::npos)
- {
- spaceEnd = lineValue.length();
- }
- numSpaces = (uint) (spaceEnd - currPos);
-
- // Get word until a space or a \n is encountered
- wordEnd = lineValue.find_first_of(spaceStr, spaceEnd);
- if (wordEnd == std::string::npos)
- {
- wordEnd = lineValue.length();
- }
-
- ucstring wordValue;
- wordValue = lineValue.substr(spaceEnd, wordEnd - spaceEnd);
-
- // compute width of word
- UTextContext::CStringInfo si;
- si = TextContext->getStringInfo(wordValue);
-
- // compute size of spaces + word
- lineWidth += numSpaces * _SpaceWidth + si.StringWidth;
-
- currPos = wordEnd;
- }
-
- // Update line width
- if (lineWidth > maxWidth)
- maxWidth = lineWidth;
-
- linePos = lineEnd+1;
- }
-
- return (sint32)maxWidth;
-}
-
-// ***************************************************************************
-sint32 CViewText::getMinUsedW() const
-{
- static const ucstring spaceOrLineFeedStr(" \n\t");
- sint32 maxWidth = 0;
-
- // Not multi line ? Same size than min
- if (!_MultiLine)
- return getMaxUsedW();
-
- // If we can clip word, size of the largest word
- if (_TextMode == ClipWord)
- {
- // No largest font parameter, return the font height
- return _FontHeight;
- }
- // If we can't clip the words, return the size of the largest word
- else if ((_TextMode == DontClipWord) || (_TextMode == Justified))
- {
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
-
- // Current position in text
- TCharPos currPos = 0;
- while (currPos < _Text.length())
- {
- // Current word
- ucstring wordValue;
- UTextContext::CStringInfo si;
- TCharPos wordEnd;
-
- // Get word until a space or a \n is encountered
- currPos = _Text.find_first_not_of(spaceOrLineFeedStr, currPos);
- if (currPos == std::string::npos)
- break;
- wordEnd = _Text.find_first_of(spaceOrLineFeedStr, currPos);
- if (wordEnd == std::string::npos)
- wordEnd = _Text.length();
-
- // Get the word
- wordValue = _Text.substr(currPos, wordEnd - currPos);
-
- // Compute width of word
- si = TextContext->getStringInfo(wordValue);
-
- // Larger ?
- sint32 stringWidth = (sint32)si.StringWidth;
- if (stringWidth>maxWidth)
- maxWidth = stringWidth;
-
- // Next word
- currPos = wordEnd;
- }
- }
-
- return maxWidth;
-}
-
-// ***************************************************************************
-void CViewText::onInvalidateContent()
-{
- _InvalidTextContext= true;
- invalidateCoords();
-}
-
-// ***************************************************************************
-void CViewText::computeFontSize ()
-{
- NL3D::UTextContext *TextContext = CViewRenderer::getTextContext();
- TextContext->setHotSpot (UTextContext::BottomLeft);
- TextContext->setShaded (_Shadow);
- TextContext->setFontSize (_FontSize);
-
- // Letter size
- UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); // for now we can't now that directly from UTextContext
- _FontHeight = (uint) si.StringHeight + (_Shadow?1:0);
- _FontLegHeight = (uint) si.StringLine + (_Shadow?1:0);
-
- // Space width
- si = TextContext->getStringInfo(ucstring(" "));
- _SpaceWidth = si.StringWidth;
-
- // Font Width
- si = TextContext->getStringInfo(ucstring("_"));
- _FontWidth = (uint)si.StringWidth;
-}
-
-
-// ***************************************************************************
-static inline bool isColorTag(const ucstring &s, uint index, uint textSize)
-{
- // Format is @{RGBA}
- if(s[index]=='@')
- {
- if( textSize>index+1 && s[index+1]=='{')
- {
- // verify 1st letter is a xdigit
- if( textSize>index+2 && isxdigit(s[index+2]))
- {
- // We have good chance its a color tag. Do last verification
- if(textSize>index+6 && s[index+6]=='}')
- {
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-// ***************************************************************************
-// isColorTag must be ok.
-static inline CRGBA getColorTag(const ucstring &s, uint &index)
-{
- // extract the color string: "FABC"
- char tmpCol[5];
- for(uint i=0;i<4;i++)
- tmpCol[i]= (char)s[index+2+i];
- tmpCol[4]= 0;
-
- // Convert to color
- CRGBA color;
- uint pCol;
- sscanf(tmpCol, "%x", &pCol);
- // Transform 4 bits to 8 bit.
- color.R= (pCol>>12)&0xF; color.R+= color.R<<4;
- color.G= (pCol>>8)&0xF; color.G+= color.G<<4;
- color.B= (pCol>>4)&0xF; color.B+= color.B<<4;
- color.A= (pCol)&0xF; color.A+= color.A<<4;
-
- // skip tag
- index+= 7;
-
- return color;
-}
-
-
-// ***************************************************************************
-const uint MaxTabDigit= 3;
-static inline bool isTabTag(const ucstring &s, uint index, uint textSize)
-{
- // Format is @{Tvalue}, where value ,1,2,3 digit.
- if(s[index]=='@')
- {
- if( textSize>index+1 && s[index+1]=='{')
- {
- if( textSize>index+2 && s[index+2]=='T')
- {
- // We have good chance its a Tab tag. Do last verification
- for(uint i=4;i<4+MaxTabDigit;i++)
- {
- if(textSize>index+i && s[index+i]=='}')
- {
- return true;
- }
- }
- }
- }
- }
-
- return false;
-}
-
-// ***************************************************************************
-// isTabTag must be ok.
-static inline sint getTabTag(const ucstring &s, uint &index)
-{
- // extract the tab min X value
- char tmpTab[MaxTabDigit+1];
- uint i;
- for(i=0;iindex+1 && s[index+1]=='{')
- {
- if( textSize>index+2 && s[index+2]=='H')
- {
- uint i = 3;
- while (textSize>index+i && s[index+i]!='}')
- i++;
-
- if (textSize>index+i && s[index+i]=='}')
- return true;
- }
- }
- }
-
- return false;
-}
-
-// ***************************************************************************
-// isTooltipTag must be ok.
-static inline ucstring getTooltipTag(const ucstring &s, uint &index)
-{
- ucstring result;
- uint i = 3;
- while (s[index+i] != '}')
- {
- result += s[index+i];
- i++;
- }
-
- // skip tag
- index += i+1;
-
- return result;
-}
-
-
-// ***************************************************************************
-void CViewText::buildFormatTagText(const ucstring &text, ucstring &textBuild, std::vector &formatTags, std::vector &tooltips)
-{
- formatTags.clear();
- tooltips.clear();
-
- // Build the text without the formatTags, and get the color tags separately
- textBuild.reserve(text.size());
- uint textSize= (uint)text.size();
- // Must herit all the props from old tags.
- CViewText::CFormatTag precTag; // set default.
- precTag.Index = 0;
- for (uint i = 0; i < textSize;)
- {
- if(isColorTag(text, i, textSize))
- {
- // get old tag.
- CViewText::CFormatTag ct= precTag;
- // get new color and skip tag.
- ct.Color= getColorTag(text, i);
- ct.Index= (uint)textBuild.size();
- formatTags.push_back(ct);
- }
- else if(isTabTag(text, i, textSize))
- {
- // get old tag.
- CViewText::CFormatTag ct= precTag;
- // get new Tab and skip tag.
- ct.TabX= getTabTag(text, i);
- ct.Index= (uint)textBuild.size();
- formatTags.push_back(ct);
- }
- else if(isTooltipTag(text, i, textSize))
- {
- // get old tag.
- CViewText::CFormatTag ct= precTag;
- // get new Tab and skip tag.
- ucstring uitt = getTooltipTag(text, i);
- if (uitt.empty())
- {
- ct.IndexTt= -1;
- }
- else
- {
- ct.IndexTt= (uint)tooltips.size();
- tooltips.push_back(uitt);
- }
-
- ct.Index= (uint)textBuild.size();
- formatTags.push_back(ct);
- }
- else
- {
- bool lineFeed= text[i]=='\n';
-
- // append to textBuild
- textBuild+= text[i];
- ++i;
-
- // if \n, reset tabulations
- if(lineFeed)
- {
- CViewText::CFormatTag ct= precTag;
- ct.TabX= 0;
- ct.Index= (uint)textBuild.size();
- formatTags.push_back(ct);
- }
- }
- // bkup
- if(!formatTags.empty())
- precTag= formatTags.back();
- }
-}
-
-
-// ***************************************************************************
-void CViewText::setTextFormatTaged(const ucstring &text)
-{
-
- // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
- ucstring tempText;
- // static to avoid reallocation
- static std::vector tempFormatTags;
- static std::vector tempTooltips;
- buildFormatTagText(text, tempText, tempFormatTags, tempTooltips);
- setCase (tempText, _CaseMode);
-
- // compare Tag arrays
- bool sameTagArray= false;
- if(_FormatTags.size()==tempFormatTags.size())
- {
- sameTagArray= true;
- for(uint i=0;i<_FormatTags.size();i++)
- {
- if(!_FormatTags[i].sameTag(tempFormatTags[i]))
- {
- sameTagArray= false;
- break;
- }
- }
- }
-
- // test transformed text with current one
- if(tempText!=_Text || !sameTagArray )
- {
- // copy tags
- _FormatTags= tempFormatTags;
- // Copy to Text (preserve Memory)
- contReset(_Text);
- _Text= tempText;
-
- CInterfaceGroup *parent = getParent();
-
- // Delete old dynamic tooltips
- for (uint i=0 ; i<_Tooltips.size() ; ++i)
- {
- if (parent)
- parent->delCtrl(_Tooltips[i]);
- else
- delete _Tooltips[i];
- }
- _Tooltips.clear();
-
- // Add new dynamic tooltips
- for (uint i=0 ; isetId(_Id+"_tt"+toString(i));
- pTooltip->setAvoidResizeParent(avoidResizeParent());
- pTooltip->setRenderLayer(getRenderLayer());
- pTooltip->setDefaultContextHelp(CI18N::get(tempTooltips[i].toString()));
- pTooltip->setParentPos(this);
- pTooltip->setParentPosRef(Hotspot_BR);
- pTooltip->setPosRef(Hotspot_BR);
- pTooltip->setToolTipParent(CCtrlBase::TTWindow);
- pTooltip->setToolTipParentPosRef(Hotspot_TTAuto);
- pTooltip->setToolTipPosRef(Hotspot_TTAuto);
- pTooltip->setActive(true);
-
- _Tooltips.push_back(pTooltip);
-
- if (parent)
- {
- pTooltip->setParent(parent);
- parent->addCtrl(_Tooltips.back());
- }
- }
-
- if (parent)
- _Setuped = true;
- else
- _Setuped = false;
-
- invalidateContent ();
- }
-
- // color format is available only if multilined
- if (!_MultiLine)
- nlwarning( toString("ViewText isn't multilined : uc_hardtext_format will not act as wanted !\n%s", text.toString().c_str()).c_str() );
-}
-
-
-void CViewText::setSingleLineTextFormatTaged(const ucstring &text)
-{
- // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
- ucstring tempText;
- static std::vector tempLetterColors;
- static std::vector tempTooltips;
-
- // parse text
- buildFormatTagText(text, tempText, tempLetterColors, tempTooltips);
- setCase (tempText, _CaseMode);
-
- // decal for spaces (not inserted in VertexBuffer)
- uint textIndex = 0;
- uint spacesNb = 0;
- for(uint i=0; icreateLetterColors();
- for(uint i=0; ipushLetterColor(formatTag.Index, formatTag.Color);
- }
-
- // test transformed text with current one
- if(tempText!=_Text || !_LetterColors || !_LetterColors->isSameLetterColors(letterColors))
- {
- _LetterColors = letterColors;
-
- TextContext->setLetterColors(letterColors, _Index);
-
- // Copy to Text (preserve Memory)
- contReset(_Text);
- _Text= tempText;
- invalidateContent ();
- }
-
- // this color format is available only if not multilined
- if (_MultiLine)
- nlwarning( toString("ViewText is multilined : uc_hardtext_single_line_format will not act as wanted !\n%s", text.toString().c_str()).c_str() );
-}
-
-
-// ***************************************************************************
-bool CViewText::isFormatTagChange(uint textIndex, uint ctIndex) const
-{
- if(ctIndex>=_FormatTags.size())
- return false;
- // return true if the textIndex is > (eg if some skip with spaces) or = (common case)
- return _FormatTags[ctIndex].Index <= textIndex;
-}
-
-// ***************************************************************************
-void CViewText::getFormatTagChange(uint textIndex, uint &ctIndex, CFormatInfo &wordFormat) const
-{
- // support the possible case with multiple color tags with same textIndex.
- while(ctIndex<_FormatTags.size() && _FormatTags[ctIndex].Index<=textIndex)
- {
- // Take the last tag.
- wordFormat.Color= _FormatTags[ctIndex].Color;
- wordFormat.TabX= _FormatTags[ctIndex].TabX;
- wordFormat.IndexTt= _FormatTags[ctIndex].IndexTt;
- // skip it.
- ctIndex++;
- }
-}
-
-
-// ***************************************************************************
-
-void CViewText::setCaseMode (TCaseMode caseMode)
-{
- _CaseMode = caseMode;
- setCase (_Text, _CaseMode);
-}
-
-// ***************************************************************************
-
-TCaseMode CViewText::getCaseMode () const
-{
- return _CaseMode;
-}
-
-// ***************************************************************************
-
-void CViewText::resetTextIndex()
-{
- _Index = 0xffffffff;
- for(uint k = 0; k < _Lines.size(); ++k)
- _Lines[k]->resetTextIndex();
-}
-
-// ***************************************************************************
-void CViewText::setup()
-{
- _Setuped= true;
-
- // Add dynamic tooltips
- for (uint i=0 ; i<_Tooltips.size() ; ++i)
- {
- CInterfaceGroup *parent = getParent();
- if (parent)
- {
- _Tooltips[i]->setParent(parent);
- parent->addCtrl(_Tooltips.back());
- }
- }
-}
-
-// ***************************************************************************
-void CViewText::serial(NLMISC::IStream &f)
-{
- #define SERIAL_UINT(val) { uint32 tmp = (uint32) val; f.serial(tmp); val = (uint) tmp; }
- #define SERIAL_SINT(val) { sint32 tmp = (sint32) val; f.serial(tmp); val = (sint) tmp; }
- CViewBase::serial(f);
- SERIAL_SINT(_FontSize);
- SERIAL_UINT(_FontWidth);
- SERIAL_UINT(_FontHeight);
- SERIAL_UINT(_FontLegHeight);
- f.serial(_SpaceWidth);
- f.serial(_Color);
- f.serial(_Shadow);
- f.serialEnum(_CaseMode);
- f.serial(_ShadowColor);
- f.serial(_LineMaxW);
- f.serial(_SingleLineTextClamped);
- f.serial(_MultiLine);
- f.serial(_MultiLineMaxWOnly);
- f.serial(_MultiLineClipEndSpace);
- f.serial(_AutoClampOffset);
- f.serialEnum(_TextMode);
- SERIAL_SINT(_MultiLineSpace);
- SERIAL_SINT(_LastMultiLineMaxW);
- f.serial(_MultiMaxLine);
-
- bool hasTag = !_FormatTags.empty();
- f.serial(hasTag);
- if (f.isReading())
- {
- ucstring text;
- f.serial(text);
- if (hasTag)
- {
- if (_MultiLine)
- {
- setTextFormatTaged(text);
- }
- else
- {
- setSingleLineTextFormatTaged(text);
- }
- }
- else
- {
- setText(text);
- }
- }
- else
- {
- f.serial(_Text);
- }
-
- #undef SERIAL_UINT
- #undef SERIAL_SINT
-}
-
-
-// ***************************************************************************
diff --git a/code/ryzom/client/src/interface_v3/view_text.h b/code/ryzom/client/src/interface_v3/view_text.h
deleted file mode 100644
index 9fe54825b..000000000
--- a/code/ryzom/client/src/interface_v3/view_text.h
+++ /dev/null
@@ -1,413 +0,0 @@
-// Ryzom - MMORPG Framework
-// 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 .
-
-
-
-#ifndef NL_VIEW_TEXT_H
-#define NL_VIEW_TEXT_H
-
-#include "nel/gui/view_base.h"
-#include "nel/gui/string_case.h"
-#include "nel/3d/u_text_context.h"
-
-namespace NLGUI
-{
- class CCtrlToolTip;
-}
-
-
-/**
- * class implementing a text view
- * \author Matthieu 'TrapII' Besson
- * \author Nicolas Vizerie
- * \author Nevrax France
- * \date 2002
- */
-class CViewText : public CViewBase
-{
-public:
- enum TTextMode { ClipWord, DontClipWord, Justified };
-public:
-
- DECLARE_UI_CLASS(CViewText)
-
-
- /// Constructor
- CViewText (const TCtorParam ¶m);
-
- /// Constructor
- CViewText (const std::string& id, const std::string Text="", sint FontSize=12,
- NLMISC::CRGBA Color=NLMISC::CRGBA(255,255,255), bool Shadow=false);
-
- virtual ~CViewText();
-
- CViewText &operator=(const CViewText &vt);
-
- void parseTextOptions (xmlNodePtr cur);
- bool parse (xmlNodePtr cur, CInterfaceGroup * parentGroup);
- virtual uint32 getMemory() { return (uint32)(sizeof(*this)+_Id.size()); }
-
- /// Updating
- virtual void draw ();
- void updateTextContext ();
- virtual void checkCoords();
- virtual void updateCoords();
- virtual void onAddToGroup();
-
- /// From CInterfaceElement
- sint32 getMaxUsedW() const;
- sint32 getMinUsedW() const;
-
- /// Accessors
-
- /// Set
-
- void setText (const ucstring &text);
- void setFontSize (sint nFontSize);
- void setColor (const NLMISC::CRGBA &color);
- void setShadow (bool bShadow);
- void setShadowColor (const NLMISC::CRGBA &color);
- void setLineMaxW (sint nMaxW, bool invalidate=true);
- void setMultiLine (bool bMultiLine);
- void setMultiLineSpace (sint nMultiLineSpace);
- void setMultiLineMaxWOnly (bool state);
- void setMultiLineClipEndSpace (bool state); // use it for multiline edit box for instance
- void setFirstLineX (uint firstLineX);
- void setMultiMaxLine(uint l) { _MultiMaxLine = l; }
-
- // Force only a subset of letter to be displayed. Default is 0/0xFFFFFFFF
- void enableStringSelection(uint start, uint end);
- void disableStringSelection();
-
- /// Get
-
- ucstring getText() const { return _Text; }
- sint getFontSize() const;
- NLMISC::CRGBA getColor() { return _Color; }
- bool getShadow() { return _Shadow; }
- NLMISC::CRGBA getShadowColor() { return _ShadowColor; }
- sint getLineMaxW() const { return _LineMaxW; }
- bool getMultiLine() const { return _MultiLine; }
- sint getMultiLineSpace() const { return _MultiLineSpace; }
- bool getMultiLineMaxWOnly() const { return _MultiLineMaxWOnly; }
- uint32 getMultiMaxLine() const { return _MultiMaxLine; }
-
- // get current Hint font width, in pixels
- uint getFontWidth() const;
- // get current font height, in pixels
- uint getFontHeight() const;
- // get current font leg height, in pixels
- uint getFontLegHeight() const;
- // Set the display mode (supported with multiline only for now)
- void setTextMode(TTextMode mode);
- TTextMode getTextMode() const { return _TextMode; }
- uint getNumLine() const;
- uint getFirstLineX() const;
- uint getLastLineW () const;
- void setUnderlined (bool underlined) { _Underlined = underlined; }
- bool getUnderlined () const { return _Underlined; }
- // true if the viewText is a single line clamped.
- bool isSingleLineTextClamped() const {return _SingleLineTextClamped;}
-
- // Character positions
-
- /** Get position of the ith character, position are relative to the BR corner of the text.
- * \param lineEnd. When set to true, return the coordinate of the previous line if the index is at the start of a line.
- * When looking at standard edit box, we see that if a line is split accross to line with no
- * This also returns the height of the line
- */
- void getCharacterPositionFromIndex(sint index, bool lineEnd, sint &x, sint &y, sint &height) const;
- /** From a coordinate relative to the BR BR corner of the text, return the index of a character.
- * If no character is found at the given position, the closest character is returned (first or last character, for the line or the whole text)
- */
- void getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &lineEnd) const;
- /** From a character index, get the index of the line it belongs to, or -1 if the index is invalid
- * \param cursorDisplayedAtEndOfPreviousLine true if the cursor is displayed at the end of the previous line that match its index
- */
- sint getLineFromIndex(uint index, bool cursorDisplayedAtEndOfPreviousLine = true) const;
- /// From a line number, get the character at which it starts, or -1 if invalid
- sint getLineStartIndex(uint line) const;
- /// From a line number, get the character at which it ends (not including any '\n' ), or -1 if invalid
- void getLineEndIndex(uint line, sint &index, bool &endOfPreviousLine) const;
-
- std::string getHardText() const { std::string result; _Text.toString (result); return result; }
- void setHardText (const std::string &ht);
-
- std::string getColorAsString() const;
- void setColorAsString(const std::string &ht);
-
- NLMISC::CRGBA getColorRGBA() const;
- void setColorRGBA(NLMISC::CRGBA col);
-
- virtual sint32 getAlpha() const { return _Color.A; }
- virtual void setAlpha (sint32 a) { _ShadowColor.A = _Color.A = (uint8)a; }
-
- /** Setup a Text with Format Tags. Text is store without color/format tags, and special array is allocated for Format association
- */
- void setTextFormatTaged(const ucstring &text);
-
- void setSingleLineTextFormatTaged(const ucstring &text);
-
- // Remove end space
- void removeEndSpaces();
-
- // Reset the text index because the text context has changed
- void resetTextIndex();
-
- // Case mode
- void setCaseMode (TCaseMode caseMode);
- TCaseMode getCaseMode () const;
-
- // OverExtendViewText
- void setOverExtendViewText(bool state) {_OverExtendViewText= state;}
- bool getOverExtendViewText() const {return _OverExtendViewText;}
-
- // OverExtendViewTextUseParentRect
- void setOverExtendViewTextUseParentRect(bool state) {_OverExtendViewTextUseParentRect= state;}
- bool getOverExtendViewTextUseParentRect() const {return _OverExtendViewTextUseParentRect;}
-
- // see if text ellipsis if done at right side of the text
- bool isClampRight() const { return _ClampRight; }
-
- int luaSetLineMaxW(CLuaState &ls);
-
- REFLECT_EXPORT_START(CViewText, CViewBase)
- REFLECT_STRING("hardtext", getHardText, setHardText);
- REFLECT_UCSTRING("uc_hardtext", getText, setText);
- REFLECT_UCSTRING("uc_hardtext_format", getText, setTextFormatTaged);
- REFLECT_UCSTRING("uc_hardtext_single_line_format", getText, setSingleLineTextFormatTaged);
- REFLECT_STRING ("color", getColorAsString, setColorAsString);
- REFLECT_RGBA ("color_rgba", getColorRGBA, setColorRGBA);
- REFLECT_SINT32 ("alpha", getAlpha, setAlpha);
- REFLECT_BOOL ("overExtendViewText", getOverExtendViewText, setOverExtendViewText);
- REFLECT_BOOL ("overExtendViewTextUseParentRect", getOverExtendViewTextUseParentRect, setOverExtendViewTextUseParentRect);
- REFLECT_LUA_METHOD("setLineMaxW", luaSetLineMaxW);
- REFLECT_EXPORT_END
-
-
- virtual void serial(NLMISC::IStream &f);
-
-protected:
-
- /// Text to display.
- ucstring _Text;
- /// index of the computed String associated to this text control
- uint _Index;
- /// info on the computed String associated to this text control
- NL3D::UTextContext::CStringInfo _Info;
- /// the font size
- sint _FontSize;
- // width of the font in pixel. Just a Hint for tabing format (computed with '_')
- uint _FontWidth;
- // height of the font in pixel.
- // use getFontHeight
- uint _FontHeight;
- uint _FontLegHeight;
- float _SpaceWidth;
- /// the text color
- NLMISC::CRGBA _Color;
- /// the shadow mode
- bool _Shadow;
- /// the case mode
- TCaseMode _CaseMode;
- /// the text shadow color
- NLMISC::CRGBA _ShadowColor;
- /// Is the line (under p loop) should be considered at bottom (if false bottom is under p leg)
- /// maxw for the line/multiline
- sint32 _LineMaxW;
- /// For single line, true if the text is clamped (ie displayed with "...")
- bool _SingleLineTextClamped;
-
- /// Multiple lines handling
- bool _MultiLine;
- bool _MultiLineMaxWOnly;
- bool _MultiLineClipEndSpace;
- uint8 _AutoClampOffset;
- TTextMode _TextMode;
- sint _MultiLineSpace;
- sint _LastMultiLineMaxW;
- uint32 _MultiMaxLine;
-
-
- /// FormatTag handling
- struct CFormatInfo
- {
- // The color to change
- NLMISC::CRGBA Color;
- // The Tabulation to apply, in number of "_" characters.
- uint TabX;
- // Index in vector
- sint IndexTt;
-
- CFormatInfo()
- {
- Color= NLMISC::CRGBA::White;
- TabX= 0;
- IndexTt = -1;
- }
-
- bool operator==(const CFormatInfo &o) const {return Color==o.Color && TabX==o.TabX && IndexTt==o.IndexTt;}
- bool operator!=(const CFormatInfo &o) const {return !operator==(o);}
- };
- struct CFormatTag : public CFormatInfo
- {
- uint Index;
-
- // compare 2 tags, not a tag and a CFormatInfo
- bool sameTag(const CFormatTag &o) const
- {
- return CFormatInfo::operator==(o) && Index==o.Index;
- }
- };
- std::vector _FormatTags;
-
- /// Get the current maxW for multiline, accordgin to parent and _MultiLineOptionMaxW
- sint getCurrentMultiLineMaxW() const;
-
-
-
-
- NL3D::ULetterColors * _LetterColors;
-
-private:
- // A word in a line
- class CWord
- {
- public:
- // default ctor
- CWord(uint numSpaces = 0) : Index(0), NumSpaces(numSpaces) {}
- ucstring Text;
- uint Index; // index of the info for this word
- NL3D::UTextContext::CStringInfo Info;
- uint NumSpaces; // number of spaces before this word
- // The specialized color/format of this word. White if none
- CFormatInfo Format;
- public:
- // build from a string, using the current text context
- void build(const ucstring &text, uint numSpaces= 0);
- };
- typedef std::vector TWordVect;
-
- // A line of text (which is made of one word with space, or of several words with no spaces in them)
- class CLine : public NLMISC::CRefCount
- {
- public:
- // ctor
- CLine();
- // Clear the line & remove text contexts
- void clear();
- // Add a new word (and its context) in the line + a number of spaces to append at the end of the line
- void addWord(const ucstring &word, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth);
- void addWord(const CWord &word, uint fontWidth);
- uint getNumWords() const { return (uint)_Words.size(); }
- CWord &getWord(uint index) { return _Words[index]; }
- float getSpaceWidth() const { return _SpaceWidth; }
- void setSpaceWidth(float width) { _SpaceWidth = width; }
- // Get the number of chars in the line, not counting the end spaces, but couting the spaces in words
- uint getNumChars() const { return _NumChars; }
- // Get the total number of spaces between words (not including those in words, but there should not be if text is justified)
- uint getNumSpaces() const { return _NumSpaces; }
- float getStringLine() const { return _StringLine; }
- float getWidthWithoutSpaces() const { return _WidthWithoutSpaces; }
- // get total width including spaces, but not including end spaces
- float getWidth() const { return _WidthWithoutSpaces + _SpaceWidth * _NumSpaces; }
- // Get the number of spaces at the end of the line
- void setEndSpaces(uint numSpaces) { _EndSpaces = numSpaces; }
- // Set the number of spaces at the end of the line
- uint getEndSpaces() const { return _EndSpaces; }
- // Test if there's a line feed at the end of the line
- bool getLF() const { return _HasLF; }
- void setLF(bool lf) { _HasLF = lf; }
- void resetTextIndex();
- private:
- TWordVect _Words;
- uint _NumChars;
- uint _NumSpaces;
- float _SpaceWidth; // width of a space, in pixels (used with multispace alignment)
- float _StringLine;
- float _WidthWithoutSpaces; // width without space (see the Field NumSpaces in the CWord class).
- // NB : space inserted inside a word are counted, however!
- uint _EndSpaces; // spaces at the end of the line
- bool _HasLF; // a linefeed is at end of line (no breaking due to line full)
- };
- /// NB : we keep pointers on lines (each line contains a vector, that we don't want to be copied, and this occurs as the vector of lines grows..)
-
- typedef NLMISC::CSmartPtr TLineSPtr;
- typedef std::vector TLinePtVect;
-private:
- /** Data of the updated text for multiline. It is built from the _Text field in the updateTextContext member function,
- * and is used to perform the draw
- */
- TLinePtVect _Lines;
-
- /// if true, and if the view text is isSingleLineTextClamped(), then an over will be drawn, with the text
- bool _OverExtendViewText : 1;
- /// if true and _OverExtendViewText true too, use the parent rectangle to know if must display the over or not
- bool _OverExtendViewTextUseParentRect : 1;
- /// Letter selection handling
- bool _AutoClamp : 1;
- bool _ClampRight : 1;
- bool _TextSelection : 1;
- bool _InvalidTextContext : 1;
- bool _Underlined : 1;
- bool _ContinuousUpdate : 1;
- bool _Setuped : 1;
-
- uint _TextSelectionStart;
- uint _TextSelectionEnd;
-
- // First line X coordinate
- uint _FirstLineX;
-
- /// Dynamic tooltips
- std::vector _Tooltips;
-
-
-private:
- void setup ();
- void setupDefault ();
-
- void setStringSelectionSkipingSpace(uint stringId, const ucstring &text, sint charStart, sint charEnd);
-
-// void pushString(const ucstring &str, bool deleteSpaceAtStart = false);
-
- /// \from CInterfaceElement
- void onInvalidateContent();
-
- // may append a new line, and append a word to the last line (no spaces)
- void flushWordInLine(ucstring &ucCurrentWord, bool &linePushed, const CFormatInfo &wordFormat);
- // Clear all the lines and free their datas
- void clearLines();
- // Update in the case of a multiline text
- void updateTextContextMultiLine(uint nMaxWidth);
- // Update in the case of a multiline text with justification
- void updateTextContextMultiLineJustified(uint nMaxWidth, bool expandSpaces);
- // Recompute font size info
- void computeFontSize ();
-
- // used for "donctClipWord" case in updateTextContextMultiLineJustified(). currLine is reseted
- void addDontClipWordLine(std::vector &currLine);
-
- // FormatTag build.
- static void buildFormatTagText(const ucstring &text, ucstring &textBuild, std::vector &formatTags, std::vector &tooltips);
- // FormatTag parsing.
- bool isFormatTagChange(uint textIndex, uint ctIndex) const;
- void getFormatTagChange(uint textIndex, uint &ctIndex, CFormatInfo &wordFormat) const;
-};
-
-#endif // NL_VIEW_TEXT_H
-
-/* End of view_text.h */
diff --git a/code/ryzom/client/src/interface_v3/view_text_formated.h b/code/ryzom/client/src/interface_v3/view_text_formated.h
index 4e60e3f1f..0f8c2d4c0 100644
--- a/code/ryzom/client/src/interface_v3/view_text_formated.h
+++ b/code/ryzom/client/src/interface_v3/view_text_formated.h
@@ -19,7 +19,7 @@
#ifndef VIEW_TEXT_FORMATED_H
#define VIEW_TEXT_FORMATED_H
-#include "view_text.h"
+#include "nel/gui/view_text.h"
/** The same as a view text id, but with some display option
* The input is a formated string, every character is copied, but subsitution is done for each character preceded by $
diff --git a/code/ryzom/client/src/interface_v3/view_text_id.h b/code/ryzom/client/src/interface_v3/view_text_id.h
index 91d6b5f6e..f976791be 100644
--- a/code/ryzom/client/src/interface_v3/view_text_id.h
+++ b/code/ryzom/client/src/interface_v3/view_text_id.h
@@ -20,7 +20,7 @@
#define NL_VIEW_TEXT_ID_H
#include "nel/misc/types_nl.h"
-#include "view_text.h"
+#include "nel/gui/view_text.h"
namespace NLMISC{
class CCDBNodeLeaf;
diff --git a/code/ryzom/client/src/login.cpp b/code/ryzom/client/src/login.cpp
index 0b96b0782..842267e67 100644
--- a/code/ryzom/client/src/login.cpp
+++ b/code/ryzom/client/src/login.cpp
@@ -37,7 +37,7 @@
#include "interface_v3/input_handler_manager.h"
#include "interface_v3/group_editbox.h"
#include "interface_v3/group_quick_help.h"
-#include "interface_v3/view_text.h"
+#include "nel/gui/view_text.h"
#include "nel/gui/ctrl_button.h"
#include "interface_v3/ctrl_text_button.h"
#include "sound_manager.h"