Spinning Topp Logo BlackTopp Studios
inc
multilinetextlayer.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _uimultilinetextlayer_cpp
41 #define _uimultilinetextlayer_cpp
42 
43 #include "UI/multilinetextlayer.h"
44 #include "UI/uimanager.h"
45 #include "UI/textline.h"
46 #include "UI/character.h"
47 #include "countedptr.h"
48 
49 #include <algorithm>
50 
51 namespace Mezzanine
52 {
53  namespace UI
54  {
56  TextLayer(ParentRenderable)
57  { }
58 
59  MultiLineTextLayer::MultiLineTextLayer(const String& FontName, QuadRenderable* ParentRenderable) :
60  TextLayer(FontName,ParentRenderable)
61  { }
62 
63  MultiLineTextLayer::MultiLineTextLayer(const Real& LineHeight, QuadRenderable* ParentRenderable) :
64  TextLayer(LineHeight,ParentRenderable)
65  { }
66 
68  { }
69 
71  {
72  //if( MaxWidth <= 0 )
73  // return;
74 
75  Whole LineIndex = 0;
76  Boole NewLineDetected = false;
77  TextLine* CurrLine = this->GetOrCreateTextLine(LineIndex);
79  CharacterIterator Start = this->Characters.begin();
80  CharacterIterator End = this->Characters.begin();
81  const CharacterIterator CharEnd = this->Characters.end();
82 
83  do{
84  if( (*Start)->IsWhiteSpace() ) {
85  // Find the next non-whitespace character.
86  while( End != CharEnd )
87  {
88  if( (*End)->IsNewLine() ) {
89  NewLineDetected = true;
90  ++End;
91  break;
92  }else if( !(*End)->IsWhiteSpace() ) {
93  break;
94  }
95 
96  ++End;
97  }
98 
99  // We got our range, append what we can.
100  CharacterIterator Result = CurrLine->AppendFittingCharacters(Start,End,MaxWidth);
101  if( Result != End || NewLineDetected ) {
102  CurrLine = this->GetOrCreateTextLine(++LineIndex);
103  End = CurrLine->AppendFittingCharacters(Result,End,MaxWidth);
104  if( Start == End ) {
105  // If these are the same, then we lack the space to append anything.
106  break;
107  }
108  }
109  // Clear out the newline for the next iteration.
110  NewLineDetected = false;
111  }else{
112  // Find the next whitespace character.
113  while( End != CharEnd )
114  {
115  if( (*End)->IsWhiteSpace() )
116  break;
117 
118  ++End;
119  }
120 
121  // We got our range, so lets try to insert it.
122  if( !CurrLine->AppendCharacters(Start,End,MaxWidth) )
123  {
124  // If we failed to insert, get the next line and try again.
125  CurrLine = this->GetOrCreateTextLine(++LineIndex);
126  if( !CurrLine->AppendCharacters(Start,End,MaxWidth) ) {
127  End = CurrLine->AppendFittingCharacters(Start,End,MaxWidth);
128  if( Start == End ) {
129  // If these are the same, then we lack the space to append anything.
130  break;
131  }
132  }
133  }
134  }
135  Start = End;
136  }while( Start != CharEnd );
137  }
139  {
140  CharacterIterator Start = --this->Characters.end();
141  CharacterIterator End = --this->Characters.end();
142  const CharacterIterator CharEnd = --this->Characters.begin();
143 
144  CharacterIteratorPair AppendPair;
145 
146  do{
147  if( (*End)->IsWhiteSpace() ) {
148  // Find the next non-whitespace character.
149  while( Start != CharEnd )
150  {
151  if( (*Start)->IsNewLine() ) {
152  NewLineDetected = true;
153  ++Start;
154  break;
155  }else if( !(*Start)->IsWhiteSpace() ) {
156  break;
157  }
158 
159  ++Start;
160  }
161 
162  AppendPair.first = Start;
163  AppendPair.second = End;
164  ++AppendPair.first;
165  ++AppendPair.second;
166 
167  // We got our range, append what we can.
168  CharacterIterator Result = CurrLine->AppendFittingCharacters(AppendPair,MaxWidth);
169  if( Result != Start || NewLineDetected ) {
170  CurrLine = this->GetOrCreateTextLine(++LineIndex);
171  Start = CurrLine->AppendFittingCharacters(Result,End,MaxWidth);
172  if( End == Start ) {
173  // If these are the same, then we lack the space to append anything.
174  break;
175  }
176  }
177  NewLineDetected = false;
178  }else{
179  // Find the next whitespace character.
180  while( Start != CharEnd )
181  {
182  if( (*Start)->IsWhiteSpace() )
183  break;
184 
185  ++Start;
186  }
187 
188  AppendPair.first = Start;
189  AppendPair.second = End;
190  ++AppendPair.first;
191  ++AppendPair.second;
192 
193  // We got our range, so lets try to insert it.
194  if( !CurrLine->AppendCharacters(AppendPair,MaxWidth) ) {
195  // If we failed to insert, get the next line and try again.
196  CurrLine = this->GetOrCreateTextLine(++LineIndex);
197  if( !CurrLine->AppendCharacters(AppendPair,MaxWidth) ) {
198  Start = CurrLine->AppendFittingCharacters(AppendPair,MaxWidth);
199  if( End == Start ) {
200  // If these are the same, then we lack the space to append anything.
201  break;
202  }
203  }
204  }
205  }
206  End = Start;
207  }while( CharEnd != CharEnd );
208  }
209 
210  // Clean up unused text lines.
211  if( this->TextLines.size() > 1 && this->TextLines.size() >= LineIndex ) {
212  TextLines.erase(this->TextLines.begin() + LineIndex + 1, this->TextLines.end());
213  }
214  }
215 
217  {
218  CharIndexPair Ret(true,0);
219  TextLineIterator LineIt = this->TextLines.begin();
220  // Check if we're too far to the top to get anything
221  if( Offset.Y < (*LineIt)->GetPositionOffset() - (*LineIt)->GetLineHeight() )
222  return CharIndexPair(false,0);
223 
224  Integer IndexCount = 0;
225  while( LineIt != TextLines.end() && Offset.Y < (*LineIt)->GetPositionOffset() )
226  {
227  IndexCount += static_cast<Integer>( (*LineIt)->GetNumCharacters() );
228  ++LineIt;
229  }
230 
231  // Check if we're too low to get anything
232  if( LineIt == (--TextLines.end()) && Offset.Y > (*LineIt)->GetPositionOffset() )
233  return CharIndexPair(false,0);
234 
235  Ret.second = IndexCount + (*LineIt)->GetIndexAtOffset(Offset.X);
236  return Ret;
237  }
238 
240  {
241  CharOffsetPair Ret;
242  Ret.first = true;
243  if( Index < 0 || static_cast<Whole>( Index ) >= this->Characters.size() ) {
244  TextLineIterator Last = --this->TextLines.end();
245  Ret.second.Y = (*Last)->GetPositionOffset();
246  Ret.second.X = (*Last)->GetOffsetAtIndex(-1);
247  return Ret;
248  }else{
249  Integer IndexCount = 0;
250 
251  TextLineIterator LineIt = this->TextLines.begin();
252  while( LineIt != this->TextLines.end() && IndexCount + static_cast<Integer>( (*LineIt)->GetNumCharacters() ) < Index )
253  {
254  IndexCount += (*LineIt)->GetNumCharacters();
255  ++LineIt;
256  }
257  Ret.second.Y = (*LineIt)->GetPositionOffset();
258  Ret.second.X = (*LineIt)->GetOffsetAtIndex( Index - IndexCount );
259  return Ret;
260  }
261  }
262 
264  {
265  if( Index >= this->TextLines.size() ) return this->CreateTextLine();
266  else return this->TextLines.at(Index);
267  }
268 
269  ///////////////////////////////////////////////////////////////////////////////
270  // Utility
271 
273  {
274  return UI::RLT_MultiLineText;
275  }
276 
277  ///////////////////////////////////////////////////////////////////////////////
278  // Text Methods
279 
280  ///////////////////////////////////////////////////////////////////////////////
281  // Serialization
282 
284  {
286  }
287 
289  {
291  }
292 
294  {
296  }
297 
299  {
300  return "MultiLineTextLayer";
301  }
302  }//UI
303 }//Mezzanine
304 
305 #endif
Characters/New Lines originate from the left, and advance to the right.
std::pair< Boole, Vector2 > CharOffsetPair
An std::pair type used as a return for index-offset conversions.
Definition: textlayer.h:88
MultiLineTextLayer(QuadRenderable *ParentRenderable)
No-Font constructor.
virtual void ProtoSerializeProperties(XML::Node &SelfRoot) const
Convert the properties of this class to an XML::Node ready for serialization.
Definition: textlayer.cpp:942
virtual ~MultiLineTextLayer()
Class destructor.
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
CharacterContainer Characters
Container with all this layers Characters.
Definition: textlayer.h:104
virtual UI::RenderLayerType GetLayerType() const
Gets the type of render layer this is.
int Integer
A datatype used to represent any integer close to.
Definition: datatypes.h:154
TextLineContainer::iterator TextLineIterator
Iterator type for TextLine instances stored by this class.
Definition: textlayer.h:82
This represents a single line of text to be rendered by a TextLayer.
Definition: textline.h:59
CharacterIterator AppendFittingCharacters(CharacterContainer &ToAdd, const Real MaxWidth)
Adds as many Characters in a range as will fit to this TextLine.
Definition: textline.cpp:260
Value representing a MultiLineTextLayer.
std::pair< Boole, Integer > CharIndexPair
An std::pair type used as a return for index-offset conversions.
Definition: textlayer.h:86
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
Characters/New Lines originate from the right, and advance to the left.
virtual String GetDerivedSerializableName() const
Gets the most derived serializable name of this Renderable.
virtual CharIndexPair GetIndexAtOffsetImpl(const Vector2 &Offset)
Gets the index of the character at the specified offset position.
virtual void ProtoDeSerializeProperties(const XML::Node &SelfRoot)
Take the data stored in an XML Node and overwrite the properties of this object with it...
Real Y
Coordinate on the Y vector.
Definition: vector2.h:69
virtual TextLine * CreateTextLine()
Creates a new TextLine.
Definition: textlayer.cpp:662
A light-weight handle for manipulating nodes in DOM tree.
Definition: node.h:89
Real X
Coordinate on the X vector.
Definition: vector2.h:67
uint32_t UInt32
An 32-bit unsigned integer.
Definition: datatypes.h:126
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
This file describes and implements a reference counted pointer that is NOT threadsafe.
virtual void ProtoDeSerializeProperties(const XML::Node &SelfRoot)
Take the data stored in an XML Node and overwrite the properties of this object with it...
Definition: textlayer.cpp:1007
virtual TextLine * GetOrCreateTextLine(const UInt32 Index)
Gets the TextLine at the requested index, or creates one if it doesn't exist.
virtual void PopulateTextLinesImpl(const Real MaxWidth)
Clears and then places characters belonging to this layer in the appropriate text lines...
RenderLayerType
This enum describes the type of RenderLayer this is for use in casting.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
Boole AppendCharacters(CharacterContainer &ToAdd, const Real MaxWidth)
Adds a series of Characters to the end of this TextLine.
Definition: textline.cpp:254
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
TextLineContainer TextLines
Container with all this layers TextLines.
Definition: textlayer.h:101
virtual CharOffsetPair GetOffsetAtIndexImpl(const Integer Index)
Gets the position of the character at the specified index.
This represents a nestable quad for an object in a GUI layout.
std::pair< CharacterIterator, CharacterIterator > CharacterIteratorPair
An std::pair type storing two character iterators, usually used to express a range.
Definition: textlayer.h:78
static String GetSerializableName()
Get the name of the the XML tag the Renderable class will leave behind as its instances are serialize...
UI::TextOrdering HorizontalOrder
The order text will have in TextLines.
Definition: textlayer.h:143
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
This is a base class for render layers that render text.
Definition: textlayer.h:64
virtual void ProtoSerializeProperties(XML::Node &SelfRoot) const
Convert the properties of this class to an XML::Node ready for serialization.
CharacterContainer::iterator CharacterIterator
Iterator type for Character instances stored by this class.
Definition: textlayer.h:70