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 }