MyGUI  3.2.1
MyGUI_EditBox.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_EditBox.h"
00009 #include "MyGUI_Gui.h"
00010 #include "MyGUI_ResourceSkin.h"
00011 #include "MyGUI_SkinManager.h"
00012 #include "MyGUI_InputManager.h"
00013 #include "MyGUI_ClipboardManager.h"
00014 #include "MyGUI_PointerManager.h"
00015 #include "MyGUI_ISubWidgetText.h"
00016 #include "MyGUI_ScrollBar.h"
00017 
00018 #include <ctype.h>
00019 
00020 namespace MyGUI
00021 {
00022 
00023     const float EDIT_CURSOR_TIMER  = 0.7f;
00024     const float EDIT_ACTION_MOUSE_TIMER  = 0.05f;
00025     const int EDIT_CURSOR_MAX_POSITION = 100000;
00026     const int EDIT_CURSOR_MIN_POSITION = -100000;
00027     const size_t EDIT_MAX_UNDO = 128;
00028     const size_t EDIT_DEFAULT_MAX_TEXT_LENGTH = 2048;
00029     const float EDIT_OFFSET_HORZ_CURSOR = 10.0f; // дополнительное смещение для курсора
00030     const int EDIT_ACTION_MOUSE_ZONE = 1500; // область для восприятия мыши за пределом эдита
00031     const std::string EDIT_CLIPBOARD_TYPE_TEXT = "Text";
00032     const int EDIT_MOUSE_WHEEL = 50; // область для восприятия мыши за пределом эдита
00033 
00034     EditBox::EditBox() :
00035         mIsPressed(false),
00036         mIsFocus(false),
00037         mCursorActive(false),
00038         mCursorTimer(0),
00039         mActionMouseTimer(0),
00040         mCursorPosition(0),
00041         mTextLength(0),
00042         mStartSelect(ITEM_NONE),
00043         mEndSelect(0),
00044         mMouseLeftPressed(false),
00045         mModeReadOnly(false),
00046         mModePassword(false),
00047         mModeMultiline(false),
00048         mModeStatic(false),
00049         mModeWordWrap(false),
00050         mTabPrinting(false),
00051         mCharPassword('*'),
00052         mOverflowToTheLeft(false),
00053         mMaxTextLength(EDIT_DEFAULT_MAX_TEXT_LENGTH),
00054         mClientText(nullptr)
00055     {
00056         mChangeContentByResize = true;
00057     }
00058 
00059     void EditBox::initialiseOverride()
00060     {
00061         Base::initialiseOverride();
00062 
00063         mOriginalPointer = getPointer();
00064 
00065         // FIXME нам нужен фокус клавы
00066         setNeedKeyFocus(true);
00067 
00069         assignWidget(mClient, "Client");
00070         if (mClient != nullptr)
00071         {
00072             mClient->eventMouseSetFocus += newDelegate(this, &EditBox::notifyMouseSetFocus);
00073             mClient->eventMouseLostFocus += newDelegate(this, &EditBox::notifyMouseLostFocus);
00074             mClient->eventMouseButtonPressed += newDelegate(this, &EditBox::notifyMousePressed);
00075             mClient->eventMouseButtonReleased += newDelegate(this, &EditBox::notifyMouseReleased);
00076             mClient->eventMouseDrag += newDelegate(this, &EditBox::notifyMouseDrag);
00077             mClient->eventMouseButtonDoubleClick += newDelegate(this, &EditBox::notifyMouseButtonDoubleClick);
00078             mClient->eventMouseWheel += newDelegate(this, &EditBox::notifyMouseWheel);
00079             setWidgetClient(mClient);
00080         }
00081 
00083         assignWidget(mVScroll, "VScroll");
00084         if (mVScroll != nullptr)
00085         {
00086             mVScroll->eventScrollChangePosition += newDelegate(this, &EditBox::notifyScrollChangePosition);
00087         }
00088 
00090         assignWidget(mHScroll, "HScroll");
00091         if (mHScroll != nullptr)
00092         {
00093             mHScroll->eventScrollChangePosition += newDelegate(this, &EditBox::notifyScrollChangePosition);
00094         }
00095 
00096         mClientText = getSubWidgetText();
00097         if (mClient != nullptr)
00098         {
00099             ISubWidgetText* text = mClient->getSubWidgetText();
00100             if (text)
00101                 mClientText = text;
00102         }
00103 
00104         updateScrollSize();
00105 
00106         // первоначальная инициализация курсора
00107         if (mClientText != nullptr)
00108             mClientText->setCursorPosition(mCursorPosition);
00109 
00110         updateSelectText();
00111     }
00112 
00113     void EditBox::shutdownOverride()
00114     {
00115         mClient = nullptr;
00116         mClientText = nullptr;
00117         mVScroll = nullptr;
00118         mHScroll = nullptr;
00119 
00120         Base::shutdownOverride();
00121     }
00122 
00123     void EditBox::notifyMouseSetFocus(Widget* _sender, Widget* _old)
00124     {
00125         if ((_old == mClient) || (mIsFocus))
00126             return;
00127 
00128         mIsFocus = true;
00129         updateEditState();
00130     }
00131 
00132     void EditBox::notifyMouseLostFocus(Widget* _sender, Widget* _new)
00133     {
00134         if ((_new == mClient) || (!mIsFocus))
00135             return;
00136 
00137         mIsFocus = false;
00138         updateEditState();
00139     }
00140 
00141     void EditBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
00142     {
00143         if (mClientText == nullptr)
00144             return;
00145 
00146         // в статике все недоступно
00147         if (mModeStatic)
00148             return;
00149 
00150         IntPoint point = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);
00151         mCursorPosition = mClientText->getCursorPosition(point);
00152         mClientText->setCursorPosition(mCursorPosition);
00153         mClientText->setVisibleCursor(true);
00154         mCursorTimer = 0;
00155         updateSelectText();
00156 
00157         if (_id == MouseButton::Left)
00158             mMouseLeftPressed = true;
00159     }
00160 
00161     void EditBox::notifyMouseReleased(Widget* _sender, int _left, int _top, MouseButton _id)
00162     {
00163         // сбрасываем всегда
00164         mMouseLeftPressed = false;
00165     }
00166 
00167     void EditBox::notifyMouseDrag(Widget* _sender, int _left, int _top, MouseButton _id)
00168     {
00169         if (_id != MouseButton::Left)
00170             return;
00171 
00172         if (mClientText == nullptr)
00173             return;
00174 
00175         // в статике все недоступно
00176         if (mModeStatic)
00177             return;
00178 
00179         // останавливаем курсор
00180         mClientText->setVisibleCursor(true);
00181 
00182         // сбрасываем все таймеры
00183         mCursorTimer = 0;
00184         mActionMouseTimer = 0;
00185 
00186         size_t Old = mCursorPosition;
00187         IntPoint point(_left, _top);
00188         mCursorPosition = mClientText->getCursorPosition(point);
00189         if (Old == mCursorPosition)
00190             return;
00191 
00192         mClientText->setCursorPosition(mCursorPosition);
00193 
00194         // если не было выделения
00195         if (mStartSelect == ITEM_NONE)
00196             mStartSelect = Old;
00197 
00198         // меняем выделение
00199         mEndSelect = (size_t)mCursorPosition;
00200         if (mStartSelect > mEndSelect)
00201             mClientText->setTextSelection(mEndSelect, mStartSelect);
00202         else
00203             mClientText->setTextSelection(mStartSelect, mEndSelect);
00204 
00205     }
00206 
00207     void EditBox::notifyMouseButtonDoubleClick(Widget* _sender)
00208     {
00209         if (mClientText == nullptr)
00210             return;
00211 
00212         // в статике все недоступно
00213         if (mModeStatic)
00214             return;
00215 
00216         const IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);
00217 
00218         size_t cursorPosition = mClientText->getCursorPosition(lastPressed);
00219         mStartSelect = cursorPosition;
00220         mEndSelect = cursorPosition;
00221 
00222         UString text = this->getOnlyText();
00223         UString::reverse_iterator iterBack = text.rend() - cursorPosition;
00224         UString::iterator iterForw = text.begin() + cursorPosition;
00225 
00226         while (iterBack != text.rend())
00227         {
00228             if (((*iterBack) < 265) && (ispunct(*iterBack) || isspace(*iterBack)))
00229                 break;
00230             ++iterBack;
00231             mStartSelect--;
00232         }
00233         while (iterForw != text.end())
00234         {
00235             if (((*iterForw) < 265) && (ispunct(*iterForw) || isspace(*iterForw)))
00236                 break;
00237             ++iterForw;
00238             mEndSelect++;
00239         }
00240 
00241         mClientText->setCursorPosition(mEndSelect);
00242         mClientText->setTextSelection(mStartSelect, mEndSelect);
00243     }
00244 
00245     void EditBox::onMouseDrag(int _left, int _top, MouseButton _id)
00246     {
00247         notifyMouseDrag(nullptr, _left, _top, _id);
00248 
00249         Base::onMouseDrag(_left, _top, _id);
00250     }
00251 
00252     void EditBox::onKeySetFocus(Widget* _old)
00253     {
00254         if (!mIsPressed)
00255         {
00256             mIsPressed = true;
00257             updateEditState();
00258 
00259             if (!mModeStatic)
00260             {
00261                 if (mClientText != nullptr)
00262                 {
00263                     mCursorActive = true;
00264                     Gui::getInstance().eventFrameStart += newDelegate(this, &EditBox::frameEntered);
00265                     mClientText->setVisibleCursor(true);
00266                     mClientText->setSelectBackground(true);
00267                     mCursorTimer = 0;
00268                 }
00269             }
00270         }
00271 
00272         Base::onKeySetFocus(_old);
00273     }
00274 
00275     void EditBox::onKeyLostFocus(Widget* _new)
00276     {
00277         if (mIsPressed)
00278         {
00279             mIsPressed = false;
00280             updateEditState();
00281 
00282             if (mClientText != nullptr)
00283             {
00284                 mCursorActive = false;
00285                 Gui::getInstance().eventFrameStart -= newDelegate(this, &EditBox::frameEntered);
00286                 mClientText->setVisibleCursor(false);
00287                 mClientText->setSelectBackground(false);
00288             }
00289         }
00290 
00291         Base::onKeyLostFocus(_new);
00292     }
00293 
00294     void EditBox::onKeyButtonPressed(KeyCode _key, Char _char)
00295     {
00296         if (mClientText == nullptr || mClient == nullptr)
00297         {
00298             Base::onKeyButtonPressed(_key, _char);
00299             return;
00300         }
00301 
00302         // в статическом режиме ничего не доступно
00303         if (mModeStatic)
00304         {
00305             Base::onKeyButtonPressed(_key, _char);
00306             return;
00307         }
00308 
00309         InputManager& input = InputManager::getInstance();
00310 
00311         mClientText->setVisibleCursor(true);
00312         mCursorTimer = 0.0f;
00313 
00314         if (_key == KeyCode::Escape)
00315         {
00316             InputManager::getInstance().setKeyFocusWidget(nullptr);
00317         }
00318         else if (_key == KeyCode::Backspace)
00319         {
00320             // если нуно то удаляем выделенный текст
00321             if (!mModeReadOnly)
00322             {
00323                 // сбрасываем повтор
00324                 commandResetRedo();
00325 
00326                 if (!deleteTextSelect(true))
00327                 {
00328                     // прыгаем на одну назад и удаляем
00329                     if (mCursorPosition != 0)
00330                     {
00331                         mCursorPosition--;
00332                         eraseText(mCursorPosition, 1, true);
00333                     }
00334                 }
00335                 // отсылаем событие о изменении
00336                 eventEditTextChange(this);
00337             }
00338 
00339         }
00340         else if (_key == KeyCode::Delete)
00341         {
00342             if (input.isShiftPressed())
00343             {
00344                 // сбрасываем повтор
00345                 commandResetRedo();
00346 
00347                 commandCut();
00348             }
00349             else if (!mModeReadOnly)
00350             {
00351                 // сбрасываем повтор
00352                 commandResetRedo();
00353 
00354                 // если нуно то удаляем выделенный текст
00355                 if (!deleteTextSelect(true))
00356                 {
00357                     if (mCursorPosition != mTextLength)
00358                     {
00359                         eraseText(mCursorPosition, 1, true);
00360                     }
00361                 }
00362                 // отсылаем событие о изменении
00363                 eventEditTextChange(this);
00364             }
00365 
00366         }
00367         else if (_key == KeyCode::Insert)
00368         {
00369             if (input.isShiftPressed())
00370             {
00371                 // сбрасываем повтор
00372                 commandResetRedo();
00373 
00374                 commandPast();
00375             }
00376             else if (input.isControlPressed())
00377             {
00378                 commandCopy();
00379             }
00380 
00381         }
00382         else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
00383         {
00384             // работаем только в режиме редактирования
00385             if (!mModeReadOnly)
00386             {
00387                 if ((mModeMultiline) && (!input.isControlPressed()))
00388                 {
00389                     // сбрасываем повтор
00390                     commandResetRedo();
00391 
00392                     // попытка объединения двух комманд
00393                     size_t size = mVectorUndoChangeInfo.size();
00394                     // непосредственно операции
00395                     deleteTextSelect(true);
00396                     insertText(TextIterator::getTextNewLine(), mCursorPosition, true);
00397                     // проверяем на возможность объединения
00398                     if ((size + 2) == mVectorUndoChangeInfo.size())
00399                         commandMerge();
00400                     // отсылаем событие о изменении
00401                     eventEditTextChange(this);
00402                 }
00403                 // при сингл лайн и и мульти+сонтрол шлем эвент
00404                 else
00405                 {
00406                     eventEditSelectAccept(this);
00407                 }
00408             }
00409 
00410         }
00411         else if (_key == KeyCode::ArrowRight)
00412         {
00413             if ((mCursorPosition) < mTextLength)
00414             {
00415                 mCursorPosition ++;
00416                 mClientText->setCursorPosition(mCursorPosition);
00417                 updateSelectText();
00418             }
00419             // сбрасываем выделение
00420             else if (isTextSelection() && !input.isShiftPressed())
00421             {
00422                 resetSelect();
00423             }
00424 
00425         }
00426         else if (_key == KeyCode::ArrowLeft)
00427         {
00428             if (mCursorPosition != 0)
00429             {
00430                 mCursorPosition --;
00431                 mClientText->setCursorPosition(mCursorPosition);
00432                 updateSelectText();
00433             }
00434             // сбрасываем выделение
00435             else if (isTextSelection() && !input.isShiftPressed())
00436             {
00437                 resetSelect();
00438             }
00439 
00440         }
00441         else if (_key == KeyCode::ArrowUp)
00442         {
00443             IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00444             point.top -= mClientText->getFontHeight();
00445             size_t old = mCursorPosition;
00446             mCursorPosition = mClientText->getCursorPosition(point);
00447             // самая верхняя строчка
00448             if (old == mCursorPosition)
00449             {
00450                 if (mCursorPosition != 0)
00451                 {
00452                     mCursorPosition = 0;
00453                     mClientText->setCursorPosition(mCursorPosition);
00454                     updateSelectText();
00455                 }
00456                 // сбрасываем выделение
00457                 else if (isTextSelection() && !input.isShiftPressed())
00458                 {
00459                     resetSelect();
00460                 }
00461             }
00462             else
00463             {
00464                 mClientText->setCursorPosition(mCursorPosition);
00465                 updateSelectText();
00466             }
00467 
00468         }
00469         else if (_key == KeyCode::ArrowDown)
00470         {
00471             IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00472             point.top += mClientText->getFontHeight();
00473             size_t old = mCursorPosition;
00474             mCursorPosition = mClientText->getCursorPosition(point);
00475             // самая нижняя строчка
00476             if (old == mCursorPosition)
00477             {
00478                 if (mCursorPosition != mTextLength)
00479                 {
00480                     mCursorPosition = mTextLength;
00481                     mClientText->setCursorPosition(mCursorPosition);
00482                     updateSelectText();
00483                 }
00484                 // сбрасываем выделение
00485                 else if (isTextSelection() && !input.isShiftPressed())
00486                 {
00487                     resetSelect();
00488                 }
00489             }
00490             else
00491             {
00492                 mClientText->setCursorPosition(mCursorPosition);
00493                 updateSelectText();
00494             }
00495 
00496         }
00497         else if (_key == KeyCode::Home)
00498         {
00499             // в начало строки
00500             if (!input.isControlPressed())
00501             {
00502                 IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00503                 point.left = EDIT_CURSOR_MIN_POSITION;
00504                 size_t old = mCursorPosition;
00505                 mCursorPosition = mClientText->getCursorPosition(point);
00506                 if (old != mCursorPosition)
00507                 {
00508                     mClientText->setCursorPosition(mCursorPosition);
00509                     updateSelectText();
00510                 }
00511                 else if (isTextSelection() && !input.isShiftPressed())
00512                 {
00513                     resetSelect();
00514                 }
00515             }
00516             // в начало всего текста
00517             else
00518             {
00519                 if (0 != mCursorPosition)
00520                 {
00521                     mCursorPosition = 0;
00522                     mClientText->setCursorPosition(mCursorPosition);
00523                     updateSelectText();
00524                 }
00525                 else if (isTextSelection() && !input.isShiftPressed())
00526                 {
00527                     resetSelect();
00528                 }
00529             }
00530 
00531         }
00532         else if (_key == KeyCode::End)
00533         {
00534             // в конец строки
00535             if (!input.isControlPressed())
00536             {
00537                 IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00538                 point.left = EDIT_CURSOR_MAX_POSITION;
00539                 size_t old = mCursorPosition;
00540                 mCursorPosition = mClientText->getCursorPosition(point);
00541                 if (old != mCursorPosition)
00542                 {
00543                     mClientText->setCursorPosition(mCursorPosition);
00544                     updateSelectText();
00545                 }
00546                 else if (isTextSelection() && !input.isShiftPressed())
00547                 {
00548                     resetSelect();
00549                 }
00550             }
00551             // в самый конец
00552             else
00553             {
00554                 if (mTextLength != mCursorPosition)
00555                 {
00556                     mCursorPosition = mTextLength;
00557                     mClientText->setCursorPosition(mCursorPosition);
00558                     updateSelectText();
00559                 }
00560                 else if (isTextSelection() && !input.isShiftPressed())
00561                 {
00562                     resetSelect();
00563                 }
00564             }
00565 
00566         }
00567         else if (_key == KeyCode::PageUp)
00568         {
00569             // на размер окна, но не меньше одной строки
00570             IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00571             point.top -= (mClient->getHeight() > mClientText->getFontHeight()) ? mClient->getHeight() : mClientText->getFontHeight();
00572             size_t old = mCursorPosition;
00573             mCursorPosition = mClientText->getCursorPosition(point);
00574             // самая верхняя строчка
00575             if (old == mCursorPosition)
00576             {
00577                 if (mCursorPosition != 0)
00578                 {
00579                     mCursorPosition = 0;
00580                     mClientText->setCursorPosition(mCursorPosition);
00581                     updateSelectText();
00582                 }
00583                 // сбрасываем выделение
00584                 else if (isTextSelection() && !input.isShiftPressed())
00585                 {
00586                     resetSelect();
00587                 }
00588             }
00589             else
00590             {
00591                 mClientText->setCursorPosition(mCursorPosition);
00592                 updateSelectText();
00593             }
00594 
00595         }
00596         else if (_key == KeyCode::PageDown)
00597         {
00598             // на размер окна, но не меньше одной строки
00599             IntPoint point = mClientText->getCursorPoint(mCursorPosition);
00600             point.top += (mClient->getHeight() > mClientText->getFontHeight()) ? mClient->getHeight() : mClientText->getFontHeight();
00601             size_t old = mCursorPosition;
00602             mCursorPosition = mClientText->getCursorPosition(point);
00603             // самая нижняя строчка
00604             if (old == mCursorPosition)
00605             {
00606                 if (mCursorPosition != mTextLength)
00607                 {
00608                     mCursorPosition = mTextLength;
00609                     mClientText->setCursorPosition(mCursorPosition);
00610                     updateSelectText();
00611                 }
00612                 // сбрасываем выделение
00613                 else if (isTextSelection() && !input.isShiftPressed())
00614                 {
00615                     resetSelect();
00616                 }
00617             }
00618             else
00619             {
00620                 mClientText->setCursorPosition(mCursorPosition);
00621                 updateSelectText();
00622             }
00623 
00624         }
00625         else if ((_key == KeyCode::LeftShift) || (_key == KeyCode::RightShift))
00626         {
00627             // для правильно выделения
00628             if (mStartSelect == ITEM_NONE)
00629             {
00630                 mStartSelect = mEndSelect = mCursorPosition;
00631             }
00632         }
00633         else
00634         {
00635             // если не нажат контрл, то обрабатываем как текст
00636             if (!input.isControlPressed())
00637             {
00638                 if (!mModeReadOnly && _char != 0)
00639                 {
00640                     // сбрасываем повтор
00641                     commandResetRedo();
00642 
00643                     // таб только если нужно
00644                     if (_char != '\t' || mTabPrinting)
00645                     {
00646                         // попытка объединения двух комманд
00647                         size_t size = mVectorUndoChangeInfo.size();
00648                         // непосредственно операции
00649                         deleteTextSelect(true);
00650                         insertText(TextIterator::getTextCharInfo(_char), mCursorPosition, true);
00651                         // проверяем на возможность объединения
00652                         if ((size + 2) == mVectorUndoChangeInfo.size())
00653                             commandMerge();
00654                         // отсылаем событие о изменении
00655                         eventEditTextChange(this);
00656                     }
00657                 }
00658             }
00659             else if (_key == KeyCode::C)
00660             {
00661                 commandCopy();
00662 
00663             }
00664             else if (_key == KeyCode::X)
00665             {
00666                 // сбрасываем повтор
00667                 commandResetRedo();
00668 
00669                 commandCut();
00670 
00671             }
00672             else if (_key == KeyCode::V)
00673             {
00674                 // сбрасываем повтор
00675                 commandResetRedo();
00676 
00677                 commandPast();
00678 
00679             }
00680             else if (_key == KeyCode::A)
00681             {
00682                 // выделяем весь текст
00683                 setTextSelection(0, mTextLength);
00684 
00685             }
00686             else if (_key == KeyCode::Z)
00687             {
00688                 // отмена
00689                 commandUndo();
00690 
00691             }
00692             else if (_key == KeyCode::Y)
00693             {
00694                 // повтор
00695                 commandRedo();
00696 
00697             }
00698         }
00699 
00700         Base::onKeyButtonPressed(_key, _char);
00701     }
00702 
00703     void EditBox::frameEntered(float _frame)
00704     {
00705         if (mClientText == nullptr)
00706             return;
00707 
00708         // в статике все недоступно
00709         if (mModeStatic)
00710             return;
00711 
00712         if (mCursorActive)
00713         {
00714             mCursorTimer += _frame;
00715 
00716             if (mCursorTimer > EDIT_CURSOR_TIMER)
00717             {
00718                 mClientText->setVisibleCursor(!mClientText->isVisibleCursor());
00719                 while (mCursorTimer > EDIT_CURSOR_TIMER)
00720                     mCursorTimer -= EDIT_CURSOR_TIMER;
00721             }
00722         }
00723 
00724         // сдвигаем курсор по положению мыши
00725         if (mMouseLeftPressed)
00726         {
00727             mActionMouseTimer += _frame;
00728 
00729             if (mActionMouseTimer > EDIT_ACTION_MOUSE_TIMER)
00730             {
00731                 IntPoint mouse = InputManager::getInstance().getMousePositionByLayer();
00732                 const IntRect& view = mClient->getAbsoluteRect();
00733                 mouse.left -= view.left;
00734                 mouse.top -= view.top;
00735                 IntPoint point;
00736 
00737                 bool action = false;
00738 
00739                 // вверх на одну строчку
00740                 if ((mouse.top < 0) && (mouse.top > -EDIT_ACTION_MOUSE_ZONE))
00741                 {
00742                     if ((mouse.left > 0) && (mouse.left <= mClient->getWidth()))
00743                     {
00744                         point = mClientText->getCursorPoint(mCursorPosition);
00745                         point.top -= mClientText->getFontHeight();
00746                         action = true;
00747                     }
00748                 }
00749                 // вниз на одну строчку
00750                 else if ((mouse.top > mClient->getHeight()) && (mouse.top < (mClient->getHeight() + EDIT_ACTION_MOUSE_ZONE)))
00751                 {
00752                     if ((mouse.left > 0) && (mouse.left <= mClient->getWidth()))
00753                     {
00754                         point = mClientText->getCursorPoint(mCursorPosition);
00755                         point.top += mClientText->getFontHeight();
00756                         action = true;
00757                     }
00758                 }
00759 
00760                 // влево на небольшое расстояние
00761                 if ((mouse.left < 0) && (mouse.left > -EDIT_ACTION_MOUSE_ZONE))
00762                 {
00763                     point = mClientText->getCursorPoint(mCursorPosition);
00764                     point.left -= (int)EDIT_OFFSET_HORZ_CURSOR;
00765                     action = true;
00766                 }
00767                 // вправо на небольшое расстояние
00768                 else if ((mouse.left > mClient->getWidth()) && (mouse.left < (mClient->getWidth() + EDIT_ACTION_MOUSE_ZONE)))
00769                 {
00770                     point = mClientText->getCursorPoint(mCursorPosition);
00771                     point.left += (int)EDIT_OFFSET_HORZ_CURSOR;
00772                     action = true;
00773                 }
00774 
00775                 if (action)
00776                 {
00777                     size_t old = mCursorPosition;
00778                     mCursorPosition = mClientText->getCursorPosition(point);
00779 
00780                     if (old != mCursorPosition)
00781                     {
00782                         mClientText->setCursorPosition(mCursorPosition);
00783 
00784                         mEndSelect = (size_t)mCursorPosition;
00785                         if (mStartSelect > mEndSelect)
00786                             mClientText->setTextSelection(mEndSelect, mStartSelect);
00787                         else
00788                             mClientText->setTextSelection(mStartSelect, mEndSelect);
00789 
00790                         // пытаемся показать курсор
00791                         updateViewWithCursor();
00792                     }
00793                 }
00794                 // если в зону не попадает то сбрасываем
00795                 else
00796                 {
00797                     mActionMouseTimer = 0;
00798                 }
00799 
00800                 while (mActionMouseTimer > EDIT_ACTION_MOUSE_TIMER)
00801                     mActionMouseTimer -= EDIT_ACTION_MOUSE_TIMER;
00802             }
00803 
00804         } // if (mMouseLeftPressed)
00805     }
00806 
00807     void EditBox::setTextCursor(size_t _index)
00808     {
00809         // сбрасываем выделение
00810         resetSelect();
00811 
00812         // новая позиция
00813         if (_index > mTextLength)
00814             _index = mTextLength;
00815 
00816         if (mCursorPosition == _index)
00817             return;
00818 
00819         mCursorPosition = _index;
00820 
00821         // обновляем по позиции
00822         if (mClientText != nullptr)
00823             mClientText->setCursorPosition(mCursorPosition);
00824 
00825         updateSelectText();
00826     }
00827 
00828     void EditBox::setTextSelection(size_t _start, size_t _end)
00829     {
00830         if (_start > mTextLength)
00831             _start = mTextLength;
00832         if (_end > mTextLength)
00833             _end = mTextLength;
00834 
00835         mStartSelect = _start;
00836         mEndSelect = _end;
00837 
00838         if (mClientText != nullptr)
00839         {
00840             if (mStartSelect > mEndSelect)
00841                 mClientText->setTextSelection(mEndSelect, mStartSelect);
00842             else
00843                 mClientText->setTextSelection(mStartSelect, mEndSelect);
00844         }
00845 
00846         if (mCursorPosition == mEndSelect)
00847             return;
00848         // курсор на конец выделения
00849         mCursorPosition = mEndSelect;
00850 
00851         // обновляем по позиции
00852         if (mClientText != nullptr)
00853             mClientText->setCursorPosition(mCursorPosition);
00854     }
00855 
00856     bool EditBox::deleteTextSelect(bool _history)
00857     {
00858         if (!isTextSelection())
00859             return false;
00860 
00861         // начало и конец выделения
00862         size_t start = getTextSelectionStart();
00863         size_t end =  getTextSelectionEnd();
00864 
00865         eraseText(start, end - start, _history);
00866 
00867         return true;
00868     }
00869 
00870     void EditBox::resetSelect()
00871     {
00872         if (mStartSelect != ITEM_NONE)
00873         {
00874             mStartSelect = ITEM_NONE;
00875             if (mClientText != nullptr)
00876                 mClientText->setTextSelection(0, 0);
00877         }
00878     }
00879 
00880     void EditBox::commandPosition(size_t _undo, size_t _redo, size_t _length, VectorChangeInfo* _info)
00881     {
00882         if (_info != nullptr)
00883             _info->push_back(TextCommandInfo(_undo, _redo, _length));
00884     }
00885 
00886     void EditBox::commandMerge()
00887     {
00888         if (mVectorUndoChangeInfo.size() < 2)
00889             return; // на всякий
00890         // сохраняем последние набор отмен
00891         VectorChangeInfo info = mVectorUndoChangeInfo.back();
00892         mVectorUndoChangeInfo.pop_back();
00893 
00894         // объединяем последовательности
00895         for (VectorChangeInfo::iterator iter = info.begin(); iter != info.end(); ++iter)
00896         {
00897             mVectorUndoChangeInfo.back().push_back((*iter));
00898         }
00899     }
00900 
00901     bool EditBox::commandUndo()
00902     {
00903         if (mVectorUndoChangeInfo.empty())
00904             return false;
00905 
00906         // сбрасываем выделение
00907         resetSelect();
00908 
00909         // сохраняем последние набор отмен
00910         VectorChangeInfo info = mVectorUndoChangeInfo.back();
00911         // перекидываем последний набор отмен
00912         mVectorUndoChangeInfo.pop_back();
00913         mVectorRedoChangeInfo.push_back(info);
00914 
00915         // берем текст для издевательств
00916         UString text = getRealString();
00917 
00918         // восстанавливаем последовательность
00919         for (VectorChangeInfo::reverse_iterator iter = info.rbegin(); iter != info.rend(); ++iter)
00920         {
00921             if ((*iter).type == TextCommandInfo::COMMAND_INSERT)
00922                 text.erase((*iter).start, (*iter).text.size());
00923             else if ((*iter).type == TextCommandInfo::COMMAND_ERASE)
00924                 text.insert((*iter).start, (*iter).text);
00925             else
00926             {
00927                 mCursorPosition = (*iter).undo;
00928                 mTextLength = (*iter).length;
00929             }
00930         }
00931 
00932         // возвращаем текст
00933         setRealString(text);
00934 
00935         // обновляем по позиции
00936         if (mClientText != nullptr)
00937             mClientText->setCursorPosition(mCursorPosition);
00938         updateSelectText();
00939 
00940         // отсылаем событие о изменении
00941         eventEditTextChange(this);
00942 
00943         return true;
00944     }
00945 
00946     bool EditBox::commandRedo()
00947     {
00948         if (mVectorRedoChangeInfo.empty())
00949             return false;
00950 
00951         // сбрасываем выделение
00952         resetSelect();
00953 
00954         // сохраняем последние набор отмен
00955         VectorChangeInfo info = mVectorRedoChangeInfo.back();
00956         // перекидываем последний набор отмен
00957         mVectorRedoChangeInfo.pop_back();
00958         mVectorUndoChangeInfo.push_back(info);
00959 
00960         // берем текст для издевательств
00961         UString text = getRealString();
00962 
00963         // восстанавливаем последовательность
00964         for (VectorChangeInfo::iterator iter = info.begin(); iter != info.end(); ++iter)
00965         {
00966             if ((*iter).type == TextCommandInfo::COMMAND_INSERT)
00967                 text.insert((*iter).start, (*iter).text);
00968             else if ((*iter).type == TextCommandInfo::COMMAND_ERASE)
00969                 text.erase((*iter).start, (*iter).text.size());
00970             else
00971             {
00972                 mCursorPosition = (*iter).redo;
00973                 mTextLength = (*iter).length;
00974             }
00975 
00976         }
00977 
00978         // возвращаем текст
00979         setRealString(text);
00980 
00981         // обновляем по позиции
00982         if (mClientText != nullptr)
00983             mClientText->setCursorPosition(mCursorPosition);
00984         updateSelectText();
00985 
00986         // отсылаем событие о изменении
00987         eventEditTextChange(this);
00988 
00989         return true;
00990     }
00991 
00992     void EditBox::saveInHistory(VectorChangeInfo* _info)
00993     {
00994         if (_info == nullptr)
00995             return;
00996         // если нет информации об изменении
00997         if ( _info->empty())
00998             return;
00999         if ((_info->size() == 1) && (_info->back().type == TextCommandInfo::COMMAND_POSITION))
01000             return;
01001 
01002         mVectorUndoChangeInfo.push_back(*_info);
01003         // проверяем на максимальный размер
01004         if (mVectorUndoChangeInfo.size() > EDIT_MAX_UNDO)
01005             mVectorUndoChangeInfo.pop_front();
01006     }
01007 
01008     // возвращает текст
01009     UString EditBox::getTextInterval(size_t _start, size_t _count)
01010     {
01011         // подстраховка
01012         if (_start > mTextLength) _start = mTextLength;
01013         // конец диапазона
01014         size_t end = _start + _count;
01015 
01016         // итератор нашей строки
01017         TextIterator iterator(getRealString());
01018 
01019         // дефолтный цвет
01020         UString colour = mClientText == nullptr ? "" : TextIterator::convertTagColour(mClientText->getTextColour());
01021 
01022         // нужно ли вставлять цвет
01023         bool need_colour = true;
01024 
01025         // цикл прохода по строке
01026         while (iterator.moveNext())
01027         {
01028             // текущаяя позиция
01029             size_t pos = iterator.getPosition();
01030 
01031             // еще рано
01032             if (pos < _start)
01033             {
01034                 // берем цвет из позиции и запоминаем
01035                 iterator.getTagColour(colour);
01036 
01037                 continue;
01038             }
01039 
01040             // проверяем на надобность начального тега
01041             else if (pos == _start)
01042             {
01043                 need_colour = ! iterator.getTagColour(colour);
01044                 // сохраняем место откуда начинается
01045                 iterator.saveStartPoint();
01046 
01047             }
01048 
01049             // а теперь просто до конца диапазона
01050             else if (pos == end)
01051                 break;
01052 
01053         }
01054 
01055         // возвращаем строку
01056         if (need_colour)
01057             return colour + iterator.getFromStart();
01058         return iterator.getFromStart();
01059     }
01060 
01061     // выделяет цветом диапазон
01062     void EditBox::_setTextColour(size_t _start, size_t _count, const Colour& _colour, bool _history)
01063     {
01064         // история изменений
01065         VectorChangeInfo* history = nullptr;
01066         if (_history)
01067             history = new VectorChangeInfo();
01068 
01069         // конец диапазона
01070         size_t end = _start + _count;
01071 
01072         // итератор нашей строки
01073         TextIterator iterator(getRealString(), history);
01074 
01075         // дефолтный цвет
01076         UString colour = mClientText == nullptr ? "" : TextIterator::convertTagColour(mClientText->getTextColour());
01077 
01078         // цикл прохода по строке
01079         while (iterator.moveNext())
01080         {
01081             // текущаяя позиция
01082             size_t pos = iterator.getPosition();
01083 
01084             // берем цвет из позиции и запоминаем
01085             iterator.getTagColour(colour);
01086 
01087             // еще рано
01088             if (pos < _start)
01089                 continue;
01090 
01091             // ставим начальный тег
01092             else if (pos == _start)
01093                 iterator.setTagColour(_colour);
01094 
01095             // внутри диапазона очищаем все
01096             else if (pos < end)
01097                 iterator.clearTagColour();
01098 
01099             // на конец ставим последний найденный или дефолтный
01100             else if (pos == end)
01101             {
01102                 iterator.setTagColour(colour);
01103                 // и выходим из цикла
01104                 break;
01105             }
01106 
01107         }
01108 
01109         // сохраняем позицию для восстановления курсора
01110         commandPosition(_start, _start + _count, mTextLength, history);
01111 
01112         // запоминаем в историю
01113         if (_history)
01114         {
01115             saveInHistory(history);
01116             delete history;
01117         }
01118         // сбрасываем историю
01119         else
01120             commandResetHistory();
01121 
01122         // и возвращаем строку на место
01123         setRealString(iterator.getText());
01124     }
01125 
01126     void EditBox::setTextSelectColour(const Colour& _colour, bool _history)
01127     {
01128         // нужно выделение
01129         if ( !isTextSelection())
01130             return;
01131         // начало и конец выделения
01132         size_t start = getTextSelectionStart();
01133         size_t end =  getTextSelectionEnd();
01134         _setTextColour(start, end - start, _colour, _history);
01135     }
01136 
01137     UString EditBox::getTextSelection()
01138     {
01139         if ( !isTextSelection())
01140             return "";
01141         size_t start = getTextSelectionStart();
01142         size_t end =  getTextSelectionEnd();
01143         return getTextInterval(start, end - start);
01144     }
01145 
01146     void EditBox::setEditPassword(bool _password)
01147     {
01148         if (mModePassword == _password)
01149             return;
01150         mModePassword = _password;
01151 
01152         if (mModePassword)
01153         {
01154             if (mClientText != nullptr)
01155             {
01156                 mPasswordText = mClientText->getCaption();
01157                 mClientText->setCaption(UString(mTextLength, '*'));
01158             }
01159         }
01160         else
01161         {
01162             if (mClientText != nullptr)
01163             {
01164                 mClientText->setCaption(mPasswordText);
01165                 mPasswordText.clear();
01166             }
01167         }
01168         // обновляем по размерам
01169         updateView();
01170         // сбрасываем историю
01171         commandResetHistory();
01172     }
01173 
01174     void EditBox::setText(const UString& _caption, bool _history)
01175     {
01176         // сбрасываем выделение
01177         resetSelect();
01178 
01179         // история изменений
01180         VectorChangeInfo* history = nullptr;
01181         if (_history)
01182             history = new VectorChangeInfo();
01183 
01184         // итератор нашей строки
01185         TextIterator iterator(getRealString(), history);
01186 
01187         // вставляем текст
01188         iterator.setText(_caption, mModeMultiline || mModeWordWrap);
01189 
01190         if (mOverflowToTheLeft)
01191         {
01192             iterator.cutMaxLengthFromBeginning(mMaxTextLength);
01193         }
01194         else
01195         {
01196             // обрезаем по максимальной длинне
01197             iterator.cutMaxLength(mMaxTextLength);
01198         }
01199 
01200         // запоминаем размер строки
01201         size_t old = mTextLength;
01202         // новая позиция и положение на конец вставки
01203         mCursorPosition = mTextLength = iterator.getSize();
01204 
01205         // сохраняем позицию для восстановления курсора
01206         commandPosition(0, mTextLength, old, history);
01207 
01208         // запоминаем в историю
01209         if (_history)
01210         {
01211             saveInHistory(history);
01212             delete history;
01213         }
01214         // сбрасываем историю
01215         else
01216             commandResetHistory();
01217 
01218         // и возвращаем строку на место
01219         setRealString(iterator.getText());
01220 
01221         // обновляем по позиции
01222         if (mClientText != nullptr)
01223             mClientText->setCursorPosition(mCursorPosition);
01224         updateSelectText();
01225     }
01226 
01227     void EditBox::insertText(const UString& _text, size_t _start, bool _history)
01228     {
01229         // сбрасываем выделение
01230         resetSelect();
01231 
01232         // если строка пустая, или размер максимален
01233         if (_text.empty())
01234             return;
01235 
01236         if ((mOverflowToTheLeft == false) && (mTextLength == mMaxTextLength))
01237             return;
01238 
01239         // история изменений
01240         VectorChangeInfo* history = nullptr;
01241         if (_history)
01242             history = new VectorChangeInfo();
01243 
01244         // итератор нашей строки
01245         TextIterator iterator(getRealString(), history);
01246 
01247         // дефолтный цвет
01248         UString colour = mClientText == nullptr ? "" : TextIterator::convertTagColour(mClientText->getTextColour());
01249         // нужен ли тег текста
01250         // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
01251         bool need_colour = ( (_text.size() > 6) && (_text[0] == L'#') && (_text[1] != L'#') );
01252 
01253         // цикл прохода по строке
01254         while (iterator.moveNext())
01255         {
01256             // текущаяя позиция
01257             size_t pos = iterator.getPosition();
01258 
01259             // текущий цвет
01260             if (need_colour)
01261                 iterator.getTagColour(colour);
01262 
01263             // если дошли то выходим
01264             if (pos == _start)
01265                 break;
01266         }
01267 
01268         // если нужен цвет то вставляем
01269         if (need_colour)
01270             iterator.setTagColour(colour);
01271 
01272         // а теперь вставляем строку
01273         iterator.insertText(_text, mModeMultiline || mModeWordWrap);
01274 
01275         if (mOverflowToTheLeft)
01276         {
01277             iterator.cutMaxLengthFromBeginning(mMaxTextLength);
01278         }
01279         else
01280         {
01281             // обрезаем по максимальной длинне
01282             iterator.cutMaxLength(mMaxTextLength);
01283         }
01284 
01285         // запоминаем размер строки
01286         size_t old = mTextLength;
01287         // новая позиция и положение на конец вставки
01288         mTextLength = iterator.getSize();
01289         mCursorPosition += mTextLength - old;
01290 
01291         // сохраняем позицию для восстановления курсора
01292         commandPosition(_start, _start + mTextLength - old, old, history);
01293 
01294         // запоминаем в историю
01295         if (_history)
01296         {
01297             saveInHistory(history);
01298             delete history;
01299         }
01300         // сбрасываем историю
01301         else
01302             commandResetHistory();
01303 
01304         // и возвращаем строку на место
01305         setRealString(iterator.getText());
01306 
01307         // обновляем по позиции
01308         if (mClientText != nullptr)
01309             mClientText->setCursorPosition(mCursorPosition);
01310         updateSelectText();
01311     }
01312 
01313     void EditBox::eraseText(size_t _start, size_t _count, bool _history)
01314     {
01315         // чета маловато
01316         if (_count == 0)
01317             return;
01318 
01319         // сбрасываем выделение
01320         resetSelect();
01321 
01322         // история изменений
01323         VectorChangeInfo* history = nullptr;
01324         if (_history)
01325             history = new VectorChangeInfo();
01326 
01327         // итератор нашей строки
01328         TextIterator iterator(getRealString(), history);
01329 
01330         // дефолтный цвет
01331         UString colour;
01332         // конец диапазона
01333         size_t end = _start + _count;
01334         bool need_colour = false;
01335 
01336         // цикл прохода по строке
01337         while (iterator.moveNext())
01338         {
01339             // текущаяя позиция
01340             size_t pos = iterator.getPosition();
01341 
01342             // еще рано
01343             if (pos < _start)
01344             {
01345                 // берем цвет из позиции и запоминаем
01346                 iterator.getTagColour(colour);
01347                 continue;
01348             }
01349 
01350             // сохраняем место откуда начинается
01351             else if (pos == _start)
01352             {
01353                 // если до диапазона был цвет, то нужно закрыть тег
01354                 if (!colour.empty())
01355                 {
01356                     need_colour = true;
01357                     colour.clear();
01358                 }
01359                 // берем цвет из позиции и запоминаем
01360                 iterator.getTagColour(colour);
01361                 iterator.saveStartPoint();
01362             }
01363 
01364             // внутри диапазона
01365             else if (pos < end)
01366             {
01367                 // берем цвет из позиции и запоминаем
01368                 iterator.getTagColour(colour);
01369             }
01370 
01371             // окончание диапазона
01372             else if (pos == end)
01373             {
01374                 // нужно ставить тег или нет
01375                 if (!colour.empty())
01376                     need_colour = true;
01377                 if (iterator.getTagColour(colour))
01378                     need_colour = false;
01379 
01380                 break;
01381             }
01382 
01383         }
01384 
01385         // удаляем диапазон
01386         iterator.eraseFromStart();
01387         // и вставляем последний цвет
01388         if (need_colour)
01389             iterator.setTagColour(colour);
01390 
01391         // сохраняем позицию для восстановления курсора
01392         commandPosition(_start + _count, _start, mTextLength, history);
01393 
01394         // на месте удаленного
01395         mCursorPosition = _start;
01396         mTextLength -= _count;
01397 
01398         // запоминаем в историю
01399         if (_history)
01400         {
01401             saveInHistory(history);
01402             delete history;
01403         }
01404         // сбрасываем историю
01405         else
01406             commandResetHistory();
01407 
01408         // и возвращаем строку на место
01409         setRealString(iterator.getText());
01410 
01411         // обновляем по позиции
01412         if (mClientText != nullptr)
01413             mClientText->setCursorPosition(mCursorPosition);
01414         updateSelectText();
01415     }
01416 
01417     void EditBox::commandCut()
01418     {
01419         // вырезаем в буфер обмена
01420         if (isTextSelection() && (!mModePassword))
01421         {
01422             ClipboardManager::getInstance().setClipboardData(EDIT_CLIPBOARD_TYPE_TEXT, getTextSelection());
01423             if (!mModeReadOnly)
01424             {
01425                 deleteTextSelect(true);
01426                 // отсылаем событие о изменении
01427                 eventEditTextChange(this);
01428             }
01429         }
01430         else
01431             ClipboardManager::getInstance().clearClipboardData(EDIT_CLIPBOARD_TYPE_TEXT);
01432     }
01433 
01434     void EditBox::commandCopy()
01435     {
01436         // копируем в буфер обмена
01437         if (isTextSelection() && (!mModePassword))
01438             ClipboardManager::getInstance().setClipboardData(EDIT_CLIPBOARD_TYPE_TEXT, getTextSelection());
01439         else
01440             ClipboardManager::getInstance().clearClipboardData(EDIT_CLIPBOARD_TYPE_TEXT);
01441     }
01442 
01443     void EditBox::commandPast()
01444     {
01445         // копируем из буфера обмена
01446         std::string clipboard = ClipboardManager::getInstance().getClipboardData(EDIT_CLIPBOARD_TYPE_TEXT);
01447         if ((!mModeReadOnly) && (!clipboard.empty()))
01448         {
01449             // попытка объединения двух комманд
01450             size_t size = mVectorUndoChangeInfo.size();
01451             // непосредственно операции
01452             deleteTextSelect(true);
01453             insertText(clipboard, mCursorPosition, true);
01454             // проверяем на возможность объединения
01455             if ((size + 2) == mVectorUndoChangeInfo.size())
01456                 commandMerge();
01457             // отсылаем событие о изменении
01458             eventEditTextChange(this);
01459         }
01460     }
01461 
01462     const UString& EditBox::getRealString()
01463     {
01464         if (mModePassword)
01465             return mPasswordText;
01466         else if (mClientText == nullptr)
01467             return mPasswordText;
01468 
01469         return mClientText->getCaption();
01470     }
01471 
01472     void EditBox::setRealString(const UString& _caption)
01473     {
01474         if (mModePassword)
01475         {
01476             mPasswordText = _caption;
01477             if (mClientText != nullptr)
01478                 mClientText->setCaption(UString(mTextLength, (UString::code_point)mCharPassword));
01479         }
01480         else
01481         {
01482             if (mClientText != nullptr)
01483                 mClientText->setCaption(_caption);
01484         }
01485     }
01486 
01487     void EditBox::setPasswordChar(Char _char)
01488     {
01489         mCharPassword = _char;
01490         if (mModePassword)
01491         {
01492             if (mClientText != nullptr)
01493                 mClientText->setCaption(UString(mTextLength, (UString::code_point)mCharPassword));
01494         }
01495     }
01496 
01497     void EditBox::updateEditState()
01498     {
01499         if (!getInheritedEnabled())
01500         {
01501             _setWidgetState("disabled");
01502         }
01503         else if (mIsPressed)
01504         {
01505             if (mIsFocus)
01506                 _setWidgetState("pushed");
01507             else
01508                 _setWidgetState("normal_checked");
01509         }
01510         else if (mIsFocus)
01511         {
01512             _setWidgetState("highlighted");
01513         }
01514         else
01515         {
01516             _setWidgetState("normal");
01517         }
01518     }
01519 
01520     void EditBox::setPosition(const IntPoint& _point)
01521     {
01522         Base::setPosition(_point);
01523     }
01524 
01525     void EditBox::eraseView()
01526     {
01527         // если перенос, то сбрасываем размер текста
01528         if (mModeWordWrap)
01529         {
01530             if (mClientText != nullptr)
01531                 mClientText->setWordWrap(true);
01532         }
01533 
01534         updateView();
01535     }
01536 
01537     void EditBox::setSize(const IntSize& _size)
01538     {
01539         Base::setSize(_size);
01540 
01541         eraseView();
01542     }
01543 
01544     void EditBox::setCoord(const IntCoord& _coord)
01545     {
01546         Base::setCoord(_coord);
01547 
01548         eraseView();
01549     }
01550 
01551     void EditBox::setCaption(const UString& _value)
01552     {
01553         setText(_value, false);
01554     }
01555 
01556     const UString& EditBox::getCaption()
01557     {
01558         return getRealString();
01559     }
01560 
01561     void EditBox::updateSelectText()
01562     {
01563         if (!mModeStatic)
01564         {
01565             InputManager& input = InputManager::getInstance();
01566             if ((input.isShiftPressed()) && (mStartSelect != ITEM_NONE))
01567             {
01568                 // меняем выделение
01569                 mEndSelect = (size_t)mCursorPosition;
01570                 if (mClientText != nullptr)
01571                 {
01572                     if (mStartSelect > mEndSelect)
01573                         mClientText->setTextSelection(mEndSelect, mStartSelect);
01574                     else
01575                         mClientText->setTextSelection(mStartSelect, mEndSelect);
01576                 }
01577 
01578             }
01579             else if (mStartSelect != ITEM_NONE)
01580             {
01581                 // сбрасываем шифт
01582                 mStartSelect = ITEM_NONE;
01583                 if (mClientText != nullptr)
01584                     mClientText->setTextSelection(0, 0);
01585             }
01586         }
01587 
01588         // пытаемся показать курсор
01589         updateViewWithCursor();
01590     }
01591 
01592     void EditBox::setTextAlign(Align _value)
01593     {
01594         Base::setTextAlign(_value);
01595 
01596         if (mClientText != nullptr)
01597             mClientText->setTextAlign(_value);
01598 
01599         // так как мы сами рулим смещениями
01600         updateView();
01601     }
01602 
01603     void EditBox::setTextColour(const Colour& _value)
01604     {
01605         Base::setTextColour(_value);
01606 
01607         if (mClientText != nullptr)
01608             mClientText->setTextColour(_value);
01609     }
01610 
01611     IntCoord EditBox::getTextRegion()
01612     {
01613         if (mClientText != nullptr)
01614             return mClientText->getCoord();
01615         return Base::getTextRegion();
01616     }
01617 
01618     IntSize EditBox::getTextSize()
01619     {
01620         if (mClientText != nullptr)
01621             return mClientText->getTextSize();
01622         return Base::getTextSize();
01623     }
01624 
01625     void EditBox::notifyScrollChangePosition(ScrollBar* _sender, size_t _position)
01626     {
01627         if (mClientText == nullptr)
01628             return;
01629 
01630         if (_sender == mVScroll)
01631         {
01632             IntPoint point = mClientText->getViewOffset();
01633             point.top = _position;
01634             mClientText->setViewOffset(point);
01635         }
01636         else if (_sender == mHScroll)
01637         {
01638             IntPoint point = mClientText->getViewOffset();
01639             point.left = _position;
01640             mClientText->setViewOffset(point);
01641         }
01642     }
01643 
01644     void EditBox::notifyMouseWheel(Widget* _sender, int _rel)
01645     {
01646         if (mClientText == nullptr)
01647             return;
01648 
01649         if (mVRange != 0)
01650         {
01651             IntPoint point = mClientText->getViewOffset();
01652             int offset = point.top;
01653             if (_rel < 0)
01654                 offset += EDIT_MOUSE_WHEEL;
01655             else
01656                 offset -= EDIT_MOUSE_WHEEL;
01657 
01658             if (offset < 0)
01659                 offset = 0;
01660             else if (offset > (int)mVRange)
01661                 offset = mVRange;
01662 
01663             if (offset != point.top)
01664             {
01665                 point.top = offset;
01666                 if (mVScroll != nullptr)
01667                     mVScroll->setScrollPosition(offset);
01668                 mClientText->setViewOffset(point);
01669             }
01670         }
01671         else if (mHRange != 0)
01672         {
01673             IntPoint point = mClientText->getViewOffset();
01674             int offset = point.left;
01675             if (_rel < 0)
01676                 offset += EDIT_MOUSE_WHEEL;
01677             else
01678                 offset -= EDIT_MOUSE_WHEEL;
01679 
01680             if (offset < 0)
01681                 offset = 0;
01682             else if (offset > (int)mHRange)
01683                 offset = mHRange;
01684 
01685             if (offset != point.left)
01686             {
01687                 point.left = offset;
01688                 if (mHScroll != nullptr)
01689                     mHScroll->setScrollPosition(offset);
01690                 mClientText->setViewOffset(point);
01691             }
01692         }
01693     }
01694 
01695     void EditBox::setEditWordWrap(bool _value)
01696     {
01697         mModeWordWrap = _value;
01698         if (mClientText != nullptr)
01699             mClientText->setWordWrap(mModeWordWrap);
01700 
01701         eraseView();
01702     }
01703 
01704     void EditBox::setFontName(const std::string& _value)
01705     {
01706         Base::setFontName(_value);
01707 
01708         if (mClientText != nullptr)
01709             mClientText->setFontName(_value);
01710 
01711         eraseView();
01712     }
01713 
01714     void EditBox::setFontHeight(int _value)
01715     {
01716         Base::setFontHeight(_value);
01717 
01718         if (mClientText != nullptr)
01719             mClientText->setFontHeight(_value);
01720 
01721         eraseView();
01722     }
01723 
01724     void EditBox::updateView()
01725     {
01726         updateScrollSize();
01727         updateScrollPosition();
01728     }
01729 
01730     void EditBox::updateViewWithCursor()
01731     {
01732         updateScrollSize();
01733         updateCursorPosition();
01734         updateScrollPosition();
01735     }
01736 
01737     void EditBox::updateCursorPosition()
01738     {
01739         if (mClientText == nullptr || mClient == nullptr)
01740             return;
01741 
01742         // размер контекста текста
01743         IntSize textSize = mClientText->getTextSize();
01744 
01745         // текущее смещение контекста текста
01746         IntPoint point = mClientText->getViewOffset();
01747         // расчетное смещение
01748         IntPoint offset = point;
01749 
01750         // абсолютные координаты курсора
01751         IntRect cursor = mClientText->getCursorRect(mCursorPosition);
01752         cursor.right ++;
01753 
01754         // абсолютные координаты вью
01755         const IntRect& view = mClient->getAbsoluteRect();
01756 
01757         // проверяем и показываем курсор
01758         if (!view.inside(cursor))
01759         {
01760             // горизонтальное смещение
01761             if (textSize.width > view.width())
01762             {
01763                 if (cursor.left < view.left)
01764                 {
01765                     offset.left = point.left - (view.left - cursor.left);
01766                     // добавляем смещение, только если курсор не перепрыгнет
01767                     if ((float(view.width()) - EDIT_OFFSET_HORZ_CURSOR) > EDIT_OFFSET_HORZ_CURSOR)
01768                         offset.left -= int(EDIT_OFFSET_HORZ_CURSOR);
01769                 }
01770                 else if (cursor.right > view.right)
01771                 {
01772                     offset.left = point.left + (cursor.right - view.right);
01773                     // добавляем смещение, только если курсор не перепрыгнет
01774                     if ((float(view.width()) - EDIT_OFFSET_HORZ_CURSOR) > EDIT_OFFSET_HORZ_CURSOR)
01775                         offset.left += int(EDIT_OFFSET_HORZ_CURSOR);
01776                 }
01777             }
01778 
01779             // вертикальное смещение
01780             if (textSize.height > view.height())
01781             {
01782                 int delta = 0;
01783                 if (cursor.height() > view.height())
01784                 {
01785                     // if text is bigger than edit height then place it in center
01786                     delta = ((cursor.bottom - view.bottom) - (view.top - cursor.top)) / 2;
01787                 }
01788                 else if (cursor.top < view.top)
01789                 {
01790                     delta = - (view.top - cursor.top);
01791                 }
01792                 else if (cursor.bottom > view.bottom)
01793                 {
01794                     delta = (cursor.bottom - view.bottom);
01795                 }
01796                 offset.top = point.top + delta;
01797             }
01798 
01799         }
01800 
01801         if (offset != point)
01802         {
01803             mClientText->setViewOffset(offset);
01804             // обновить скролы
01805             if (mVScroll != nullptr)
01806                 mVScroll->setScrollPosition(offset.top);
01807             if (mHScroll != nullptr)
01808                 mHScroll->setScrollPosition(offset.left);
01809         }
01810     }
01811 
01812     void EditBox::setContentPosition(const IntPoint& _point)
01813     {
01814         if (mClientText != nullptr)
01815             mClientText->setViewOffset(_point);
01816     }
01817 
01818     IntSize EditBox::getViewSize()
01819     {
01820         if (mClientText != nullptr)
01821             return mClientText->getSize();
01822         return ScrollViewBase::getViewSize();
01823     }
01824 
01825     IntSize EditBox::getContentSize()
01826     {
01827         if (mClientText != nullptr)
01828             return mClientText->getTextSize();
01829         return ScrollViewBase::getContentSize();
01830     }
01831 
01832     size_t EditBox::getVScrollPage()
01833     {
01834         if (mClientText != nullptr)
01835             return (size_t)mClientText->getFontHeight();
01836         return ScrollViewBase::getVScrollPage();
01837     }
01838 
01839     size_t EditBox::getHScrollPage()
01840     {
01841         if (mClientText != nullptr)
01842             return (size_t)mClientText->getFontHeight();
01843         return ScrollViewBase::getHScrollPage();
01844     }
01845 
01846     IntPoint EditBox::getContentPosition()
01847     {
01848         if (mClientText != nullptr)
01849             return mClientText->getViewOffset();
01850         return ScrollViewBase::getContentPosition();
01851     }
01852 
01853     Align EditBox::getContentAlign()
01854     {
01855         if (mClientText != nullptr)
01856             return mClientText->getTextAlign();
01857         return ScrollViewBase::getContentAlign();
01858     }
01859 
01860     void EditBox::setTextIntervalColour(size_t _start, size_t _count, const Colour& _colour)
01861     {
01862         _setTextColour(_start, _count, _colour, false);
01863     }
01864 
01865     size_t EditBox::getTextSelectionStart() const
01866     {
01867         return (mStartSelect == ITEM_NONE) ? ITEM_NONE : (mStartSelect > mEndSelect ? mEndSelect : mStartSelect);
01868     }
01869 
01870     size_t EditBox::getTextSelectionEnd() const
01871     {
01872         return (mStartSelect == ITEM_NONE) ? ITEM_NONE : (mStartSelect > mEndSelect ? mStartSelect : mEndSelect);
01873     }
01874 
01875     bool EditBox::isTextSelection() const
01876     {
01877         return (mStartSelect != ITEM_NONE) && (mStartSelect != mEndSelect);
01878     }
01879 
01880     void EditBox::deleteTextSelection()
01881     {
01882         deleteTextSelect(false);
01883     }
01884 
01885     void EditBox::setTextSelectionColour(const Colour& _colour)
01886     {
01887         setTextSelectColour(_colour, false);
01888     }
01889 
01890     size_t EditBox::getTextSelectionLength() const
01891     {
01892         return mEndSelect - mStartSelect;
01893     }
01894 
01895     void EditBox::setOnlyText(const UString& _text)
01896     {
01897         setText(TextIterator::toTagsString(_text), false);
01898     }
01899 
01900     UString EditBox::getOnlyText()
01901     {
01902         return TextIterator::getOnlyText(getRealString());
01903     }
01904 
01905     void EditBox::insertText(const UString& _text, size_t _index)
01906     {
01907         insertText(_text, _index, false);
01908     }
01909 
01910     void EditBox::addText(const UString& _text)
01911     {
01912         insertText(_text, ITEM_NONE, false);
01913     }
01914 
01915     void EditBox::eraseText(size_t _start, size_t _count)
01916     {
01917         eraseText(_start, _count, false);
01918     }
01919 
01920     void EditBox::setEditReadOnly(bool _value)
01921     {
01922         mModeReadOnly = _value;
01923         // сбрасываем историю
01924         commandResetHistory();
01925     }
01926 
01927     void EditBox::setEditMultiLine(bool _value)
01928     {
01929         mModeMultiline = _value;
01930         // на всякий, для убирания переносов
01931         if (!mModeMultiline)
01932         {
01933             setText(getRealString(), false);
01934         }
01935         // обновляем по размерам
01936         else
01937         {
01938             updateView();
01939         }
01940         // сбрасываем историю
01941         commandResetHistory();
01942     }
01943 
01944     void EditBox::setEditStatic(bool _value)
01945     {
01946         mModeStatic = _value;
01947         resetSelect();
01948 
01949         if (mClient != nullptr)
01950         {
01951             if (mModeStatic)
01952                 mClient->setPointer("");
01953             else
01954                 mClient->setPointer(mOriginalPointer);
01955         }
01956     }
01957 
01958     void EditBox::setPasswordChar(const UString& _value)
01959     {
01960         if (!_value.empty())
01961             setPasswordChar(_value[0]);
01962     }
01963 
01964     void EditBox::setVisibleVScroll(bool _value)
01965     {
01966         mVisibleVScroll = _value;
01967         updateView();
01968     }
01969 
01970     void EditBox::setVisibleHScroll(bool _value)
01971     {
01972         mVisibleHScroll = _value;
01973         updateView();
01974     }
01975 
01976     size_t EditBox::getVScrollRange() const
01977     {
01978         return mVRange + 1;
01979     }
01980 
01981     size_t EditBox::getVScrollPosition()
01982     {
01983         return mClientText == nullptr ? 0 : mClientText->getViewOffset().top;
01984     }
01985 
01986     void EditBox::setVScrollPosition(size_t _index)
01987     {
01988         if (mClientText == nullptr)
01989             return;
01990 
01991         if (_index > mVRange)
01992             _index = mVRange;
01993 
01994         IntPoint point = mClientText->getViewOffset();
01995         point.top = _index;
01996 
01997         mClientText->setViewOffset(point);
01998         // обновить скролы
01999         if (mVScroll != nullptr)
02000             mVScroll->setScrollPosition(point.top);
02001     }
02002 
02003     size_t EditBox::getHScrollRange() const
02004     {
02005         return mHRange + 1;
02006     }
02007 
02008     size_t EditBox::getHScrollPosition()
02009     {
02010         return mClientText == nullptr ? 0 : mClientText->getViewOffset().left;
02011     }
02012 
02013     void EditBox::setHScrollPosition(size_t _index)
02014     {
02015         if (mClientText == nullptr)
02016             return;
02017 
02018         if (_index > mHRange)
02019             _index = mHRange;
02020 
02021         IntPoint point = mClientText->getViewOffset();
02022         point.left = _index;
02023 
02024         mClientText->setViewOffset(point);
02025         // обновить скролы
02026         if (mHScroll != nullptr)
02027             mHScroll->setScrollPosition(point.left);
02028     }
02029 
02030     bool EditBox::getInvertSelected()
02031     {
02032         return mClientText == nullptr ? false : mClientText->getInvertSelected();
02033     }
02034 
02035     void EditBox::setInvertSelected(bool _value)
02036     {
02037         if (mClientText != nullptr)
02038             mClientText->setInvertSelected(_value);
02039     }
02040 
02041     void EditBox::setPropertyOverride(const std::string& _key, const std::string& _value)
02042     {
02044         if (_key == "CursorPosition")
02045             setTextCursor(utility::parseValue<size_t>(_value));
02046 
02048         else if (_key == "TextSelect")
02049             setTextSelection(utility::parseValue< types::TSize<size_t> >(_value).width, utility::parseValue< types::TSize<size_t> >(_value).height);
02050 
02052         else if (_key == "ReadOnly")
02053             setEditReadOnly(utility::parseValue<bool>(_value));
02054 
02056         else if (_key == "Password")
02057             setEditPassword(utility::parseValue<bool>(_value));
02058 
02060         else if (_key == "MultiLine")
02061             setEditMultiLine(utility::parseValue<bool>(_value));
02062 
02064         else if (_key == "PasswordChar")
02065             setPasswordChar(_value);
02066 
02068         else if (_key == "MaxTextLength")
02069             setMaxTextLength(utility::parseValue<size_t>(_value));
02070 
02072         else if (_key == "OverflowToTheLeft")
02073             setOverflowToTheLeft(utility::parseValue<bool>(_value));
02074 
02076         else if (_key == "Static")
02077             setEditStatic(utility::parseValue<bool>(_value));
02078 
02080         else if (_key == "VisibleVScroll")
02081             setVisibleVScroll(utility::parseValue<bool>(_value));
02082 
02084         else if (_key == "VisibleHScroll")
02085             setVisibleHScroll(utility::parseValue<bool>(_value));
02086 
02088         else if (_key == "WordWrap")
02089             setEditWordWrap(utility::parseValue<bool>(_value));
02090 
02092         else if (_key == "TabPrinting")
02093             setTabPrinting(utility::parseValue<bool>(_value));
02094 
02096         else if (_key == "InvertSelected")
02097             setInvertSelected(utility::parseValue<bool>(_value));
02098 
02099         else
02100         {
02101             Base::setPropertyOverride(_key, _value);
02102             return;
02103         }
02104 
02105         eventChangeProperty(this, _key, _value);
02106     }
02107 
02108     size_t EditBox::getTextCursor() const
02109     {
02110         return mCursorPosition;
02111     }
02112 
02113     size_t EditBox::getTextLength() const
02114     {
02115         return mTextLength;
02116     }
02117 
02118     void EditBox::setOverflowToTheLeft(bool _value)
02119     {
02120         mOverflowToTheLeft = _value;
02121     }
02122 
02123     bool EditBox::getOverflowToTheLeft() const
02124     {
02125         return mOverflowToTheLeft;
02126     }
02127 
02128     void EditBox::setMaxTextLength(size_t _value)
02129     {
02130         mMaxTextLength = _value;
02131     }
02132 
02133     size_t EditBox::getMaxTextLength() const
02134     {
02135         return mMaxTextLength;
02136     }
02137 
02138     bool EditBox::getEditReadOnly() const
02139     {
02140         return mModeReadOnly;
02141     }
02142 
02143     bool EditBox::getEditPassword() const
02144     {
02145         return mModePassword;
02146     }
02147 
02148     bool EditBox::getEditMultiLine() const
02149     {
02150         return mModeMultiline;
02151     }
02152 
02153     bool EditBox::getEditStatic() const
02154     {
02155         return mModeStatic;
02156     }
02157 
02158     Char EditBox::getPasswordChar() const
02159     {
02160         return mCharPassword;
02161     }
02162 
02163     bool EditBox::getEditWordWrap() const
02164     {
02165         return mModeWordWrap;
02166     }
02167 
02168     void EditBox::setTabPrinting(bool _value)
02169     {
02170         mTabPrinting = _value;
02171     }
02172 
02173     bool EditBox::getTabPrinting() const
02174     {
02175         return mTabPrinting;
02176     }
02177 
02178     void EditBox::setPosition(int _left, int _top)
02179     {
02180         setPosition(IntPoint(_left, _top));
02181     }
02182 
02183     void EditBox::setSize(int _width, int _height)
02184     {
02185         setSize(IntSize(_width, _height));
02186     }
02187 
02188     void EditBox::setCoord(int _left, int _top, int _width, int _height)
02189     {
02190         setCoord(IntCoord(_left, _top, _width, _height));
02191     }
02192 
02193     bool EditBox::isVisibleVScroll() const
02194     {
02195         return mVisibleVScroll;
02196     }
02197 
02198     bool EditBox::isVisibleHScroll() const
02199     {
02200         return mVisibleHScroll;
02201     }
02202 
02203     void EditBox::commandResetRedo()
02204     {
02205         mVectorRedoChangeInfo.clear();
02206     }
02207 
02208     void EditBox::commandResetHistory()
02209     {
02210         mVectorRedoChangeInfo.clear();
02211         mVectorUndoChangeInfo.clear();
02212     }
02213 
02214     void EditBox::setTextShadowColour(const Colour& _value)
02215     {
02216         Base::setTextShadowColour(_value);
02217 
02218         if (mClientText != nullptr)
02219             mClientText->setShadowColour(_value);
02220     }
02221 
02222     void EditBox::setTextShadow(bool _value)
02223     {
02224         Base::setTextShadow(_value);
02225 
02226         if (mClientText != nullptr)
02227             mClientText->setShadow(_value);
02228     }
02229 
02230 } // namespace MyGUI