Apply clang-format-all.sh using the _clang-format file through all the cpp/.h files. make sure not to apply it to certain serialization structures, since some parser expects the * as part of the name, instead of type. This commit contains no other changes aside from adding and applying clang-format-all.sh
207 lines
4.2 KiB
C++
207 lines
4.2 KiB
C++
/*
|
|
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();
|
|
}
|
|
} |