RichLabel.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. GWEN
  3. Copyright (c) 2010 Facepunch Studios
  4. See license in Gwen.h
  5. */
  6. #include "Gwen/Gwen.h"
  7. #include "Gwen/Controls/RichLabel.h"
  8. #include "Gwen/Controls/Label.h"
  9. #include "Gwen/Utility.h"
  10. using namespace Gwen;
  11. using namespace Gwen::Controls;
  12. const unsigned char Type_Text = 0;
  13. const unsigned char Type_Newline = 1;
  14. GWEN_CONTROL_CONSTRUCTOR( RichLabel )
  15. {
  16. m_bNeedsRebuild = false;
  17. }
  18. void RichLabel::AddLineBreak()
  19. {
  20. DividedText t;
  21. t.type = Type_Newline;
  22. m_TextBlocks.push_back( t );
  23. }
  24. void RichLabel::AddText( const Gwen::TextObject& text, Gwen::Color color, Gwen::Font* font )
  25. {
  26. if ( text.m_Data.size() == 0 ) return;
  27. Gwen::Utility::Strings::UnicodeList lst;
  28. Gwen::Utility::Strings::Split( text.GetUnicode(), L"\n", lst, false );
  29. for (size_t i=0; i<lst.size(); i++ )
  30. {
  31. if ( i > 0 ) AddLineBreak();
  32. DividedText t;
  33. t.type = Type_Text;
  34. t.text = lst[i];
  35. t.color = color;
  36. t.font = font;
  37. m_TextBlocks.push_back( t );
  38. m_bNeedsRebuild = true;
  39. Invalidate();
  40. }
  41. }
  42. bool RichLabel::SizeToChildren( bool w, bool h )
  43. {
  44. Rebuild();
  45. return BaseClass::SizeToChildren( w, h );
  46. }
  47. void RichLabel::SplitLabel( const Gwen::UnicodeString& text, Gwen::Font* pFont, const DividedText& txt, int& x, int& y, int& lineheight )
  48. {
  49. Gwen::Utility::Strings::UnicodeList lst;
  50. Gwen::Utility::Strings::Split( text, L" ", lst, true );
  51. if ( lst.size() == 0 ) return;
  52. int iSpaceLeft = Width() - x;
  53. // Does the whole word fit in?
  54. {
  55. Gwen::Point StringSize = GetSkin()->GetRender()->MeasureText( pFont, text );
  56. if ( iSpaceLeft > StringSize.x )
  57. {
  58. return CreateLabel( text, txt, x, y, lineheight, true );
  59. }
  60. }
  61. // If the first word is bigger than the line, just give up.
  62. {
  63. Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, lst[0] );
  64. if ( WordSize.x >= iSpaceLeft )
  65. {
  66. CreateLabel( lst[0], txt, x, y, lineheight, true );
  67. if ( lst[0].size() >= text.size() ) return;
  68. Gwen::UnicodeString LeftOver = text.substr( lst[0].size() + 1 );
  69. return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
  70. }
  71. }
  72. Gwen::UnicodeString strNewString = L"";
  73. for ( size_t i=0; i<lst.size(); i++ )
  74. {
  75. Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, strNewString + lst[i] );
  76. if ( WordSize.x > iSpaceLeft )
  77. {
  78. CreateLabel( strNewString, txt, x, y, lineheight, true );
  79. x = 0;
  80. y += lineheight;
  81. break;;
  82. }
  83. strNewString += lst[i];
  84. }
  85. Gwen::UnicodeString LeftOver = text.substr( strNewString.size() + 1 );
  86. return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
  87. }
  88. void RichLabel::CreateLabel( const Gwen::UnicodeString& text, const DividedText& txt, int& x, int& y, int& lineheight, bool NoSplit )
  89. {
  90. //
  91. // Use default font or is one set?
  92. //
  93. Gwen::Font* pFont = GetSkin()->GetDefaultFont();
  94. if ( txt.font ) pFont = txt.font;
  95. //
  96. // This string is too long for us, split it up.
  97. //
  98. Gwen::Point p = GetSkin()->GetRender()->MeasureText( pFont, text );
  99. if ( lineheight == -1 )
  100. {
  101. lineheight = p.y;
  102. }
  103. if ( !NoSplit )
  104. {
  105. if ( x + p.x > Width() )
  106. {
  107. return SplitLabel( text, pFont, txt, x, y, lineheight );
  108. }
  109. }
  110. //
  111. // Wrap
  112. //
  113. if ( x + p.x >= Width() )
  114. {
  115. CreateNewline( x, y, lineheight );
  116. }
  117. Gwen::Controls::Label* pLabel = new Gwen::Controls::Label( this );
  118. pLabel->SetText( x == 0 ? Gwen::Utility::Strings::TrimLeft<Gwen::UnicodeString>( text, L" " ) : text );
  119. pLabel->SetTextColor( txt.color );
  120. pLabel->SetFont( pFont );
  121. pLabel->SizeToContents();
  122. pLabel->SetPos( x, y );
  123. //lineheight = (lineheight + pLabel->Height()) / 2;
  124. x += pLabel->Width();
  125. if ( x >= Width() )
  126. {
  127. CreateNewline( x, y, lineheight );
  128. }
  129. }
  130. void RichLabel::CreateNewline( int& x, int& y, int& lineheight )
  131. {
  132. x = 0;
  133. y += lineheight;
  134. }
  135. void RichLabel::Rebuild()
  136. {
  137. RemoveAllChildren();
  138. int x = 0;
  139. int y = 0;
  140. int lineheight = -1;
  141. for ( DividedText::List::iterator it = m_TextBlocks.begin(); it != m_TextBlocks.end(); ++it )
  142. {
  143. if ( it->type == Type_Newline )
  144. {
  145. CreateNewline( x, y, lineheight );
  146. continue;
  147. }
  148. if ( it->type == Type_Text )
  149. {
  150. CreateLabel( (*it).text, *it, x, y, lineheight, false );
  151. continue;
  152. }
  153. }
  154. m_bNeedsRebuild = false;
  155. }
  156. void RichLabel::OnBoundsChanged( Gwen::Rect oldBounds )
  157. {
  158. BaseClass::OnBoundsChanged( oldBounds );
  159. Rebuild();
  160. }
  161. void RichLabel::Layout( Gwen::Skin::Base* skin )
  162. {
  163. BaseClass::Layout( skin );
  164. if ( m_bNeedsRebuild )
  165. {
  166. Rebuild();
  167. }
  168. }