current versions of all of my basic framework sources, build configurations/scripts, and supporting assets
209 lines
4.2 KiB
C++
209 lines
4.2 KiB
C++
/*
|
|
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<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::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; 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::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<Gwen::String>( 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();
|
|
}
|
|
} |