MyGUI  3.0.1
MyGUI_Edit.cpp
Go to the documentation of this file.
1 
7 /*
8  This file is part of MyGUI.
9 
10  MyGUI is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  MyGUI is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #include "MyGUI_Precompiled.h"
24 #include "MyGUI_Gui.h"
25 #include "MyGUI_Edit.h"
26 #include "MyGUI_ResourceSkin.h"
27 #include "MyGUI_SkinManager.h"
28 #include "MyGUI_InputManager.h"
29 #include "MyGUI_ClipboardManager.h"
30 #include "MyGUI_PointerManager.h"
31 #include "MyGUI_ISubWidgetText.h"
32 #include "MyGUI_VScroll.h"
33 #include "MyGUI_HScroll.h"
34 
35 namespace MyGUI
36 {
37 
38  const float EDIT_CURSOR_TIMER = 0.7f;
39  const float EDIT_ACTION_MOUSE_TIMER = 0.05f;
40  const int EDIT_CURSOR_MAX_POSITION = 100000;
41  const int EDIT_CURSOR_MIN_POSITION = -100000;
42  const size_t EDIT_MAX_UNDO = 128;
43  const size_t EDIT_DEFAULT_MAX_TEXT_LENGTH = 2048;
44  const float EDIT_OFFSET_HORZ_CURSOR = 10.0f; // дополнительное смещение для курсора
45  const int EDIT_ACTION_MOUSE_ZONE = 1500; // область для восприятия мыши за пределом эдита
46  const std::string EDIT_CLIPBOARD_TYPE_TEXT = "Text";
47  const int EDIT_MOUSE_WHEEL = 50; // область для восприятия мыши за пределом эдита
48 
50  mIsPressed(false),
51  mIsFocus(false),
52  mCursorActive(false),
53  mCursorTimer(0),
54  mActionMouseTimer(0),
55  mCursorPosition(0),
56  mTextLength(0),
57  mStartSelect(ITEM_NONE),
58  mEndSelect(0),
59  mMouseLeftPressed(false),
60  mModeReadOnly(false),
61  mModePassword(false),
62  mModeMultiline(false),
63  mModeStatic(false),
64  mModeWordWrap(false),
65  mTabPrinting(false),
66  mCharPassword('*'),
67  mOverflowToTheLeft(false),
68  mMaxTextLength(EDIT_DEFAULT_MAX_TEXT_LENGTH)
69  {
71  }
72 
73  void Edit::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
74  {
75  Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
76 
77  initialiseWidgetSkin(_info);
78  }
79 
81  {
82  shutdownWidgetSkin();
83  }
84 
86  {
87  shutdownWidgetSkin();
89  initialiseWidgetSkin(_info);
90  }
91 
92  void Edit::initialiseWidgetSkin(ResourceSkin* _info)
93  {
95 
96  // нам нужен фокус клавы
97  mNeedKeyFocus = true;
98 
99  for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
100  {
101  if (*(*iter)->_getInternalData<std::string>() == "Client")
102  {
103  MYGUI_DEBUG_ASSERT( ! mWidgetClient, "widget already assigned");
104  mWidgetClient = (*iter);
113  }
114  else if (*(*iter)->_getInternalData<std::string>() == "VScroll")
115  {
116  MYGUI_DEBUG_ASSERT( ! mVScroll, "widget already assigned");
117  mVScroll = (*iter)->castType<VScroll>();
119  }
120  else if (*(*iter)->_getInternalData<std::string>() == "HScroll")
121  {
122  MYGUI_DEBUG_ASSERT( ! mHScroll, "widget already assigned");
123  mHScroll = (*iter)->castType<HScroll>();
125  }
126  }
127 
128  //MYGUI_ASSERT(nullptr != mWidgetClient, "Child Widget Client not found in skin (Edit must have Client)");
129 
130  if (mWidgetClient != nullptr)
131  {
132  ISubWidgetText* text = mWidgetClient->getSubWidgetText();
133  if (text) mText = text;
134  }
135 
136  //MYGUI_ASSERT(nullptr != mText, "TextEdit not found in skin (Edit or Client must have TextEdit)");
137 
138  // парсим свойства
139  const MapString& properties = _info->getProperties();
140  if (!properties.empty())
141  {
142  MapString::const_iterator iter = properties.end();
143  if ((iter = properties.find("WordWrap")) != properties.end()) setEditWordWrap(utility::parseValue<bool>(iter->second));
144  else if ((iter = properties.find("InvertSelected")) != properties.end()) setInvertSelected(utility::parseValue<bool>(iter->second));
145  }
146 
148 
149  // первоначальная инициализация курсора
150  if (mText != nullptr)
152  updateSelectText();
153  }
154 
155  void Edit::shutdownWidgetSkin()
156  {
157  mWidgetClient = nullptr;
158  mVScroll= nullptr;
159  mHScroll = nullptr;
160  }
161 
163  {
164  if ( (_old == mWidgetClient) || (mIsFocus) ) return;
165  mIsFocus = true;
166  updateEditState();
167  }
168 
170  {
171  if ( (_new == mWidgetClient) || (!mIsFocus) ) return;
172  mIsFocus = false;
173  updateEditState();
174  }
175 
176  void Edit::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
177  {
178  if (mText == nullptr)
179  return;
180 
181  // в статике все недоступно
182  if (mModeStatic)
183  return;
184 
188  mText->setVisibleCursor(true);
189  mCursorTimer = 0;
190  updateSelectText();
191 
192  if (_id == MouseButton::Left) mMouseLeftPressed = true;
193  }
194 
195  void Edit::notifyMouseReleased(Widget* _sender, int _left, int _top, MouseButton _id)
196  {
197  // сбрасываем всегда
198  mMouseLeftPressed = false;
199  }
200 
201  void Edit::notifyMouseDrag(Widget* _sender, int _left, int _top)
202  {
203  if (mText == nullptr)
204  return;
205 
206  // в статике все недоступно
207  if (mModeStatic) return;
208 
209  // останавливаем курсор
210  mText->setVisibleCursor(true);
211 
212  // сбрасываем все таймеры
213  mCursorTimer = 0;
214  mActionMouseTimer = 0;
215 
216  size_t Old = mCursorPosition;
217  IntPoint point(_left, _top);
219  if (Old == mCursorPosition) return;
220 
222 
223  // если не было выделения
224  if (mStartSelect == ITEM_NONE) mStartSelect = Old;
225 
226  // меняем выделение
227  mEndSelect = (size_t)mCursorPosition;
230 
231  }
232 
234  {
235  if (mText == nullptr)
236  return;
237 
238  // в статике все недоступно
239  if (mModeStatic)
240  return;
241 
242  const IntPoint& lastPressed = InputManager::getInstance().getLastLeftPressed();
243 
244  size_t cursorPosition = mText->getCursorPosition(lastPressed);
245  mStartSelect = cursorPosition;
246  mEndSelect = cursorPosition;
247 
248  UString text = this->getOnlyText();
249  UString::reverse_iterator iterBack = text.rend() - cursorPosition;
250  UString::iterator iterForw = text.begin() + cursorPosition;
251 
252  while (iterBack != text.rend())
253  {
254  if (((*iterBack)<265) && (ispunct(*iterBack) || isspace(*iterBack))) break;
255  iterBack++;
256  mStartSelect--;
257  }
258  while (iterForw != text.end())
259  {
260  if (((*iterForw)<265) && (ispunct(*iterForw) || isspace(*iterForw))) break;
261  iterForw++;
262  mEndSelect++;
263  }
264 
267  }
268 
269  void Edit::onMouseDrag(int _left, int _top)
270  {
271  notifyMouseDrag(nullptr, _left, _top);
272 
273  Base::onMouseDrag(_left, _top);
274  }
275 
277  {
278  if (!mIsPressed)
279  {
280  mIsPressed = true;
281  updateEditState();
282 
283  if (!mModeStatic)
284  {
285  if (mText != nullptr)
286  {
287  mCursorActive = true;
288  Gui::getInstance().eventFrameStart += newDelegate(this, &Edit::frameEntered);
289  mText->setVisibleCursor(true);
290  mText->setSelectBackground(true);
291  mCursorTimer = 0;
292  }
293  }
294  }
295 
296  Base::onKeySetFocus(_old);
297  }
298 
300  {
301  if (mIsPressed)
302  {
303  mIsPressed = false;
304  updateEditState();
305 
306  if (mText != nullptr)
307  {
308  mCursorActive = false;
309  Gui::getInstance().eventFrameStart -= newDelegate(this, &Edit::frameEntered);
310  mText->setVisibleCursor(false);
311  mText->setSelectBackground(false);
312  }
313  }
314 
315  Base::onKeyLostFocus(_new);
316  }
317 
319  {
320  if (mText == nullptr || mWidgetClient == nullptr)
321  {
322  Base::onKeyButtonPressed(_key, _char);
323  return;
324  }
325 
326  // в статическом режиме ничего не доступно
327  if (mModeStatic)
328  {
329  Base::onKeyButtonPressed(_key, _char);
330  return;
331  }
332 
334 
335  mText->setVisibleCursor(true);
336  mCursorTimer = 0.0f;
337 
338  if (_key == KeyCode::Escape)
339  {
341  }
342  else if (_key == KeyCode::Backspace)
343  {
344  // если нуно то удаляем выделенный текст
345  if (!mModeReadOnly)
346  {
347  if (!deleteTextSelect(true))
348  {
349  // прыгаем на одну назад и удаляем
350  if (mCursorPosition != 0)
351  {
352  mCursorPosition--;
353  eraseText(mCursorPosition, 1, true);
354  }
355  }
356  // отсылаем событие о изменении
357  eventEditTextChange(this);
358  }
359 
360  }
361  else if (_key == KeyCode::Delete)
362  {
363  if (input.isShiftPressed()) commandCut();
364  else if (!mModeReadOnly)
365  {
366  // если нуно то удаляем выделенный текст
367  if (!deleteTextSelect(true))
368  {
370  {
371  eraseText(mCursorPosition, 1, true);
372  }
373  }
374  // отсылаем событие о изменении
375  eventEditTextChange(this);
376  }
377 
378  }
379  else if (_key == KeyCode::Insert)
380  {
381  if (input.isShiftPressed()) commandPast();
382  else if (input.isControlPressed()) commandCopy();
383 
384  }
385  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
386  {
387  // работаем только в режиме редактирования
388  if (!mModeReadOnly)
389  {
390  if ((mModeMultiline) && (!input.isControlPressed()))
391  {
392  // попытка объединения двух комманд
393  size_t size = mVectorUndoChangeInfo.size();
394  // непосредственно операции
395  deleteTextSelect(true);
397  // проверяем на возможность объединения
398  if ((size+2) == mVectorUndoChangeInfo.size()) commandMerge();
399  // отсылаем событие о изменении
400  eventEditTextChange(this);
401  }
402  // при сингл лайн и и мульти+сонтрол шлем эвент
403  else
404  {
405  eventEditSelectAccept(this);
406  }
407  }
408 
409  }
410  else if (_key == KeyCode::ArrowRight)
411  {
413  {
414  mCursorPosition ++;
416  updateSelectText();
417  }
418  // сбрасываем выделение
419  else if (isTextSelection() && !input.isShiftPressed())
420  {
421  resetSelect();
422  }
423 
424  }
425  else if (_key == KeyCode::ArrowLeft)
426  {
427  if (mCursorPosition != 0)
428  {
429  mCursorPosition --;
431  updateSelectText();
432  }
433  // сбрасываем выделение
434  else if (isTextSelection() && !input.isShiftPressed())
435  {
436  resetSelect();
437  }
438 
439  }
440  else if (_key == KeyCode::ArrowUp)
441  {
443  point.top -= mText->getFontHeight();
444  size_t old = mCursorPosition;
446  // самая верхняя строчка
447  if ( old == mCursorPosition )
448  {
449  if (mCursorPosition != 0)
450  {
451  mCursorPosition = 0;
453  updateSelectText();
454  }
455  // сбрасываем выделение
456  else if (isTextSelection() && !input.isShiftPressed())
457  {
458  resetSelect();
459  }
460  }
461  else
462  {
464  updateSelectText();
465  }
466 
467  }
468  else if (_key == KeyCode::ArrowDown)
469  {
471  point.top += mText->getFontHeight();
472  size_t old = mCursorPosition;
474  // самая нижняя строчка
475  if ( old == mCursorPosition )
476  {
478  {
481  updateSelectText();
482  }
483  // сбрасываем выделение
484  else if (isTextSelection() && !input.isShiftPressed())
485  {
486  resetSelect();
487  }
488  }
489  else
490  {
492  updateSelectText();
493  }
494 
495  }
496  else if (_key == KeyCode::Home)
497  {
498  // в начало строки
499  if ( !input.isControlPressed())
500  {
503  size_t old = mCursorPosition;
505  if ( old != mCursorPosition )
506  {
508  updateSelectText();
509  }
510  else if (isTextSelection() && !input.isShiftPressed())
511  {
512  resetSelect();
513  }
514  }
515  // в начало всего текста
516  else
517  {
518  if (0 != mCursorPosition)
519  {
520  mCursorPosition = 0;
522  updateSelectText();
523  }
524  else if (isTextSelection() && !input.isShiftPressed())
525  {
526  resetSelect();
527  }
528  }
529 
530  }
531  else if (_key == KeyCode::End)
532  {
533  // в конец строки
534  if ( ! input.isControlPressed())
535  {
538  size_t old = mCursorPosition;
540  if ( old != mCursorPosition )
541  {
543  updateSelectText();
544  }
545  else if (isTextSelection() && !input.isShiftPressed())
546  {
547  resetSelect();
548  }
549  }
550  // в самый конец
551  else
552  {
554  {
557  updateSelectText();
558  }
559  else if (isTextSelection() && !input.isShiftPressed())
560  {
561  resetSelect();
562  }
563  }
564 
565  }
566  else if (_key == KeyCode::PageUp)
567  {
568  // на размер окна, но не меньше одной строки
571  size_t old = mCursorPosition;
573  // самая верхняя строчка
574  if ( old == mCursorPosition )
575  {
576  if (mCursorPosition != 0)
577  {
578  mCursorPosition = 0;
580  updateSelectText();
581  }
582  // сбрасываем выделение
583  else if (isTextSelection() && !input.isShiftPressed())
584  {
585  resetSelect();
586  }
587  }
588  else
589  {
591  updateSelectText();
592  }
593 
594  }
595  else if (_key == KeyCode::PageDown)
596  {
597  // на размер окна, но не меньше одной строки
600  size_t old = mCursorPosition;
602  // самая нижняя строчка
603  if ( old == mCursorPosition )
604  {
606  {
609  updateSelectText();
610  }
611  // сбрасываем выделение
612  else if (isTextSelection() && !input.isShiftPressed())
613  {
614  resetSelect();
615  }
616  }
617  else
618  {
620  updateSelectText();
621  }
622 
623  }
624  else if ((_key == KeyCode::LeftShift) || (_key == KeyCode::RightShift))
625  {
626  // для правильно выделения
627  if (mStartSelect == ITEM_NONE)
628  {
630  }
631  }
632  else if (_char != 0)
633  {
634 
635  // если не нажат контрл, то обрабатываем как текст
636  if (!input.isControlPressed())
637  {
638  if (!mModeReadOnly)
639  {
640  // таб только если нужно
641  if (_char != '\t' || mTabPrinting)
642  {
643  // попытка объединения двух комманд
644  size_t size = mVectorUndoChangeInfo.size();
645  // непосредственно операции
646  deleteTextSelect(true);
648  // проверяем на возможность объединения
649  if ((size+2) == mVectorUndoChangeInfo.size()) commandMerge();
650  // отсылаем событие о изменении
651  eventEditTextChange(this);
652  }
653  }
654  }
655  else if (_key == KeyCode::C)
656  {
657  commandCopy();
658 
659  }
660  else if (_key == KeyCode::X)
661  {
662  commandCut();
663 
664  }
665  else if (_key == KeyCode::V)
666  {
667  commandPast();
668 
669  }
670  else if (_key == KeyCode::A)
671  {
672  // выделяем весь текст
674 
675  }
676  else if (_key == KeyCode::Z)
677  {
678  // отмена
679  commandUndo();
680 
681  }
682  else if (_key == KeyCode::Y)
683  {
684  // повтор
685  commandRedo();
686 
687  }
688  }
689 
690  Base::onKeyButtonPressed(_key, _char);
691  }
692 
693  void Edit::frameEntered(float _frame)
694  {
695  if (mText == nullptr)
696  return;
697 
698  // в статике все недоступно
699  if (mModeStatic)
700  return;
701 
702  if (mCursorActive)
703  {
704  mCursorTimer += _frame;
705 
707  {
710  }
711  }
712 
713  // сдвигаем курсор по положению мыши
714  if (mMouseLeftPressed)
715  {
716  mActionMouseTimer += _frame;
717 
719  {
720 
722  const IntRect& view = mWidgetClient->getAbsoluteRect();
723  mouse.left -= view.left;
724  mouse.top -= view.top;
725  IntPoint point;
726 
727  bool action = false;
728 
729  // вверх на одну строчку
730  if ( (mouse.top < 0) && (mouse.top > -EDIT_ACTION_MOUSE_ZONE) )
731  {
732  if ( (mouse.left > 0) && (mouse.left <= mWidgetClient->getWidth()) )
733  {
735  point.top -= mText->getFontHeight();
736  action = true;
737  }
738  }
739  // вниз на одну строчку
740  else if ( (mouse.top > mWidgetClient->getHeight()) && (mouse.top < (mWidgetClient->getHeight() + EDIT_ACTION_MOUSE_ZONE)) )
741  {
742  if ( (mouse.left > 0) && (mouse.left <= mWidgetClient->getWidth()) )
743  {
745  point.top += mText->getFontHeight();
746  action = true;
747  }
748  }
749 
750  // влево на небольшое расстояние
751  if ( (mouse.left < 0) && (mouse.left > -EDIT_ACTION_MOUSE_ZONE) )
752  {
754  point.left -= (int)EDIT_OFFSET_HORZ_CURSOR;
755  action = true;
756  }
757  // вправо на небольшое расстояние
758  else if ( (mouse.left > mWidgetClient->getWidth()) && (mouse.left < (mWidgetClient->getWidth() + EDIT_ACTION_MOUSE_ZONE)) )
759  {
761  point.left += (int)EDIT_OFFSET_HORZ_CURSOR;
762  action = true;
763  }
764 
765  if (action)
766  {
767  size_t old = mCursorPosition;
769 
770  if ( old != mCursorPosition )
771  {
772 
774 
775  mEndSelect = (size_t)mCursorPosition;
778 
779  // пытаемся показать курсор
781  }
782 
783  }
784  // если в зону не попадает то сбрасываем
785  else mActionMouseTimer = 0;
786 
788  }
789 
790  } // if (mMouseLeftPressed)
791  }
792 
793  void Edit::setTextCursor(size_t _index)
794  {
795  // сбрасываем выделение
796  resetSelect();
797 
798  // новая позиция
799  if (_index > mTextLength) _index = mTextLength;
800  if (mCursorPosition == _index) return;
801  mCursorPosition = _index;
802 
803  // обновляем по позиции
804  if (mText != nullptr)
806  updateSelectText();
807  }
808 
809  void Edit::setTextSelection(size_t _start, size_t _end)
810  {
811  if (_start > mTextLength) _start = mTextLength;
812  if (_end > mTextLength) _end = mTextLength;
813 
814  mStartSelect = _start;
815  mEndSelect = _end;
816 
817  if (mText != nullptr)
818  {
821  }
822 
823  if (mCursorPosition == mEndSelect) return;
824  // курсор на конец выделения
826 
827  // обновляем по позиции
828  if (mText != nullptr)
830  }
831 
832  bool Edit::deleteTextSelect(bool _history)
833  {
834  if ( ! isTextSelection()) return false;
835 
836  // начало и конец выделения
837  size_t start = getTextSelectionStart();
838  size_t end = getTextSelectionEnd();
839 
840  eraseText(start, end - start, _history);
841 
842  return true;
843  }
844 
845  void Edit::resetSelect()
846  {
847  if (mStartSelect != ITEM_NONE)
848  {
850  if (mText != nullptr)
851  mText->setTextSelection(0, 0);
852  }
853  }
854 
855  void Edit::commandPosition(size_t _undo, size_t _redo, size_t _length, VectorChangeInfo * _info)
856  {
857  if (_info != nullptr) _info->push_back(TextCommandInfo(_undo, _redo, _length));
858  }
859 
860  void Edit::commandMerge()
861  {
862  if (mVectorUndoChangeInfo.size() < 2) return; // на всякий
863  // сохраняем последние набор отмен
865  mVectorUndoChangeInfo.pop_back();
866 
867  // объединяем последовательности
868  for (VectorChangeInfo::iterator iter=info.begin(); iter!=info.end(); ++iter)
869  {
870  mVectorUndoChangeInfo.back().push_back((*iter));
871  }
872  }
873 
874  bool Edit::commandUndo()
875  {
876  if (mVectorUndoChangeInfo.empty()) return false;
877 
878  // сбрасываем выделение
879  resetSelect();
880 
881  // сохраняем последние набор отмен
883  // перекидываем последний набор отмен
884  mVectorUndoChangeInfo.pop_back();
885  mVectorRedoChangeInfo.push_back(info);
886 
887  // берем текст для издевательств
888  UString text = getRealString();
889 
890  // восстанавливаем последовательность
891  for (VectorChangeInfo::reverse_iterator iter=info.rbegin(); iter!=info.rend(); iter++)
892  {
893 
894  if ((*iter).type == TextCommandInfo::COMMAND_INSERT) text.erase((*iter).start, (*iter).text.size());
895  else if ((*iter).type == TextCommandInfo::COMMAND_ERASE) text.insert((*iter).start, (*iter).text);
896  else
897  {
898  mCursorPosition = (*iter).undo;
899  mTextLength = (*iter).length;
900  }
901  }
902 
903  // возвращаем текст
904  setRealString(text);
905 
906  // обновляем по позиции
907  if (mText != nullptr)
909  updateSelectText();
910 
911  // отсылаем событие о изменении
912  eventEditTextChange(this);
913 
914  return true;
915  }
916 
917  bool Edit::commandRedo()
918  {
919  if (mVectorRedoChangeInfo.empty()) return false;
920 
921  // сбрасываем выделение
922  resetSelect();
923 
924  // сохраняем последние набор отмен
926  // перекидываем последний набор отмен
927  mVectorRedoChangeInfo.pop_back();
928  mVectorUndoChangeInfo.push_back(info);
929 
930  // берем текст для издевательств
931  UString text = getRealString();
932 
933  // восстанавливаем последовательность
934  for (VectorChangeInfo::iterator iter=info.begin(); iter!=info.end(); ++iter)
935  {
936 
937  if ((*iter).type == TextCommandInfo::COMMAND_INSERT) text.insert((*iter).start, (*iter).text);
938  else if ((*iter).type == TextCommandInfo::COMMAND_ERASE) text.erase((*iter).start, (*iter).text.size());
939  else
940  {
941  mCursorPosition = (*iter).redo;
942  mTextLength = (*iter).length;
943  }
944 
945  }
946 
947  // возвращаем текст
948  setRealString(text);
949 
950  // обновляем по позиции
951  if (mText != nullptr)
953  updateSelectText();
954 
955  // отсылаем событие о изменении
956  eventEditTextChange(this);
957 
958  return true;
959  }
960 
961  void Edit::saveInHistory(VectorChangeInfo * _info)
962  {
963  if (_info == nullptr) return;
964  // если нет информации об изменении
965  if ( _info->empty() ) return;
966  if ( (_info->size() == 1) && (_info->back().type == TextCommandInfo::COMMAND_POSITION)) return;
967 
968  mVectorUndoChangeInfo.push_back(*_info);
969  // проверяем на максимальный размер
971  mVectorUndoChangeInfo.pop_front();
972  }
973 
974  // возвращает текст
975  UString Edit::getTextInterval(size_t _start, size_t _count)
976  {
977  // подстраховка
978  if (_start > mTextLength) _start = mTextLength;
979  // конец диапазона
980  size_t end = _start + _count;
981 
982  // итератор нашей строки
983  TextIterator iterator(getRealString());
984 
985  // дефолтный цвет
986  UString colour = mText == nullptr ? "" : TextIterator::convertTagColour(mText->getTextColour());
987 
988  // нужно ли вставлять цвет
989  bool need_colour = true;
990 
991  // цикл прохода по строке
992  while (iterator.moveNext())
993  {
994  // текущаяя позиция
995  size_t pos = iterator.getPosition();
996 
997  // еще рано
998  if (pos < _start)
999  {
1000  // берем цвет из позиции и запоминаем
1001  iterator.getTagColour(colour);
1002 
1003  continue;
1004  }
1005 
1006  // проверяем на надобность начального тега
1007  else if (pos == _start)
1008  {
1009  need_colour = ! iterator.getTagColour(colour);
1010  // сохраняем место откуда начинается
1011  iterator.saveStartPoint();
1012 
1013  }
1014 
1015  // а теперь просто до конца диапазона
1016  else if (pos == end) break;
1017 
1018  }
1019 
1020  // возвращаем строку
1021  if (need_colour) return colour + iterator.getFromStart();
1022  return iterator.getFromStart();
1023  }
1024 
1025  // выделяет цветом диапазон
1026  void Edit::_setTextColour(size_t _start, size_t _count, const Colour& _colour, bool _history)
1027  {
1028  // при изменениях сразу сбрасываем повтор
1029  commandResetRedo();
1030 
1031  // история изменений
1032  VectorChangeInfo * history = nullptr;
1033  if (_history) history = new VectorChangeInfo();
1034 
1035  // конец диапазона
1036  size_t end = _start + _count;
1037 
1038  // итератор нашей строки
1039  TextIterator iterator(getRealString(), history);
1040 
1041  // дефолтный цвет
1042  UString colour = mText == nullptr ? "" : TextIterator::convertTagColour(mText->getTextColour());
1043 
1044  // цикл прохода по строке
1045  while (iterator.moveNext())
1046  {
1047 
1048  // текущаяя позиция
1049  size_t pos = iterator.getPosition();
1050 
1051  // берем цвет из позиции и запоминаем
1052  iterator.getTagColour(colour);
1053 
1054  // еще рано
1055  if (pos < _start) continue;
1056 
1057  // ставим начальный тег
1058  else if (pos == _start)
1059  iterator.setTagColour(_colour);
1060 
1061  // внутри диапазона очищаем все
1062  else if (pos < end)
1063  iterator.clearTagColour();
1064 
1065  // на конец ставим последний найденный или дефолтный
1066  else if (pos == end)
1067  {
1068  iterator.setTagColour(colour);
1069  // и выходим из цикла
1070  break;
1071  }
1072 
1073  }
1074 
1075  // сохраняем позицию для восстановления курсора
1076  commandPosition(_start, _start+_count, mTextLength, history);
1077 
1078  // запоминаем в историю
1079  if (_history)
1080  {
1081  saveInHistory(history);
1082  delete history;
1083  }
1084  // сбрасываем историю
1085  else commandResetHistory();
1086 
1087  // и возвращаем строку на место
1088  setRealString(iterator.getText());
1089 
1090  }
1091 
1092  void Edit::setTextSelectColour(const Colour& _colour, bool _history)
1093  {
1094  // нужно выделение
1095  if ( !isTextSelection()) return;
1096  // начало и конец выделения
1097  size_t start = getTextSelectionStart();
1098  size_t end = getTextSelectionEnd();
1099  _setTextColour(start, end-start, _colour, _history);
1100  }
1101 
1103  {
1104  if ( !isTextSelection()) return "";
1105  size_t start = getTextSelectionStart();
1106  size_t end = getTextSelectionEnd();
1107  return getTextInterval(start, end-start);
1108  }
1109 
1110  void Edit::setEditPassword(bool _password)
1111  {
1112  if (mModePassword == _password) return;
1113  mModePassword = _password;
1114  if (mModePassword)
1115  {
1116  if (mText != nullptr)
1117  {
1120  }
1121  }
1122  else
1123  {
1124  if (mText != nullptr)
1125  {
1127  mPasswordText.clear();
1128  }
1129  }
1130  // обновляем по размерам
1131  updateView();
1132  // сбрасываем историю
1133  commandResetHistory();
1134  }
1135 
1136  void Edit::setText(const UString& _caption, bool _history)
1137  {
1138  // сбрасываем выделение
1139  resetSelect();
1140 
1141  // история изменений
1142  VectorChangeInfo * history = nullptr;
1143  if (_history) history = new VectorChangeInfo();
1144 
1145  // итератор нашей строки
1146  TextIterator iterator(getRealString(), history);
1147 
1148  // вставляем текст
1149  iterator.setText(_caption, mModeMultiline || mModeWordWrap);
1150 
1151  if (mOverflowToTheLeft)
1152  {
1153  iterator.cutMaxLengthFromBeginning(mMaxTextLength);
1154  }
1155  else
1156  {
1157  // обрезаем по максимальной длинне
1158  iterator.cutMaxLength(mMaxTextLength);
1159  }
1160 
1161  // запоминаем размер строки
1162  size_t old = mTextLength;
1163  // новая позиция и положение на конец вставки
1164  mCursorPosition = mTextLength = iterator.getSize();
1165 
1166  // сохраняем позицию для восстановления курсора
1167  commandPosition(0, mTextLength, old, history);
1168 
1169  // запоминаем в историю
1170  if (_history)
1171  {
1172  saveInHistory(history);
1173  delete history;
1174  }
1175  // сбрасываем историю
1176  else commandResetHistory();
1177 
1178  // и возвращаем строку на место
1179  setRealString(iterator.getText());
1180 
1181  // обновляем по позиции
1182  if (mText != nullptr)
1184  updateSelectText();
1185  }
1186 
1187  void Edit::insertText(const UString& _text, size_t _start, bool _history)
1188  {
1189  // сбрасываем выделение
1190  resetSelect();
1191 
1192  // если строка пустая, или размер максимален
1193  if (_text.empty()) return;
1194 
1195  if ((mOverflowToTheLeft == false) && (mTextLength == mMaxTextLength)) return;
1196 
1197  // история изменений
1198  VectorChangeInfo * history = nullptr;
1199  if (_history) history = new VectorChangeInfo();
1200 
1201  // итератор нашей строки
1202  TextIterator iterator(getRealString(), history);
1203 
1204  // дефолтный цвет
1205  UString colour = mText == nullptr ? "" : TextIterator::convertTagColour(mText->getTextColour());
1206  // нужен ли тег текста
1207  // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
1208  bool need_colour = ( (_text.size() > 6) && (_text[0] == L'#') && (_text[1] != L'#') );
1209 
1210  // цикл прохода по строке
1211  while (iterator.moveNext())
1212  {
1213 
1214  // текущаяя позиция
1215  size_t pos = iterator.getPosition();
1216 
1217  // текущий цвет
1218  if (need_colour) iterator.getTagColour(colour);
1219 
1220  // если дошли то выходим
1221  if (pos == _start) break;
1222 
1223  }
1224 
1225  // если нужен цвет то вставляем
1226  if (need_colour) iterator.setTagColour(colour);
1227 
1228  // а теперь вставляем строку
1229  iterator.insertText(_text, mModeMultiline || mModeWordWrap);
1230 
1231  if (mOverflowToTheLeft)
1232  {
1233  iterator.cutMaxLengthFromBeginning(mMaxTextLength);
1234  }
1235  else
1236  {
1237  // обрезаем по максимальной длинне
1238  iterator.cutMaxLength(mMaxTextLength);
1239  }
1240 
1241  // запоминаем размер строки
1242  size_t old = mTextLength;
1243  // новая позиция и положение на конец вставки
1244  mTextLength = iterator.getSize();
1245  mCursorPosition += mTextLength - old;
1246 
1247  // сохраняем позицию для восстановления курсора
1248  commandPosition(_start, _start + mTextLength - old, old, history);
1249 
1250  // запоминаем в историю
1251  if (_history)
1252  {
1253  saveInHistory(history);
1254  delete history;
1255  }
1256  // сбрасываем историю
1257  else commandResetHistory();
1258 
1259  // и возвращаем строку на место
1260  setRealString(iterator.getText());
1261 
1262  // обновляем по позиции
1263  if (mText != nullptr)
1265  updateSelectText();
1266  }
1267 
1268  void Edit::eraseText(size_t _start, size_t _count, bool _history)
1269  {
1270  // чета маловато
1271  if (_count == 0) return;
1272 
1273  // сбрасываем выделение
1274  resetSelect();
1275 
1276  // история изменений
1277  VectorChangeInfo * history = nullptr;
1278  if (_history) history = new VectorChangeInfo();
1279 
1280  // итератор нашей строки
1281  TextIterator iterator(getRealString(), history);
1282 
1283  // дефолтный цвет
1284  UString colour;
1285  // конец диапазона
1286  size_t end = _start + _count;
1287  bool need_colour = false;
1288 
1289  // цикл прохода по строке
1290  while (iterator.moveNext())
1291  {
1292 
1293  // текущаяя позиция
1294  size_t pos = iterator.getPosition();
1295 
1296  // еще рано
1297  if (pos < _start)
1298  {
1299  // берем цвет из позиции и запоминаем
1300  iterator.getTagColour(colour);
1301  continue;
1302  }
1303 
1304  // сохраняем место откуда начинается
1305  else if (pos == _start)
1306  {
1307  // если до диапазона был цвет, то нужно закрыть тег
1308  if ( ! colour.empty())
1309  {
1310  need_colour = true;
1311  colour.clear();
1312  }
1313  // берем цвет из позиции и запоминаем
1314  iterator.getTagColour(colour);
1315  iterator.saveStartPoint();
1316  }
1317 
1318  // внутри диапазона
1319  else if (pos < end)
1320  {
1321  // берем цвет из позиции и запоминаем
1322  iterator.getTagColour(colour);
1323  }
1324 
1325  // окончание диапазона
1326  else if (pos == end)
1327  {
1328  // нужно ставить тег или нет
1329  if ( ! colour.empty()) need_colour = true;
1330  if ( iterator.getTagColour(colour)) need_colour = false;
1331 
1332  break;
1333  }
1334 
1335  }
1336 
1337  // удаляем диапазон
1338  iterator.eraseFromStart();
1339  // и вставляем последний цвет
1340  if (need_colour) iterator.setTagColour(colour);
1341 
1342  // сохраняем позицию для восстановления курсора
1343  commandPosition(_start + _count, _start, mTextLength, history);
1344 
1345  // на месте удаленного
1346  mCursorPosition = _start;
1347  mTextLength -= _count;
1348 
1349  // запоминаем в историю
1350  if (_history)
1351  {
1352  saveInHistory(history);
1353  delete history;
1354  }
1355  // сбрасываем историю
1356  else commandResetHistory();
1357 
1358  // и возвращаем строку на место
1359  setRealString(iterator.getText());
1360 
1361  // обновляем по позиции
1362  if (mText != nullptr)
1364  updateSelectText();
1365  }
1366 
1367  void Edit::commandCut()
1368  {
1369  // вырезаем в буфер обмена
1370  if ( isTextSelection() && (!mModePassword) )
1371  {
1373  if (!mModeReadOnly)
1374  {
1375  deleteTextSelect(true);
1376  // отсылаем событие о изменении
1377  eventEditTextChange(this);
1378  }
1379  }
1381  }
1382 
1383  void Edit::commandCopy()
1384  {
1385  // копируем в буфер обмена
1388  }
1389 
1390  void Edit::commandPast()
1391  {
1392  // копируем из буфера обмена
1394  if ( (!mModeReadOnly) && ( !clipboard.empty()) )
1395  {
1396  // попытка объединения двух комманд
1397  size_t size = mVectorUndoChangeInfo.size();
1398  // непосредственно операции
1399  deleteTextSelect(true);
1400  insertText(clipboard, mCursorPosition, true);
1401  // проверяем на возможность объединения
1402  if ((size+2) == mVectorUndoChangeInfo.size()) commandMerge();
1403  // отсылаем событие о изменении
1404  eventEditTextChange(this);
1405  }
1406  }
1407 
1408  const UString& Edit::getRealString()
1409  {
1410  if (mModePassword) return mPasswordText;
1411  else if (mText == nullptr) return mPasswordText;
1412 
1413  return mText->getCaption();
1414  }
1415 
1416  void Edit::setRealString(const UString& _caption)
1417  {
1418  if (mModePassword)
1419  {
1420  mPasswordText = _caption;
1421  if (mText != nullptr)
1423  }
1424  else
1425  {
1426  if (mText != nullptr)
1427  mText->setCaption(_caption);
1428  }
1429  }
1430 
1432  {
1433  mCharPassword = _char;
1434  if (mModePassword)
1435  {
1436  if (mText != nullptr)
1438  }
1439  }
1440 
1441  void Edit::updateEditState()
1442  {
1443  if (!mEnabled) setState("disabled");
1444  else if (mIsPressed)
1445  {
1446  if (mIsFocus) setState("pushed");
1447  else setState("normal_checked");
1448  }
1449  else if (mIsFocus) setState("highlighted");
1450  else setState("normal");
1451  }
1452 
1453  void Edit::setPosition(const IntPoint& _point)
1454  {
1455  Base::setPosition(_point);
1456  }
1457 
1459  {
1460  // если перенос, то сбрасываем размер текста
1461  if (mModeWordWrap)
1462  {
1463  if (mText != nullptr)
1464  mText->setWordWrap(true);
1465  }
1466 
1467  updateView();
1468  }
1469 
1470  void Edit::setSize(const IntSize& _size)
1471  {
1472  Base::setSize(_size);
1473 
1474  eraseView();
1475  }
1476 
1477  void Edit::setCoord(const IntCoord& _coord)
1478  {
1479  Base::setCoord(_coord);
1480 
1481  eraseView();
1482  }
1483 
1484  void Edit::setCaption(const UString& _value)
1485  {
1486  setText(_value, false);
1487  }
1488 
1490  {
1491  return getRealString();
1492  }
1493 
1494  void Edit::updateSelectText()
1495  {
1496  if (!mModeStatic)
1497  {
1498 
1500  if ( (input.isShiftPressed()) && (mStartSelect != ITEM_NONE) )
1501  {
1502  // меняем выделение
1503  mEndSelect = (size_t)mCursorPosition;
1504  if (mText != nullptr)
1505  {
1508  }
1509 
1510  }
1511  else if (mStartSelect != ITEM_NONE)
1512  {
1513  // сбрасываем шифт
1515  if (mText != nullptr)
1516  mText->setTextSelection(0, 0);
1517  }
1518  }
1519 
1520  // пытаемся показать курсор
1522  }
1523 
1525  {
1526  Base::setTextAlign(_align);
1527 
1528  // так как мы сами рулим смещениями
1529  updateView();
1530  }
1531 
1532  void Edit::notifyScrollChangePosition(VScroll* _sender, size_t _position)
1533  {
1534  if (mText == nullptr)
1535  return;
1536 
1537  if (_sender == mVScroll)
1538  {
1539  IntPoint point = mText->getViewOffset();
1540  point.top = _position;
1541  mText->setViewOffset(point);
1542  }
1543  else if (_sender == mHScroll)
1544  {
1545  IntPoint point = mText->getViewOffset();
1546  point.left = _position;
1547  mText->setViewOffset(point);
1548  }
1549  }
1550 
1551  void Edit::notifyMouseWheel(Widget* _sender, int _rel)
1552  {
1553  if (mText == nullptr)
1554  return;
1555 
1556  if (mVRange != 0)
1557  {
1558  IntPoint point = mText->getViewOffset();
1559  int offset = point.top;
1560  if (_rel < 0) offset += EDIT_MOUSE_WHEEL;
1561  else offset -= EDIT_MOUSE_WHEEL;
1562 
1563  if (offset < 0) offset = 0;
1564  else if (offset > (int)mVRange) offset = mVRange;
1565 
1566  if (offset != point.top)
1567  {
1568  point.top = offset;
1569  if (mVScroll != nullptr)
1570  mVScroll->setScrollPosition(offset);
1571  mText->setViewOffset(point);
1572  }
1573  }
1574  else if (mHRange != 0)
1575  {
1576  IntPoint point = mText->getViewOffset();
1577  int offset = point.left;
1578  if (_rel < 0) offset += EDIT_MOUSE_WHEEL;
1579  else offset -= EDIT_MOUSE_WHEEL;
1580 
1581  if (offset < 0) offset = 0;
1582  else if (offset > (int)mHRange) offset = mHRange;
1583 
1584  if (offset != point.left)
1585  {
1586  point.left = offset;
1587  if (mHScroll != nullptr)
1588  mHScroll->setScrollPosition(offset);
1589  mText->setViewOffset(point);
1590  }
1591  }
1592  }
1593 
1594  void Edit::setEditWordWrap(bool _value)
1595  {
1596  mModeWordWrap = _value;
1597  if (mText != nullptr)
1599 
1600  eraseView();
1601  }
1602 
1603  void Edit::setFontName(const std::string& _value)
1604  {
1605  Base::setFontName(_value);
1606 
1607  eraseView();
1608  }
1609 
1610  void Edit::setFontHeight(int _value)
1611  {
1612  Base::setFontHeight(_value);
1613 
1614  eraseView();
1615  }
1616 
1618  {
1619  updateScrollSize();
1621  }
1622 
1624  {
1625  updateScrollSize();
1626  updateCursorPosition();
1628  }
1629 
1630  void Edit::updateCursorPosition()
1631  {
1632  if (mText == nullptr || mWidgetClient == nullptr)
1633  return;
1634 
1635  // размер контекста текста
1636  IntSize textSize = mText->getTextSize();
1637 
1638  // текущее смещение контекста текста
1639  IntPoint point = mText->getViewOffset();
1640  // расчетное смещение
1641  IntPoint offset = point;
1642 
1643  // абсолютные координаты курсора
1645  cursor.right ++;
1646 
1647  // абсолютные координаты вью
1648  const IntRect& view = mWidgetClient->getAbsoluteRect();
1649 
1650  // проверяем и показываем курсор
1651  if (!view.inside(cursor))
1652  {
1653  // горизонтальное смещение
1654  // FIXME проверить, помоему просто >
1655  if (textSize.width >= view.width())
1656  {
1657  if (cursor.left < view.left)
1658  {
1659  offset.left = point.left - (view.left - cursor.left);
1660  // добавляем смещение, только если курсор не перепрыгнет
1661  if ((float(view.width()) - EDIT_OFFSET_HORZ_CURSOR) > EDIT_OFFSET_HORZ_CURSOR) offset.left -= int(EDIT_OFFSET_HORZ_CURSOR);
1662  }
1663  else if (cursor.right > view.right)
1664  {
1665  offset.left = point.left + (cursor.right - view.right);
1666  // добавляем смещение, только если курсор не перепрыгнет
1667  if ((float(view.width()) - EDIT_OFFSET_HORZ_CURSOR) > EDIT_OFFSET_HORZ_CURSOR) offset.left += int(EDIT_OFFSET_HORZ_CURSOR);
1668  }
1669  }
1670 
1671  // вертикальное смещение
1672  // FIXME проверить, помоему просто >
1673  if (textSize.height >= view.height())
1674  {
1675  if (cursor.top < view.top)
1676  {
1677  offset.top = point.top - (view.top - cursor.top);
1678  }
1679  else if (cursor.bottom > view.bottom)
1680  {
1681  offset.top = point.top + (cursor.bottom - view.bottom);
1682  }
1683  }
1684 
1685  }
1686 
1687  if (offset != point)
1688  {
1689  mText->setViewOffset(offset);
1690  // обновить скролы
1691  if (mVScroll != nullptr)
1692  mVScroll->setScrollPosition(offset.top);
1693  if (mHScroll != nullptr)
1694  mHScroll->setScrollPosition(offset.left);
1695  }
1696  }
1697 
1698  void Edit::setContentPosition(const IntPoint& _point)
1699  {
1700  if (mText != nullptr)
1701  mText->setViewOffset(_point);
1702  }
1703 
1704  IntSize Edit::getViewSize() const
1705  {
1706  return mWidgetClient == nullptr ? getSize() : mWidgetClient->getSize();
1707  }
1708 
1709  IntSize Edit::getContentSize()
1710  {
1711  return mText == nullptr ? IntSize() : mText->getTextSize();
1712  }
1713 
1714  size_t Edit::getVScrollPage()
1715  {
1716  return (size_t)getFontHeight();
1717  }
1718 
1719  size_t Edit::getHScrollPage()
1720  {
1721  return (size_t)getFontHeight();
1722  }
1723 
1724  IntPoint Edit::getContentPosition()
1725  {
1726  return mText == nullptr ? IntPoint() : mText->getViewOffset();
1727  }
1728 
1729  Align Edit::getContentAlign()
1730  {
1731  return mText == nullptr ? Align::Default : mText->getTextAlign();
1732  }
1733 
1734  void Edit::setTextIntervalColour(size_t _start, size_t _count, const Colour& _colour)
1735  {
1736  _setTextColour(_start, _count, _colour, false);
1737  }
1738 
1740  {
1742  }
1743 
1745  {
1747  }
1748 
1750  {
1751  return ( (mStartSelect != ITEM_NONE) && (mStartSelect != mEndSelect) );
1752  }
1753 
1755  {
1756  deleteTextSelect(false);
1757  }
1758 
1760  {
1761  setTextSelectColour(_colour, false);
1762  }
1763 
1765  {
1766  return mEndSelect - mStartSelect;
1767  }
1768 
1769  void Edit::setOnlyText(const UString& _text)
1770  {
1771  setText(TextIterator::toTagsString(_text), false);
1772  }
1773 
1775  {
1776  return TextIterator::getOnlyText(getRealString());
1777  }
1778 
1779  void Edit::insertText(const UString& _text, size_t _index)
1780  {
1781  insertText(_text, _index, false);
1782  }
1783 
1784  void Edit::addText(const UString& _text)
1785  {
1786  insertText(_text, ITEM_NONE, false);
1787  }
1788 
1789  void Edit::eraseText(size_t _start, size_t _count)
1790  {
1791  eraseText(_start, _count, false);
1792  }
1793 
1794  void Edit::setEditReadOnly(bool _read)
1795  {
1796  mModeReadOnly = _read;
1797  // сбрасываем историю
1798  commandResetHistory();
1799  }
1800 
1801  void Edit::setEditMultiLine(bool _multi)
1802  {
1803  mModeMultiline = _multi;
1804  // на всякий, для уберания переносов
1805  if (!mModeMultiline)
1806  {
1807  setText(getRealString(), false);
1808  }
1809  // обновляем по размерам
1810  else updateView();
1811  // сбрасываем историю
1812  commandResetHistory();
1813  }
1814 
1815  void Edit::setEditStatic(bool _static)
1816  {
1817  mModeStatic = _static;
1818  resetSelect();
1819 
1820  if (mWidgetClient != nullptr)
1821  {
1824  }
1825  }
1826 
1827  void Edit::setPasswordChar(const UString& _char)
1828  {
1829  if (!_char.empty()) setPasswordChar(_char[0]);
1830  }
1831 
1832  void Edit::setVisibleVScroll(bool _value)
1833  {
1834  mVisibleVScroll = _value;
1835  updateView();
1836  }
1837 
1838  void Edit::setVisibleHScroll(bool _value)
1839  {
1840  mVisibleHScroll = _value;
1841  updateView();
1842  }
1843 
1844  void Edit::setProperty(const std::string& _key, const std::string& _value)
1845  {
1846  if (_key == "Edit_CursorPosition") setTextCursor(utility::parseValue<size_t>(_value));
1847  else if (_key == "Edit_TextSelect") setTextSelection(utility::parseValue< types::TSize<size_t> >(_value).width, utility::parseValue< types::TSize<size_t> >(_value).height);
1848  else if (_key == "Edit_ReadOnly") setEditReadOnly(utility::parseValue<bool>(_value));
1849  else if (_key == "Edit_Password") setEditPassword(utility::parseValue<bool>(_value));
1850  else if (_key == "Edit_MultiLine") setEditMultiLine(utility::parseValue<bool>(_value));
1851  else if (_key == "Edit_PasswordChar") setPasswordChar(_value);
1852  else if (_key == "Edit_MaxTextLength") setMaxTextLength(utility::parseValue<size_t>(_value));
1853  else if (_key == "Edit_OverflowToTheLeft") setOverflowToTheLeft(utility::parseValue<bool>(_value));
1854  else if (_key == "Edit_Static") setEditStatic(utility::parseValue<bool>(_value));
1855  else if (_key == "Edit_VisibleVScroll") setVisibleVScroll(utility::parseValue<bool>(_value));
1856  else if (_key == "Edit_VisibleHScroll") setVisibleHScroll(utility::parseValue<bool>(_value));
1857  else if (_key == "Edit_WordWrap") setEditWordWrap(utility::parseValue<bool>(_value));
1858  else if (_key == "Edit_TabPrinting") setTabPrinting(utility::parseValue<bool>(_value));
1859  else if (_key == "Edit_InvertSelected") setInvertSelected(utility::parseValue<bool>(_value));
1860 
1861 #ifndef MYGUI_DONT_USE_OBSOLETE
1862  else if (_key == "Edit_ShowVScroll")
1863  {
1864  MYGUI_LOG(Warning, "Edit_ShowVScroll is obsolete, use Edit_VisibleVScroll");
1865  setVisibleVScroll(utility::parseValue<bool>(_value));
1866  }
1867  else if (_key == "Edit_ShowHScroll")
1868  {
1869  MYGUI_LOG(Warning, "Edit_ShowHScroll is obsolete, use Edit_VisibleHScroll");
1870  setVisibleHScroll(utility::parseValue<bool>(_value));
1871  }
1872 #endif // MYGUI_DONT_USE_OBSOLETE
1873 
1874  else
1875  {
1876  Base::setProperty(_key, _value);
1877  return;
1878  }
1879  eventChangeProperty(this, _key, _value);
1880  }
1881 
1883  {
1884  return mVRange + 1;
1885  }
1886 
1888  {
1889  return mText == nullptr ? 0 : mText->getViewOffset().top;
1890  }
1891 
1892  void Edit::setVScrollPosition(size_t _index)
1893  {
1894  if (mText == nullptr)
1895  return;
1896 
1897  if (_index > mVRange)
1898  _index = mVRange;
1899 
1900  IntPoint point = mText->getViewOffset();
1901  point.top = _index;
1902 
1903  mText->setViewOffset(point);
1904  // обновить скролы
1905  if (mVScroll != nullptr)
1906  mVScroll->setScrollPosition(point.top);
1907  }
1908 
1910  {
1911  return mHRange + 1;
1912  }
1913 
1915  {
1916  return mText == nullptr ? 0 : mText->getViewOffset().left;
1917  }
1918 
1919  void Edit::setHScrollPosition(size_t _index)
1920  {
1921  if (mText == nullptr)
1922  return;
1923 
1924  if (_index > mHRange)
1925  _index = mHRange;
1926 
1927  IntPoint point = mText->getViewOffset();
1928  point.left = _index;
1929 
1930  mText->setViewOffset(point);
1931  // обновить скролы
1932  if (mHScroll != nullptr)
1934  }
1935 
1937  {
1938  return mText == nullptr ? false : mText->getInvertSelected();
1939  }
1940 
1941  void Edit::setInvertSelected(bool _value)
1942  {
1943  if (mText != nullptr)
1944  mText->setInvertSelected(_value);
1945  }
1946 
1947 } // namespace MyGUI