/******************************************************************** * Text field that allows multiple lines. * * Written by Dan Andersson, 2014 ********************************************************************/ #ifndef DANBIAS_CLIENT_TEXT_FIELD_H #define DANBIAS_CLIENT_TEXT_FIELD_H #include #include #include "ButtonRectangle.h" #include "OysterMath.h" #include "Utilities.h" namespace DanBias { namespace Client { template class TextField : public ButtonRectangle { public: TextField(); TextField( ::std::wstring backgroundTexture, ::Oyster::Math::Float4 textColor, ::Oyster::Math::Float4 backColor, Owner owner, Oyster::Math::Float3 pos, Oyster::Math::Float2 size, ResizeAspectRatio resize = ResizeAspectRatio_Height ); virtual ~TextField(); virtual void RenderText(); const ::std::wstring & operator[]( unsigned int i ) const; ::std::wstring & operator[]( unsigned int i ); void SetFontHeight( ::Oyster::Math::Float h ); void SetLineSpacing( ::Oyster::Math::Float ls ); void SetBottomAligned(); void SetTopAligned(); unsigned int GetNumLines() const; unsigned int GetMaxLineLength() const; void ReserveLines( unsigned int num ); void ClearText(); void AppendText( const ::std::wstring &text ); void PopBack(); void PopFront(); private: bool isBottomAligned; ::Oyster::Math::Float fontHeight, lineSpacing; ::std::vector<::std::wstring> lines; }; // IMPLEMENTATIONS ////////////////////////////////////////////////// template TextField::TextField() : ButtonRectangle() { this->fontHeight = 0.025f; this->lineSpacing = 0.001f; this->isBottomAligned = true; } template TextField::TextField( ::std::wstring backgroundTexture, ::Oyster::Math::Float4 textColor, ::Oyster::Math::Float4 backColor, Owner owner, Oyster::Math::Float3 pos, Oyster::Math::Float2 size, ResizeAspectRatio resize ) : ButtonRectangle( backgroundTexture, L"", textColor, backColor, backColor, backColor, owner, pos, size, resize ) { this->fontHeight = 0.025f; this->lineSpacing = 0.001f; this->isBottomAligned = true; } template TextField::~TextField() {} template void TextField::RenderText() { ::Oyster::Math::Float lineStep = this->fontHeight + this->lineSpacing; ::Oyster::Math::Float2 rowSize = ::Oyster::Math::Float2( this->size.x, this->fontHeight ); ::Oyster::Math::Float3 fieldTopLeft = this->pos - Float3( this->size * 0.25f, 0.0f ); ::Oyster::Math::Float3 topLeft = fieldTopLeft; if( this->isBottomAligned ) { topLeft.y += this->size.y - lineStep; auto line = this->lines.rbegin(); for( ; line != this->lines.rend(); ++line ) { if( topLeft.y < fieldTopLeft.y ) break; ::Oyster::Graphics::API::RenderText( (*line), topLeft, rowSize, this->fontHeight, this->textColor ); topLeft.y -= lineStep; } } else { topLeft.y += this->lineSpacing; auto line = this->lines.begin(); for( ; line != this->lines.end(); ++line ) { if( topLeft.y >= fieldTopLeft.y + this->size.y ) break; ::Oyster::Graphics::API::RenderText( (*line), topLeft, rowSize, this->fontHeight, this->textColor ); topLeft.y += lineStep; } } } template const ::std::wstring & TextField::operator[]( unsigned int i ) const { return this->lines[(::std::vector<::std::wstring>::size_type)i]; } template ::std::wstring & TextField::operator[]( unsigned int i ) { return this->lines[(::std::vector<::std::wstring>::size_type)i]; } template void TextField::SetFontHeight( ::Oyster::Math::Float h ) { this->fontHeight = h; } template void TextField::SetLineSpacing( ::Oyster::Math::Float ls ) { this->lineSpacing = ls; } template void TextField::SetBottomAligned() { this->isBottomAligned = true; } template void TextField::SetTopAligned() { this->isBottomAligned = false; } template unsigned int TextField::GetNumLines() const { return (unsigned int)this->lines.size(); } template void TextField::ReserveLines( unsigned int num ) { this->lines.reserve( (::std::vector<::std::wstring>::size_type)num ); } template void TextField::ClearText() { this->lines.resize( 0 ); } template void TextField::AppendText( const ::std::wstring &text ) { ::std::vector<::std::wstring> split; split.reserve( 10 ); ::Utility::String::Split( split, text, L"\n", 0 ); auto line = split.begin(); for( ; line != split.end(); ++line ) { this->lines.push_back( (*line) ); } } template void TextField::PopBack() { this->lines.pop_back(); } template void TextField::PopFront() { ::std::vector<::std::wstring>::size_type i = 0, n = this->lines.size() - 1; for( ; i < n; ++i ) { this->lines[i] = this->lines[i+1]; } this->lines.pop_back(); } } } #endif