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 TextIterator()13 TextIterator::TextIterator() : 14 mPosition(0), 15 mSize(ITEM_NONE), 16 mFirst(true), 17 mHistory(nullptr) 18 { 19 } 20 TextIterator(const UString & _text,VectorChangeInfo * _history)21 TextIterator::TextIterator(const UString& _text, VectorChangeInfo* _history) : 22 mText(_text), 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 moveNext()33 bool TextIterator::moveNext() 34 { 35 if (mCurrent == mEnd) return false; 36 else if (mFirst) 37 { 38 mFirst = false; 39 return true; 40 } 41 42 // ставим на следующий символ проскакивая все тэги 43 for (UString::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 // возвращает цвет getTagColour(UString & _colour) const110 bool TextIterator::getTagColour(UString& _colour) const 111 { 112 if (mCurrent == mEnd) return false; 113 114 UString::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 setTagColour(const Colour & _colour)126 bool TextIterator::setTagColour(const Colour& _colour) 127 { 128 if (mCurrent == mEnd) return false; 129 // очищаем все цвета 130 clearTagColour(); 131 // на всякий 132 if (mCurrent == mEnd) return false; 133 134 const size_t SIZE = 16; 135 wchar_t buff[SIZE]; 136 137 #ifdef __MINGW32__ 138 swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255)); 139 #else 140 swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255)); 141 #endif 142 // непосредственная вставка 143 UString tmpStr = UString(buff); 144 insert(mCurrent, tmpStr); 145 146 return true; 147 } 148 setTagColour(UString _colour)149 bool TextIterator::setTagColour(UString _colour) 150 { 151 if (mCurrent == mEnd) return false; 152 // очищаем все цвета 153 clearTagColour(); 154 // на всякий 155 if (mCurrent == mEnd) return false; 156 157 // проверяем на цвет хоть чуть чуть 158 if ( (_colour.size() != 7) || (_colour.find(L'#', 1) != MyGUI::UString::npos) ) return false; 159 160 // непосредственная вставка 161 insert(mCurrent, _colour); 162 163 return true; 164 } 165 166 // возвращает размер строки getSize() const167 size_t TextIterator::getSize() const 168 { 169 if (mSize != ITEM_NONE) return mSize; 170 mSize = mPosition; 171 172 for (UString::iterator iter = mCurrent; iter != mEnd; ++iter) 173 { 174 175 if ((*iter) == L'#') 176 { 177 // следующий символ 178 ++ iter; 179 if (iter == mEnd) break; 180 181 // тэг цвета 182 if ((*iter) != L'#') 183 { 184 // остальные 5 символов цвета 185 for (size_t pos = 0; pos < 5; pos++) 186 { 187 ++ iter; 188 if (iter == mEnd) 189 { 190 --iter; 191 break; 192 } 193 } 194 continue; 195 } 196 } 197 198 // обыкновенный символ 199 mSize ++; 200 } 201 202 return mSize; 203 } 204 205 // возвращает текст без тегов getOnlyText(const UString & _text)206 UString TextIterator::getOnlyText(const UString& _text) 207 { 208 UString ret; 209 ret.reserve(_text.size()); 210 211 UString::const_iterator end = _text.end(); 212 for (UString::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 ret; 243 } 244 245 // возвращает цвет getTagColour(UString & _colour,UString::iterator & _iter) const246 bool TextIterator::getTagColour(UString& _colour, UString::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 clearNewLine(UString & _text)272 void TextIterator::clearNewLine(UString& _text) 273 { 274 for (UString::iterator iter = _text.begin(); iter != _text.end(); ++iter) 275 { 276 if ( ((*iter) == FontCodeType::NEL) || 277 ((*iter) == FontCodeType::CR) || 278 ((*iter) == FontCodeType::LF) ) 279 { 280 (*iter) = FontCodeType::Space; 281 } 282 } 283 } 284 saveStartPoint()285 bool TextIterator::saveStartPoint() 286 { 287 if (mCurrent == mEnd) return false; 288 mSave = mCurrent; 289 return true; 290 } 291 getFromStart()292 UString TextIterator::getFromStart() 293 { 294 if (mSave == mEnd) return L""; 295 size_t start = mSave - mText.begin(); 296 return mText.substr(start, mCurrent - mText.begin() - start); 297 } 298 eraseFromStart()299 bool TextIterator::eraseFromStart() 300 { 301 if (mSave == mEnd) return false; 302 mCurrent = erase(mSave, mCurrent); 303 mSave = mEnd = mText.end(); 304 return true; 305 } 306 insertText(const UString & _insert,bool _multiLine)307 void TextIterator::insertText(const UString& _insert, bool _multiLine) 308 { 309 UString text = _insert; 310 311 // нормализуем 312 normaliseNewLine(text); 313 314 if (!_multiLine) 315 clearNewLine(text); 316 317 insert(mCurrent, text); 318 } 319 setText(const UString & _text,bool _multiLine)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); 335 } 336 getTextCharInfo(Char _char)337 UString TextIterator::getTextCharInfo(Char _char) 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 convertTagColour(const Colour & _colour)345 UString TextIterator::convertTagColour(const Colour& _colour) 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 toTagsString(const UString & _text)358 UString TextIterator::toTagsString(const UString& _text) 359 { 360 // преобразуем в строку с тегами 361 UString text(_text); 362 for (UString::iterator iter = text.begin(); iter != text.end(); ++iter) 363 { 364 // потом переделать через TextIterator чтобы отвязать понятие тег от эдита 365 if (L'#' == (*iter)) iter = text.insert(++iter, L'#'); 366 } 367 return text; 368 } 369 insert(UString::iterator & _start,UString & _insert)370 void TextIterator::insert(UString::iterator& _start, UString& _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 erase(UString::iterator _start,UString::iterator _end)387 UString::iterator TextIterator::erase(UString::iterator _start, UString::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 clear()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 cutMaxLength(size_t _max)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::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 cutMaxLengthFromBeginning(size_t _max)466 void TextIterator::cutMaxLengthFromBeginning(size_t _max) 467 { 468 // узнаем размер без тегов 469 size_t size = getSize(); 470 if (size <= _max) return; 471 472 // разница 473 size_t diff = size - _max; 474 475 // последний цвет 476 UString::iterator iter_colour = mEnd; 477 478 // теперь пройдем от начала и узнаем реальную позицию разницы 479 UString::iterator iter = mText.begin(); 480 for (; iter != mEnd; ++iter) 481 { 482 if ((*iter) == L'#') 483 { 484 UString::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 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 clearTagColour()530 void TextIterator::clearTagColour() 531 { 532 if (mCurrent == mEnd) return; 533 534 UString::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 getPosition() const545 size_t TextIterator::getPosition() const 546 { 547 return mPosition; 548 } 549 getText() const550 const UString& TextIterator::getText() const 551 { 552 return mText; 553 } 554 clearText()555 void TextIterator::clearText() 556 { 557 clear(); 558 } 559 getTextNewLine()560 UString TextIterator::getTextNewLine() 561 { 562 return L"\n"; 563 } 564 normaliseNewLine(UString & _text)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 580