MyGUI 3.4.3
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"
9
10namespace 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)
36 return false;
37 if (mFirst)
38 {
39 mFirst = false;
40 return true;
41 }
42
43 // jump to next character, skipping tags (#)
44 for (UString::utf32string::iterator iter = mCurrent; iter != mEnd; ++iter)
45 {
46 if ((*iter) == L'#')
47 {
48 // следующий символ
49 ++iter;
50 if (iter == mEnd)
51 {
52 mCurrent = mEnd;
53 return false;
54 }
55
56 // две решетки подряд
57 if ((*iter) == L'#')
58 {
59 // следующий символ
60 mPosition++;
61 ++iter;
62 if (iter == mEnd)
63 {
64 mCurrent = mEnd;
65 return false;
66 }
67
68 // указатель на следующий символ
69 mCurrent = iter;
70 return true;
71 }
72
73 // остальные 5 символов цвета
74 for (size_t pos = 0; pos < 5; pos++)
75 {
76 // следующий символ
77 ++iter;
78 if (iter == mEnd)
79 {
80 mCurrent = mEnd;
81 return false;
82 }
83 }
84 }
85 else
86 {
87 // обыкновенный символ
88 mPosition++;
89 ++iter;
90 if (iter == mEnd)
91 {
92 mCurrent = mEnd;
93 return false;
94 }
95
96 // указатель на следующий символ
97 mCurrent = iter;
98 return true;
99 }
100 }
101
102 return false;
103 }
104
105 // возвращает цвет
107 {
108 if (mCurrent == mEnd)
109 return false;
110
111 UString::utf32string::iterator iter = mCurrent;
112
113 // нам нужен последний цвет
114 bool ret = false;
115 while (getTagColour(_colour, iter))
116 {
117 ret = true;
118 }
119
120 return ret;
121 }
122
124 {
125 if (mCurrent == mEnd)
126 return false;
128 if (mCurrent == mEnd)
129 return false;
130
131 const size_t SIZE = 16;
132 wchar_t buff[SIZE];
133
134#ifdef __MINGW32__
135 swprintf(
136 buff,
137 L"#%.2X%.2X%.2X\0",
138 (int)(_colour.red * 255),
139 (int)(_colour.green * 255),
140 (int)(_colour.blue * 255));
141#else
142 swprintf(
143 buff,
144 SIZE,
145 L"#%.2X%.2X%.2X\0",
146 (int)(_colour.red * 255),
147 (int)(_colour.green * 255),
148 (int)(_colour.blue * 255));
149#endif
150 UString tmpStr = UString(buff);
151 insert(mCurrent, tmpStr.asUTF32());
152
153 return true;
154 }
155
157 {
158 if (mCurrent == mEnd)
159 return false;
161 if (mCurrent == mEnd)
162 return false;
163
164 // check if it looks like a colour tag
165 if ((_colour.size() != 7) || (_colour.find(L'#', 1) != MyGUI::UString::npos))
166 return false;
167
168 insert(mCurrent, _colour);
169
170 return true;
171 }
172
174 {
175 return setTagColour(_colour.asUTF32());
176 }
177
178 // возвращает размер строки
180 {
181 if (mSize != ITEM_NONE)
182 return mSize;
183 mSize = mPosition;
184
185 for (UString::utf32string::const_iterator iter = mCurrent; iter != mEnd; ++iter)
186 {
187 if ((*iter) == L'#')
188 {
189 // следующий символ
190 ++iter;
191 if (iter == mEnd)
192 break;
193
194 // тэг цвета
195 if ((*iter) != L'#')
196 {
197 // остальные 5 символов цвета
198 for (size_t pos = 0; pos < 5; pos++)
199 {
200 ++iter;
201 if (iter == mEnd)
202 {
203 --iter;
204 break;
205 }
206 }
207 continue;
208 }
209 }
210
211 // обыкновенный символ
212 mSize++;
213 }
214
215 return mSize;
216 }
217
218 // возвращает текст без тегов
220 {
222 UString::utf32string text(_text.asUTF32());
223 ret.reserve(text.size());
224
225 UString::utf32string::const_iterator end = text.end();
226 for (UString::utf32string::const_iterator iter = text.begin(); iter != end; ++iter)
227 {
228 if ((*iter) == L'#')
229 {
230 // следующий символ
231 ++iter;
232 if (iter == end)
233 break;
234
235 // тэг цвета
236 if ((*iter) != L'#')
237 {
238 // остальные 5 символов цвета
239 for (size_t pos = 0; pos < 5; pos++)
240 {
241 ++iter;
242 if (iter == end)
243 {
244 --iter;
245 break;
246 }
247 }
248 continue;
249 }
250 }
251
252 // обыкновенный символ
253 ret.push_back(*iter);
254 }
255
256 return UString(ret);
257 }
258
259 // возвращает цвет
260 bool TextIterator::getTagColour(UString& _colour, UString::utf32string::iterator& _iter) const
261 {
262 if ((_iter == mEnd) || ((*_iter) != L'#'))
263 return false;
264
265 // следующий символ
266 ++_iter;
267 if ((_iter == mEnd) || ((*_iter) == L'#'))
268 return false;
269
270 // берем цвет
271 wchar_t buff[16] = L"#FFFFFF\0";
272 buff[1] = (wchar_t)(*_iter);
273 for (size_t pos = 2; pos < 7; pos++)
274 {
275 ++_iter;
276 if (_iter == mEnd)
277 return false;
278 buff[pos] = (wchar_t)(*_iter);
279 }
280
281 // ставим на следующий тег или символ
282 ++_iter;
283
284 // возвращаем цвет
285 _colour = buff;
286 return true;
287 }
288
290 {
291 for (UString::iterator iter = _text.begin(); iter != _text.end(); iter.moveNext())
292 {
293 auto character = iter.getCharacter();
294 if (character == FontCodeType::NEL || character == FontCodeType::CR || character == FontCodeType::LF)
295 {
296 (*iter) = FontCodeType::Space;
297 }
298 }
299 }
300
302 {
303 if (mCurrent == mEnd)
304 return false;
305 mSave = mCurrent;
306 return true;
307 }
308
310 {
311 if (mSave == mEnd)
312 return {};
313 size_t start = mSave - mText.begin();
314 return UString(mText.substr(start, mCurrent - mText.begin() - start));
315 }
316
318 {
319 if (mSave == mEnd)
320 return false;
321 mCurrent = erase(mSave, mCurrent);
322 mSave = mEnd = mText.end();
323 return true;
324 }
325
326 void TextIterator::insertText(const UString& _insert, bool _multiLine)
327 {
328 UString text = _insert;
329
330 normaliseNewLine(text);
331
332 if (!_multiLine)
333 clearNewLine(text);
334
335 insert(mCurrent, text.asUTF32());
336 }
337
338 void TextIterator::setText(const UString& _text, bool _multiLine)
339 {
340 // сначала все очищаем
341 clear();
342
343 // а теперь вставляем
344 UString text = _text;
345
346 // нормализуем
347 normaliseNewLine(text);
348
349 if (!_multiLine)
350 clearNewLine(text);
351
352 insert(mCurrent, text.asUTF32());
353 }
354
356 {
357 if (_char == L'#')
358 return L"##";
359 wchar_t buff[16] = L"_\0";
360 buff[0] = (wchar_t)_char;
361 return buff;
362 }
363
365 {
366 const size_t SIZE = 16;
367 wchar_t buff[SIZE];
368//FIXME
369#ifdef __MINGW32__
370 swprintf(
371 buff,
372 L"#%.2X%.2X%.2X\0",
373 (int)(_colour.red * 255),
374 (int)(_colour.green * 255),
375 (int)(_colour.blue * 255));
376#else
377 swprintf(
378 buff,
379 SIZE,
380 L"#%.2X%.2X%.2X\0",
381 (int)(_colour.red * 255),
382 (int)(_colour.green * 255),
383 (int)(_colour.blue * 255));
384#endif
385 return buff;
386 }
387
389 {
390 // преобразуем в строку с тегами
391 UString text(_text);
392 for (UString::iterator iter = text.begin(); iter != text.end(); iter.moveNext())
393 {
394 // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
395 if (L'#' == (*iter))
396 iter = text.insert(iter.moveNext(), L'#');
397 }
398 return text;
399 }
400
401 void TextIterator::insert(UString::utf32string::iterator& _start, const UString::utf32string& _insert)
402 {
403 // сбрасываем размер
404 mSize = ITEM_NONE;
405 // записываем в историю
406 if (mHistory)
407 mHistory->push_back(TextCommandInfo(_insert, _start - mText.begin(), TextCommandInfo::COMMAND_INSERT));
408 // запоминаем позицию итератора
409 size_t pos = _start - mText.begin();
410 size_t pos_save = (mSave == mEnd) ? ITEM_NONE : _start - mText.begin();
411 // непосредственно вставляем
412 mText.insert(_start, _insert.begin(), _insert.end());
413 // возвращаем итераторы
414 _start = mText.begin() + pos;
415 mEnd = mText.end();
416 (pos_save == ITEM_NONE) ? mSave = mEnd : mSave = mText.begin() + pos_save;
417 }
418
419 UString::utf32string::iterator TextIterator::erase(
420 UString::utf32string::iterator _start,
421 UString::utf32string::iterator _end)
422 {
423 // сбрасываем размер
424 mSize = ITEM_NONE;
425 // сохраняем в историю
426 size_t start = _start - mText.begin();
427 if (mHistory)
428 mHistory->push_back(
429 TextCommandInfo(mText.substr(start, _end - _start), start, TextCommandInfo::COMMAND_ERASE));
430 // возвращаем итератор
431 return mText.erase(_start, _end);
432 }
433
434 void TextIterator::clear()
435 {
436 if (mText.empty())
437 return;
438
439 // записываем в историю
440 if (mHistory)
441 mHistory->push_back(TextCommandInfo(mText, 0, TextCommandInfo::COMMAND_ERASE));
442
443 // все сбрасываем
444 mText.clear();
445 mCurrent = mText.begin();
446 mEnd = mSave = mText.end();
447 mSize = ITEM_NONE;
448 }
449
451 {
452 if ((mSize != ITEM_NONE) && (mSize <= _max))
453 return;
454 if (mPosition > _max)
455 {
456 // придется считать сначала
457 mSize = mPosition = 0;
458 mCurrent = mText.begin();
459 mEnd = mSave = mText.end();
460 }
461
462 mSize = mPosition;
463
464 for (UString::utf32string::iterator iter = mCurrent; iter != mEnd; ++iter)
465 {
466 if ((*iter) == L'#')
467 {
468 // следующий символ
469 ++iter;
470 if (iter == mEnd)
471 break;
472
473 // тэг цвета
474 if ((*iter) != L'#')
475 {
476 // остальные 5 символов цвета
477 for (size_t pos = 0; pos < 5; pos++)
478 {
479 ++iter;
480 if (iter == mEnd)
481 {
482 --iter;
483 break;
484 }
485 }
486 continue;
487 }
488 }
489
490 // проверяем и обрезаем
491 if (mSize == _max)
492 {
493 mPosition = mSize; // сохраняем
494 mCurrent = erase(iter, mEnd);
495 mSave = mEnd = mText.end();
496 mSize = mPosition; // восстанавливаем
497 return;
498 }
499
500 // увеличиваем
501 mSize++;
502 }
503 }
504
506 {
507 // узнаем размер без тегов
508 size_t size = getSize();
509 if (size <= _max)
510 return;
511
512 // разница
513 size_t diff = size - _max;
514
515 // последний цвет
516 UString::utf32string::iterator iter_colour = mEnd;
517
518 // теперь пройдем от начала и узнаем реальную позицию разницы
519 UString::utf32string::iterator iter = mText.begin();
520 for (; iter != mEnd; ++iter)
521 {
522 if ((*iter) == L'#')
523 {
524 UString::utf32string::iterator save = iter;
525
526 // следующий символ
527 ++iter;
528 if (iter == mEnd)
529 break;
530
531 // тэг цвета
532 if ((*iter) != L'#')
533 {
534 // остальные 5 символов цвета
535 for (size_t pos = 0; pos < 5; pos++)
536 {
537 ++iter;
538 if (iter == mEnd)
539 {
540 --iter;
541 break;
542 }
543 }
544 // сохраняем цвет
545 iter_colour = save;
546 }
547 continue;
548 }
549 // обычный символ был
550 if (diff == 0)
551 break;
552 --diff;
553 }
554
556 // если бы цвет, то вставляем назад
557 if (iter_colour != mEnd)
558 {
559 colour.append(iter_colour, iter_colour + size_t(7));
560 }
561
562 mCurrent = erase(mText.begin(), iter);
563 mEnd = mText.end();
564 mSave = mText.end(); //FIXME
565 mPosition = 0;
566 mSize = _max;
567
568 if (!colour.empty())
569 setTagColour(colour);
570 }
571
573 {
574 if (mCurrent == mEnd)
575 return;
576
577 UString::utf32string::iterator iter = mCurrent;
578 UString colour;
579 // нам нужен последний цвет
580 while (getTagColour(colour, iter))
581 {
582 // обязательно обновляем итераторы
583 iter = mCurrent = erase(mCurrent, iter);
584 mEnd = mText.end();
585 }
586 }
587
589 {
590 return mPosition;
591 }
592
594 {
595 return UString(mText);
596 }
597
599 {
600 clear();
601 }
602
604 {
605 return L"\n";
606 }
607
608 void TextIterator::normaliseNewLine(UString& _text)
609 {
610 for (size_t index = 0; index < _text.size(); ++index)
611 {
612 Char character = _text[index];
613 if ((character == FontCodeType::CR) && ((index + 1) < _text.size()) &&
614 (_text[index + 1] == FontCodeType::LF))
615 {
616 _text.erase(index, 1);
617 }
618 }
619 }
620
621} // 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)
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
std::vector< TextCommandInfo > VectorChangeInfo
unsigned int Char
Definition MyGUI_Types.h:50
constexpr size_t ITEM_NONE