00001 #include "gui_fontstring.hpp"
00002
00003 #include "gui_layeredregion.hpp"
00004 #include "gui_manager.hpp"
00005 #include "gui_out.hpp"
00006
00007 #include <sstream>
00008
00009 namespace gui
00010 {
00011 const uint OUTLINE_QUALITY = 10;
00012 const float OUTLINE_THICKNESS = 2.0f;
00013
00014 font_string::font_string(manager* pManager) : layered_region(pManager),
00015 uiHeight_(0), fSpacing_(0.0f), mJustifyH_(text::ALIGN_CENTER),
00016 mJustifyV_(text::ALIGN_MIDDLE), iXOffset_(0), iYOffset_(0),
00017 bIsOutlined_(false), bCanNonSpaceWrap_(false), bCanWordWrap_(true),
00018 bAddEllipsis_(true), bFormattingEnabled_(true), mTextColor_(color::WHITE),
00019 bHasShadow_(false), mShadowColor_(color::BLACK), iShadowXOffset_(0),
00020 iShadowYOffset_(0)
00021 {
00022 lType_.push_back("FontString");
00023 }
00024
00025 font_string::~font_string()
00026 {
00027 }
00028
00029 void font_string::render()
00030 {
00031 if (pText_ && is_visible())
00032 {
00033 float fX = 0.0f, fY = 0.0f;
00034
00035 if (std::isinf(pText_->get_box_width()))
00036 {
00037 switch (mJustifyH_)
00038 {
00039 case text::ALIGN_LEFT : fX = lBorderList_[BORDER_LEFT]; break;
00040 case text::ALIGN_CENTER : fX = (lBorderList_[BORDER_LEFT] + lBorderList_[BORDER_RIGHT])/2; break;
00041 case text::ALIGN_RIGHT : fX = lBorderList_[BORDER_RIGHT]; break;
00042 }
00043 }
00044 else
00045 fX = lBorderList_[BORDER_LEFT];
00046
00047 if (std::isinf(pText_->get_box_height()))
00048 {
00049 switch (mJustifyV_)
00050 {
00051 case text::ALIGN_TOP : fY = lBorderList_[BORDER_TOP]; break;
00052 case text::ALIGN_MIDDLE : fY = (lBorderList_[BORDER_TOP] + lBorderList_[BORDER_BOTTOM])/2; break;
00053 case text::ALIGN_BOTTOM : fY = lBorderList_[BORDER_BOTTOM]; break;
00054 }
00055 }
00056 else
00057 fY = lBorderList_[BORDER_TOP];
00058
00059 fX += iXOffset_;
00060 fY += iYOffset_;
00061
00062 if (bHasShadow_)
00063 {
00064 pText_->set_color(mShadowColor_, true);
00065 pText_->render(fX + iShadowXOffset_, fY + iShadowYOffset_);
00066 }
00067
00068 if (bIsOutlined_)
00069 {
00070 pText_->set_color(color(0, 0, 0, mTextColor_.a), true);
00071 for (uint i = 0; i < OUTLINE_QUALITY; ++i)
00072 {
00073 static const float PI2 = 2.0f*acos(-1);
00074
00075 pText_->render(
00076 fX + OUTLINE_THICKNESS*cos(PI2*float(i)/OUTLINE_QUALITY),
00077 fY + OUTLINE_THICKNESS*sin(PI2*float(i)/OUTLINE_QUALITY)
00078 );
00079 }
00080 }
00081
00082 pText_->set_color(mTextColor_);
00083 pText_->render(fX, fY);
00084 }
00085 }
00086
00087 void font_string::update(float fDelta)
00088 {
00089
00090 #define DEBUG_LOG(msg)
00091
00092 DEBUG_LOG(" ~");
00093 if (pText_)
00094 {
00095 DEBUG_LOG(" Update text");
00096 pText_->update();
00097 }
00098
00099 uiobject::update(fDelta);
00100 DEBUG_LOG(" .");
00101 }
00102
00103 std::string font_string::serialize(const std::string& sTab) const
00104 {
00105 std::ostringstream sStr;
00106
00107 sStr << layered_region::serialize(sTab);
00108
00109 sStr << sTab << " # Font name : " << sFontName_ << "\n";
00110 sStr << sTab << " # Font height : " << uiHeight_ << "\n";
00111 sStr << sTab << " # Text ready : " << (pText_ != nullptr) << "\n";
00112 sStr << sTab << " # Text : \"" << sText_ << "\"\n";
00113 sStr << sTab << " # Outlined : " << bIsOutlined_ << "\n";
00114 sStr << sTab << " # Text color : " << mTextColor_ << "\n";
00115 sStr << sTab << " # Spacing : " << fSpacing_ << "\n";
00116 sStr << sTab << " # Justify :\n";
00117 sStr << sTab << " #-###\n";
00118 sStr << sTab << " | # horizontal : ";
00119 switch (mJustifyH_)
00120 {
00121 case text::ALIGN_LEFT : sStr << "LEFT\n"; break;
00122 case text::ALIGN_CENTER : sStr << "CENTER\n"; break;
00123 case text::ALIGN_RIGHT : sStr << "RIGHT\n"; break;
00124 default : sStr << "<error>\n"; break;
00125 }
00126 sStr << sTab << " | # vertical : ";
00127 switch (mJustifyH_)
00128 {
00129 case text::ALIGN_TOP : sStr << "TOP\n"; break;
00130 case text::ALIGN_MIDDLE : sStr << "MIDDLE\n"; break;
00131 case text::ALIGN_BOTTOM : sStr << "BOTTOM\n"; break;
00132 default : sStr << "<error>\n"; break;
00133 }
00134 sStr << sTab << " #-###\n";
00135 sStr << sTab << " # NonSpaceW. : " << bCanNonSpaceWrap_ << "\n";
00136 if (bHasShadow_)
00137 {
00138 sStr << sTab << " # Shadow off. : (" << iShadowXOffset_ << ", " << iShadowYOffset_ << ")\n";
00139 sStr << sTab << " # Shadow col. : " << mShadowColor_ << "\n";
00140 }
00141
00142 return sStr.str();
00143 }
00144
00145 void font_string::create_glue()
00146 {
00147 utils::wptr<lua::state> pLua = pManager_->get_lua();
00148 pLua->push_string(sName_);
00149 lGlueList_.push_back(pLua->push_new<lua_font_string>());
00150 pLua->set_global(sLuaName_);
00151 pLua->pop();
00152 }
00153
00154 void font_string::copy_from(uiobject* pObj)
00155 {
00156 uiobject::copy_from(pObj);
00157
00158 font_string* pFontString = dynamic_cast<font_string*>(pObj);
00159
00160 if (pFontString)
00161 {
00162 std::string sFontName = pFontString->get_font_name();
00163 uint uiHeight = pFontString->get_font_height();
00164 if (!sFontName.empty() && uiHeight != 0)
00165 this->set_font(sFontName, uiHeight);
00166
00167 this->set_justify_h(pFontString->get_justify_h());
00168 this->set_justify_v(pFontString->get_justify_v());
00169 this->set_spacing(pFontString->get_spacing());
00170 this->set_text(pFontString->get_text());
00171 this->set_outlined(pFontString->is_outlined());
00172 if (pFontString->has_shadow())
00173 {
00174 this->set_shadow(true);
00175 this->set_shadow_color(pFontString->get_shadow_color());
00176 this->set_shadow_offsets(pFontString->get_shadow_offsets());
00177 }
00178 this->set_text_color(pFontString->get_text_color());
00179 this->set_non_space_wrap(pFontString->can_non_space_wrap());
00180 }
00181 }
00182
00183 const std::string& font_string::get_font_name() const
00184 {
00185 return sFontName_;
00186 }
00187
00188 uint font_string::get_font_height() const
00189 {
00190 return uiHeight_;
00191 }
00192
00193 void font_string::set_outlined(bool bIsOutlined)
00194 {
00195 if (bIsOutlined_ != bIsOutlined)
00196 {
00197 bIsOutlined_ = bIsOutlined;
00198 notify_renderer_need_redraw();
00199 }
00200 }
00201
00202 bool font_string::is_outlined() const
00203 {
00204 return bIsOutlined_;
00205 }
00206
00207 text::alignment font_string::get_justify_h() const
00208 {
00209 return mJustifyH_;
00210 }
00211
00212 text::vertical_alignment font_string::get_justify_v() const
00213 {
00214 return mJustifyV_;
00215 }
00216
00217 const color& font_string::get_shadow_color() const
00218 {
00219 return mShadowColor_;
00220 }
00221
00222 std::array<int,2> font_string::get_shadow_offsets() const
00223 {
00224 return {{iShadowXOffset_, iShadowYOffset_}};
00225 }
00226
00227 std::array<int,2> font_string::get_offsets() const
00228 {
00229 return {{iXOffset_, iYOffset_}};
00230 }
00231
00232 int font_string::get_shadow_x_offset() const
00233 {
00234 return iShadowXOffset_;
00235 }
00236
00237 int font_string::get_shadow_y_offset() const
00238 {
00239 return iShadowYOffset_;
00240 }
00241
00242 float font_string::get_spacing() const
00243 {
00244 return fSpacing_;
00245 }
00246
00247 const color& font_string::get_text_color() const
00248 {
00249 return mTextColor_;
00250 }
00251
00252 void font_string::set_font(const std::string& sFontName, uint uiHeight)
00253 {
00254 sFontName_ = sFontName;
00255 uiHeight_ = uiHeight;
00256
00257 pText_ = utils::refptr<text>(new text(pManager_, sFontName, uiHeight));
00258 pText_->set_remove_starting_spaces(true);
00259 pText_->set_text(sText_);
00260 pText_->set_alignment(mJustifyH_);
00261 pText_->set_vertical_alignment(mJustifyV_);
00262 pText_->set_tracking(fSpacing_);
00263 pText_->enable_word_wrap(bCanWordWrap_, bAddEllipsis_);
00264 pText_->enable_formatting(bFormattingEnabled_);
00265
00266 fire_update_borders();
00267 notify_renderer_need_redraw();
00268 }
00269
00270 void font_string::set_justify_h(text::alignment mJustifyH)
00271 {
00272 if (mJustifyH_ != mJustifyH)
00273 {
00274 mJustifyH_ = mJustifyH;
00275 if (pText_)
00276 {
00277 pText_->set_alignment(mJustifyH_);
00278 notify_renderer_need_redraw();
00279 }
00280 }
00281 }
00282
00283 void font_string::set_justify_v(text::vertical_alignment mJustifyV)
00284 {
00285 if (mJustifyV_ != mJustifyV)
00286 {
00287 mJustifyV_ = mJustifyV;
00288 if (pText_)
00289 {
00290 pText_->set_vertical_alignment(mJustifyV_);
00291 notify_renderer_need_redraw();
00292 }
00293 }
00294 }
00295
00296 void font_string::set_shadow_color(const color& mShadowColor)
00297 {
00298 if (mShadowColor_ != mShadowColor)
00299 {
00300 mShadowColor_ = mShadowColor;
00301 if (bHasShadow_)
00302 notify_renderer_need_redraw();
00303 }
00304 }
00305
00306 void font_string::set_shadow_offsets(int iShadowXOffset, int iShadowYOffset)
00307 {
00308 if (iShadowXOffset_ != iShadowXOffset || iShadowYOffset_ != iShadowYOffset)
00309 {
00310 iShadowXOffset_ = iShadowXOffset;
00311 iShadowYOffset_ = iShadowYOffset;
00312 if (bHasShadow_)
00313 notify_renderer_need_redraw();
00314 }
00315 }
00316
00317 void font_string::set_shadow_offsets(const std::array<int,2>& lShadowOffsets)
00318 {
00319 if (iShadowXOffset_ != lShadowOffsets[0] || iShadowYOffset_ != lShadowOffsets[1])
00320 {
00321 iShadowXOffset_ = lShadowOffsets[0];
00322 iShadowYOffset_ = lShadowOffsets[1];
00323 if (bHasShadow_)
00324 notify_renderer_need_redraw();
00325 }
00326 }
00327
00328 void font_string::set_offsets(int iXOffset, int iYOffset)
00329 {
00330 if (iXOffset_ != iXOffset || iYOffset_ != iYOffset)
00331 {
00332 iXOffset_ = iXOffset;
00333 iYOffset_ = iYOffset;
00334 notify_renderer_need_redraw();
00335 }
00336 }
00337
00338 void font_string::set_offsets(const std::array<int,2>& lOffsets)
00339 {
00340 if (iXOffset_ != lOffsets[0] || iYOffset_ != lOffsets[1])
00341 {
00342 iXOffset_ = lOffsets[0];
00343 iYOffset_ = lOffsets[1];
00344 notify_renderer_need_redraw();
00345 }
00346 }
00347
00348 void font_string::set_spacing(float fSpacing)
00349 {
00350 if (fSpacing_ != fSpacing)
00351 {
00352 fSpacing_ = fSpacing;
00353 if (pText_)
00354 {
00355 pText_->set_tracking(fSpacing_);
00356 notify_renderer_need_redraw();
00357 }
00358 }
00359 }
00360
00361 void font_string::set_text_color(const color& mTextColor)
00362 {
00363 if (mTextColor_ != mTextColor)
00364 {
00365 mTextColor_ = mTextColor;
00366 notify_renderer_need_redraw();
00367 }
00368 }
00369
00370 bool font_string::can_non_space_wrap() const
00371 {
00372 return bCanNonSpaceWrap_;
00373 }
00374
00375 float font_string::get_string_height() const
00376 {
00377 if (pText_)
00378 return pText_->get_text_height();
00379 else
00380 return 0.0f;
00381 }
00382
00383 float font_string::get_string_width() const
00384 {
00385 if (pText_)
00386 return pText_->get_text_width();
00387 else
00388 return 0.0f;
00389 }
00390
00391 const std::string& font_string::get_text() const
00392 {
00393 return sText_;
00394 }
00395
00396 const utils::ustring& font_string::get_unicode_text() const
00397 {
00398 static const utils::ustring empty;
00399 if (pText_)
00400 return pText_->get_unicode_text();
00401 else
00402 return empty;
00403 }
00404
00405 void font_string::set_non_space_wrap(bool bCanNonSpaceWrap)
00406 {
00407 if (bCanNonSpaceWrap_ != bCanNonSpaceWrap)
00408 {
00409 bCanNonSpaceWrap_ = bCanNonSpaceWrap;
00410 notify_renderer_need_redraw();
00411 }
00412 }
00413
00414 bool font_string::has_shadow() const
00415 {
00416 return bHasShadow_;
00417 }
00418
00419 void font_string::set_shadow(bool bHasShadow)
00420 {
00421 if (bHasShadow_ != bHasShadow)
00422 {
00423 bHasShadow_ = bHasShadow;
00424 notify_renderer_need_redraw();
00425 }
00426 }
00427
00428 void font_string::set_word_wrap(bool bCanWordWrap, bool bAddEllipsis)
00429 {
00430 bCanWordWrap_ = bCanWordWrap;
00431 bAddEllipsis_ = bAddEllipsis;
00432 if (pText_)
00433 pText_->enable_word_wrap(bCanWordWrap_, bAddEllipsis_);
00434 }
00435
00436 bool font_string::can_word_wrap() const
00437 {
00438 return bCanWordWrap_;
00439 }
00440
00441 void font_string::enable_formatting(bool bFormatting)
00442 {
00443 bFormattingEnabled_ = bFormatting;
00444 if (pText_)
00445 pText_->enable_formatting(bFormattingEnabled_);
00446 }
00447
00448 bool font_string::is_formatting_enabled() const
00449 {
00450 return bFormattingEnabled_;
00451 }
00452
00453 void font_string::set_text(const std::string& sText)
00454 {
00455 if (sText_ != sText)
00456 {
00457 sText_ = sText;
00458 if (pText_)
00459 {
00460 pText_->set_text(sText_);
00461 fire_update_borders();
00462 }
00463 }
00464 }
00465
00466 utils::wptr<text> font_string::get_text_object()
00467 {
00468 return pText_;
00469 }
00470
00471 void font_string::update_borders_() const
00472 {
00473 if (!pText_)
00474 return uiobject::update_borders_();
00475
00476 if (!bUpdateBorders_)
00477 return;
00478
00479
00480 #define DEBUG_LOG(msg)
00481
00482 bool bOldReady = bReady_;
00483 bReady_ = true;
00484
00485 if (bUpdateDimensions_)
00486 {
00487 DEBUG_LOG(" Update dimentions");
00488 update_dimensions_();
00489 bUpdateDimensions_ = false;
00490 }
00491
00492 if (!lAnchorList_.empty())
00493 {
00494 float fLeft = 0.0f, fRight = 0.0f, fTop = 0.0f, fBottom = 0.0f;
00495 float fXCenter = 0.0f, fYCenter = 0.0f;
00496
00497 DEBUG_LOG(" Read anchors");
00498 read_anchors_(fLeft, fRight, fTop, fBottom, fXCenter, fYCenter);
00499
00500 if (uiAbsWidth_ == 0u)
00501 {
00502 if (lDefinedBorderList_[BORDER_LEFT] && lDefinedBorderList_[BORDER_RIGHT])
00503 pText_->set_box_width(fRight - fLeft);
00504 else
00505 pText_->set_box_width(std::numeric_limits<float>::infinity());
00506 }
00507 else
00508 pText_->set_box_width(uiAbsWidth_);
00509
00510 if (uiAbsHeight_ == 0u)
00511 {
00512 if (lDefinedBorderList_[BORDER_TOP] && lDefinedBorderList_[BORDER_BOTTOM])
00513 pText_->set_box_height(fBottom - fTop);
00514 else
00515 pText_->set_box_height(std::numeric_limits<float>::infinity());
00516 }
00517 else
00518 pText_->set_box_height(uiAbsHeight_);
00519
00520 DEBUG_LOG(" Make borders");
00521 if (uiAbsHeight_ != 0u)
00522 make_borders_(fTop, fBottom, fYCenter, uiAbsHeight_);
00523 else
00524 make_borders_(fTop, fBottom, fYCenter, pText_->get_height());
00525
00526 if (uiAbsWidth_ != 0u)
00527 make_borders_(fLeft, fRight, fXCenter, uiAbsWidth_);
00528 else
00529 make_borders_(fLeft, fRight, fXCenter, pText_->get_width());
00530
00531 if (bReady_)
00532 {
00533 int iLeft = fLeft, iRight = fRight, iTop = fTop, iBottom = fBottom;
00534
00535 if (iRight < iLeft)
00536 iRight = iLeft+1;
00537 if (iBottom < iTop)
00538 iBottom = iTop+1;
00539
00540 lBorderList_[BORDER_LEFT] = iLeft;
00541 lBorderList_[BORDER_RIGHT] = iRight;
00542 lBorderList_[BORDER_TOP] = iTop;
00543 lBorderList_[BORDER_BOTTOM] = iBottom;
00544
00545 DEBUG_LOG(" Update dimentions");
00546 update_dimensions_();
00547 }
00548 else
00549 lBorderList_ = {{0, 0, 0, 0}};
00550
00551 bUpdateBorders_ = false;
00552 }
00553 else
00554 bReady_ = false;
00555
00556 if (bReady_ || (!bReady_ && bOldReady))
00557 {
00558 DEBUG_LOG(" Fire redraw");
00559 notify_renderer_need_redraw();
00560 }
00561 DEBUG_LOG(" @");
00562 }
00563 }