123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- GWEN
- Copyright (c) 2010 Facepunch Studios
- See license in Gwen.h
- */
- #include "Gwen/Gwen.h"
- #include "Gwen/Controls/RichLabel.h"
- #include "Gwen/Controls/Label.h"
- #include "Gwen/Utility.h"
- using namespace Gwen;
- using namespace Gwen::Controls;
- const unsigned char Type_Text = 0;
- const unsigned char Type_Newline = 1;
- GWEN_CONTROL_CONSTRUCTOR( RichLabel )
- {
- m_bNeedsRebuild = false;
- }
- void RichLabel::AddLineBreak()
- {
- DividedText t;
- t.type = Type_Newline;
- m_TextBlocks.push_back( t );
- }
- void RichLabel::AddText( const Gwen::TextObject& text, Gwen::Color color, Gwen::Font* font )
- {
- if ( text.m_Data.size() == 0 ) return;
- Gwen::Utility::Strings::UnicodeList lst;
- Gwen::Utility::Strings::Split( text.GetUnicode(), L"\n", lst, false );
- for (size_t i=0; i<lst.size(); i++ )
- {
- if ( i > 0 ) AddLineBreak();
- DividedText t;
- t.type = Type_Text;
- t.text = lst[i];
- t.color = color;
- t.font = font;
- m_TextBlocks.push_back( t );
- m_bNeedsRebuild = true;
- Invalidate();
- }
- }
- bool RichLabel::SizeToChildren( bool w, bool h )
- {
- Rebuild();
- return BaseClass::SizeToChildren( w, h );
- }
- void RichLabel::SplitLabel( const Gwen::UnicodeString& text, Gwen::Font* pFont, const DividedText& txt, int& x, int& y, int& lineheight )
- {
- Gwen::Utility::Strings::UnicodeList lst;
- Gwen::Utility::Strings::Split( text, L" ", lst, true );
- if ( lst.size() == 0 ) return;
- int iSpaceLeft = Width() - x;
- // Does the whole word fit in?
- {
- Gwen::Point StringSize = GetSkin()->GetRender()->MeasureText( pFont, text );
- if ( iSpaceLeft > StringSize.x )
- {
- return CreateLabel( text, txt, x, y, lineheight, true );
- }
- }
- // If the first word is bigger than the line, just give up.
- {
- Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, lst[0] );
- if ( WordSize.x >= iSpaceLeft )
- {
- CreateLabel( lst[0], txt, x, y, lineheight, true );
- if ( lst[0].size() >= text.size() ) return;
- Gwen::UnicodeString LeftOver = text.substr( lst[0].size() + 1 );
- return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
- }
- }
- Gwen::UnicodeString strNewString = L"";
- for ( size_t i=0; i<lst.size(); i++ )
- {
- Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, strNewString + lst[i] );
- if ( WordSize.x > iSpaceLeft )
- {
- CreateLabel( strNewString, txt, x, y, lineheight, true );
- x = 0;
- y += lineheight;
- break;;
- }
- strNewString += lst[i];
- }
- Gwen::UnicodeString LeftOver = text.substr( strNewString.size() + 1 );
- return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
- }
- void RichLabel::CreateLabel( const Gwen::UnicodeString& text, const DividedText& txt, int& x, int& y, int& lineheight, bool NoSplit )
- {
- //
- // Use default font or is one set?
- //
- Gwen::Font* pFont = GetSkin()->GetDefaultFont();
- if ( txt.font ) pFont = txt.font;
- //
- // This string is too long for us, split it up.
- //
- Gwen::Point p = GetSkin()->GetRender()->MeasureText( pFont, text );
- if ( lineheight == -1 )
- {
- lineheight = p.y;
- }
- if ( !NoSplit )
- {
- if ( x + p.x > Width() )
- {
- return SplitLabel( text, pFont, txt, x, y, lineheight );
- }
- }
- //
- // Wrap
- //
- if ( x + p.x >= Width() )
- {
- CreateNewline( x, y, lineheight );
- }
- Gwen::Controls::Label* pLabel = new Gwen::Controls::Label( this );
- pLabel->SetText( x == 0 ? Gwen::Utility::Strings::TrimLeft<Gwen::UnicodeString>( text, L" " ) : text );
- pLabel->SetTextColor( txt.color );
- pLabel->SetFont( pFont );
- pLabel->SizeToContents();
- pLabel->SetPos( x, y );
- //lineheight = (lineheight + pLabel->Height()) / 2;
- x += pLabel->Width();
- if ( x >= Width() )
- {
- CreateNewline( x, y, lineheight );
- }
- }
- void RichLabel::CreateNewline( int& x, int& y, int& lineheight )
- {
- x = 0;
- y += lineheight;
- }
- void RichLabel::Rebuild()
- {
- RemoveAllChildren();
- int x = 0;
- int y = 0;
- int lineheight = -1;
- for ( DividedText::List::iterator it = m_TextBlocks.begin(); it != m_TextBlocks.end(); ++it )
- {
- if ( it->type == Type_Newline )
- {
- CreateNewline( x, y, lineheight );
- continue;
- }
- if ( it->type == Type_Text )
- {
- CreateLabel( (*it).text, *it, x, y, lineheight, false );
- continue;
- }
- }
- m_bNeedsRebuild = false;
- }
- void RichLabel::OnBoundsChanged( Gwen::Rect oldBounds )
- {
- BaseClass::OnBoundsChanged( oldBounds );
- Rebuild();
- }
- void RichLabel::Layout( Gwen::Skin::Base* skin )
- {
- BaseClass::Layout( skin );
- if ( m_bNeedsRebuild )
- {
- Rebuild();
- }
- }
|