00001 #include "gui_editbox.hpp"
00002 #include "gui_fontstring.hpp"
00003 #include "gui_texture.hpp"
00004 #include "gui_manager.hpp"
00005 #include "gui_sprite.hpp"
00006 #include "gui_event.hpp"
00007 #include "gui_out.hpp"
00008 #include "input.hpp"
00009 
00010 using namespace input;
00011 
00012 namespace gui
00013 {
00014 edit_box::edit_box(manager* pManager) : focus_frame(pManager),
00015     uiDisplayPos_(0), uiNumLetters_(0), uiMaxLetters_(-1), bNumericOnly_(false),
00016     bPositiveOnly_(false), bIntegerOnly_(false), bPasswordMode_(false),
00017     bMultiLine_(false), bArrowsIgnored_(false),
00018     pHighlight_(nullptr), mHighlightColor_(1.0f, 1.0f, 1.0f, 0.35f),
00019     uiSelectionStartPos_(0), uiSelectionEndPos_(0), bSelectedText_(false),
00020     pCarret_(nullptr), dBlinkSpeed_(0.5),
00021     mCarretTimer_(dBlinkSpeed_, periodic_timer::START_FIRST_TICK, false),
00022     uiMaxHistoryLines_(uint(-1)), pFontString_(nullptr),
00023     lTextInsets_({{0, 0, 0, 0}}), uiLastKeyPressed_(0u), dKeyRepeatSpeed_(0.03),
00024     mKeyRepeatTimer_(dKeyRepeatSpeed_, periodic_timer::START_FIRST_TICK, true)
00025 {
00026     lType_.push_back("EditBox");
00027 
00028     iterCarretPos_ = sUnicodeText_.begin();
00029 
00030     register_for_drag({"LeftButton"});
00031 }
00032 
00033 edit_box::~edit_box()
00034 {
00035     set_focus(false);
00036 }
00037 
00038 bool edit_box::can_use_script(const std::string& sScriptName) const
00039 {
00040     if (frame::can_use_script(sScriptName))
00041         return true;
00042     else if ((sScriptName == "OnChar") ||
00043         (sScriptName == "OnCursorChanged") ||
00044         (sScriptName == "OnEditFocusGained") ||
00045         (sScriptName == "OnEditFocusLost") ||
00046         (sScriptName == "OnEnterPressed") ||
00047         (sScriptName == "OnEscapePressed") ||
00048         (sScriptName == "OnSpacePressed") ||
00049         (sScriptName == "OnTabPressed") ||
00050         (sScriptName == "OnTextChanged") ||
00051         (sScriptName == "OnTextSet"))
00052         return true;
00053     else
00054         return false;
00055 }
00056 
00057 void edit_box::copy_from(uiobject* pObj)
00058 {
00059     focus_frame::copy_from(pObj);
00060 
00061     edit_box* pEditBox = dynamic_cast<edit_box*>(pObj);
00062 
00063     if (pEditBox)
00064     {
00065         this->set_max_letters(pEditBox->get_max_letters());
00066         this->set_blink_speed(pEditBox->get_blink_speed());
00067         this->set_numeric_only(pEditBox->is_numeric_only());
00068         this->set_positive_only(pEditBox->is_positive_only());
00069         this->set_integer_only(pEditBox->is_integer_only());
00070         this->enable_password_mode(pEditBox->is_password_mode_enabled());
00071         this->set_multi_line(pEditBox->is_multi_line());
00072         this->set_max_history_lines(pEditBox->get_max_history_lines());
00073         this->set_text_insets(pEditBox->get_text_insets());
00074 
00075         font_string* pFS = pEditBox->get_font_string();
00076         if (pFS)
00077         {
00078             this->create_font_string_();
00079 
00080             if (this->is_virtual())
00081                 pFontString_->set_virtual();
00082 
00083             pFontString_->set_name(pFS->get_name());
00084             if (!pManager_->add_uiobject(pFontString_))
00085             {
00086                 gui::out << gui::warning << "gui::" << lType_.back() << " : "
00087                     "Trying to add \""+pFS->get_name()+"\" to \""+sName_+"\",\n"
00088                     "but its name was already taken : \""+pFontString_->get_name()+"\". Skipped." << std::endl;
00089                 delete pFontString_; pFontString_ = nullptr;
00090             }
00091             else
00092             {
00093                 if (!is_virtual())
00094                     pFontString_->create_glue();
00095 
00096                 this->add_region(pFontString_);
00097                 pFontString_->copy_from(pFS);
00098 
00099                 if (!is_virtual())
00100                     pFontString_->enable_formatting(false);
00101 
00102                 pFontString_->notify_loaded();
00103             }
00104         }
00105     }
00106 }
00107 
00108 void edit_box::update(float fDelta)
00109 {
00110     frame::update(fDelta);
00111 
00112     if (bMouseDragged_)
00113     {
00114         uint uiPos = get_letter_id_at_(iMousePosX_, iMousePosY_);
00115         if (uiPos != uiSelectionEndPos_)
00116         {
00117             if (uiPos != uint(-1))
00118             {
00119                 highlight_text(uiSelectionStartPos_, uiPos);
00120                 iterCarretPos_ = sUnicodeText_.begin() + uiPos;
00121                 update_carret_position_();
00122             }
00123             else
00124             {
00125                 uint uiTemp = uiSelectionStartPos_;
00126                 unlight_text();
00127                 uiSelectionStartPos_ = uiTemp;
00128                 iterCarretPos_ = sUnicodeText_.begin() + uiSelectionStartPos_;
00129                 update_carret_position_();
00130             }
00131         }
00132     }
00133 
00134     if (bFocus_)
00135     {
00136         mCarretTimer_.update(fDelta);
00137 
00138         if (mCarretTimer_.ticks())
00139         {
00140             if (!pCarret_)
00141                 create_carret_();
00142 
00143             if (pCarret_)
00144             {
00145                 if (pCarret_->is_shown())
00146                     pCarret_->hide();
00147                 else
00148                     pCarret_->show();
00149             }
00150         }
00151     }
00152 
00153     if (bFocus_ && uiLastKeyPressed_ != 0u &&
00154         pManager_->get_input_manager()->key_is_down_long((key::code)uiLastKeyPressed_, true))
00155     {
00156         if (mKeyRepeatTimer_.is_paused())
00157             mKeyRepeatTimer_.start();
00158 
00159         mKeyRepeatTimer_.update(fDelta);
00160 
00161         if (mKeyRepeatTimer_.ticks())
00162             process_key_(uiLastKeyPressed_);
00163     }
00164 }
00165 
00166 void edit_box::on_event(const event& mEvent)
00167 {
00168     frame::on_event(mEvent);
00169 
00170     if (!pManager_->is_input_enabled())
00171         return;
00172 
00173     if (mEvent.get_name() == "TEXT_ENTERED" && bFocus_)
00174     {
00175         char32_t c = mEvent.get(0)->get<char32_t>();
00176         if (add_char_(c))
00177         {
00178             event mKeyEvent;
00179             mKeyEvent.add(utils::unicode_to_UTF8(utils::ustring(1, c)));
00180             on("Char", &mKeyEvent);
00181         }
00182         return;
00183     }
00184 
00185     if (mEvent.get_name() == "MOUSE_PRESSED" && bMouseInFrame_)
00186     {
00187         set_focus(true);
00188         unlight_text();
00189 
00190         move_carret_at_(iMousePosX_, iMousePosY_);
00191         return;
00192     }
00193 
00194     if (mEvent.get_name() == "KEY_PRESSED" && bFocus_)
00195     {
00196         uint uiChar = mEvent[0].get<uint>();
00197         if (uiChar == key::K_RETURN || uiChar == key::K_NUMPADENTER)
00198             on("EnterPressed");
00199         else if (uiChar == key::K_END)
00200         {
00201             uint uiPreviousCarretPos = iterCarretPos_ - sUnicodeText_.begin();
00202 
00203             iterCarretPos_ = sUnicodeText_.end();
00204             update_carret_position_();
00205 
00206             if (pManager_->get_input_manager()->shift_is_pressed())
00207             {
00208                 if (bSelectedText_)
00209                     highlight_text(uiSelectionStartPos_, iterCarretPos_ - sUnicodeText_.begin());
00210                 else
00211                     highlight_text(uiPreviousCarretPos, iterCarretPos_ - sUnicodeText_.begin());
00212             }
00213             else
00214                 unlight_text();
00215 
00216             return;
00217         }
00218         else if (uiChar == key::K_HOME)
00219         {
00220             uint uiPreviousCarretPos = iterCarretPos_ - sUnicodeText_.begin();
00221 
00222             iterCarretPos_ = sUnicodeText_.begin();
00223             update_carret_position_();
00224 
00225             if (pManager_->get_input_manager()->shift_is_pressed())
00226             {
00227                 if (bSelectedText_)
00228                     highlight_text(uiSelectionStartPos_, iterCarretPos_ - sUnicodeText_.begin());
00229                 else
00230                     highlight_text(uiPreviousCarretPos, iterCarretPos_ - sUnicodeText_.begin());
00231             }
00232             else
00233                 unlight_text();
00234 
00235             return;
00236         }
00237         else if (uiChar == key::K_TAB)
00238             on("TabPressed");
00239         else if (uiChar == key::K_SPACE)
00240             on("SpacePressed");
00241 
00242         uiLastKeyPressed_ = uiChar;
00243 
00244         process_key_(uiChar);
00245     }
00246     else if (mEvent.get_name() == "KEY_RELEASED")
00247     {
00248         uint uiChar = mEvent[0].get<uint>();
00249 
00250         if (uiChar == key::K_ESCAPE)
00251         {
00252             on("EscapePressed");
00253             return;
00254         }
00255 
00256         if (uiChar == uiLastKeyPressed_)
00257         {
00258             uiLastKeyPressed_ = 0u;
00259             mKeyRepeatTimer_.stop();
00260         }
00261     }
00262 }
00263 
00264 void edit_box::enable_keyboard(bool bIsKeyboardEnabled)
00265 {
00266     if (!bVirtual_)
00267     {
00268         if (bIsKeyboardEnabled && !bIsKeyboardEnabled_)
00269             event_receiver::register_event("TEXT_ENTERED");
00270         else if (!bIsKeyboardEnabled && bIsKeyboardEnabled_)
00271             event_receiver::unregister_event("TEXT_ENTERED");
00272     }
00273 
00274     frame::enable_keyboard(bIsKeyboardEnabled);
00275 }
00276 
00277 void edit_box::on(const std::string& sScriptName, event* pEvent)
00278 {
00279     if (bFocus_ && (sScriptName == "KeyUp" || sScriptName == "KeyDown"))
00280         return;
00281 
00282     if (lDefinedScriptList_.find(sScriptName) != lDefinedScriptList_.end())
00283     {
00284         utils::wptr<lua::state> pLua = pManager_->get_lua();
00285 
00286         if (sScriptName == "Char")
00287         {
00288             
00289             if (pEvent)
00290             {
00291                 pLua->push_string(pEvent->get(0)->get<std::string>());
00292                 pLua->set_global("arg1");
00293             }
00294         }
00295     }
00296 
00297     frame::on(sScriptName, pEvent);
00298 
00299     if (sScriptName == "SizeChanged")
00300     {
00301         update_displayed_text_();
00302         update_font_string_();
00303         update_carret_position_();
00304     }
00305 
00306     if (sScriptName == "DragStart")
00307         uiSelectionEndPos_ = uiSelectionStartPos_ = get_letter_id_at_(iMousePosX_, iMousePosY_);
00308 }
00309 
00310 void edit_box::create_glue()
00311 {
00312     if (bVirtual_)
00313     {
00314         utils::wptr<lua::state> pLua = pManager_->get_lua();
00315         pLua->push_number(uiID_);
00316         lGlueList_.push_back(pLua->push_new<lua_virtual_glue>());
00317         pLua->set_global(sLuaName_);
00318         pLua->pop();
00319     }
00320     else
00321     {
00322         utils::wptr<lua::state> pLua = pManager_->get_lua();
00323         pLua->push_string(sLuaName_);
00324         lGlueList_.push_back(pLua->push_new<lua_edit_box>());
00325         pLua->set_global(sLuaName_);
00326         pLua->pop();
00327     }
00328 }
00329 
00330 void edit_box::set_text(const std::string& sText)
00331 {
00332     if (sText != sText_)
00333     {
00334         unlight_text();
00335         sText_ = sText;
00336         check_text_();
00337         update_displayed_text_();
00338         iterCarretPos_ = sUnicodeText_.end();
00339         update_font_string_();
00340         update_carret_position_();
00341         on("TextSet");
00342         on("TextChanged");
00343     }
00344 }
00345 
00346 const std::string& edit_box::get_text() const
00347 {
00348     return sText_;
00349 }
00350 
00351 void edit_box::unlight_text()
00352 {
00353     uiSelectionStartPos_ = uiSelectionEndPos_ = 0u;
00354     bSelectedText_ = false;
00355 
00356     if (pHighlight_)
00357         pHighlight_->hide();
00358 }
00359 
00360 void edit_box::highlight_text(uint uiStart, uint uiEnd, bool bForceUpdate)
00361 {
00362     if (!pHighlight_)
00363         create_highlight_();
00364 
00365     if (!pHighlight_)
00366         return;
00367 
00368     uint uiLeft  = std::min(uiStart, uiEnd);
00369     uint uiRight = std::max(uiStart, uiEnd);
00370 
00371     if (uiLeft == uiRight || uiRight < uiDisplayPos_ || uiLeft >= uiDisplayPos_ + sDisplayedText_.size())
00372         pHighlight_->hide();
00373     else
00374         pHighlight_->show();
00375 
00376     if (uiSelectionStartPos_ != uiStart || uiSelectionEndPos_ != uiEnd || bForceUpdate)
00377     {
00378         if (uiLeft != uiRight && uiRight >= uiDisplayPos_ &&
00379             uiLeft < uiDisplayPos_ + sDisplayedText_.size() &&
00380             pFontString_ && pFontString_->get_text_object())
00381         {
00382             bSelectedText_ = true;
00383 
00384             int iLeftPos = 0;
00385             int iRightPos = pFontString_->get_right() - pFontString_->get_left();
00386 
00387             utils::wptr<text> pText = pFontString_->get_text_object();
00388             const std::vector<text::letter>& lLetters = pText->get_letter_cache();
00389 
00390             std::vector<text::letter>::const_iterator iter;
00391             foreach (iter, lLetters)
00392             {
00393                 uint uiPos = iter - lLetters.begin() + uiDisplayPos_;
00394 
00395                 if (uiPos == uiLeft)
00396                     iLeftPos = int(iter->fX1) + lTextInsets_[BORDER_LEFT];
00397 
00398                 if (uiPos == uiRight - 1)
00399                 {
00400                     iRightPos = int(iter->fX2) + lTextInsets_[BORDER_LEFT];
00401                     break;
00402                 }
00403             }
00404 
00405             pHighlight_->set_abs_point(ANCHOR_LEFT,  sName_, ANCHOR_LEFT, iLeftPos,  0);
00406             pHighlight_->set_abs_point(ANCHOR_RIGHT, sName_, ANCHOR_LEFT, iRightPos, 0);
00407         }
00408     }
00409 
00410     uiSelectionStartPos_ = uiStart;
00411     uiSelectionEndPos_   = uiEnd;
00412 }
00413 
00414 void edit_box::set_highlight_color(const color& mColor)
00415 {
00416     if (mHighlightColor_ != mColor)
00417     {
00418         mHighlightColor_ = mColor;
00419 
00420         if (!pHighlight_)
00421             create_highlight_();
00422 
00423         if (!pHighlight_)
00424             return;
00425 
00426         pHighlight_->set_color(mHighlightColor_);
00427     }
00428 }
00429 
00430 void edit_box::insert_after_cursor(const std::string& sText)
00431 {
00432     if (!sText.empty())
00433     {
00434         if (bNumericOnly_ && !utils::is_number(sText))
00435             return;
00436 
00437         utils::ustring sUStr = utils::UTF8_to_unicode(sText);
00438         if (sUnicodeText_.size() + sUStr.size() <= uiMaxLetters_)
00439         {
00440             unlight_text();
00441             sUnicodeText_.insert(iterCarretPos_, sUStr.begin(), sUStr.end());
00442             iterCarretPos_ += sUStr.size();
00443             sText_ = utils::unicode_to_UTF8(sUnicodeText_);
00444             uiNumLetters_ = sUnicodeText_.size();
00445 
00446             update_displayed_text_();
00447             update_font_string_();
00448             update_carret_position_();
00449         }
00450     }
00451 }
00452 
00453 void edit_box::set_max_letters(uint uiMaxLetters)
00454 {
00455     if (uiMaxLetters == 0)
00456     {
00457         uiMaxLetters_ = uint(-1);
00458         return;
00459     }
00460 
00461     if (uiMaxLetters_ != uiMaxLetters)
00462     {
00463         uiMaxLetters_ = uiMaxLetters;
00464 
00465         uint uiCarretPos = iterCarretPos_ - sUnicodeText_.begin();
00466 
00467         check_text_();
00468 
00469         if (uiCarretPos > uiMaxLetters_)
00470         {
00471             iterCarretPos_ = sUnicodeText_.end();
00472             update_displayed_text_();
00473             update_font_string_();
00474             update_carret_position_();
00475         }
00476         else
00477             iterCarretPos_ = sUnicodeText_.begin() + uiCarretPos;
00478     }
00479 }
00480 
00481 uint edit_box::get_max_letters() const
00482 {
00483     return uiMaxLetters_;
00484 }
00485 
00486 uint edit_box::get_num_letters() const
00487 {
00488     return uiNumLetters_;
00489 }
00490 
00491 void edit_box::set_blink_speed(const double& dBlinkSpeed)
00492 {
00493     if (dBlinkSpeed_ != dBlinkSpeed)
00494     {
00495         dBlinkSpeed_ = dBlinkSpeed;
00496         mCarretTimer_ = periodic_timer(dBlinkSpeed_, periodic_timer::START_FIRST_TICK, false);
00497     }
00498 }
00499 
00500 const double& edit_box::get_blink_speed() const
00501 {
00502     return dBlinkSpeed_;
00503 }
00504 
00505 void edit_box::set_numeric_only(bool bNumericOnly)
00506 {
00507     if (bNumericOnly_ != bNumericOnly)
00508     {
00509         bNumericOnly_ = bNumericOnly;
00510 
00511         if (bNumericOnly_)
00512         {
00513             check_text_();
00514             iterCarretPos_ = sUnicodeText_.end();
00515             update_displayed_text_();
00516             update_carret_position_();
00517         }
00518     }
00519 }
00520 
00521 void edit_box::set_positive_only(bool bPositiveOnly)
00522 {
00523     if (bPositiveOnly_ != bPositiveOnly)
00524     {
00525         bPositiveOnly_ = bPositiveOnly;
00526 
00527         if (bNumericOnly_ && bPositiveOnly_)
00528         {
00529             check_text_();
00530             iterCarretPos_ = sUnicodeText_.end();
00531             update_displayed_text_();
00532             update_carret_position_();
00533         }
00534     }
00535 }
00536 
00537 void edit_box::set_integer_only(bool bIntegerOnly)
00538 {
00539     if (bIntegerOnly_ != bIntegerOnly)
00540     {
00541         bIntegerOnly_ = bIntegerOnly;
00542 
00543         if (bIntegerOnly_ && bPositiveOnly_)
00544         {
00545             check_text_();
00546             iterCarretPos_ = sUnicodeText_.end();
00547             update_displayed_text_();
00548             update_carret_position_();
00549         }
00550     }
00551 }
00552 
00553 bool edit_box::is_numeric_only() const
00554 {
00555     return bNumericOnly_;
00556 }
00557 
00558 bool edit_box::is_positive_only() const
00559 {
00560     return bPositiveOnly_;
00561 }
00562 
00563 bool edit_box::is_integer_only() const
00564 {
00565     return bIntegerOnly_;
00566 }
00567 
00568 void edit_box::enable_password_mode(bool bEnable)
00569 {
00570     if (bPasswordMode_ != bEnable)
00571     {
00572         bPasswordMode_ = bEnable;
00573 
00574         update_displayed_text_();
00575         update_font_string_();
00576         update_carret_position_();
00577     }
00578 }
00579 
00580 bool edit_box::is_password_mode_enabled() const
00581 {
00582     return bPasswordMode_;
00583 }
00584 
00585 void edit_box::set_multi_line(bool bMultiLine)
00586 {
00587     if (bMultiLine_ != bMultiLine)
00588     {
00589         bMultiLine_ = bMultiLine;
00590 
00591         if (pFontString_)
00592             pFontString_->set_word_wrap(bMultiLine_, bMultiLine_);
00593 
00594         check_text_();
00595         iterCarretPos_ = sUnicodeText_.end();
00596         update_displayed_text_();
00597         update_carret_position_();
00598     }
00599 }
00600 
00601 bool edit_box::is_multi_line() const
00602 {
00603     return bMultiLine_;
00604 }
00605 
00606 void edit_box::set_max_history_lines(uint uiMaxHistoryLines)
00607 {
00608     if (uiMaxHistoryLines == 0)
00609     {
00610         uiMaxHistoryLines_ = uint(-1);
00611         return;
00612     }
00613 
00614     if (uiMaxHistoryLines_ != uiMaxHistoryLines)
00615     {
00616         uiMaxHistoryLines_ = uiMaxHistoryLines;
00617 
00618         while (lHistoryLineList_.size() > uiMaxHistoryLines_)
00619             lHistoryLineList_.pop_front();
00620     }
00621 }
00622 
00623 uint edit_box::get_max_history_lines() const
00624 {
00625     return uiMaxHistoryLines_;
00626 }
00627 
00628 void edit_box::add_history_line(const std::string& sHistoryLine)
00629 {
00630     lHistoryLineList_.push_back(sHistoryLine);
00631 
00632     while (lHistoryLineList_.size() > uiMaxHistoryLines_)
00633         lHistoryLineList_.pop_front();
00634 }
00635 
00636 const std::deque<std::string>& edit_box::get_history_lines() const
00637 {
00638     return lHistoryLineList_;
00639 }
00640 
00641 void edit_box::set_arrows_ignored(bool bArrowsIgnored)
00642 {
00643     bArrowsIgnored_ = bArrowsIgnored;
00644 }
00645 
00646 void edit_box::set_text_insets(int iLeft, int iRight, int iTop, int iBottom)
00647 {
00648     set_text_insets({{iLeft, iRight, iTop, iBottom}});
00649 }
00650 
00651 void edit_box::set_text_insets(const std::array<int,4>& lInsets)
00652 {
00653     lTextInsets_ = lInsets;
00654 
00655     if (pFontString_)
00656     {
00657         pFontString_->clear_all_points();
00658         pFontString_->set_abs_point(
00659             ANCHOR_TOPLEFT, sName_, ANCHOR_TOPLEFT, lTextInsets_[BORDER_LEFT], lTextInsets_[BORDER_TOP]
00660         );
00661         pFontString_->set_abs_point(
00662             ANCHOR_BOTTOMRIGHT, sName_, ANCHOR_BOTTOMRIGHT, lTextInsets_[BORDER_RIGHT], lTextInsets_[BORDER_BOTTOM]
00663         );
00664 
00665         update_displayed_text_();
00666         update_font_string_();
00667         update_carret_position_();
00668     }
00669 }
00670 
00671 const std::array<int,4>& edit_box::get_text_insets() const
00672 {
00673     return lTextInsets_;
00674 }
00675 
00676 void edit_box::notify_focus(bool bFocus)
00677 {
00678     if (bFocus_ != bFocus)
00679     {
00680         bFocus_ = bFocus;
00681         if (bFocus_)
00682         {
00683             if (!pCarret_)
00684                 create_carret_();
00685 
00686             if (pCarret_)
00687                 pCarret_->show();
00688 
00689             mCarretTimer_.zero();
00690 
00691             lQueuedEventList_.push_back("EditFocusGained");
00692         }
00693         else
00694         {
00695             if (pCarret_)
00696                 pCarret_->hide();
00697 
00698             lQueuedEventList_.push_back("EditFocusLost");
00699         }
00700     }
00701 }
00702 
00703 void edit_box::notify_invisible_(bool bTriggerEvents)
00704 {
00705     set_focus(false);
00706     frame::notify_invisible_(bTriggerEvents);
00707 }
00708 
00709 font_string* edit_box::get_font_string()
00710 {
00711     return pFontString_;
00712 }
00713 
00714 font_string* edit_box::create_font_string_()
00715 {
00716     if (!pFontString_)
00717     {
00718         pFontString_ = new font_string(pManager_);
00719         pFontString_->set_special();
00720         pFontString_->set_parent(this);
00721         pFontString_->set_draw_layer(LAYER_ARTWORK);
00722         pFontString_->set_word_wrap(bMultiLine_, bMultiLine_);
00723     }
00724 
00725     return pFontString_;
00726 }
00727 
00728 void edit_box::create_highlight_()
00729 {
00730     pHighlight_ = new texture(pManager_);
00731     pHighlight_->set_special();
00732     pHighlight_->set_parent(this);
00733     pHighlight_->set_draw_layer(LAYER_HIGHLIGHT);
00734     pHighlight_->set_name("$parentHighlight");
00735 
00736     if (!pManager_->add_uiobject(pHighlight_))
00737     {
00738         gui::out << gui::warning << "gui::" << lType_.back() << " : "
00739             "Trying to create highlight texture for \""+sName_+"\",\n"
00740             "but its name was already taken : \""+pHighlight_->get_name()+"\". Skipped." << std::endl;
00741         delete pHighlight_; pHighlight_ = nullptr;
00742         return;
00743     }
00744 
00745     pHighlight_->create_glue();
00746     add_region(pHighlight_);
00747 
00748     pHighlight_->set_abs_point(
00749         ANCHOR_TOP,    sName_, ANCHOR_TOP,    0,  lTextInsets_[BORDER_TOP]
00750     );
00751     pHighlight_->set_abs_point(
00752         ANCHOR_BOTTOM, sName_, ANCHOR_BOTTOM, 0, -lTextInsets_[BORDER_BOTTOM]
00753     );
00754 
00755     pHighlight_->set_color(mHighlightColor_);
00756     pHighlight_->notify_loaded();
00757 }
00758 
00759 void edit_box::create_carret_()
00760 {
00761     if (pFontString_ && pFontString_->get_text_object())
00762     {
00763         pCarret_ = new texture(pManager_);
00764         pCarret_->set_special();
00765         pCarret_->set_parent(this);
00766         pCarret_->set_draw_layer(LAYER_HIGHLIGHT);
00767         pCarret_->set_name("$parentCarret");
00768 
00769         if (!pManager_->add_uiobject(pCarret_))
00770         {
00771             gui::out << gui::warning << "gui::" << lType_.back() << " : "
00772                 "Trying to create carret texture for \""+sName_+"\",\n"
00773                 "but its name was already taken : \""+pCarret_->get_name()+"\". Skipped." << std::endl;
00774             delete pCarret_; pCarret_ = nullptr;
00775             return;
00776         }
00777 
00778         pCarret_->create_glue();
00779         add_region(pCarret_);
00780 
00781         utils::refptr<sprite> pSprite = pFontString_->get_text_object()->create_sprite((uint)(unsigned char)'|');
00782         pSprite->set_color(pFontString_->get_text_color());
00783 
00784         pCarret_->set_sprite(pSprite);
00785         pCarret_->set_abs_point(ANCHOR_CENTER, sName_, ANCHOR_LEFT, lTextInsets_[BORDER_LEFT] - 1, 0);
00786 
00787         pCarret_->notify_loaded();
00788     }
00789 }
00790 
00791 void edit_box::check_text_()
00792 {
00793     sUnicodeText_ = utils::UTF8_to_unicode(sText_);
00794 
00795     if (!utils::is_number(sText_) && bNumericOnly_)
00796         sUnicodeText_.clear();
00797     else
00798     {
00799         if (sUnicodeText_.size() > uiMaxLetters_)
00800             sUnicodeText_.resize(uiMaxLetters_);
00801     }
00802 
00803     uiNumLetters_ = sUnicodeText_.size();
00804 
00805     sText_ = utils::unicode_to_UTF8(sUnicodeText_);
00806 }
00807 
00808 void edit_box::update_displayed_text_()
00809 {
00810     if (pFontString_ && pFontString_->get_text_object())
00811     {
00812         if (bPasswordMode_)
00813             sDisplayedText_ = utils::ustring(utils::UTF8_to_unicode('*'), sUnicodeText_.size());
00814         else
00815             sDisplayedText_ = sUnicodeText_;
00816 
00817         if (!bMultiLine_)
00818         {
00819             utils::wptr<text> pTextObject = pFontString_->get_text_object();
00820 
00821             if (!std::isinf(pTextObject->get_box_width()))
00822             {
00823                 sDisplayedText_.erase(0, uiDisplayPos_);
00824 
00825                 while (pTextObject->get_string_width(sDisplayedText_) > pTextObject->get_box_width())
00826                     sDisplayedText_.erase(sDisplayedText_.size()-2, 1);
00827             }
00828         }
00829     }
00830 }
00831 
00832 void edit_box::update_font_string_()
00833 {
00834     if (!pFontString_)
00835         return;
00836 
00837     pFontString_->set_text(utils::unicode_to_UTF8(sDisplayedText_));
00838 
00839     if (bSelectedText_)
00840         highlight_text(uiSelectionStartPos_, uiSelectionEndPos_, true);
00841 }
00842 
00843 void edit_box::update_carret_position_()
00844 {
00845     if (pFontString_ && pFontString_->get_text_object() && pCarret_)
00846     {
00847         if (sDisplayedText_.empty())
00848         {
00849             anchor_point mPoint;
00850             int iOffset = 0;
00851             switch (pFontString_->get_justify_h())
00852             {
00853                 case text::ALIGN_LEFT :
00854                     mPoint = ANCHOR_LEFT;
00855                     iOffset = lTextInsets_[BORDER_LEFT] - 1;
00856                     break;
00857                 case text::ALIGN_CENTER :
00858                     mPoint = ANCHOR_CENTER;
00859                     break;
00860                 case text::ALIGN_RIGHT :
00861                     mPoint = ANCHOR_RIGHT;
00862                     iOffset = -lTextInsets_[BORDER_RIGHT] - 1;
00863                     break;
00864                 default : mPoint = ANCHOR_LEFT; break;
00865             }
00866             pCarret_->set_abs_point(
00867                 ANCHOR_CENTER, sName_, mPoint, iOffset, 0
00868             );
00869             return;
00870         }
00871 
00872         utils::wptr<text> pText = pFontString_->get_text_object();
00873         utils::ustring::iterator iterDisplayCarret;
00874 
00875         if (!bMultiLine_)
00876         {
00877             uint uiGlobalPos = iterCarretPos_ - sUnicodeText_.begin();
00878 
00879             if (uiDisplayPos_ > uiGlobalPos)
00880             {
00881                 
00882                 float fBoxWidth = pText->get_box_width();
00883                 float fLeftStringMaxSize = fBoxWidth*0.25f;
00884                 float fLeftStringSize = 0.0f;
00885                 utils::ustring sLeftString;
00886 
00887                 utils::ustring::iterator iter = iterCarretPos_;
00888                 while ((iter != sUnicodeText_.begin()) && (fLeftStringSize < fLeftStringMaxSize))
00889                 {
00890                     --iter;
00891                     sLeftString.insert(sLeftString.begin(), *iter);
00892                     fLeftStringSize = pText->get_string_width(sLeftString);
00893                 }
00894 
00895                 uiDisplayPos_ = iter - sUnicodeText_.begin();
00896                 update_displayed_text_();
00897                 update_font_string_();
00898             }
00899 
00900             uint uiCarretPos = uiGlobalPos - uiDisplayPos_;
00901             if (uiCarretPos > sDisplayedText_.size())
00902             {
00903                 
00904                 float fBoxWidth = pText->get_box_width();
00905                 float fLeftStringMaxSize = fBoxWidth*0.75f;
00906                 float fLeftStringSize = 0.0f;
00907                 utils::ustring sLeftString;
00908 
00909                 utils::ustring::iterator iter = iterCarretPos_;
00910                 while ((iterCarretPos_ != sUnicodeText_.begin()) && (fLeftStringSize < fLeftStringMaxSize))
00911                 {
00912                     --iter;
00913                     sLeftString.insert(sLeftString.begin(), *iter);
00914                     fLeftStringSize = pText->get_string_width(sLeftString);
00915                 }
00916 
00917                 uiDisplayPos_ = iter - sUnicodeText_.begin();
00918                 update_displayed_text_();
00919                 update_font_string_();
00920 
00921                 uiCarretPos = uiGlobalPos - uiDisplayPos_;
00922             }
00923 
00924             iterDisplayCarret = sDisplayedText_.begin() + uiCarretPos;
00925         }
00926         else
00927             iterDisplayCarret = sDisplayedText_.begin() + (iterCarretPos_ - sUnicodeText_.begin()) - uiDisplayPos_;
00928 
00929         const std::vector<text::letter>& lLetters = pText->get_letter_cache();
00930         std::vector<text::letter>::const_iterator iterLetter = lLetters.begin();
00931 
00932         float fYOffset = 0.0f;
00933 
00934         utils::ustring::const_iterator iter;
00935         for (iter = sDisplayedText_.begin(); iter != iterDisplayCarret; ++iter)
00936         {
00937             float fLastY = iterLetter->fY1;
00938             ++iterLetter;
00939             if (iterLetter != lLetters.end() && fLastY != iterLetter->fY1)
00940                 fYOffset += iterLetter->fY1 - fLastY;
00941         }
00942 
00943         if (iterLetter == lLetters.begin())
00944         {
00945             pCarret_->set_abs_point(
00946                 ANCHOR_CENTER, sName_, ANCHOR_LEFT,
00947                 lTextInsets_[BORDER_LEFT] + int(iterLetter->fX1) - 1, int(fYOffset)
00948             );
00949         }
00950         else
00951         {
00952             --iterLetter;
00953             pCarret_->set_abs_point(
00954                 ANCHOR_CENTER, sName_, ANCHOR_LEFT,
00955                 lTextInsets_[BORDER_LEFT] + int(iterLetter->fX2) - 1, int(fYOffset)
00956             );
00957         }
00958 
00959         mCarretTimer_.zero();
00960         pCarret_->show();
00961     }
00962 }
00963 
00964 bool edit_box::add_char_(char32_t sUnicode)
00965 {
00966     if (bSelectedText_)
00967         remove_char_();
00968 
00969     if (uiNumLetters_ + 1 >= uiMaxLetters_)
00970         return false;
00971 
00972     if (bNumericOnly_)
00973     {
00974         if (sUnicode == U'.')
00975         {
00976             if (bIntegerOnly_)
00977                 return false;
00978 
00979             if (sUnicodeText_.find(U'.'))
00980                 return false;
00981         }
00982         else if (sUnicode == U'+' || sUnicode == U'-')
00983         {
00984             if (bPositiveOnly_)
00985                 return false;
00986 
00987             if (iterCarretPos_ != sUnicodeText_.begin() ||
00988                 sUnicodeText_.find(U'+') || sUnicodeText_.find(U'-'))
00989                 return false;
00990         }
00991         else if (sUnicode < U'0' || sUnicode > U'9')
00992             return false;
00993     }
00994 
00995     iterCarretPos_ = sUnicodeText_.insert(iterCarretPos_, sUnicode) + 1;
00996     ++uiNumLetters_;
00997 
00998     sText_ = utils::unicode_to_UTF8(sUnicodeText_);
00999 
01000     update_displayed_text_();
01001     update_font_string_();
01002     update_carret_position_();
01003 
01004     if (pCarret_)
01005         pCarret_->show();
01006 
01007     mCarretTimer_.zero();
01008 
01009     on("TextChanged");
01010 
01011     return true;
01012 }
01013 
01014 bool edit_box::remove_char_()
01015 {
01016     if (bSelectedText_)
01017     {
01018         if (uiSelectionStartPos_ != uiSelectionEndPos_)
01019         {
01020             uint uiLeft = std::min(uiSelectionStartPos_, uiSelectionEndPos_);
01021             uint uiRight = std::max(uiSelectionStartPos_, uiSelectionEndPos_);
01022 
01023             sUnicodeText_.erase(uiLeft, uiRight - uiLeft);
01024             sText_ = utils::unicode_to_UTF8(sUnicodeText_);
01025             uiNumLetters_ = sUnicodeText_.size();
01026 
01027             iterCarretPos_ = sUnicodeText_.begin() + uiLeft;
01028             on("TextChanged");
01029         }
01030 
01031         unlight_text();
01032     }
01033     else
01034     {
01035         if (iterCarretPos_ == sUnicodeText_.end())
01036             return false;
01037 
01038         iterCarretPos_ = sUnicodeText_.erase(iterCarretPos_);
01039         sText_ = utils::unicode_to_UTF8(sUnicodeText_);
01040         --uiNumLetters_;
01041         on("TextChanged");
01042     }
01043 
01044     update_displayed_text_();
01045     update_font_string_();
01046     update_carret_position_();
01047 
01048     if (pCarret_)
01049         pCarret_->show();
01050 
01051     mCarretTimer_.zero();
01052 
01053     return true;
01054 }
01055 
01056 uint edit_box::get_letter_id_at_(int iX, int iY)
01057 {
01058     if (pFontString_ && pFontString_->get_text_object())
01059     {
01060         utils::wptr<text> pText = pFontString_->get_text_object();
01061         const std::vector<text::letter>& lLetters = pText->get_letter_cache();
01062 
01063         if (lLetters.empty())
01064             return uiDisplayPos_;
01065 
01066         float fX = float(iX - lBorderList_[BORDER_LEFT] - lTextInsets_[BORDER_LEFT]);
01067         
01068 
01069         if (!bMultiLine_)
01070         {
01071             if (iX < lBorderList_[BORDER_LEFT] + lTextInsets_[BORDER_LEFT])
01072                 return uiDisplayPos_;
01073             else if (iX > lBorderList_[BORDER_RIGHT] - lTextInsets_[BORDER_RIGHT])
01074                 return lLetters.size() + uiDisplayPos_;
01075 
01076             std::vector<text::letter>::const_iterator iter;
01077             foreach (iter, lLetters)
01078             {
01079                 if (fX < (iter->fX1 + iter->fX2)/2.0f)
01080                     return (iter - lLetters.begin()) + uiDisplayPos_;
01081             }
01082 
01083             return lLetters.size() + uiDisplayPos_;
01084         }
01085         else
01086         {
01087             
01088             return uiDisplayPos_;
01089         }
01090 
01091     }
01092 
01093     return uint(-1);
01094 }
01095 
01096 bool edit_box::move_carret_at_(int iX, int iY)
01097 {
01098     uint uiPos = get_letter_id_at_(iX, iY);
01099     if (uiPos != uint(-1))
01100     {
01101         iterCarretPos_ = sUnicodeText_.begin() + uiPos;
01102         update_carret_position_();
01103         return true;
01104     }
01105     else
01106         return false;
01107 }
01108 
01109 bool edit_box::move_carret_horizontally_(bool bForward)
01110 {
01111     if (bForward)
01112     {
01113         if (iterCarretPos_ != sUnicodeText_.end())
01114         {
01115             ++iterCarretPos_;
01116             update_carret_position_();
01117 
01118             if (pCarret_)
01119                 pCarret_->show();
01120 
01121             mCarretTimer_.zero();
01122 
01123             return true;
01124         }
01125         else
01126             return false;
01127     }
01128     else
01129     {
01130         if (iterCarretPos_ != sUnicodeText_.begin())
01131         {
01132             --iterCarretPos_;
01133             update_carret_position_();
01134 
01135             if (pCarret_)
01136                 pCarret_->show();
01137 
01138             mCarretTimer_.zero();
01139 
01140             return true;
01141         }
01142         else
01143             return false;
01144     }
01145 }
01146 
01147 bool edit_box::move_carret_vertically_(bool bDown)
01148 {
01149     if (bMultiLine_)
01150     {
01151         
01152         return false;
01153     }
01154     else
01155     {
01156         utils::ustring::iterator iterOld = iterCarretPos_;
01157 
01158         if (bDown)
01159             iterCarretPos_ = sUnicodeText_.end();
01160         else
01161             iterCarretPos_ = sUnicodeText_.begin();
01162 
01163         if (iterOld != iterCarretPos_)
01164         {
01165             update_carret_position_();
01166 
01167             if (pCarret_)
01168                 pCarret_->show();
01169 
01170             mCarretTimer_.zero();
01171 
01172             return true;
01173         }
01174         else
01175             return false;
01176     }
01177 }
01178 
01179 void edit_box::process_key_(uint uiKey)
01180 {
01181     if (uiKey == key::K_RETURN || uiKey == key::K_NUMPADENTER)
01182     {
01183         if (bMultiLine_)
01184         {
01185             if (add_char_(U'\n'))
01186             {
01187                 event mKeyEvent;
01188                 mKeyEvent.add(std::string("\n"));
01189                 on("OnChar", &mKeyEvent);
01190             }
01191         }
01192     }
01193     else if (uiKey == key::K_BACK)
01194     {
01195         if (!bSelectedText_)
01196         {
01197             if (move_carret_horizontally_(false))
01198                 remove_char_();
01199         }
01200         else
01201             remove_char_();
01202     }
01203     else if (uiKey == key::K_DELETE)
01204         remove_char_();
01205     else if (uiKey == key::K_LEFT || uiKey == key::K_RIGHT || uiKey == key::K_UP || uiKey == key::K_DOWN)
01206     {
01207         if (!bArrowsIgnored_)
01208         {
01209             uint uiPreviousCarretPos = iterCarretPos_ - sUnicodeText_.begin();
01210 
01211             if (uiKey == key::K_LEFT)
01212                 move_carret_horizontally_(false);
01213             else if (uiKey == key::K_RIGHT)
01214                 move_carret_horizontally_(true);
01215             else if (uiKey == key::K_UP)
01216                 move_carret_vertically_(false);
01217             else if (uiKey == key::K_DOWN)
01218                 move_carret_vertically_(true);
01219 
01220             if (pManager_->get_input_manager()->shift_is_pressed())
01221             {
01222                 if (bSelectedText_)
01223                     highlight_text(uiSelectionStartPos_, iterCarretPos_ - sUnicodeText_.begin());
01224                 else
01225                     highlight_text(uiPreviousCarretPos, iterCarretPos_ - sUnicodeText_.begin());
01226             }
01227             else
01228                 unlight_text();
01229         }
01230     }
01231 }
01232 
01233 periodic_timer::periodic_timer(const double& dDuration, start_type mType, bool bTickFirst) :
01234     dElapsed_(bTickFirst ? dDuration : 0.0), dDuration_(dDuration), bPaused_(true),
01235     bFirstTick_(true), mType_(mType)
01236 {
01237     if (mType == START_NOW)
01238         start();
01239 }
01240 
01241 const double& periodic_timer::get_elapsed()
01242 {
01243     return dElapsed_;
01244 }
01245 
01246 const double& periodic_timer::get_period() const
01247 {
01248     return dDuration_;
01249 }
01250 
01251 bool periodic_timer::is_paused() const
01252 {
01253     return bPaused_;
01254 }
01255 
01256 bool periodic_timer::ticks()
01257 {
01258     if (mType_ == START_FIRST_TICK && bFirstTick_)
01259     {
01260         start();
01261         bFirstTick_ = false;
01262     }
01263 
01264     if (dElapsed_ >= dDuration_)
01265     {
01266         if (!bPaused_)
01267             zero();
01268 
01269         return true;
01270     }
01271     else
01272         return false;
01273 }
01274 
01275 void periodic_timer::stop()
01276 {
01277     dElapsed_ = 0.0;
01278     bPaused_ = true;
01279 }
01280 
01281 void periodic_timer::pause()
01282 {
01283     bPaused_ = true;
01284 }
01285 
01286 void periodic_timer::start()
01287 {
01288     bPaused_ = false;
01289 }
01290 
01291 void periodic_timer::zero()
01292 {
01293     dElapsed_ = 0.0;
01294 }
01295 
01296 void periodic_timer::update(double dDelta)
01297 {
01298     dElapsed_ += dDelta;
01299 }
01300 }