1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/misc/bit_mem_stream.h"
24 #include "nel/misc/i18n.h"
26 #include "nel/gui/view_text.h"
27 #include "nel/gui/view_renderer.h"
28 #include "nel/gui/widget_manager.h"
29 #include "nel/gui/group_container_base.h"
30 #include "nel/gui/ctrl_tooltip.h"
31 #include "nel/misc/xml_auto_ptr.h"
32 #include "nel/gui/lua_ihm.h"
33 #include "nel/gui/view_pointer_base.h"
36 using namespace NLMISC
;
43 typedef std::string::size_type TCharPos
; // index of a chracter in a string
45 REGISTER_UI_CLASS(CViewText
)
50 // ***************************************************************************
51 void CViewText::setupDefault ()
55 _CaseMode
= CaseNormal
;
57 _StrikeThrough
= false;
58 _ContinuousUpdate
= false;
67 _ParentPosRef
= Hotspot_BL
;
71 CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
76 _Color
= CRGBA(255,255,255,255);
78 _ShadowOutline
= false;
79 _ShadowColor
= CRGBA(0,0,0,255);
84 _TextMode
= DontClipWord
;
86 _LineMaxW
= std::numeric_limits
<sint32
>::max();
87 _MultiLineMaxWOnly
= false;
88 _MultiLineClipEndSpace
= false;
89 _LastMultiLineMaxW
= 0;
94 _Scale
= CWidgetManager::getInstance()->getInterfaceScale();
100 _TextSelection
= false;
101 _TextSelectionStart
= 0;
102 _TextSelectionEnd
= std::numeric_limits
<uint
>::max();
104 _InvalidTextContext
= true;
107 _SingleLineTextClamped
= false;
108 _OverExtendViewText
= false;
109 _OverExtendViewTextUseParentRect
= false;
112 _ClampRight
= true; // clamp on the right of the text
113 _OverflowText
= "...";
117 _LetterColors
= NULL
;
119 _AutoClampOffset
= 0;
122 // - "_" that should be the character with the lowest part
123 // - A with an accent for the highest part
124 // https://www.compart.com/en/unicode/U+00C4
125 _FontSizingChars
= "_\xC3\x84q";
126 // fallback if SizingChars are not supported by font
127 _FontSizingFallback
= "|XO";
131 // ***************************************************************************
133 NLMISC_REGISTER_OBJECT(CViewBase
, CViewText
, std::string
, "text");
135 CViewText::CViewText(const TCtorParam
¶m
)
140 CWidgetManager::getInstance()->registerInterfaceScaleWatcher(this);
144 // ***************************************************************************
145 CViewText:: CViewText (const std::string
& id
, const std::string Text
, sint FontSize
,
146 NLMISC::CRGBA Color
, bool Shadow
, bool ShadowOutline
)
147 :CViewBase(TCtorParam())
152 _FontSize
= FontSize
+ CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
153 _FontSizeCoef
= true;
156 _ShadowOutline
= ShadowOutline
;
160 CWidgetManager::getInstance()->registerInterfaceScaleWatcher(this);
163 // ***************************************************************************
164 CViewText::~CViewText()
166 CWidgetManager::getInstance()->unregisterInterfaceScaleWatcher(this);
168 if (_Index
!= 0xFFFFFFFF)
169 CViewRenderer::getTextContext(_FontName
)->erase (_Index
);
173 for (uint i
=0 ; i
<_Tooltips
.size() ; ++i
)
179 // ***************************************************************************
180 CViewText
&CViewText::operator=(const CViewText
&vt
)
182 if (_Index
!= 0xFFFFFFFF)
183 CViewRenderer::getTextContext(_FontName
)->erase (_Index
);
185 // Create database entries
186 _Active
= vt
._Active
;
191 _SizeRef
= vt
._SizeRef
;
192 _SizeDivW
= vt
._SizeDivW
;
193 _SizeDivH
= vt
._SizeDivH
;
194 _ParentPosRef
= vt
._ParentPosRef
;
195 _PosRef
= vt
._PosRef
;
197 _FontSize
= vt
._FontSize
;
198 _FontSizeCoef
= vt
._FontSizeCoef
;
199 _Embolden
= vt
._Embolden
;
200 _Oblique
= vt
._Oblique
;
201 _Underlined
= vt
._Underlined
;
202 _StrikeThrough
= vt
._StrikeThrough
;
204 _Shadow
= vt
._Shadow
;
205 _ShadowOutline
= vt
._ShadowOutline
;
206 _ShadowColor
= vt
._ShadowColor
;
210 _LineMaxW
= std::numeric_limits
<sint32
>::max();
211 _MultiLineMaxWOnly
= false;
212 _MultiLineClipEndSpace
= false;
213 _LastMultiLineMaxW
= 0;
216 _ModulateGlobalColor
= vt
._ModulateGlobalColor
;
217 _Localized
= vt
._Localized
;
219 // remove previous lines
221 _InvalidTextContext
= true;
227 std::string
CViewText::getProperty( const std::string
&name
) const
229 std::string prop
= getTextProperty( name
);
234 if( name
== "hardtext" )
236 return getHardText();
239 if( name
== "hardtext_format" )
241 return _HardTextFormat
;
244 return CViewBase::getProperty( name
);
248 std::string
CViewText::getTextProperty( const std::string
&name
) const
250 if( name
== "localize" )
252 return toString(_Localized
);
255 if( name
== "color" )
257 return toString( _Color
);
260 if( name
== "global_color" )
262 return toString( _ModulateGlobalColor
);
265 if( name
== "fontsize" )
268 return toString(_FontSize
- CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32());
270 return toString(_FontSize
);
273 if ( name
== "fontsize_coef" )
275 return toString(_FontSizeCoef
);
278 if( name
== "fontweight" )
285 if( name
== "fontstyle" )
293 if( name
== "shadow" )
295 return toString( _Shadow
);
298 if( name
== "shadow_outline" )
300 return toString( _ShadowOutline
);
303 if( name
== "shadow_color" )
305 return toString( _ShadowColor
);
308 if( name
== "multi_line" )
310 return toString( _MultiLine
);
313 if( name
== "justification" )
322 return "dont_clip_word";
336 if( name
== "line_maxw" )
338 return toString( _LineMaxW
);
341 if( name
== "multi_line_space" )
343 return toString( _MultiLineSpace
);
346 if( name
== "multi_line_maxw_only" )
348 return toString( _MultiLineMaxWOnly
);
351 if( name
== "multi_max_line" )
353 return toString( _MultiMaxLine
);
356 if( name
== "multi_min_line" )
358 return toString( _MultiMinLine
);
361 if( name
== "underlined" )
363 return toString( _Underlined
);
366 if( name
== "strikethrough" )
368 return toString( _StrikeThrough
);
371 if( name
== "case_mode" )
373 return toString( uint32( _CaseMode
) );
376 if( name
== "over_extend_view_text" )
378 return toString( _OverExtendViewText
);
381 if( name
== "over_extend_parent_rect" )
383 return toString( _OverExtendViewTextUseParentRect
);
386 if( name
== "auto_clamp" )
388 return toString( _AutoClamp
);
391 if( name
== "clamp_right" )
393 return toString( _ClampRight
);
396 if( name
== "auto_clamp_offset" )
398 return toString( _AutoClampOffset
);
401 if( name
== "continuous_update" )
403 return toString( _ContinuousUpdate
);
406 if ( name
== "sizing_chars" )
408 return _FontSizingChars
;
411 if ( name
== "sizing_fallback" )
413 return _FontSizingFallback
;
419 void CViewText::setProperty( const std::string
&name
, const std::string
&value
)
421 if( setTextProperty( name
, value
) )
424 CViewBase::setProperty( name
, value
);
427 bool CViewText::setTextProperty( const std::string
&name
, const std::string
&value
)
429 if( name
== "localize" )
432 if (fromString(value
, b
))
435 setTextLocalized(_HardText
.empty() ? _Text
: _HardText
); // FIXME: setCase?
441 if( name
== "color" )
444 if( fromString( value
, c
) )
449 if( name
== "global_color" )
452 if( fromString( value
, b
) )
453 _ModulateGlobalColor
= b
;
457 if( name
== "fontsize" )
460 if( fromString( value
, i
) )
461 _FontSize
= i
+ CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
465 if( name
== "fontsize_coef" )
468 bool oldValue
= _FontSizeCoef
;
469 if (fromString( value
, b
) )
471 // must only change font size when current state changes
472 if (_FontSizeCoef
!= oldValue
)
475 _FontSize
+= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
477 _FontSize
-= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
481 if( name
== "fontweight" )
488 if( name
== "fontstyle" )
490 if( value
== "oblique" )
495 if( name
== "shadow" )
498 if( fromString( value
, b
) )
503 if( name
== "shadow_outline" )
506 if( fromString( value
, b
) )
511 if( name
== "shadow_color" )
514 if( fromString( value
, c
) )
519 if( name
== "shadow_x" )
522 if( fromString( value
, sx
) )
527 if( name
== "shadow_y" )
530 if( fromString( value
, sy
) )
535 if( name
== "multi_line" )
538 if( fromString( value
, b
) )
543 if( name
== "justification" )
545 if( value
== "clip_word" )
546 _TextMode
= ClipWord
;
548 if( value
== "dont_clip_word" )
549 _TextMode
= DontClipWord
;
551 if( value
== "justified" )
552 _TextMode
= Justified
;
554 if( value
== "centered" )
555 _TextMode
= Centered
;
560 if( name
== "line_maxw" )
563 if( fromString( value
, i
) )
568 if( name
== "multi_line_space" )
571 if( fromString( value
, i
) )
576 if( name
== "multi_line_maxw_only" )
579 if( fromString( value
, b
) )
580 _MultiLineMaxWOnly
= b
;
584 if( name
== "multi_max_line" )
587 if( fromString( value
, i
) )
592 if( name
== "multi_min_line" )
595 if( fromString( value
, i
) )
600 if( name
== "underlined" )
603 if( fromString( value
, b
) )
608 if( name
== "strikethrough" )
611 if( fromString( value
, b
) )
616 if( name
== "case_mode" )
619 if( fromString( value
, i
) )
620 _CaseMode
= (TCaseMode
)i
;
624 if( name
== "over_extend_view_text" )
627 if( fromString( value
, b
) )
628 _OverExtendViewText
= b
;
632 if( name
== "over_extend_parent_rect" )
635 if( fromString( value
, b
) )
636 _OverExtendViewTextUseParentRect
= b
;
640 if( name
== "auto_clamp" )
643 if( fromString( value
, b
) )
648 if( name
== "clamp_right" )
651 if( fromString( value
, b
) )
656 if( name
== "auto_clamp_offset" )
659 if( fromString( value
, i
) )
660 _AutoClampOffset
= i
;
664 if( name
== "continuous_update" )
667 if( fromString( value
, b
) )
668 _ContinuousUpdate
= b
;
674 setTextLocalized(value
); // FIXME: setCase?
680 if( name
== "hardtext" )
683 setTextLocalized(value
); // FIXME: setCase?
689 if( name
== "hardtext_format" )
691 _HardTextFormat
= value
;
694 setTextFormatTaged( _HardTextFormat
);
696 setSingleLineTextFormatTaged( _HardTextFormat
);
701 if( name
== "sizing_chars" )
703 _FontSizingChars
= value
;
707 if( name
== "sizing_fallback" )
709 _FontSizingFallback
= value
;
717 bool CViewText::serializeTextOptions( xmlNodePtr node
) const
719 xmlSetProp( node
, BAD_CAST
"localize", BAD_CAST
toString( _Localized
).c_str() );
721 xmlSetProp( node
, BAD_CAST
"color", BAD_CAST
toString( _Color
).c_str() );
722 xmlSetProp( node
, BAD_CAST
"global_color", BAD_CAST
toString( _ModulateGlobalColor
).c_str() );
724 sint32 fontSize
= _FontSize
;
725 if (_FontSizeCoef
) fontSize
-= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
726 xmlSetProp( node
, BAD_CAST
"fontsize", BAD_CAST
toString(fontSize
).c_str() );
727 xmlSetProp( node
, BAD_CAST
"fontsize_coef", BAD_CAST
toString(_FontSizeCoef
).c_str() );
729 std::string
fontweight("normal");
732 xmlSetProp( node
, BAD_CAST
"fontweight", BAD_CAST fontweight
.c_str() );
734 std::string
fontstyle("normal");
736 fontstyle
= "oblique";
737 xmlSetProp( node
, BAD_CAST
"fontstyle", BAD_CAST fontstyle
.c_str() );
739 xmlSetProp( node
, BAD_CAST
"shadow", BAD_CAST
toString( _Shadow
).c_str() );
740 xmlSetProp( node
, BAD_CAST
"shadow_outline", BAD_CAST
toString( _ShadowOutline
).c_str() );
741 xmlSetProp( node
, BAD_CAST
"shadow_color", BAD_CAST
toString( _ShadowColor
).c_str() );
742 xmlSetProp( node
, BAD_CAST
"shadow_x", BAD_CAST
toString( _ShadowX
).c_str() );
743 xmlSetProp( node
, BAD_CAST
"shadow_y", BAD_CAST
toString( _ShadowY
).c_str() );
744 xmlSetProp( node
, BAD_CAST
"multi_line", BAD_CAST
toString( _MultiLine
).c_str() );
755 just
= "dont_clip_word";
767 xmlSetProp( node
, BAD_CAST
"justification", BAD_CAST just
.c_str() );
768 xmlSetProp( node
, BAD_CAST
"line_maxw", BAD_CAST
toString( _LineMaxW
).c_str() );
769 xmlSetProp( node
, BAD_CAST
"multi_line_space", BAD_CAST
toString( _MultiLineSpace
).c_str() );
770 xmlSetProp( node
, BAD_CAST
"multi_line_maxw_only", BAD_CAST
toString( _MultiLineMaxWOnly
).c_str() );
771 xmlSetProp( node
, BAD_CAST
"multi_max_line", BAD_CAST
toString( _MultiMaxLine
).c_str() );
772 xmlSetProp( node
, BAD_CAST
"multi_min_line", BAD_CAST
toString( _MultiMinLine
).c_str() );
773 xmlSetProp( node
, BAD_CAST
"underlined", BAD_CAST
toString( _Underlined
).c_str() );
774 xmlSetProp( node
, BAD_CAST
"strikethrough", BAD_CAST
toString( _StrikeThrough
).c_str() );
775 xmlSetProp( node
, BAD_CAST
"case_mode", BAD_CAST
toString( uint32( _CaseMode
) ).c_str() );
776 xmlSetProp( node
, BAD_CAST
"over_extend_view_text", BAD_CAST
toString( _OverExtendViewText
).c_str() );
777 xmlSetProp( node
, BAD_CAST
"over_extend_parent_rect",
778 BAD_CAST
toString( _OverExtendViewTextUseParentRect
).c_str() );
779 xmlSetProp( node
, BAD_CAST
"auto_clamp", BAD_CAST
toString( _AutoClamp
).c_str() );
780 xmlSetProp( node
, BAD_CAST
"clamp_right", BAD_CAST
toString( _ClampRight
).c_str() );
781 xmlSetProp( node
, BAD_CAST
"auto_clamp_offset", BAD_CAST
toString( _AutoClampOffset
).c_str() );
782 xmlSetProp( node
, BAD_CAST
"continuous_update", BAD_CAST
toString( _ContinuousUpdate
).c_str() );
783 xmlSetProp( node
, BAD_CAST
"sizing_chars", BAD_CAST _FontSizingChars
.c_str() );
784 xmlSetProp( node
, BAD_CAST
"sizing_fallback", BAD_CAST _FontSizingFallback
.c_str() );
790 xmlNodePtr
CViewText::serialize( xmlNodePtr parentNode
, const char *type
) const
792 xmlNodePtr node
= CViewBase::serialize( parentNode
, type
);
796 xmlSetProp( node
, BAD_CAST
"type", BAD_CAST
"text" );
798 serializeTextOptions( node
);
800 xmlSetProp( node
, BAD_CAST
"text", BAD_CAST (_HardText
.empty() ? _Text
.c_str() : _HardText
.c_str()) );
801 xmlSetProp( node
, BAD_CAST
"hardtext_format", BAD_CAST _HardTextFormat
.c_str() );
806 // ***************************************************************************
807 void CViewText::parseTextOptions (xmlNodePtr cur
)
811 prop
= xmlGetProp (cur
, (xmlChar
*)"localize");
812 if (prop
) _Localized
= convertBool((const char*)prop
);
814 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"color" );
815 _Color
= CRGBA(255,255,255,255);
817 _Color
= convertColor(prop
);
819 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"global_color");
821 _ModulateGlobalColor
= convertBool(prop
);
823 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"fontsize" );
824 _FontSize
= 12 + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
827 fromString((const char*)prop
, _FontSize
);
828 _FontSize
+= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
831 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"fontsize_coef" );
832 _FontSizeCoef
= true;
835 _FontSizeCoef
= convertBool(prop
);
837 _FontSize
-= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
841 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"fontweight" );
845 if (nlstricmp("bold", (const char*)prop
) == 0) _Embolden
= true;
846 else nlwarning("<CViewText::parse> bad fontweight '%s'", (const char *)prop
);
849 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"fontstyle" );
853 if (nlstricmp("oblique", (const char *) prop
) == 0) _Oblique
= true;
854 else nlwarning("<CViewText::parse> bad fontstyle '%s'", (const char *)prop
);
857 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"shadow" );
860 _Shadow
= convertBool(prop
);
862 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"shadow_outline" );
863 _ShadowOutline
= false;
865 _ShadowOutline
= convertBool(prop
);
867 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"shadow_color" );
868 _ShadowColor
= CRGBA(0,0,0,255);
870 _ShadowColor
= convertColor(prop
);
872 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"shadow_x" );
875 fromString( (const char *)prop
, _ShadowX
);
877 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"shadow_y" );
880 fromString( (const char *)prop
, _ShadowY
);
882 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"multi_line" );
885 _MultiLine
= convertBool(prop
);
887 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"justification" );
890 if (nlstricmp("clip_word", (const char *) prop
) == 0) _TextMode
= ClipWord
;
891 else if (nlstricmp("dont_clip_word", (const char *) prop
) == 0) _TextMode
= DontClipWord
;
892 else if (nlstricmp("justified", (const char *) prop
) == 0) _TextMode
= Justified
;
893 else if (nlstricmp("centered", (const char *) prop
) == 0) _TextMode
= Centered
;
894 else nlwarning("<CViewText::parse> bad text mode");
897 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"line_maxw" );
898 _LineMaxW
= std::numeric_limits
<sint32
>::max();
900 fromString((const char*)prop
, _LineMaxW
);
902 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"multi_line_space" );
905 fromString((const char*)prop
, _MultiLineSpace
);
907 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"multi_line_maxw_only" );
908 _MultiLineMaxWOnly
= false;
910 _MultiLineMaxWOnly
= convertBool(prop
);
912 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"multi_max_line" );
915 fromString((const char*)prop
, _MultiMaxLine
);
917 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"multi_min_line" );
920 fromString((const char*)prop
, _MultiMinLine
);
922 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"underlined" );
925 _Underlined
= convertBool(prop
);
927 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"strikethrough" );
928 _StrikeThrough
= false;
930 _StrikeThrough
= convertBool(prop
);
932 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"case_mode" );
933 _CaseMode
= CaseNormal
;
937 fromString((const char*)prop
, caseMode
);
938 _CaseMode
= (TCaseMode
)caseMode
;
941 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"over_extend_view_text" );
942 _OverExtendViewText
= false;
944 _OverExtendViewText
= convertBool(prop
);
946 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"over_extend_parent_rect" );
947 _OverExtendViewTextUseParentRect
= false;
949 _OverExtendViewTextUseParentRect
= convertBool(prop
);
951 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"auto_clamp" );
954 _AutoClamp
= convertBool(prop
);
956 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"clamp_right" );
959 _ClampRight
= convertBool(prop
);
961 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"auto_clamp_offset" );
962 _AutoClampOffset
= 0;
964 fromString((const char*)prop
, _AutoClampOffset
);
966 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"continuous_update" );
969 _ContinuousUpdate
= convertBool(prop
);
972 // "_Ä" lowest/highest chars (underscore, A+diaeresis)
973 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"sizing_chars" );
975 _FontSizingChars
= (const char*)prop
;
977 _FontSizingChars
= "_\xC3\x84q";
979 // fallback if SizingChars are not supported by font
980 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"sizing_fallback" );
982 _FontSizingFallback
= (const char *)prop
;
984 _FontSizingFallback
= "|XO";
990 * parse an xml node and initialize the base view mambers. Must call CViewBase::parse
991 * \param cur : pointer to the xml node to be parsed
992 * \param parentGroup : the parent group of the view
993 * \partam id : a refence to the string that will receive the view ID
994 * \return true if success
996 // ***************************************************************************
997 bool CViewText::parse(xmlNodePtr cur
, CInterfaceGroup
* parentGroup
)
1001 //try to get props that can be inherited from groups
1002 //if a property is not defined, try to find it in the parent group.
1003 //if it is undefined, set it to zero
1005 if (! CViewBase::parse(cur
,parentGroup
) )
1008 //set w and h to 0 : they depend on the string contained
1012 //try to get the NEEDED specific props
1013 parseTextOptions(cur
);
1015 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"hardtext" );
1018 const char *propPtr
= prop
;
1020 setTextLocalized(propPtr
);
1021 setCase(_Text
, _CaseMode
);
1025 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"hardtext_format" );
1028 const char *propPtr
= prop
;
1029 _HardTextFormat
= propPtr
;
1033 if (NLMISC::startsWith(propPtr
, "u:"))
1034 setTextFormatTaged(std::string(propPtr
).substr(2));
1036 setTextFormatTaged(CI18N::get(propPtr
));
1040 setSingleLineTextFormatTaged(CI18N::get(propPtr
));
1044 invalidateContent ();
1049 // ***************************************************************************
1050 sint
CViewText::getCurrentMultiLineMaxW() const
1052 if(_MultiLineMaxWOnly
)
1056 sint offset
= (sint
)_XReal
- (sint
)_Parent
->getXReal();
1057 return std::min(_Parent
->getInnerWidth() - offset
, (sint
)_LineMaxW
);
1062 // ***************************************************************************
1063 void CViewText::checkCoords ()
1065 if ((_MultiLine
)&&(_Parent
!= NULL
))
1067 // If never setuped, and if text is not empty
1068 if (_Lines
.empty() && !_Text
.empty())
1069 invalidateContent ();
1071 sint currentMaxW
= getCurrentMultiLineMaxW();
1072 if ( _LastMultiLineMaxW
!= currentMaxW
)
1074 if (_ContinuousUpdate
)
1076 _LastMultiLineMaxW
= currentMaxW
;
1077 invalidateContent();
1081 CCtrlBase
*pCB
= CWidgetManager::getInstance()->getCapturePointerLeft();
1084 if( pCB
->isResizer() )
1086 // We are resizing !!!!
1090 _LastMultiLineMaxW
= currentMaxW
;
1091 invalidateContent();
1096 _LastMultiLineMaxW
= currentMaxW
;
1097 invalidateContent();
1104 if (_Index
== 0xFFFFFFFF)
1105 invalidateContent ();
1111 // ***************************************************************************
1112 void CViewText::draw ()
1114 H_AUTO( RZ_Interface_CViewText_draw
)
1116 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
1119 //rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(64,64,64,255));
1121 // debug text with mouse hover
1122 if(CWidgetManager::getInstance()->getPointer())
1124 // but must check first if mouse is over
1125 sint32 x
= CWidgetManager::getInstance()->getPointer()->getX();
1126 sint32 y
= CWidgetManager::getInstance()->getPointer()->getY();
1128 // use parent clip or self clip?
1129 if(_OverExtendViewTextUseParentRect
)
1130 mouseIn
= _Parent
&& _Parent
->isIn(x
,y
);
1133 // if the mouse cursor is in the clip area
1136 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), CRGBA(200,200,200,255));
1137 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
+_HReal
, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), CRGBA(200,200,200,255));
1138 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
, 1, _HReal
, 0, false, rVR
.getBlankTextureId(), CRGBA(200,200,200,255));
1139 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
+_WReal
, _YReal
, 1, _HReal
, 0, false, rVR
.getBlankTextureId(), CRGBA(200,200,200,255));
1145 sint32 ClipX
, ClipY
, ClipW
, ClipH
;
1146 rVR
.getClipWindow (ClipX
, ClipY
, ClipW
, ClipH
);
1147 if (((_XReal
) > (ClipX
+ClipW
)) || ((_XReal
+_WReal
) < ClipX
) ||
1148 ((_YReal
) > (ClipY
+ClipH
)) || ((_YReal
+_HReal
) < ClipY
))
1151 // hack: allow shadow to overflow outside parent box.
1152 // In CGroupHTML context, clip is set for row
1153 if (std::abs(_ShadowX
) > 0)
1158 if (std::abs(_ShadowY
) > 0)
1164 // *** Screen Minimized?
1165 if (rVR
.isMinimized())
1168 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
1171 // *** get current color
1173 if(getModulateGlobalColor())
1175 CRGBA gcfc
= CWidgetManager::getInstance()->getGlobalColorForContent();
1176 col
.modulateFromColor (_Color
, gcfc
);
1177 shcol
.modulateFromColor (_ShadowColor
, gcfc
);
1182 shcol
= _ShadowColor
;
1183 col
.A
= (uint8
)(((sint
)col
.A
*((sint
)CWidgetManager::getInstance()->getGlobalColorForContent().A
+1))>>8);
1184 shcol
.A
= (uint8
)(((sint
)shcol
.A
*((sint
)CWidgetManager::getInstance()->getGlobalColorForContent().A
+1))>>8);
1188 rVR
.getScreenOOSize (oow
, ooh
);
1190 // *** Draw multiline
1191 if ((_MultiLine
)&&(_Parent
!= NULL
))
1193 if (_Lines
.empty()) return;
1195 TextContext
->setHotSpot (UTextContext::BottomLeft
);
1196 TextContext
->setShaded (_Shadow
);
1197 TextContext
->setShadeOutline (_ShadowOutline
);
1198 TextContext
->setShadeColor (shcol
);
1199 TextContext
->setShadeExtent (_ShadowX
*oow
, _ShadowY
*ooh
);
1200 TextContext
->setFontSize (_FontSize
*_Scale
);
1201 TextContext
->setEmbolden (_Embolden
);
1202 TextContext
->setOblique (_Oblique
);
1204 // Y is the base line of the string, so it must be grown up.
1205 float y
= _YReal
* _Scale
+ _FontLegHeight
;
1207 if (_MultiMinLine
> _Lines
.size())
1209 y
+= getMultiMinOffsetY() * _Scale
;
1212 // special selection code
1216 for (sint i
= 0; i
<(sint
)_Lines
.size(); i
++)
1218 CLine
&currLine
= *_Lines
[i
];
1219 for(uint k
= 0; k
< currLine
.getNumWords(); ++k
)
1221 CWord
&currWord
= currLine
.getWord(k
);
1222 charIndex
+= currWord
.NumSpaces
;
1223 sint cStart
= max(charIndex
, (sint
)_TextSelectionStart
);
1224 sint cEnd
= min(charIndex
+(sint
)currWord
.Info
.StringLength
, (sint
)_TextSelectionEnd
);
1226 // range must be valid
1229 // select subset. Arg, must skip spaces because not inserted in VertexBuffer.
1230 setStringSelectionSkipingSpace(currWord
.Index
, currWord
.Text
, cStart
-charIndex
, cEnd
-charIndex
);
1235 TextContext
->setStringSelection(currWord
.Index
, 0, 0);
1239 charIndex
+= (sint
)currWord
.Info
.StringLength
;
1241 charIndex
+= currLine
.getEndSpaces() + (currLine
.getLF() ? 1 : 0);
1246 for (sint i
= (sint
)_Lines
.size()-1; i
>= 0; --i
)
1248 CLine
&currLine
= *_Lines
[i
];
1249 // current x position
1250 float px
= (float) (_XReal
* _Scale
+ ((i
==0) ? _FirstLineX
: 0.f
));
1252 // Center line to computed maximum line width (_WReal)
1254 // Does not give most accurate result when _WReal is much smaller than parent,
1255 // but _WReal also defines mouseover hotspot/tooltip area.
1257 // May not work correctly in CGroupParagraph (multiple text elements).
1259 if (_TextMode
== Centered
)
1260 px
+= (float)(_WReal
* _Scale
- (currLine
.getWidth() + (i
== 0 ? _FirstLineX
: 0.f
)) )/ 2.f
;
1262 // draw each words of the line
1263 for(uint k
= 0; k
< currLine
.getNumWords(); ++k
)
1265 CWord
&currWord
= currLine
.getWord(k
);
1267 // Change the current color
1268 if(currWord
.Format
.Color
==CRGBA::White
)
1269 TextContext
->setStringColor(currWord
.Index
, col
);
1273 mCol
.modulateFromColor(col
, currWord
.Format
.Color
);
1274 TextContext
->setStringColor(currWord
.Index
, mCol
);
1277 // skip spaces before current word
1278 float firstSpace
= currWord
.NumSpaces
* currLine
.getSpaceWidth();
1279 sint line_width
= 0;
1280 if (_Underlined
|| _StrikeThrough
)
1282 line_width
= (sint
)floorf(currLine
.getWidthWithoutSpaces() + currLine
.getSpaceWidth());
1283 line_width
-= (sint
)floorf(firstSpace
);
1286 // skip tabulation before current word
1287 if(currWord
.Format
.TabX
)
1288 px
= max(px
, (float)(_XReal
* _Scale
+ currWord
.Format
.TabX
*_TabWidth
));
1290 // draw. We take floorf px to avoid filtering of letters that are not located on a pixel boundary
1291 float fx
= px
/ _Scale
;
1292 float fy
= y
/ _Scale
;
1293 rVR
.drawText (_RenderLayer
, fx
, fy
, currWord
.Index
, ClipX
, ClipY
, ClipX
+ClipW
, ClipY
+ClipH
, *TextContext
);
1297 rVR
.drawRotFlipBitmap (_RenderLayer
, fx
, fy
- _FontLegHeight
*0.6f
/ _Scale
, line_width
/ _Scale
, 1.0f
/ _Scale
, 0, false, rVR
.getBlankTextureId(), col
);
1300 rVR
.drawRotFlipBitmap (_RenderLayer
, fx
, fy
+ _FontHeight
*0.2f
/ _Scale
, line_width
/ _Scale
, 1.0f
/ _Scale
, 0, false, rVR
.getBlankTextureId(), col
);
1303 px
+= currWord
.Info
.StringWidth
;
1306 y
+= (_FontHeight
+ _MultiLineSpace
* _Scale
);
1312 for (sint i
= 0; i
<(sint
)_Lines
.size(); i
++)
1314 CLine
&currLine
= *_Lines
[i
];
1315 for(uint k
= 0; k
< currLine
.getNumWords(); ++k
)
1317 TextContext
->resetStringSelection(currLine
.getWord(k
).Index
);
1322 // *** Single Line Version (currently no support for text justification)
1325 nlassert(_Index
!= 0xFFFFFFFF);
1327 TextContext
->setHotSpot (UTextContext::BottomLeft
);
1328 TextContext
->setShaded (_Shadow
);
1329 TextContext
->setShadeOutline (_ShadowOutline
);
1330 TextContext
->setShadeColor (shcol
);
1331 TextContext
->setShadeExtent (_ShadowX
*oow
, _ShadowY
*ooh
);
1332 TextContext
->setFontSize (_FontSize
*_Scale
);
1333 TextContext
->setEmbolden (_Embolden
);
1334 TextContext
->setOblique (_Oblique
);
1336 if(_LetterColors
!=NULL
&& !TextContext
->isSameLetterColors(_LetterColors
, _Index
))
1338 TextContext
->setLetterColors(_LetterColors
, _Index
);
1341 // Y is the base line of the string, so it must be grown up.
1342 float y
= _YReal
* _Scale
+ _FontLegHeight
;
1344 // special selection code
1346 // select subset. Arg, must skip spaces because not inserted in VertexBuffer.
1347 setStringSelectionSkipingSpace(_Index
, _Text
, _TextSelectionStart
, _TextSelectionEnd
);
1349 // Change the current color
1350 TextContext
->setStringColor(_Index
, col
);
1353 rVR
.drawText (_RenderLayer
, _XReal
, y
/ _Scale
, _Index
, ClipX
, ClipY
, ClipX
+ClipW
, ClipY
+ClipH
, *TextContext
);
1357 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
- _FontLegHeight
*0.3f
/_Scale
, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), col
);
1360 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
+ _FontHeight
*0.2f
/ _Scale
, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), col
);
1364 TextContext
->resetStringSelection(_Index
);
1366 // if single line clamped, may allow to draw an over
1367 if(isSingleLineTextClamped() && _OverExtendViewText
&& CWidgetManager::getInstance()->getPointer())
1369 // but must check first if mouse is over
1370 sint32 x
= CWidgetManager::getInstance()->getPointer()->getX();
1371 sint32 y
= CWidgetManager::getInstance()->getPointer()->getY();
1373 // use parent clip or self clip?
1374 if(_OverExtendViewTextUseParentRect
)
1375 mouseIn
= _Parent
&& _Parent
->isIn(x
,y
);
1378 // if the mouse cursor is in the clip area
1381 // check the window under the mouse is the root window
1382 CInterfaceGroup
*pIG
= CWidgetManager::getInstance()->getWindowUnder(x
,y
);
1383 CInterfaceElement
*pParent
= this;
1384 bool bFound
= false;
1385 while (pParent
!= NULL
)
1392 pParent
= pParent
->getParent();
1395 // ok => let this view text be the extend over one
1398 // last check: the window must not be currently moved
1399 CGroupContainerBase
*gc
= dynamic_cast<CGroupContainerBase
*>(pIG
);
1400 if(!gc
|| !gc
->isMoving())
1402 CRGBA col
= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionViewTextOverBackColor
).getValColor();
1403 CWidgetManager::getInstance()->setOverExtendViewText(this, col
);
1411 // ***************************************************************************
1412 void CViewText::onAddToGroup()
1414 // Add tooltips if not done
1419 // ***************************************************************************
1420 void CViewText::setTextMode(TTextMode mode
)
1422 if (mode
!= _TextMode
)
1425 invalidateContent ();
1429 #ifdef RYZOM_LUA_UCSTRING
1430 // ***************************************************************************
1431 void CViewText::setTextAsUtf16(const ucstring
&text
)
1433 setText(text
.toUtf8());
1437 // ***************************************************************************
1438 void CViewText::setTextLocalized(const std::string
&text
, bool localized
)
1440 if (localized
!= _Localized
)
1442 _Localized
= localized
;
1444 // Always recompute if localization and text changed
1445 setTextLocalized(text
);
1446 setCase(_Text
, _CaseMode
);
1448 invalidateContent();
1456 // ***************************************************************************
1457 void CViewText::setLocalized(bool localized
)
1459 if (localized
!= _Localized
)
1461 const std::string
&text
= _HardText
.empty() ? _Text
: _HardText
;
1462 _Localized
= localized
;
1463 if (!text
.empty() && NLMISC::startsWith(text
, "ui"))
1465 setTextLocalized(text
);
1466 setCase(_Text
, _CaseMode
);
1468 invalidateContent();
1472 nlassert(_Text
.empty() || ((_Localized
&& (NLMISC::startsWith(getHardText(), "ui"))) == (_HardText
.empty() == _Text
.empty())));
1475 // ***************************************************************************
1476 void CViewText::setTextLocalized(const std::string
&text
)
1478 if (_Localized
&& NLMISC::startsWith(text
, "ui"))
1481 _Text
= CI18N::get(text
);
1490 // ***************************************************************************
1491 void CViewText::setText(const std::string
&text
)
1493 // common case: no special format, no case mode => easy cache test
1494 if (_FormatTags
.empty() && _CaseMode
== CaseNormal
)
1496 if (_HardText
.empty() ? text
!= _Text
: text
!= _HardText
)
1498 setTextLocalized(text
);
1500 // no need to call "setCase (_Text, _CaseMode);" since CaseNormal:
1501 invalidateContent();
1506 // if the view text had some format before, no choice, must recompute all
1507 if (!_FormatTags
.empty())
1509 setTextLocalized(text
);
1510 setCase(_Text
, _CaseMode
);
1512 invalidateContent();
1514 // else test if after the case change the cache succeed
1517 // compute the temp cased text
1518 std::string holdText
, holdHardText
;
1519 holdText
.swap(_Text
);
1520 holdHardText
.swap(_HardText
);
1521 setTextLocalized(text
);
1522 setCase(_Text
, _CaseMode
);
1523 if (holdText
!= _Text
)
1526 invalidateContent();
1530 holdText
.swap(_Text
);
1535 nlassert(_Text
.empty() || ((_Localized
&& (NLMISC::startsWith(text
, "ui"))) == (_HardText
.empty() == _Text
.empty())));
1537 // clear format tags if any
1538 _FormatTags
.clear();
1541 // ***************************************************************************
1542 void CViewText::setFontSizing(const std::string
&chars
, const std::string
&fallback
)
1544 _FontSizingChars
= chars
;
1545 _FontSizingFallback
= fallback
;
1548 // ***************************************************************************
1549 void CViewText::setFontName(const std::string
&name
)
1551 if (_FontName
== name
)
1554 if (_Index
!= 0xFFFFFFFF)
1555 CViewRenderer::getTextContext(_FontName
)->erase (_Index
);
1562 invalidateContent();
1565 // ***************************************************************************
1566 void CViewText::setFontSize (sint nFontSize
, bool coef
)
1568 _FontSize
= nFontSize
;
1569 if (coef
) _FontSize
+= CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
1570 _FontSizeCoef
= coef
;
1572 invalidateContent();
1575 // ***************************************************************************
1576 sint
CViewText::getFontSize() const
1579 return _FontSize
- CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont
).getValSInt32();
1584 // ***************************************************************************
1585 void CViewText::setEmbolden (bool embolden
)
1587 _Embolden
= embolden
;
1589 invalidateContent();
1592 // ***************************************************************************
1593 void CViewText::setOblique (bool oblique
)
1597 invalidateContent();
1600 // ***************************************************************************
1601 void CViewText::setColor(const NLMISC::CRGBA
& color
)
1606 // ***************************************************************************
1607 void CViewText::setShadow (bool bShadow
)
1611 invalidateContent();
1614 // ***************************************************************************
1615 void CViewText::setShadowOutline (bool bShadowOutline
)
1617 _ShadowOutline
= bShadowOutline
;
1619 invalidateContent();
1622 // ***************************************************************************
1623 void CViewText::setShadowColor(const NLMISC::CRGBA
& color
)
1625 _ShadowColor
= color
;
1628 // ***************************************************************************
1629 void CViewText::setShadowOffset(sint32 x
, sint32 y
)
1635 // ***************************************************************************
1636 void CViewText::setLineMaxW (sint nMaxW
, bool invalidate
)
1638 if(_LineMaxW
!=nMaxW
)
1642 invalidateContent();
1646 // ***************************************************************************
1647 int CViewText::luaSetLineMaxW(CLuaState
&ls
)
1649 CLuaIHM::checkArgCount(ls
, "setLineMaxW", 1);
1651 if(CLuaIHM::popSINT32(ls
, value
))
1653 setLineMaxW(ceilf(value
/ _Scale
));
1658 // ***************************************************************************
1659 void CViewText::setMultiLine (bool bMultiLine
)
1661 _MultiLine
= bMultiLine
;
1662 invalidateContent();
1665 // ***************************************************************************
1666 void CViewText::setMultiLineSpace (sint nMultiLineSpace
)
1668 _MultiLineSpace
= nMultiLineSpace
;
1669 invalidateContent();
1672 // ***************************************************************************
1673 void CViewText::setMultiLineMaxWOnly (bool state
)
1675 _MultiLineMaxWOnly
= state
;
1676 invalidateContent();
1679 // ***************************************************************************
1680 void CViewText::setMultiLineClipEndSpace (bool state
)
1682 _MultiLineClipEndSpace
= state
;
1683 invalidateContent();
1686 // ***************************************************************************
1687 uint
CViewText::getFontWidth() const
1689 return _FontWidth
/ _Scale
;
1692 // ***************************************************************************
1693 uint
CViewText::getFontHeight() const
1695 return _FontHeight
/ _Scale
;
1698 // ***************************************************************************
1699 uint
CViewText::getFontLegHeight() const
1701 return _FontLegHeight
/ _Scale
;
1704 // ***************************************************************************
1705 float CViewText::getLineHeight() const
1707 return _FontHeight
/ _Scale
+ _MultiLineSpace
;
1710 // ***************************************************************************
1711 uint
CViewText::getMultiMinOffsetY() const
1714 if (_MultiMinLine
> _Lines
.size())
1716 // first line is always present even if _Lines is empty
1717 uint nbLines
= _MultiMinLine
- std::max((sint
)1, (sint
)_Lines
.size());
1718 dy
= (nbLines
* _FontHeight
+ (nbLines
- 1) * _MultiLineSpace
* _Scale
) / _Scale
;
1723 // ***************************************************************************
1724 void CViewText::flushWordInLine(std::string
&ucCurrentWord
, bool &linePushed
, const CFormatInfo
&wordFormat
)
1726 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
1727 // create a new line?
1730 _Lines
.push_back(TLineSPtr(new CLine
));
1733 // Append to the last line
1734 _Lines
.back()->addWord(ucCurrentWord
, 0, wordFormat
, _FontWidth
, _TabWidth
, *TextContext
);
1736 ucCurrentWord
.clear();
1740 // ***************************************************************************
1741 void CViewText::updateTextContextMultiLine(float nMaxWidth
)
1744 UTextContext::CStringInfo si
;
1747 std::string ucCurrentWord
;
1748 CFormatInfo wordFormat
;
1750 float rWidthCurrentLine
= 0;
1751 bool linePushed
= false;
1753 // uint textSize= (uint)_Text.size();
1754 uint formatTagIndex
= 0;
1755 nMaxWidth
*= _Scale
;
1756 //for (i = 0; i < textSize; ++i)
1757 CUtfStringView
sv(_Text
);
1758 ::u32string
ucStrLetter(1, ' ');
1759 for (CUtfStringView::iterator
it(sv
.begin()), end(sv
.end()); it
!= end
; ++it
, ++i
)
1761 if(isFormatTagChange(i
, formatTagIndex
))
1763 // If the word was not empty before this color tag
1764 if(!ucCurrentWord
.empty())
1765 flushWordInLine(ucCurrentWord
, linePushed
, wordFormat
);
1767 // get new color and skip ctIndex.
1768 getFormatTagChange(i
, formatTagIndex
, wordFormat
);
1770 // Ensure the line witdh count the tab
1771 rWidthCurrentLine
= max(rWidthCurrentLine
, (float)wordFormat
.TabX
*_TabWidth
);
1774 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
1780 flushWordInLine(ucCurrentWord
, linePushed
, wordFormat
);
1783 rWidthCurrentLine
= 0;
1787 ucStrLetter
[0] = *it
;
1788 si
= TextContext
->getStringInfo (ucStrLetter
);
1789 if ((rWidthCurrentLine
+ si
.StringWidth
) > nMaxWidth
)
1791 flushWordInLine(ucCurrentWord
, linePushed
, wordFormat
);
1793 // reset line state, and begin with the cut letter
1795 rWidthCurrentLine
= si
.StringWidth
;
1796 ucCurrentWord
.clear();
1797 CUtfStringView::append(ucCurrentWord
, *it
);
1801 // Grow the current word
1802 CUtfStringView::append(ucCurrentWord
, *it
);
1803 rWidthCurrentLine
+= si
.StringWidth
;
1808 if (ucCurrentWord
.length())
1810 flushWordInLine(ucCurrentWord
, linePushed
, wordFormat
);
1815 // ***************************************************************************
1816 void CViewText::addDontClipWordLine(std::vector
<CWord
> &currLine
)
1818 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
1819 // create a new line
1820 _Lines
.push_back(TLineSPtr(new CLine
));
1822 // Fill it with words. if all words of same color, create only one CWord
1823 if (!currLine
.empty())
1825 CFormatInfo lineWordFormat
= currLine
[0].Format
;
1826 std::string lineWord
;
1827 for(uint i
=0;i
<currLine
.size();i
++)
1829 // If different from last, flush
1830 if(currLine
[i
].Format
!=lineWordFormat
)
1832 // add the current lineWord to the line.
1833 _Lines
.back()->addWord(lineWord
, 0, lineWordFormat
, _FontWidth
, _TabWidth
, *TextContext
);
1834 // get new lineWordFormat
1835 lineWordFormat
= currLine
[i
].Format
;
1840 // Append the word with space to the lineWord.
1841 std::string
blank(currLine
[i
].NumSpaces
, ' ');
1843 lineWord
+= currLine
[i
].Text
;
1846 if(!lineWord
.empty())
1847 _Lines
.back()->addWord(lineWord
, 0, lineWordFormat
, _FontWidth
, _TabWidth
, *TextContext
);
1854 // ***************************************************************************
1855 void CViewText::updateTextContextMultiLineJustified(float nMaxWidth
, bool expandSpaces
)
1857 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
1858 UTextContext::CStringInfo si
;
1860 TCharPos currPos
= 0;
1862 // precLineWidth valid only id precedent line is part of same paragraph.
1863 float precLineWidth
= 0;
1864 float lineWidth
= (float)_FirstLineX
; // width of the current line
1865 uint numWordsInLine
= 0; // number of words in the current line
1866 bool isParagraphStart
= true; // A paragraph is a group of characters between 2 \n
1870 vector
<CWord
> currLine
; // if spaces are not expanded, all words of a line are inserted here (NB: index and stringInfo not filled)
1871 std::string wordValue
;
1872 CFormatInfo wordFormat
;
1873 uint formatTagIndex
= 0;
1875 nMaxWidth
*= _Scale
;
1876 while (currPos
!= _Text
.length())
1881 float newLineWidth
= 0;
1884 if (_Text
[currPos
] == '\n')
1891 // Skip spaces and count them
1892 spaceEnd
= _Text
.find_first_not_of(" ", currPos
);
1893 if (spaceEnd
== std::string::npos
)
1895 spaceEnd
= _Text
.length();
1897 numSpaces
= (uint
) (spaceEnd
- currPos
);
1898 if (!isParagraphStart
&& numSpaces
!= 0 && numWordsInLine
== 0) // Are these the first spaces of the line ?
1900 if (!_Lines
.empty())
1902 /* Yoyo: I changed this (added the "cut space"), because in editBox, it is so strange when
1903 the word hit the end of line, and if you add spaces just after, nothing happens because
1904 cursor pos is clamped at end of line.
1906 // Cannot put all of thoses spaces to the prec end of line?
1907 if(_MultiLineClipEndSpace
&& precLineWidth
+ numSpaces
* _SpaceWidth
> nMaxWidth
)
1909 // put some of these spaces at the end of the previous line.
1910 sint maxNumSpaces
= (sint
)floorf((nMaxWidth
- precLineWidth
) / _SpaceWidth
);
1911 _Lines
.back()->setEndSpaces(maxNumSpaces
);
1912 // And start the new lines with the remaining spaces.
1913 numSpaces
-= maxNumSpaces
;
1914 currPos
+= maxNumSpaces
;
1918 // ok, put all spaces to previous line
1919 _Lines
.back()->setEndSpaces(numSpaces
);
1923 if(currPos
>=_Text
.length())
1928 // Detect change of wordFormat at the beginning of the word
1929 if(isFormatTagChange((uint
)spaceEnd
, formatTagIndex
))
1931 getFormatTagChange((uint
)spaceEnd
, formatTagIndex
, wordFormat
);
1934 // Get word until a space, a \n, or a FormatTagChange is encountered
1936 for(i
= (uint
)spaceEnd
;i
<(uint
)_Text
.length();i
++)
1939 if(c
==' ' || c
=='\n')
1941 // If change of color tag, stop the word, but don't take the new color now.
1942 if(isFormatTagChange(i
, formatTagIndex
))
1948 // Get the word value.
1949 wordValue
= _Text
.substr(spaceEnd
, wordEnd
- spaceEnd
);
1950 // compute width of word
1951 si
= TextContext
->getStringInfo(wordValue
);
1953 // compute size of spaces/Tab + word
1954 newLineWidth
= lineWidth
+ numSpaces
* _SpaceWidth
;
1955 newLineWidth
= max(newLineWidth
, (float)wordFormat
.TabX
*_TabWidth
);
1956 newLineWidth
+= si
.StringWidth
;
1959 // Does the word go beyond the end of line ?
1960 if (!lineFeed
&& newLineWidth
> nMaxWidth
)
1962 // Have we enough room for this word on a line ?
1963 bool roomForThisWord
= (numWordsInLine
> 0) || ( (newLineWidth
- lineWidth
) < nMaxWidth
);
1965 // not enough room for that word
1966 // If it is the only word of the line, just split it
1967 // Otherwise, scale the spaces between words so that the line as the maximum width
1968 if (roomForThisWord
)
1972 nlassert(!_Lines
.empty());
1973 nlassert(_Lines
.back()->getNumWords() > 0);
1975 // Yoyo: if the line has tab, then don't justify
1976 if(wordFormat
.TabX
> 0)
1977 _Lines
.back()->setSpaceWidth(_SpaceWidth
);
1980 // Scale the width so that the line has the maximum width
1981 float roomForSpaces
= nMaxWidth
- _Lines
.back()->getWidthWithoutSpaces();
1982 uint startNumSpaces
= _Lines
.back()->getNumSpaces();
1983 if (startNumSpaces
!= 0)
1985 _Lines
.back()->setSpaceWidth(roomForSpaces
/ startNumSpaces
);
1989 _Lines
.back()->setSpaceWidth(_SpaceWidth
);
1997 // we dont change the position in the input string so that the current will be processed on the next line
2000 else // it is the only word on the line..
2003 // 1) Check if spaces go beyond the end of line
2004 if (numSpaces
* _SpaceWidth
> nMaxWidth
)
2006 uint maxNumSpaces
= std::max(1U, (uint
) (nMaxWidth
/ _SpaceWidth
));
2007 CWord spaceWord
; // a word with only spaces in it
2008 spaceWord
.build ("", *TextContext
, maxNumSpaces
);
2009 spaceWord
.Format
= wordFormat
;
2010 _Lines
.push_back(TLineSPtr(new CLine
));
2011 _Lines
.back()->addWord(spaceWord
, _FontWidth
, _TabWidth
);
2014 _Lines
.back()->setSpaceWidth(nMaxWidth
/ (float) maxNumSpaces
);
2018 _Lines
.back()->setSpaceWidth(_SpaceWidth
);
2020 currPos
= currPos
+ maxNumSpaces
;
2024 float px
= numSpaces
* _SpaceWidth
;
2025 ::u32string
oneChar(1, ' ');
2026 CUtfStringView
wsv(wordValue
);
2027 CUtfStringView::iterator
wit(wsv
.begin()), wend(wsv
.end());
2028 for (; wit
!= wend
; ++wit
)
2031 si
= TextContext
->getStringInfo(oneChar
);
2032 if ((uint
) (px
+ si
.StringWidth
) > nMaxWidth
) break;
2033 px
+= si
.StringWidth
;
2035 ptrdiff_t currChar
= std::max((ptrdiff_t)1, (ptrdiff_t)wit
.ptr() - (ptrdiff_t)wsv
.ptr()); // must fit at least one character otherwise there's an infinite loop
2036 wordValue
= _Text
.substr(spaceEnd
, currChar
);
2038 word
.build(wordValue
, *TextContext
, numSpaces
);
2039 word
.Format
= wordFormat
;
2040 _Lines
.push_back(TLineSPtr(new CLine
));
2041 float roomForSpaces
= nMaxWidth
- word
.Info
.StringWidth
;
2042 if (expandSpaces
&& numSpaces
!= 0)
2044 _Lines
.back()->setSpaceWidth(roomForSpaces
/ (float) numSpaces
);
2048 _Lines
.back()->setSpaceWidth(0);
2050 _Lines
.back()->addWord(word
, _FontWidth
, _TabWidth
);
2051 currPos
= currPos
+ numSpaces
+ currChar
;
2056 precLineWidth
= lineWidth
;
2058 isParagraphStart
= false;
2060 else if (!lineFeed
) // the end of line hasn't been reached
2064 // add in the current line (and create one if necessary)
2065 if (numWordsInLine
== 0)
2067 _Lines
.push_back(TLineSPtr(new CLine
));
2068 _Lines
.back()->setSpaceWidth(_SpaceWidth
);
2070 if (!wordValue
.empty() || numSpaces
!= 0)
2073 word
.build(wordValue
, *TextContext
, numSpaces
);
2074 word
.Format
= wordFormat
;
2075 // update line width
2076 _Lines
.back()->addWord(word
, _FontWidth
, _TabWidth
);
2083 // Don't build here, this is used as temp data.
2084 word
.Text
= wordValue
;
2085 word
.NumSpaces
= numSpaces
;
2086 word
.Format
= wordFormat
;
2087 // Append to the temp Data.
2088 currLine
.push_back(word
);
2092 lineWidth
= newLineWidth
;
2097 // '\n' was encountered
2099 isParagraphStart
= true;
2101 if (lineFeed
|| breakLine
) // '\n' was encoutered, or a linefeed has been asked
2103 // !expandSpaces => insert minimum words according to word color.
2106 // Add the new line.
2107 addDontClipWordLine(currLine
);
2111 _Lines
.back()->setLF(true);
2114 // expandSpaces => just add a empty line.
2117 if (numWordsInLine
== 0)
2119 // if nothing has been inserted in this line, create at least an empty line
2120 _Lines
.push_back(TLineSPtr(new CLine
));
2124 _Lines
.back()->setLF(true);
2132 // if current line hasn't been pushed, add it
2133 if (!expandSpaces
&& !currLine
.empty())
2136 addDontClipWordLine(currLine
);
2139 // if the text ends with \n, must insert the last line ourself
2140 if (!_Text
.empty() && _Text
[_Text
.length() - 1] == '\n')
2142 _Lines
.push_back(TLineSPtr(new CLine
));
2147 // ***************************************************************************
2148 void CViewText::updateTextContext ()
2150 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
2152 TextContext
->setHotSpot (UTextContext::BottomLeft
);
2153 TextContext
->setShaded (_Shadow
);
2154 TextContext
->setShadeOutline (_ShadowOutline
);
2155 TextContext
->setFontSize (_FontSize
*_Scale
);
2156 TextContext
->setEmbolden (_Embolden
);
2157 TextContext
->setOblique (_Oblique
);
2160 _SingleLineTextClamped
= false;
2162 if ((_MultiLine
)&&(_Parent
!= NULL
))
2164 float nMaxWidth
= getCurrentMultiLineMaxW();
2165 _LastMultiLineMaxW
= nMaxWidth
;
2169 // parent size may not be known yet
2174 case ClipWord
: updateTextContextMultiLine(nMaxWidth
); break;
2175 case Centered
: // fallthru to DontClipWord
2176 case DontClipWord
: updateTextContextMultiLineJustified(nMaxWidth
, false); break;
2177 case Justified
: updateTextContextMultiLineJustified(nMaxWidth
, true); break;
2180 // Special case for multiline limited in number of lines
2181 if (!_Lines
.empty() && (_MultiMaxLine
> 0) && (_Lines
.size() > _MultiMaxLine
))
2183 while (_Lines
.size() > _MultiMaxLine
)
2185 _Lines
.back()->clear(*TextContext
);
2188 if (_OverflowText
.size() > 0)
2191 CViewText::CLine
*endLine
= new CViewText::CLine
;
2193 w
.build(_OverflowText
, *TextContext
);
2194 endLine
->addWord(w
, _FontWidth
, _TabWidth
);
2195 _Lines
.push_back(TLineSPtr(endLine
));
2200 float rMultiLineSpace
= _MultiLineSpace
* _Scale
;
2202 for (uint i
= 0; i
< _Lines
.size(); ++i
)
2204 rTotalW
= std::max(_Lines
[i
]->getWidth() + ((i
==0)?_FirstLineX
:0), rTotalW
);
2206 _W
= (sint
)ceilf(rTotalW
/ _Scale
);
2207 _H
= std::max(_FontHeight
/ _Scale
, ceilf((_FontHeight
* _Lines
.size() + std::max(0, sint(_Lines
.size()) - 1) * rMultiLineSpace
) / _Scale
));
2209 // See if we should pretend to have at least X lines
2210 if (_MultiMinLine
> 1)
2211 _H
= std::max(_H
, sint((_FontHeight
* _MultiMinLine
+ (_MultiMinLine
- 1) * rMultiLineSpace
)/_Scale
));
2213 // Compute tooltips size
2214 if (!_Tooltips
.empty())
2215 for (uint i
=0 ; i
<_Lines
.size() ; ++i
)
2217 for (uint j
=0 ; j
<_Lines
[i
]->getNumWords() ; ++j
)
2219 CWord word
= _Lines
[i
]->getWord(j
);
2221 if (word
.Format
.IndexTt
!= -1)
2223 if (_Tooltips
.size() > (uint
)word
.Format
.IndexTt
)
2225 CCtrlToolTip
*pTooltip
= _Tooltips
[word
.Format
.IndexTt
];
2227 sint y
= (sint
) ceilf(((_FontHeight
+ rMultiLineSpace
) * (_Lines
.size() - i
- 1))/_Scale
);
2231 pTooltip
->setW(getCurrentMultiLineMaxW());
2232 pTooltip
->setH(_FontHeight
);
2238 else // Single line code
2240 if (_Index
!= 0xFFFFFFFF)
2241 TextContext
->erase (_Index
);
2243 // Common case: no W clamp
2244 _Index
= TextContext
->textPush (_Text
);
2245 _Info
= TextContext
->getStringInfo (_Index
);
2246 _W
= (sint
)ceilf(_Info
.StringWidth
/ _Scale
);
2248 // Rare case: clamp W => recompute slowly, cut letters
2251 TextContext
->erase (_Index
);
2254 UTextContext::CStringInfo si
;
2255 std::string ucCurrentLine
;
2256 ucCurrentLine
.reserve(_Text
.size());
2258 // Append ... to the end of line
2259 float dotWidth
= 0.f
;
2260 if (_OverflowText
.size() > 0)
2262 si
= TextContext
->getStringInfo(_OverflowText
);
2263 dotWidth
= si
.StringWidth
;
2266 // scale LineMaxW to actual font size
2267 float fLineMaxW
= (float)_LineMaxW
* _Scale
;
2268 float rWidthCurrentLine
= 0;
2272 CUtfStringView
sv(_Text
);
2273 ::u32string ucStrLetter
= ::u32string(1, (u32char
)' ');
2274 for (CUtfStringView::iterator
it(sv
.begin()), end(sv
.end()); it
!= end
; ++it
)
2276 ucStrLetter
[0] = *it
;
2277 si
= TextContext
->getStringInfo (ucStrLetter
);
2278 if ((rWidthCurrentLine
+ si
.StringWidth
+ dotWidth
) > fLineMaxW
)
2284 // Grow the current line
2285 CUtfStringView::append(ucCurrentLine
, *it
);
2286 rWidthCurrentLine
+= si
.StringWidth
;
2291 if (_OverflowText
.size() > 0)
2293 ucCurrentLine
+= _OverflowText
;
2298 // FIXME: Optimize reverse UTF iteration
2299 ::u32string uctext
= CUtfStringView(_Text
).toUtf32();
2300 ::u32string ucStrLetter
= ::u32string(1, (u32char
)' ');
2301 for (sint i
= (sint
)uctext
.size() - 1; i
>= 0; --i
)
2303 ucStrLetter
[0] = uctext
[i
];
2304 si
= TextContext
->getStringInfo (ucStrLetter
);
2305 if ((rWidthCurrentLine
+ si
.StringWidth
+ dotWidth
) > fLineMaxW
)
2311 // Grow the current line
2313 CUtfStringView::append(tmp
, uctext
[i
]);
2314 ucCurrentLine
= tmp
+ ucCurrentLine
;
2315 rWidthCurrentLine
+= si
.StringWidth
;
2320 if (_OverflowText
.size() > 0)
2322 ucCurrentLine
= _OverflowText
+ ucCurrentLine
;
2326 // And so setup this trunc text
2327 _Index
= TextContext
->textPush (ucCurrentLine
);
2328 _Info
= TextContext
->getStringInfo (_Index
);
2329 _W
= (sint
)ceilf(_Info
.StringWidth
/ _Scale
);
2331 _SingleLineTextClamped
= true;
2334 // same height always
2335 _H
= (sint
)ceilf(_FontHeight
/ _Scale
);
2338 _InvalidTextContext
= false;
2341 // ***************************************************************************
2342 void CViewText::updateCoords()
2346 CViewBase::updateCoords ();
2348 // If there's no parent, try the parent of the parent element.
2349 // Since we will be under the same group
2350 CInterfaceGroup
*parent
= _Parent
;
2351 if( parent
== NULL
)
2353 if( _ParentElm
!= NULL
)
2354 parent
= _ParentElm
->getParent();
2359 // avoid resizing parents to compute the limiter
2360 while (parent
&& (parent
->getResizeFromChildW() || parent
->isGroupList() ))
2362 // NB nico : the dynamic_cast for CGroupList is bad!!
2363 // can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
2365 parent
= parent
->getParent();
2371 sint32 parentRight
= parent
->getXReal() + parent
->getWReal() - (sint32
) _AutoClampOffset
;
2372 setLineMaxW(std::max((sint32
) 0, parentRight
- _XReal
));
2376 sint32 parentLeft
= parent
->getXReal() + (sint32
) _AutoClampOffset
;
2377 setLineMaxW(std::max((sint32
) 0, _XReal
+ _WReal
- parentLeft
));
2383 if(_InvalidTextContext
)
2384 updateTextContext();
2386 CViewBase::updateCoords ();
2389 // ***************************************************************************
2390 sint
CViewText::getLineFromIndex(uint index
, bool cursorDisplayedAtEndOfPreviousLine
/* = true*/) const
2392 if (index
> _Text
.length()) return -1;
2396 for(sint i
= 0; i
< (sint
) _Lines
.size(); ++i
)
2398 CLine
&currLine
= *_Lines
[i
];
2399 uint newCharIndex
= charIndex
+ currLine
.getNumChars() + currLine
.getEndSpaces() + (currLine
.getLF() ? 1 : 0);
2400 if (newCharIndex
> index
)
2402 if (i
!= 0 && cursorDisplayedAtEndOfPreviousLine
&& charIndex
== index
)
2411 charIndex
= newCharIndex
;
2413 // return (sint)_Lines.size() - 1;
2422 // ***************************************************************************
2423 sint
CViewText::getLineStartIndex(uint line
) const
2426 if (line
>= _Lines
.size()) return -1;
2427 for(uint i
= 0; i
< line
; ++i
)
2429 CLine
&currLine
= *_Lines
[i
];
2430 charIndex
+= currLine
.getNumChars() + currLine
.getEndSpaces() + (currLine
.getLF() ? 1 : 0);
2432 // skip all spaces at start of line (unless there are only spaces in the line)
2433 std::string::size_type nextPos
= _Text
.find_first_not_of(' ', charIndex
);
2434 if (nextPos
!= std::string::npos
)
2436 if (getLineFromIndex(charIndex
) == (sint
) line
)
2438 return (sint
) nextPos
;
2444 // ***************************************************************************
2445 void CViewText::getLineEndIndex(uint line
, sint
&index
, bool &endOfPreviousLine
) const
2447 sint startIndex
= getLineStartIndex(line
);
2448 if (startIndex
== -1)
2451 endOfPreviousLine
= false;
2454 index
= startIndex
+ _Lines
[line
]->getNumChars() + _Lines
[line
]->getEndSpaces();
2455 endOfPreviousLine
= !_Lines
[line
]->getLF();
2458 #ifdef RYZOM_LUA_UCSTRING
2459 // ***************************************************************************
2460 void CViewText::setHardTextAsUtf16(const ucstring
&ht
)
2462 setHardText(ht
.toUtf8());
2466 // ***************************************************************************
2467 void CViewText::setHardText (const std::string
&ht
)
2471 setText(std::string());
2477 #ifdef RYZOM_LUA_UCSTRING
2478 // ***************************************************************************
2479 ucstring
CViewText::getTextAsUtf16() const
2481 return CUtfStringView(getText()).toUtf16();
2484 // ***************************************************************************
2485 ucstring
CViewText::getHardTextAsUtf16() const
2487 return CUtfStringView(getHardText()).toUtf16();
2491 // ***************************************************************************
2492 string
CViewText::getColorAsString() const
2494 return NLMISC::toString(_Color
.R
) + " " + NLMISC::toString(_Color
.G
) + " " + NLMISC::toString(_Color
.B
) + " " + NLMISC::toString(_Color
.A
);
2497 // ***************************************************************************
2498 void CViewText::setColorAsString(const string
&ht
)
2500 _Color
= convertColor (ht
.c_str());
2503 // ***************************************************************************
2504 NLMISC::CRGBA
CViewText::getColorRGBA() const
2509 // ***************************************************************************
2510 void CViewText::setColorRGBA(NLMISC::CRGBA col
)
2515 // ***************************************************************************
2516 void CViewText::getCharacterPositionFromIndex(sint index
, bool cursorAtPreviousLineEnd
, float &x
, float &y
, float &height
) const
2518 if (!_TextLength
&& _Text
.size())
2519 _TextLength
= CUtfStringView(_Text
).count();
2520 NLMISC::clamp(index
, 0, (sint
)_TextLength
);
2521 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
2522 TextContext
->setHotSpot (UTextContext::BottomLeft
);
2523 TextContext
->setShaded (_Shadow
);
2524 TextContext
->setShadeOutline (_ShadowOutline
);
2525 TextContext
->setFontSize (_FontSize
*_Scale
);
2526 TextContext
->setEmbolden (_Embolden
);
2527 TextContext
->setOblique (_Oblique
);
2528 height
= getLineHeight();
2533 float dy
= getMultiMinOffsetY() * _Scale
;
2534 float nMaxWidth
= getCurrentMultiLineMaxW() * _Scale
;
2537 // special case for end of text
2538 if (index
>= (sint
)_TextLength
)
2548 CLine
&lastLine
= *_Lines
.back();
2549 fx
= lastLine
.getWidth() + lastLine
.getEndSpaces() * lastLine
.getSpaceWidth();
2550 fx
= std::min(fx
, nMaxWidth
);
2557 for(sint i
= 0; i
< (sint
) _Lines
.size(); ++i
)
2559 if (i
!= 0 && charIndex
== (uint
) index
&& cursorAtPreviousLineEnd
)
2561 // should display the character at the end of previous line
2562 CLine
&currLine
= *_Lines
[i
- 1];
2563 fy
= (_FontHeight
+ _MultiLineSpace
* _Scale
) * (_Lines
.size() - i
) + dy
;
2564 fx
= currLine
.getWidth() + currLine
.getEndSpaces() * currLine
.getSpaceWidth();
2565 fx
= std::min(fx
, nMaxWidth
);
2571 CLine
&currLine
= *_Lines
[i
];
2572 uint newCharIndex
= charIndex
+ currLine
.getNumChars() + currLine
.getEndSpaces() + (_Lines
[i
]->getLF() ? 1 : 0);
2573 if ((sint
) newCharIndex
> index
)
2575 // ok, this line contains the character, now, see which word contains it.
2576 fy
= (_FontHeight
+ _MultiLineSpace
* _Scale
) * (_Lines
.size() - 1 - i
) + dy
;
2577 // see if the index is in the spaces at the end of line
2578 if (index
- charIndex
>= currLine
.getNumChars())
2580 uint numSpaces
= index
- charIndex
- currLine
.getNumChars();
2581 fx
= currLine
.getWidth() + numSpaces
* _SpaceWidth
;
2582 fx
= std::min(fx
, nMaxWidth
);
2588 // now, search containing word in current line
2589 float px
= (float)_FirstLineX
;
2590 for(uint k
= 0; k
< currLine
.getNumWords(); ++k
)
2592 CWord
&currWord
= currLine
.getWord(k
);
2593 if ((sint
) (charIndex
+ currWord
.NumSpaces
+ currWord
.Info
.StringLength
) >= index
)
2595 // character is in currWord or the in spaces preceding it
2596 // check if the character is in the word
2597 if ((uint
) (index
- charIndex
) > currWord
.NumSpaces
)
2599 // get the x position
2601 UTextContext::CStringInfo si
= TextContext
->getStringInfo(currWord
.Text
, (ptrdiff_t)index
- charIndex
- currWord
.NumSpaces
);
2602 fx
= px
+ si
.StringWidth
+ currWord
.NumSpaces
* currLine
.getSpaceWidth();
2610 // character is in the spaces preceding the word
2611 fx
= px
+ currLine
.getSpaceWidth() * (index
- charIndex
);
2618 charIndex
+= (uint
)currWord
.Info
.StringLength
+ currWord
.NumSpaces
;
2619 px
+= currWord
.NumSpaces
* currLine
.getSpaceWidth() + currWord
.Info
.StringWidth
;
2622 charIndex
= newCharIndex
;
2628 // get the x position
2630 UTextContext::CStringInfo si
= TextContext
->getStringInfo(_Text
, index
);
2632 x
= (sint
) ceilf(si
.StringWidth
/ _Scale
);
2636 // ***************************************************************************
2637 // Tool fct : From a word and a x coordinate (font scale), give the matching character index
2638 static uint
getCharacterIndex(const std::string
&textValue
, float x
, NL3D::UTextContext
&textContext
)
2642 UTextContext::CStringInfo si
;
2643 ::u32string
singleChar(1, ' ');
2645 NLMISC::CUtfStringView
sv(textValue
);
2646 for (NLMISC::CUtfStringView::iterator
it(sv
.begin()), end(sv
.end()); it
!= end
; ++it
, ++i
)
2648 // get character width
2649 singleChar
[0] = *it
;
2650 si
= textContext
.getStringInfo(singleChar
);
2651 px
+= si
.StringWidth
;
2652 // the character is at the i - 1 position
2655 // if the half of the character is after the cursor, then prefer select the next one (like in Word)
2656 if(px
-si
.StringWidth
/2.f
< x
)
2664 // ***************************************************************************
2665 void CViewText::getCharacterIndexFromPosition(float x
, float y
, uint
&index
, bool &cursorAtPreviousLineEnd
) const
2667 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
2669 if (!_TextLength
&& _Text
.size())
2670 _TextLength
= CUtfStringView(_Text
).count();
2673 y
= roundf(y
* _Scale
);
2675 // setup the text context
2676 TextContext
->setHotSpot (UTextContext::BottomLeft
);
2677 TextContext
->setShaded (_Shadow
);
2678 TextContext
->setShadeOutline (_ShadowOutline
);
2679 TextContext
->setFontSize (_FontSize
*_Scale
);
2680 TextContext
->setEmbolden (_Embolden
);
2681 TextContext
->setOblique (_Oblique
);
2682 // find the line where the character is
2683 // CViewRenderer &rVR = *CViewRenderer::getInstance();
2687 y
-= getMultiMinOffsetY() * _Scale
;
2692 index
= (uint
)_TextLength
;
2693 cursorAtPreviousLineEnd
= false;
2697 for (line
= (uint
)_Lines
.size() - 1; line
>= 0; --line
)
2699 float newPy
= py
+ _FontHeight
+ _MultiLineSpace
* _Scale
;
2709 cursorAtPreviousLineEnd
= false;
2710 return; // above the first line, so take character 0
2712 // compute character index at start of line
2714 for (i
= 0; i
< line
; ++i
)
2716 charPos
+= _Lines
[i
]->getNumChars() + _Lines
[i
]->getEndSpaces() + (_Lines
[i
]->getLF() ? 1 : 0);
2718 // seek word that contains the character
2719 CLine
&currLine
= *_Lines
[line
];
2720 // See if character is in the ending spaces
2721 if (x
>= (sint
) currLine
.getWidth())
2723 // Add _SpaceWidth/2 to select between chars
2724 sint numSpaces
= _SpaceWidth
!= 0 ? (sint
) (((float) x
+ _SpaceWidth
/2 - currLine
.getWidth()) / _SpaceWidth
)
2726 clamp(numSpaces
, 0, (sint
)currLine
.getEndSpaces());
2727 index
= charPos
+ currLine
.getNumChars() + numSpaces
;
2728 cursorAtPreviousLineEnd
= !_Lines
[i
]->getLF();
2732 cursorAtPreviousLineEnd
= false;
2733 float px
= (float)_FirstLineX
;
2734 for(uint k
= 0; k
< currLine
.getNumWords(); ++k
)
2736 CWord
&currWord
= currLine
.getWord(k
);
2737 float spacesWidth
= currLine
.getSpaceWidth() * currWord
.NumSpaces
;
2738 float newPx
= px
+ currWord
.Info
.StringWidth
+ spacesWidth
;
2739 if (newPx
>= x
) // if the word contains the x position..
2741 if (x
< (px
+ spacesWidth
))
2743 // the coords x is in the spaces that are preceding the word
2744 // Add spaceWidth/2 to select between chars
2745 sint numSpaces
= currLine
.getSpaceWidth() != 0 ? (sint
) ((x
+ currLine
.getSpaceWidth()/2 - px
) / currLine
.getSpaceWidth())
2747 clamp(numSpaces
, 0, (sint
)currWord
.NumSpaces
);
2748 index
= numSpaces
+ charPos
;
2753 // the coord is in the word itself
2754 index
= charPos
+ currWord
.NumSpaces
+ getCharacterIndex(currWord
.Text
, x
- (px
+ spacesWidth
), *TextContext
);
2759 charPos
+= (uint
)currWord
.Info
.StringLength
+ currWord
.NumSpaces
;
2766 cursorAtPreviousLineEnd
= false;
2769 index
= (uint
)_TextLength
;
2772 if (y
> (sint
) _FontHeight
)
2777 index
= getCharacterIndex(_Text
, x
, *TextContext
);
2782 // ***************************************************************************
2783 void CViewText::enableStringSelection(uint start
, uint end
)
2785 _TextSelection
= true;
2786 _TextSelectionStart
= start
;
2787 _TextSelectionEnd
= end
;
2790 // ***************************************************************************
2791 void CViewText::disableStringSelection()
2793 _TextSelection
= false;
2794 _TextSelectionStart
= 0;
2795 _TextSelectionEnd
= std::numeric_limits
<uint
>::max();
2798 // ***************************************************************************
2799 void CViewText::setStringSelectionSkipingSpace(uint stringId
, const std::string
&text
, sint charStart
, sint charEnd
)
2801 sint quadStart
= charStart
;
2802 sint quadSize
= charEnd
-charStart
;
2804 CUtfStringView
sv(text
);
2805 CUtfStringView::iterator
it(sv
.begin()), end(sv
.end());
2806 for (j
= 0; it
!= end
&& j
< charStart
; ++j
, ++it
)
2808 if(*it
== (u32char
)' ')
2811 for (j
= charStart
; it
!= end
&& j
< charEnd
; ++j
, ++it
)
2813 if(*it
== (u32char
)' ')
2816 // select what quad to skip
2817 CViewRenderer::getTextContext(_FontName
)->setStringSelection(stringId
, quadStart
, quadSize
); // FIXME: This assumes spaces are the only empty glyphs!
2820 // ***************************************************************************
2821 void CViewText::clearLines()
2823 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
2824 for(uint k
= 0; k
< _Lines
.size(); ++k
)
2826 _Lines
[k
]->clear(*TextContext
);
2831 // ***************************************************************************
2832 uint
CViewText::getNumLine() const
2836 return (uint
)_Lines
.size();
2840 return _Text
.empty() ? 0 : 1;
2844 // ***************************************************************************
2845 uint
CViewText::getFirstLineX() const
2847 return _FirstLineX
/ _Scale
;
2850 // ***************************************************************************
2851 uint
CViewText::getLastLineW () const
2853 if (!_Lines
.empty())
2854 return (uint
)_Lines
.back()->getWidth() / _Scale
;
2858 // ***************************************************************************
2859 void CViewText::setFirstLineX(sint firstLineX
)
2861 _FirstLineX
= firstLineX
* _Scale
;
2864 /////////////////////////////////////
2865 // CViewText::CLine implementation //
2866 /////////////////////////////////////
2868 // ***************************************************************************
2869 CViewText::CLine::CLine() : _NumChars(0),
2873 _WidthWithoutSpaces(0.f
),
2879 // ***************************************************************************
2880 void CViewText::CLine::addWord(const std::string
&text
, uint numSpaces
, const CFormatInfo
&wordFormat
, float fontWidth
, float tabWidth
, NL3D::UTextContext
&textContext
)
2883 word
.build(text
, textContext
, numSpaces
);
2884 word
.Format
= wordFormat
;
2885 addWord(word
, fontWidth
, tabWidth
);
2888 // ***************************************************************************
2889 void CViewText::CLine::addWord(const CWord
&word
, float fontWidth
, float tabWidth
)
2891 _Words
.push_back(word
);
2892 _NumChars
+= word
.NumSpaces
+ uint(word
.Info
.StringLength
);
2893 _NumSpaces
+= word
.NumSpaces
;
2894 if (fabsf(word
.Info
.StringLine
) > fabsf(_StringLine
))
2896 _StringLine
= word
.Info
.StringLine
;
2898 // the width of the line must reach at least the Tab
2899 _WidthWithoutSpaces
= max(_WidthWithoutSpaces
, word
.Format
.TabX
* tabWidth
);
2900 // append the text space
2901 _WidthWithoutSpaces
+= word
.Info
.StringWidth
;
2904 // ***************************************************************************
2905 void CViewText::CLine::clear(NL3D::UTextContext
&textContext
)
2907 for(uint k
= 0; k
< _Words
.size(); ++k
)
2909 if (_Words
[k
].Index
!= 0xffffffff)
2910 textContext
.erase(_Words
[k
].Index
);
2917 // ***************************************************************************
2918 void CViewText::CLine::resetTextIndex()
2920 for(uint k
= 0; k
< _Words
.size(); ++k
)
2922 _Words
[k
].Index
= 0xffffffff;
2926 // ***************************************************************************
2927 void CViewText::CWord::build(const std::string
&text
, NL3D::UTextContext
&textContext
, uint numSpaces
)
2930 NumSpaces
= numSpaces
;
2931 Index
= textContext
.textPush(text
);
2932 Info
= textContext
.getStringInfo(Index
);
2933 nlassert(Info
.StringLength
== CUtfStringView(text
).count());
2936 // ***************************************************************************
2937 void CViewText::removeEndSpaces()
2939 sint i
= (sint
)_Text
.size()-1;
2940 while ((i
>=0) && ((_Text
[i
] < 0x20) || (_Text
[i
] == ' ')))
2947 // ***************************************************************************
2948 sint32
CViewText::getMaxUsedW() const
2950 static const char *spaceStr(" \t");
2951 static const char *lineFeedStr("\n");
2954 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
2955 TextContext
->setHotSpot (UTextContext::BottomLeft
);
2956 TextContext
->setShaded (_Shadow
);
2957 TextContext
->setShadeOutline (_ShadowOutline
);
2958 TextContext
->setFontSize (_FontSize
*_Scale
);
2959 TextContext
->setEmbolden (_Embolden
);
2960 TextContext
->setOblique (_Oblique
);
2962 TCharPos linePos
= 0;
2963 while (linePos
< _Text
.length())
2965 // Get the end of the line
2966 float lineWidth
= 0;
2968 lineEnd
= _Text
.find_first_of("\n", linePos
);
2969 if (lineEnd
== std::string::npos
)
2971 lineEnd
= _Text
.length();
2974 std::string lineValue
;
2975 lineValue
= _Text
.substr(linePos
, lineEnd
- linePos
);
2977 TCharPos currPos
= 0;
2978 while (currPos
!= lineValue
.length())
2984 // Skip spaces and count them
2985 spaceEnd
= lineValue
.find_first_not_of(spaceStr
, currPos
);
2986 if (spaceEnd
== std::string::npos
)
2988 spaceEnd
= lineValue
.length();
2990 numSpaces
= (uint
) (spaceEnd
- currPos
);
2992 // Get word until a space or a \n is encountered
2993 wordEnd
= lineValue
.find_first_of(spaceStr
, spaceEnd
);
2994 if (wordEnd
== std::string::npos
)
2996 wordEnd
= lineValue
.length();
2999 std::string wordValue
;
3000 wordValue
= lineValue
.substr(spaceEnd
, wordEnd
- spaceEnd
);
3002 // compute width of word
3003 UTextContext::CStringInfo si
;
3004 si
= TextContext
->getStringInfo(wordValue
);
3006 // compute size of spaces + word
3007 lineWidth
+= numSpaces
* _SpaceWidth
+ si
.StringWidth
;
3012 // Update line width
3013 if (lineWidth
> maxWidth
)
3014 maxWidth
= lineWidth
;
3016 linePos
= lineEnd
+1;
3019 return (sint32
)ceilf(maxWidth
/ _Scale
);
3022 // ***************************************************************************
3023 sint32
CViewText::getMinUsedW() const
3025 static const char *spaceOrLineFeedStr(" \n\t");
3026 float maxWidth
= 0.0f
;
3028 // Not multi line ? Same size than min
3030 return getMaxUsedW();
3032 // If we can clip word, size of the largest word
3033 if (_TextMode
== ClipWord
)
3035 // No largest font parameter, return the font height
3036 return (sint32
)ceilf(_FontHeight
/ _Scale
);
3038 // If we can't clip the words, return the size of the largest word
3039 else if ((_TextMode
== DontClipWord
) || (_TextMode
== Justified
) || (_TextMode
== Centered
))
3041 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
3042 TextContext
->setHotSpot (UTextContext::BottomLeft
);
3043 TextContext
->setShaded (_Shadow
);
3044 TextContext
->setShadeOutline (_ShadowOutline
);
3045 TextContext
->setFontSize (_FontSize
*_Scale
);
3046 TextContext
->setEmbolden (_Embolden
);
3047 TextContext
->setOblique (_Oblique
);
3049 // Current position in text
3050 TCharPos currPos
= 0;
3051 while (currPos
< _Text
.length())
3054 std::string wordValue
;
3055 UTextContext::CStringInfo si
;
3058 // Get word until a space or a \n is encountered
3059 currPos
= _Text
.find_first_not_of(spaceOrLineFeedStr
, currPos
);
3060 if (currPos
== std::string::npos
)
3062 wordEnd
= _Text
.find_first_of(spaceOrLineFeedStr
, currPos
);
3063 if (wordEnd
== std::string::npos
)
3064 wordEnd
= _Text
.length();
3067 wordValue
= _Text
.substr(currPos
, wordEnd
- currPos
);
3069 // Compute width of word
3070 si
= TextContext
->getStringInfo(wordValue
);
3073 if (maxWidth
< si
.StringWidth
)
3074 maxWidth
= si
.StringWidth
;
3081 return ceilf(maxWidth
/ _Scale
);
3084 // ***************************************************************************
3085 void CViewText::onInvalidateContent()
3087 _InvalidTextContext
= true;
3090 _ParentElm
->invalidateCoords();
3095 // ***************************************************************************
3096 void CViewText::onInterfaceScaleChanged()
3098 _Scale
= CWidgetManager::getInstance()->getInterfaceScale();
3101 invalidateContent();
3103 CViewBase::onInterfaceScaleChanged();
3106 // ***************************************************************************
3107 void CViewText::computeFontSize ()
3109 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
3110 TextContext
->setHotSpot (UTextContext::BottomLeft
);
3111 TextContext
->setShaded (_Shadow
);
3112 TextContext
->setShadeOutline (_ShadowOutline
);
3113 TextContext
->setFontSize (_FontSize
* _Scale
);
3114 TextContext
->setEmbolden (_Embolden
);
3115 TextContext
->setOblique (_Oblique
);
3117 UTextContext::CStringInfo si
= TextContext
->getStringInfo("XO");
3118 float xoHeight
= si
.StringHeight
;
3120 si
= TextContext
->getStringInfo("XO\xC3\x81\xC3\x83");
3121 float upHeight
= si
.StringHeight
;
3123 si
= TextContext
->getStringInfo("XOgq");
3124 float downHeight
= si
.StringHeight
;
3125 float legHeight
= si
.StringLine
;
3127 nlassert(upHeight
>= xoHeight
);
3128 nlassert(downHeight
>= xoHeight
);
3130 if (downHeight
> upHeight
)
3132 diff
= downHeight
- xoHeight
;
3136 diff
= upHeight
- xoHeight
;
3137 legHeight
+= upHeight
- downHeight
;
3140 _FontHeight
= xoHeight
+ diff
+ diff
;
3141 _FontLegHeight
= legHeight
;
3144 si
= TextContext
->getStringInfo(" ");
3145 _SpaceWidth
= si
.StringWidth
;
3148 si
= TextContext
->getStringInfo("O");
3149 _FontWidth
= si
.StringWidth
;
3151 // Tab Width (used for {Txx})
3152 // if not set to "_", breaks item help window
3153 si
= TextContext
->getStringInfo("_");
3154 _TabWidth
= si
.StringWidth
;
3158 // ***************************************************************************
3159 static inline bool isColorTag(const std::string
&s
, uint index
, uint textSize
)
3161 // Format is @{RGBA}
3164 if( textSize
>index
+1 && s
[index
+1]=='{')
3166 // verify 1st letter is a xdigit
3167 if( textSize
>index
+2 && isxdigit(s
[index
+2]))
3169 // We have good chance its a color tag. Do last verification
3170 if(textSize
>index
+6 && s
[index
+6]=='}')
3181 // ***************************************************************************
3182 // isColorTag must be ok.
3183 static inline CRGBA
getColorTag(const std::string
&s
, uint
&index
)
3185 // extract the color string: "FABC"
3187 for(uint i
=0;i
<4;i
++)
3188 tmpCol
[i
]= (char)s
[index
+2+i
];
3194 sscanf(tmpCol
, "%x", &pCol
);
3195 // Transform 4 bits to 8 bit.
3196 color
.R
= (pCol
>>12)&0xF; color
.R
+= color
.R
<<4;
3197 color
.G
= (pCol
>>8)&0xF; color
.G
+= color
.G
<<4;
3198 color
.B
= (pCol
>>4)&0xF; color
.B
+= color
.B
<<4;
3199 color
.A
= (pCol
)&0xF; color
.A
+= color
.A
<<4;
3208 // ***************************************************************************
3209 const uint MaxTabDigit
= 3;
3210 static inline bool isTabTag(const std::string
&s
, uint index
, uint textSize
)
3212 // Format is @{Tvalue}, where value ,1,2,3 digit.
3215 if( textSize
>index
+1 && s
[index
+1]=='{')
3217 if( textSize
>index
+2 && s
[index
+2]=='T')
3219 // We have good chance its a Tab tag. Do last verification
3220 for(uint i
=4;i
<4+MaxTabDigit
;i
++)
3222 if(textSize
>index
+i
&& s
[index
+i
]=='}')
3234 // ***************************************************************************
3235 // isTabTag must be ok.
3236 static inline sint
getTabTag(const std::string
&s
, uint
&index
)
3238 // extract the tab min X value
3239 char tmpTab
[MaxTabDigit
+1];
3241 for(i
=0;i
<MaxTabDigit
;i
++)
3243 if(s
[index
+3+i
]=='}')
3245 tmpTab
[i
]= (char)s
[index
+3+i
];
3253 fromString(tmpTab
, ret
);
3258 // ***************************************************************************
3259 static inline bool isTooltipTag(const std::string
&s
, uint index
, uint textSize
)
3261 // Format is @{Huitt*}
3264 if( textSize
>index
+1 && s
[index
+1]=='{')
3266 if( textSize
>index
+2 && s
[index
+2]=='H')
3269 while (textSize
>index
+i
&& s
[index
+i
]!='}')
3272 if (textSize
>index
+i
&& s
[index
+i
]=='}')
3281 // ***************************************************************************
3282 // isTooltipTag must be ok.
3283 static inline std::string
getTooltipTag(const std::string
&s
, uint
&index
)
3287 while (s
[index
+i
] != '}')
3289 result
+= s
[index
+i
];
3300 // ***************************************************************************
3301 void CViewText::buildFormatTagText(const std::string
&text
, std::string
&textBuild
, std::vector
<CViewText::CFormatTag
> &formatTags
, std::vector
<std::string
> &tooltips
)
3306 // Build the text without the formatTags, and get the color tags separately
3307 textBuild
.reserve(text
.size());
3308 uint textSize
= (uint
)text
.size();
3309 // Must herit all the props from old tags.
3310 CViewText::CFormatTag precTag
; // set default.
3312 for (uint i
= 0; i
< textSize
;)
3314 if(isColorTag(text
, i
, textSize
))
3317 CViewText::CFormatTag ct
= precTag
;
3318 // get new color and skip tag.
3319 ct
.Color
= getColorTag(text
, i
);
3320 ct
.Index
= (uint
)textBuild
.size();
3321 formatTags
.push_back(ct
);
3323 else if(isTabTag(text
, i
, textSize
))
3326 CViewText::CFormatTag ct
= precTag
;
3327 // get new Tab and skip tag.
3328 ct
.TabX
= getTabTag(text
, i
);
3329 ct
.Index
= (uint
)textBuild
.size();
3330 formatTags
.push_back(ct
);
3332 else if(isTooltipTag(text
, i
, textSize
))
3335 CViewText::CFormatTag ct
= precTag
;
3336 // get new Tab and skip tag.
3337 string uitt
= getTooltipTag(text
, i
);
3344 ct
.IndexTt
= (uint
)tooltips
.size();
3345 tooltips
.push_back(uitt
);
3348 ct
.Index
= (uint
)textBuild
.size();
3349 formatTags
.push_back(ct
);
3353 bool lineFeed
= text
[i
]=='\n';
3355 // append to textBuild
3356 textBuild
+= text
[i
];
3359 // if \n, reset tabulations
3362 CViewText::CFormatTag ct
= precTag
;
3364 ct
.Index
= (uint
)textBuild
.size();
3365 formatTags
.push_back(ct
);
3369 if(!formatTags
.empty())
3370 precTag
= formatTags
.back();
3374 #ifdef RYZOM_LUA_UCSTRING
3375 // ***************************************************************************
3376 void CViewText::setTextFormatTagedAsUtf16(const ucstring
&text
)
3378 setTextFormatTaged(text
.toUtf8());
3382 // ***************************************************************************
3383 void CViewText::setTextFormatTaged(const std::string
&text
)
3388 // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
3389 std::string tempText
;
3390 // static to avoid reallocation
3391 static std::vector
<CFormatTag
> tempFormatTags
;
3392 static std::vector
<std::string
> tempTooltips
;
3393 buildFormatTagText(text
, tempText
, tempFormatTags
, tempTooltips
);
3394 setCase (tempText
, _CaseMode
);
3396 // compare Tag arrays
3397 bool sameTagArray
= false;
3398 if(_FormatTags
.size()==tempFormatTags
.size())
3401 for(uint i
=0;i
<_FormatTags
.size();i
++)
3403 if(!_FormatTags
[i
].sameTag(tempFormatTags
[i
]))
3405 sameTagArray
= false;
3411 // test transformed text with current one
3412 if(tempText
!=_Text
|| !sameTagArray
)
3415 _FormatTags
= tempFormatTags
;
3416 // Copy to Text (preserve Memory)
3422 CInterfaceGroup
*parent
= getParent();
3424 // Delete old dynamic tooltips
3425 for (uint i
=0 ; i
<_Tooltips
.size() ; ++i
)
3428 parent
->delCtrl(_Tooltips
[i
]);
3430 delete _Tooltips
[i
];
3434 // Add new dynamic tooltips
3435 for (uint i
=0 ; i
<tempTooltips
.size() ; ++i
)
3437 CCtrlToolTip
*pTooltip
= new CCtrlToolTip(CCtrlToolTip::TCtorParam());
3438 pTooltip
->setId(_Id
+"_tt"+toString(i
));
3439 pTooltip
->setAvoidResizeParent(avoidResizeParent());
3440 pTooltip
->setRenderLayer(getRenderLayer());
3441 std::string tempTooltipStr
= tempTooltips
[i
];
3442 bool isI18N
= NLMISC::startsWith(tempTooltipStr
, "ui");
3443 pTooltip
->setDefaultContextHelp(isI18N
? CI18N::get(tempTooltipStr
) : tempTooltipStr
);
3444 pTooltip
->setParentPos(this);
3445 pTooltip
->setParentPosRef(Hotspot_BR
);
3446 pTooltip
->setPosRef(Hotspot_BR
);
3447 pTooltip
->setToolTipParent(CCtrlBase::TTWindow
);
3448 pTooltip
->setToolTipParentPosRef(Hotspot_TTAuto
);
3449 pTooltip
->setToolTipPosRef(Hotspot_TTAuto
);
3450 pTooltip
->setActive(true);
3452 _Tooltips
.push_back(pTooltip
);
3456 pTooltip
->setParent(parent
);
3457 parent
->addCtrl(_Tooltips
.back());
3466 invalidateContent ();
3469 // color format is available only if multilined
3471 nlwarning("ViewText isn't multilined : uc_hardtext_format will not act as wanted !\n%s", text
.c_str());
3474 #ifdef RYZOM_LUA_UCSTRING
3475 void CViewText::setSingleLineTextFormatTagedAsUtf16(const ucstring
&text
)
3477 setSingleLineTextFormatTaged(text
.toUtf8());
3481 void CViewText::setSingleLineTextFormatTaged(const std::string
&text
)
3486 // to allow cache (avoid infinite recurse in updateCoords() in some case), compute in temp
3487 std::string tempText
;
3488 static std::vector
<CFormatTag
> tempLetterColors
;
3489 static std::vector
<std::string
> tempTooltips
;
3492 buildFormatTagText(text
, tempText
, tempLetterColors
, tempTooltips
);
3493 setCase (tempText
, _CaseMode
);
3495 // decal for spaces (not inserted in VertexBuffer)
3498 for(uint i
=0; i
<tempLetterColors
.size(); i
++)
3500 CFormatTag
& formatTag
= tempLetterColors
[i
];
3502 while(textIndex
<formatTag
.Index
)
3504 if(tempText
[textIndex
] == ' ')
3510 formatTag
.Index
-= spacesNb
;
3513 // convert in ULetterColors
3514 NL3D::UTextContext
*TextContext
= CViewRenderer::getTextContext(_FontName
);
3515 ULetterColors
* letterColors
= TextContext
->createLetterColors();
3516 for(uint i
=0; i
<tempLetterColors
.size(); i
++)
3518 const CFormatTag
& formatTag
= tempLetterColors
[i
];
3519 letterColors
->pushLetterColor(formatTag
.Index
, formatTag
.Color
);
3522 // test transformed text with current one
3523 if(tempText
!=_Text
|| !_LetterColors
|| !_LetterColors
->isSameLetterColors(letterColors
))
3525 _LetterColors
= letterColors
;
3527 TextContext
->setLetterColors(letterColors
, _Index
);
3529 // Copy to Text (preserve Memory)
3534 invalidateContent ();
3537 // this color format is available only if not multilined
3539 nlwarning("ViewText is multilined : uc_hardtext_single_line_format will not act as wanted !\n%s", text
.c_str());
3543 // ***************************************************************************
3544 bool CViewText::isFormatTagChange(uint textIndex
, uint ctIndex
) const
3546 if(ctIndex
>=_FormatTags
.size())
3548 // return true if the textIndex is > (eg if some skip with spaces) or = (common case)
3549 return _FormatTags
[ctIndex
].Index
<= textIndex
;
3552 // ***************************************************************************
3553 void CViewText::getFormatTagChange(uint textIndex
, uint
&ctIndex
, CFormatInfo
&wordFormat
) const
3555 // support the possible case with multiple color tags with same textIndex.
3556 while(ctIndex
<_FormatTags
.size() && _FormatTags
[ctIndex
].Index
<=textIndex
)
3558 // Take the last tag.
3559 wordFormat
.Color
= _FormatTags
[ctIndex
].Color
;
3560 wordFormat
.TabX
= _FormatTags
[ctIndex
].TabX
;
3561 wordFormat
.IndexTt
= _FormatTags
[ctIndex
].IndexTt
;
3568 // ***************************************************************************
3570 void CViewText::setCaseMode (TCaseMode caseMode
)
3572 _CaseMode
= caseMode
;
3573 setCase (_Text
, _CaseMode
);
3577 // ***************************************************************************
3579 TCaseMode
CViewText::getCaseMode () const
3584 // ***************************************************************************
3586 void CViewText::resetTextIndex()
3588 _Index
= 0xffffffff;
3589 for(uint k
= 0; k
< _Lines
.size(); ++k
)
3590 _Lines
[k
]->resetTextIndex();
3593 // ***************************************************************************
3594 void CViewText::setup()
3598 // Add dynamic tooltips
3599 for (uint i
=0 ; i
<_Tooltips
.size() ; ++i
)
3601 CInterfaceGroup
*parent
= getParent();
3604 _Tooltips
[i
]->setParent(parent
);
3605 parent
->addCtrl(_Tooltips
.back());
3610 // ***************************************************************************
3611 void CViewText::serial(NLMISC::IStream
&f
)
3613 #define SERIAL_UINT(val) { uint32 tmp = (uint32) val; f.serial(tmp); val = (uint) tmp; }
3614 #define SERIAL_SINT(val) { sint32 tmp = (sint32) val; f.serial(tmp); val = (sint) tmp; }
3615 CViewBase::serial(f
);
3617 int version
= f
.serialVersion(101);
3618 nlassert(version
>= 100);
3620 f
.serial(_Localized
);
3621 SERIAL_SINT(_FontSize
);
3622 SERIAL_UINT(_FontWidth
);
3623 SERIAL_UINT(_TabWidth
);
3624 SERIAL_UINT(_FontHeight
);
3625 SERIAL_UINT(_FontLegHeight
);
3626 f
.serial(_SpaceWidth
);
3629 f
.serial(_ShadowOutline
);
3630 f
.serialEnum(_CaseMode
);
3631 f
.serial(_ShadowColor
);
3632 f
.serial(_LineMaxW
);
3633 f
.serial(_SingleLineTextClamped
);
3634 f
.serial(_MultiLine
);
3635 f
.serial(_MultiLineMaxWOnly
);
3636 f
.serial(_MultiLineClipEndSpace
);
3637 f
.serial(_AutoClampOffset
);
3638 f
.serialEnum(_TextMode
);
3639 SERIAL_SINT(_MultiLineSpace
);
3640 SERIAL_SINT(_LastMultiLineMaxW
);
3641 f
.serial(_MultiMaxLine
);
3643 bool hasTag
= !_FormatTags
.empty();
3653 setTextFormatTaged(text
.toUtf8());
3657 setSingleLineTextFormatTaged(text
.toUtf8());
3662 setText(text
.toUtf8());
3667 ucstring text
= CUtfStringView(_Text
).toUtf16();
3676 // ***************************************************************************