/* GWEN Copyright (c) 2010 Facepunch Studios See license in Gwen.h */ #include "../gwen.h" #include "gwen_richlabel.h" #include "gwen_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.length() == 0 ) return; Gwen::Utility::Strings::List lst; Gwen::Utility::Strings::Split( text.Get(), "\n", lst, false ); for (size_t i=0; 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::String& text, Gwen::Font* pFont, const DividedText& txt, int& x, int& y, int& lineheight ) { Gwen::Utility::Strings::List lst; Gwen::Utility::Strings::Split( text, " ", 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::String LeftOver = text.substr( lst[0].size() + 1 ); return SplitLabel( LeftOver, pFont, txt, x, y, lineheight ); } } Gwen::String strNewString = ""; for ( size_t i=0; iGetRender()->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::String LeftOver = text.substr( strNewString.size() + 1 ); return SplitLabel( LeftOver, pFont, txt, x, y, lineheight ); } void RichLabel::CreateLabel( const Gwen::String& 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( text, " " ) : 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(); } }