MyGUI  3.4.1
MyGUI_TextIterator.cpp
Go to the documentation of this file.
1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
8 #include "MyGUI_TextIterator.h"
9 
10 namespace MyGUI
11 {
12 
13  TextIterator::TextIterator() :
14  mPosition(0),
15  mSize(ITEM_NONE),
16  mFirst(true),
17  mHistory(nullptr)
18  {
19  }
20 
21  TextIterator::TextIterator(const UString& _text, VectorChangeInfo* _history) :
22  mText(_text.asUTF32()),
23  mCurrent(mText.begin()),
24  mEnd(mText.end()),
25  mSave(mEnd),
26  mPosition(0),
27  mSize(ITEM_NONE),
28  mFirst(true),
29  mHistory(_history)
30  {
31  }
32 
34  {
35  if (mCurrent == mEnd) return false;
36  else if (mFirst)
37  {
38  mFirst = false;
39  return true;
40  }
41 
42  // jump to next character, skipping tags (#)
43  for (UString::utf32string::iterator iter = mCurrent; iter != mEnd; ++iter)
44  {
45 
46  if ((*iter) == L'#')
47  {
48 
49  // следующий символ
50  ++ iter;
51  if (iter == mEnd)
52  {
53  mCurrent = mEnd;
54  return false;
55  }
56 
57  // две решетки подряд
58  if ((*iter) == L'#')
59  {
60 
61  // следующий символ
62  mPosition ++;
63  ++iter;
64  if (iter == mEnd)
65  {
66  mCurrent = mEnd;
67  return false;
68  }
69 
70  // указатель на следующий символ
71  mCurrent = iter;
72  return true;
73  }
74 
75  // остальные 5 символов цвета
76  for (size_t pos = 0; pos < 5; pos++)
77  {
78  // следующий символ
79  ++ iter;
80  if (iter == mEnd)
81  {
82  mCurrent = mEnd;
83  return false;
84  }
85  }
86 
87  }
88  else
89  {
90 
91  // обыкновенный символ
92  mPosition ++;
93  ++iter;
94  if (iter == mEnd)
95  {
96  mCurrent = mEnd;
97  return false;
98  }
99 
100  // указатель на следующий символ
101  mCurrent = iter;
102  return true;
103  }
104  }
105 
106  return false;
107  }
108 
109  // возвращает цвет
110  bool TextIterator::getTagColour(UString& _colour) const
111  {
112  if (mCurrent == mEnd) return false;
113 
114  UString::utf32string::iterator iter = mCurrent;
115 
116  // нам нужен последний цвет
117  bool ret = false;
118  while (getTagColour(_colour, iter))
119  {
120  ret = true;
121  }
122 
123  return ret;
124  }
125 
126  bool TextIterator::setTagColour(const Colour& _colour)
127  {
128  if (mCurrent == mEnd) return false;
129  clearTagColour();
130  if (mCurrent == mEnd) return false;
131 
132  const size_t SIZE = 16;
133  wchar_t buff[SIZE];
134 
135 #ifdef __MINGW32__
136  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
137 #else
138  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
139 #endif
140  UString tmpStr = UString(buff);
141  insert(mCurrent, tmpStr.asUTF32());
142 
143  return true;
144  }
145 
147  {
148  if (mCurrent == mEnd) return false;
149  clearTagColour();
150  if (mCurrent == mEnd) return false;
151 
152  // check if it looks like a colour tag
153  if ( (_colour.size() != 7) || (_colour.find(L'#', 1) != MyGUI::UString::npos) ) return false;
154 
155  insert(mCurrent, _colour);
156 
157  return true;
158  }
159 
160  bool TextIterator::setTagColour(const UString& _colour)
161  {
162  return setTagColour(_colour.asUTF32());
163  }
164 
165  // возвращает размер строки
166  size_t TextIterator::getSize() const
167  {
168  if (mSize != ITEM_NONE) return mSize;
169  mSize = mPosition;
170 
171  for (UString::utf32string::const_iterator iter = mCurrent; iter != mEnd; ++iter)
172  {
173 
174  if ((*iter) == L'#')
175  {
176  // следующий символ
177  ++ iter;
178  if (iter == mEnd) break;
179 
180  // тэг цвета
181  if ((*iter) != L'#')
182  {
183  // остальные 5 символов цвета
184  for (size_t pos = 0; pos < 5; pos++)
185  {
186  ++ iter;
187  if (iter == mEnd)
188  {
189  --iter;
190  break;
191  }
192  }
193  continue;
194  }
195  }
196 
197  // обыкновенный символ
198  mSize ++;
199  }
200 
201  return mSize;
202  }
203 
204  // возвращает текст без тегов
206  {
208  UString::utf32string text(_text.asUTF32());
209  ret.reserve(text.size());
210 
211  UString::utf32string::const_iterator end = text.end();
212  for (UString::utf32string::const_iterator iter = text.begin(); iter != end; ++iter)
213  {
214 
215  if ((*iter) == L'#')
216  {
217  // следующий символ
218  ++ iter;
219  if (iter == end) break;
220 
221  // тэг цвета
222  if ((*iter) != L'#')
223  {
224  // остальные 5 символов цвета
225  for (size_t pos = 0; pos < 5; pos++)
226  {
227  ++ iter;
228  if (iter == end)
229  {
230  --iter;
231  break;
232  }
233  }
234  continue;
235  }
236  }
237 
238  // обыкновенный символ
239  ret.push_back(*iter);
240  }
241 
242  return UString(ret);
243  }
244 
245  // возвращает цвет
246  bool TextIterator::getTagColour(UString& _colour, UString::utf32string::iterator& _iter) const
247  {
248  if ( (_iter == mEnd) || ((*_iter) != L'#') ) return false;
249 
250  // следующий символ
251  ++_iter;
252  if ( (_iter == mEnd) || ((*_iter) == L'#') ) return false;
253 
254  // берем цвет
255  wchar_t buff[16] = L"#FFFFFF\0";
256  buff[1] = (wchar_t)(*_iter);
257  for (size_t pos = 2; pos < 7; pos++)
258  {
259  ++_iter;
260  if ( _iter == mEnd ) return false;
261  buff[pos] = (wchar_t)(*_iter);
262  }
263 
264  // ставим на следующий тег или символ
265  ++_iter;
266 
267  // возвращаем цвет
268  _colour = buff;
269  return true;
270  }
271 
273  {
274  for (UString::iterator iter = _text.begin(); iter != _text.end(); iter.moveNext())
275  {
276  auto character = iter.getCharacter();
277  if (character == FontCodeType::NEL ||
278  character == FontCodeType::CR ||
279  character == FontCodeType::LF )
280  {
281  (*iter) = FontCodeType::Space;
282  }
283  }
284  }
285 
287  {
288  if (mCurrent == mEnd) return false;
289  mSave = mCurrent;
290  return true;
291  }
292 
294  {
295  if (mSave == mEnd) return L"";
296  size_t start = mSave - mText.begin();
297  return UString(mText.substr(start, mCurrent - mText.begin() - start));
298  }
299 
301  {
302  if (mSave == mEnd) return false;
303  mCurrent = erase(mSave, mCurrent);
304  mSave = mEnd = mText.end();
305  return true;
306  }
307 
308  void TextIterator::insertText(const UString& _insert, bool _multiLine)
309  {
310  UString text = _insert;
311 
312  normaliseNewLine(text);
313 
314  if (!_multiLine)
315  clearNewLine(text);
316 
317  insert(mCurrent, text.asUTF32());
318  }
319 
320  void TextIterator::setText(const UString& _text, bool _multiLine)
321  {
322  // сначала все очищаем
323  clear();
324 
325  // а теперь вставляем
326  UString text = _text;
327 
328  // нормализуем
329  normaliseNewLine(text);
330 
331  if (!_multiLine)
332  clearNewLine(text);
333 
334  insert(mCurrent, text.asUTF32());
335  }
336 
338  {
339  if (_char == L'#') return L"##";
340  wchar_t buff[16] = L"_\0";
341  buff[0] = (wchar_t)_char;
342  return buff;
343  }
344 
346  {
347  const size_t SIZE = 16;
348  wchar_t buff[SIZE];
349 //FIXME
350 #ifdef __MINGW32__
351  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
352 #else
353  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
354 #endif
355  return buff;
356  }
357 
359  {
360  // преобразуем в строку с тегами
361  UString text(_text);
362  for (UString::iterator iter = text.begin(); iter != text.end(); iter.moveNext())
363  {
364  // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
365  if (L'#' == (*iter)) iter = text.insert(iter.moveNext(), L'#');
366  }
367  return text;
368  }
369 
370  void TextIterator::insert(UString::utf32string::iterator& _start, const UString::utf32string& _insert)
371  {
372  // сбрасываем размер
373  mSize = ITEM_NONE;
374  // записываем в историю
375  if (mHistory) mHistory->push_back(TextCommandInfo(_insert, _start - mText.begin(), TextCommandInfo::COMMAND_INSERT));
376  // запоминаем позицию итератора
377  size_t pos = _start - mText.begin();
378  size_t pos_save = (mSave == mEnd) ? ITEM_NONE : _start - mText.begin();
379  // непосредственно вставляем
380  mText.insert(_start, _insert.begin(), _insert.end());
381  // возвращаем итераторы
382  _start = mText.begin() + pos;
383  mEnd = mText.end();
384  (pos_save == ITEM_NONE) ? mSave = mEnd : mSave = mText.begin() + pos_save;
385  }
386 
387  UString::utf32string::iterator TextIterator::erase(UString::utf32string::iterator _start, UString::utf32string::iterator _end)
388  {
389  // сбрасываем размер
390  mSize = ITEM_NONE;
391  // сохраняем в историю
392  size_t start = _start - mText.begin();
393  if (mHistory) mHistory->push_back(TextCommandInfo(mText.substr(start, _end - _start), start, TextCommandInfo::COMMAND_ERASE));
394  // возвращаем итератор
395  return mText.erase(_start, _end);
396  }
397 
398  void TextIterator::clear()
399  {
400  if (mText.empty()) return;
401 
402  // записываем в историю
403  if (mHistory) mHistory->push_back(TextCommandInfo(mText, 0, TextCommandInfo::COMMAND_ERASE));
404 
405  // все сбрасываем
406  mText.clear();
407  mCurrent = mText.begin();
408  mEnd = mSave = mText.end();
409  mSize = ITEM_NONE;
410  }
411 
412  void TextIterator::cutMaxLength(size_t _max)
413  {
414  if ( (mSize != ITEM_NONE) && (mSize <= _max) ) return;
415  if (mPosition > _max)
416  {
417  // придется считать сначала
418  mSize = mPosition = 0;
419  mCurrent = mText.begin();
420  mEnd = mSave = mText.end();
421  }
422 
423  mSize = mPosition;
424 
425  for (UString::utf32string::iterator iter = mCurrent; iter != mEnd; ++iter)
426  {
427 
428  if ((*iter) == L'#')
429  {
430  // следующий символ
431  ++ iter;
432  if (iter == mEnd) break;
433 
434  // тэг цвета
435  if ((*iter) != L'#')
436  {
437  // остальные 5 символов цвета
438  for (size_t pos = 0; pos < 5; pos++)
439  {
440  ++ iter;
441  if (iter == mEnd)
442  {
443  -- iter;
444  break;
445  }
446  }
447  continue;
448  }
449  }
450 
451  // проверяем и обрезаем
452  if (mSize == _max)
453  {
454  mPosition = mSize; // сохраняем
455  mCurrent = erase(iter, mEnd);
456  mSave = mEnd = mText.end();
457  mSize = mPosition; // восстанавливаем
458  return;
459  }
460 
461  // увеличиваем
462  mSize ++;
463  }
464  }
465 
467  {
468  // узнаем размер без тегов
469  size_t size = getSize();
470  if (size <= _max) return;
471 
472  // разница
473  size_t diff = size - _max;
474 
475  // последний цвет
476  UString::utf32string::iterator iter_colour = mEnd;
477 
478  // теперь пройдем от начала и узнаем реальную позицию разницы
479  UString::utf32string::iterator iter = mText.begin();
480  for (; iter != mEnd; ++iter)
481  {
482  if ((*iter) == L'#')
483  {
484  UString::utf32string::iterator save = iter;
485 
486  // следующий символ
487  ++ iter;
488  if (iter == mEnd) break;
489 
490  // тэг цвета
491  if ((*iter) != L'#')
492  {
493  // остальные 5 символов цвета
494  for (size_t pos = 0; pos < 5; pos++)
495  {
496  ++ iter;
497  if (iter == mEnd)
498  {
499  -- iter;
500  break;
501  }
502  }
503  // сохраняем цвет
504  iter_colour = save;
505  }
506  continue;
507  }
508  // обычный символ был
509  if (diff == 0) break;
510  -- diff;
511  }
512 
513  UString::utf32string colour;
514  // если бы цвет, то вставляем назад
515  if (iter_colour != mEnd)
516  {
517  colour.append(iter_colour, iter_colour + size_t(7));
518  }
519 
520  mCurrent = erase(mText.begin(), iter);
521  mEnd = mText.end();
522  mSave = mText.end(); //FIXME
523  mPosition = 0;
524  mSize = _max;
525 
526  if ( ! colour.empty() ) setTagColour(colour);
527 
528  }
529 
531  {
532  if (mCurrent == mEnd) return;
533 
534  UString::utf32string::iterator iter = mCurrent;
535  UString colour;
536  // нам нужен последний цвет
537  while (getTagColour(colour, iter))
538  {
539  // обязательно обновляем итераторы
540  iter = mCurrent = erase(mCurrent, iter);
541  mEnd = mText.end();
542  }
543  }
544 
546  {
547  return mPosition;
548  }
549 
551  {
552  return UString(mText);
553  }
554 
556  {
557  clear();
558  }
559 
561  {
562  return L"\n";
563  }
564 
565  void TextIterator::normaliseNewLine(UString& _text)
566  {
567  for (size_t index = 0; index < _text.size(); ++index)
568  {
569  Char character = _text[index];
570  if ((character == FontCodeType::CR) &&
571  ((index + 1) < _text.size()) &&
572  (_text[index + 1] == FontCodeType::LF))
573  {
574  _text.erase(index, 1);
575  }
576  }
577  }
578 
579 } // namespace MyGUI
static UString getOnlyText(const UString &_text)
void clearNewLine(UString &_text)
static UString getTextNewLine()
static UString getTextCharInfo(Char _char)
void cutMaxLength(size_t _max)
bool setTagColour(const Colour &_colour)
UString getFromStart() const
static UString convertTagColour(const Colour &_colour)
static UString toTagsString(const UString &_text)
void cutMaxLengthFromBeginning(size_t _max)
void setText(const UString &_text, bool _multiLine)
void insertText(const UString &_insert, bool _multiLine)
bool getTagColour(UString &_colour) const
forward iterator for UString
_fwd_iterator & moveNext()
advances to the next Unicode character, honoring surrogate pairs in the UTF-16 stream
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
iterator insert(iterator i, const code_point &ch)
inserts ch before the code point denoted by i
size_type size() const
Returns the number of code points in the current string.
const utf32string & asUTF32() const
returns the current string in UTF-32 form within a utf32string
std::basic_string< unicode_char > utf32string
string type used for returning UTF-32 formatted data
iterator erase(iterator loc)
removes the code point pointed to by loc, returning an iterator to the next character
iterator end()
returns an iterator just past the end of the string
static const size_type npos
the usual constant representing: not found, no limit, etc
iterator begin()
returns an iterator to the first element of the string
const size_t ITEM_NONE
Definition: MyGUI_Macros.h:17
unsigned int Char
Definition: MyGUI_Types.h:49
std::vector< TextCommandInfo > VectorChangeInfo