00001 #include "gui_scrollframe.hpp"
00002 #include "gui_frame.hpp"
00003 #include "gui_texture.hpp"
00004 #include "gui_manager.hpp"
00005 #include "gui_rendertarget.hpp"
00006 #include "gui_out.hpp"
00007
00008 namespace gui
00009 {
00010 scroll_frame::scroll_frame(manager* pManager) : frame(pManager),
00011 iHorizontalScroll_(0), iHorizontalScrollRange_(0), iVerticalScroll_(0),
00012 iVerticalScrollRange_(0), pScrollChild_(nullptr),
00013 bRebuildScrollRenderTarget_(false), bRedrawScrollRenderTarget_(false),
00014 bUpdateScrollRange_(false), pScrollRenderTarget_(nullptr),
00015 pScrollTexture_(nullptr), bRebuildScrollStrataList_(false),
00016 bMouseInScrollTexture_(false), pOveredScrollChild_(nullptr)
00017 {
00018
00019 lType_.push_back("ScrollFrame");
00020 }
00021
00022 scroll_frame::~scroll_frame()
00023 {
00024 }
00025
00026 bool scroll_frame::can_use_script(const std::string& sScriptName) const
00027 {
00028 if (frame::can_use_script(sScriptName))
00029 return true;
00030 else if ((sScriptName == "OnHorizontalScroll") ||
00031 (sScriptName == "OnScrollRangeChanged") ||
00032 (sScriptName == "OnVerticalScroll"))
00033 return true;
00034 else
00035 return false;
00036 }
00037
00038 void scroll_frame::on(const std::string& sScriptName, event* pEvent)
00039 {
00040 frame::on(sScriptName, pEvent);
00041
00042 if (sScriptName == "SizeChanged")
00043 bRebuildScrollRenderTarget_ = true;
00044 }
00045
00046 void scroll_frame::copy_from(uiobject* pObj)
00047 {
00048 frame::copy_from(pObj);
00049
00050 scroll_frame* pScrollFrame = dynamic_cast<scroll_frame*>(pObj);
00051
00052 if (pScrollFrame)
00053 {
00054 this->set_horizontal_scroll(pScrollFrame->get_horizontal_scroll());
00055 this->set_vertical_scroll(pScrollFrame->get_vertical_scroll());
00056
00057 if (pScrollFrame->get_scroll_child())
00058 {
00059 frame* pScrollChild = pManager_->create_frame(pScrollFrame->get_scroll_child()->get_object_type());
00060 if (pScrollChild)
00061 {
00062 pScrollChild->set_parent(this);
00063 if (this->is_virtual())
00064 pScrollChild->set_virtual();
00065 pScrollChild->set_name(pScrollFrame->get_scroll_child()->get_raw_name());
00066 if (!pManager_->add_uiobject(pScrollChild))
00067 {
00068 gui::out << gui::warning << "gui::" << lType_.back() << " : "
00069 "Trying to add \""+pScrollChild->get_name()+"\" to \""+sName_+
00070 "\", but its name was already taken : \""+pScrollChild->get_name()+"\". Skipped." << std::endl;
00071 delete pScrollChild;
00072 }
00073 else
00074 {
00075 pScrollChild->create_glue();
00076 this->add_child(pScrollChild);
00077 pScrollChild->copy_from(pScrollFrame->get_scroll_child());
00078 pScrollChild->notify_loaded();
00079
00080 this->set_scroll_child(pScrollChild);
00081 }
00082 }
00083 }
00084 }
00085 }
00086
00087 void scroll_frame::set_scroll_child(frame* pFrame)
00088 {
00089 if (pScrollChild_)
00090 {
00091 pScrollChild_->set_manually_rendered(false);
00092 pScrollChild_->modify_point(ANCHOR_TOPLEFT)->set_abs_offset(
00093 lBorderList_[BORDER_LEFT] - iHorizontalScroll_,
00094 lBorderList_[BORDER_TOP] - iVerticalScroll_
00095 );
00096
00097 lScrollChildList_.clear();
00098 lScrollStrataList_.clear();
00099 }
00100 else if (!is_virtual() && !pScrollTexture_)
00101 {
00102
00103 pScrollTexture_ = new texture(pManager_);
00104 pScrollTexture_->set_special();
00105 pScrollTexture_->set_parent(this);
00106 pScrollTexture_->set_draw_layer("ARTWORK");
00107 pScrollTexture_->set_name("$parentScrollTexture");
00108
00109 if (!pManager_->add_uiobject(pScrollTexture_))
00110 {
00111 gui::out << gui::warning << "gui::" << lType_.back() << " : "
00112 "Trying to create scroll texture for \""+sName_+"\",\n"
00113 "but its name was already taken : \""+pScrollTexture_->get_name()+"\". Skipped." << std::endl;
00114 delete pScrollTexture_; pScrollTexture_ = nullptr;
00115 return;
00116 }
00117
00118 pScrollTexture_->create_glue();
00119 add_region(pScrollTexture_);
00120
00121 pScrollTexture_->set_all_points(this);
00122
00123 if (pScrollRenderTarget_)
00124 pScrollTexture_->set_texture(pScrollRenderTarget_);
00125
00126 pScrollTexture_->notify_loaded();
00127
00128 bRebuildScrollRenderTarget_ = true;
00129 }
00130
00131 pScrollChild_ = pFrame;
00132
00133 if (pScrollChild_)
00134 {
00135 if (pScrollChild_->get_parent() != this)
00136 {
00137 pScrollChild_->set_parent(this);
00138 add_child(pScrollChild_);
00139 }
00140
00141 pScrollChild_->set_manually_rendered(true, this);
00142 pScrollChild_->clear_all_points();
00143 pScrollChild_->set_abs_point(ANCHOR_TOPLEFT, "", ANCHOR_TOPLEFT, -iHorizontalScroll_, -iVerticalScroll_);
00144
00145 add_to_scroll_child_list_(pScrollChild_);
00146
00147 iHorizontalScrollRange_ = int(pScrollChild_->get_abs_width()) - int(uiAbsWidth_);
00148 if (iHorizontalScrollRange_ < 0) iHorizontalScrollRange_ = 0;
00149
00150 iVerticalScrollRange_ = int(pScrollChild_->get_abs_height()) - int(uiAbsHeight_);
00151 if (iVerticalScrollRange_ < 0) iVerticalScrollRange_ = 0;
00152
00153 on("ScrollRangeChanged");
00154
00155 bUpdateScrollRange_ = false;
00156 }
00157
00158 bRebuildScrollStrataList_ = true;
00159 fire_redraw();
00160 }
00161
00162 frame* scroll_frame::get_scroll_child()
00163 {
00164 return pScrollChild_;
00165 }
00166
00167 void scroll_frame::set_horizontal_scroll(int iHorizontalScroll)
00168 {
00169 if (iHorizontalScroll_ != iHorizontalScroll)
00170 {
00171 iHorizontalScroll_ = iHorizontalScroll;
00172 lQueuedEventList_.push_back("HorizontalScroll");
00173
00174 pScrollChild_->modify_point(ANCHOR_TOPLEFT)->set_abs_offset(-iHorizontalScroll_, -iVerticalScroll_);
00175 fire_redraw();
00176 }
00177 }
00178
00179 int scroll_frame::get_horizontal_scroll() const
00180 {
00181 return iHorizontalScroll_;
00182 }
00183
00184 int scroll_frame::get_horizontal_scroll_range() const
00185 {
00186 return iHorizontalScrollRange_;
00187 }
00188
00189 void scroll_frame::set_vertical_scroll(int iVerticalScroll)
00190 {
00191 if (iVerticalScroll_ != iVerticalScroll)
00192 {
00193 iVerticalScroll_ = iVerticalScroll;
00194 lQueuedEventList_.push_back("VerticalScroll");
00195
00196 pScrollChild_->modify_point(ANCHOR_TOPLEFT)->set_abs_offset(-iHorizontalScroll_, -iVerticalScroll_);
00197 fire_redraw();
00198 }
00199 }
00200
00201 int scroll_frame::get_vertical_scroll() const
00202 {
00203 return iVerticalScroll_;
00204 }
00205
00206 int scroll_frame::get_vertical_scroll_range() const
00207 {
00208 return iVerticalScrollRange_;
00209 }
00210
00211 void scroll_frame::update(float fDelta)
00212 {
00213 uint uiOldChildWidth = 0;
00214 uint uiOldChildHeight = 0;
00215
00216 if (pScrollChild_)
00217 {
00218 uiOldChildWidth = pScrollChild_->get_abs_width();
00219 uiOldChildHeight = pScrollChild_->get_abs_height();
00220 }
00221
00222 frame::update(fDelta);
00223
00224 if (pScrollChild_ && (uiOldChildWidth != pScrollChild_->get_abs_width() ||
00225 uiOldChildHeight != pScrollChild_->get_abs_height()))
00226 {
00227 bUpdateScrollRange_ = true;
00228 fire_redraw();
00229 }
00230
00231 if (is_visible())
00232 {
00233 if (bRebuildScrollRenderTarget_ && pScrollTexture_)
00234 {
00235 rebuild_scroll_render_target_();
00236 bRebuildScrollRenderTarget_ = false;
00237 fire_redraw();
00238 }
00239
00240 if (bUpdateScrollRange_)
00241 {
00242 update_scroll_range_();
00243 bUpdateScrollRange_ = false;
00244 }
00245
00246 if (bRebuildScrollStrataList_)
00247 {
00248 rebuild_scroll_strata_list_();
00249 bRebuildScrollStrataList_ = false;
00250 fire_redraw();
00251 }
00252
00253 if (pScrollChild_)
00254 update_scroll_child_input_();
00255
00256 if (pScrollChild_ && pScrollRenderTarget_ && bRedrawScrollRenderTarget_)
00257 {
00258 render_scroll_strata_list_();
00259 bRedrawScrollRenderTarget_ = false;
00260 }
00261 }
00262 }
00263
00264 void scroll_frame::update_scroll_range_()
00265 {
00266 iHorizontalScrollRange_ = int(pScrollChild_->get_abs_width()) - int(uiAbsWidth_);
00267 if (iHorizontalScrollRange_ < 0) iHorizontalScrollRange_ = 0;
00268
00269 iVerticalScrollRange_ = int(pScrollChild_->get_abs_height()) - int(uiAbsHeight_);
00270 if (iVerticalScrollRange_ < 0) iVerticalScrollRange_ = 0;
00271
00272 on("ScrollRangeChanged");
00273 }
00274
00275 void scroll_frame::update_scroll_child_input_()
00276 {
00277 int iX = iMousePosX_ - lBorderList_[BORDER_LEFT];
00278 int iY = iMousePosY_ - lBorderList_[BORDER_TOP];
00279
00280 if (bMouseInScrollTexture_)
00281 {
00282 frame* pOveredFrame = nullptr;
00283
00284 std::map<frame_strata, strata>::const_iterator iterStrata = lScrollStrataList_.end();
00285 while (iterStrata != lScrollStrataList_.begin() && !pOveredFrame)
00286 {
00287 --iterStrata;
00288 const strata& mStrata = iterStrata->second;
00289
00290 std::map<int, level>::const_iterator iterLevel = mStrata.lLevelList.end();
00291 while (iterLevel != mStrata.lLevelList.begin() && !pOveredFrame)
00292 {
00293 --iterLevel;
00294 const level& mLevel = iterLevel->second;
00295
00296 std::vector<frame*>::const_iterator iterFrame;
00297 foreach (iterFrame, mLevel.lFrameList)
00298 {
00299 frame* pFrame = *iterFrame;
00300 if (pFrame->is_mouse_enabled() && pFrame->is_visible() && pFrame->is_in_frame(iX, iY))
00301 {
00302 pOveredFrame = pFrame;
00303 break;
00304 }
00305 }
00306 }
00307 }
00308
00309 if (pOveredFrame != pOveredScrollChild_)
00310 {
00311 if (pOveredScrollChild_)
00312 pOveredScrollChild_->notify_mouse_in_frame(false, iX, iY);
00313
00314 pOveredScrollChild_ = pOveredFrame;
00315 }
00316
00317 if (pOveredScrollChild_)
00318 pOveredScrollChild_->notify_mouse_in_frame(true, iX, iY);
00319 }
00320 else if (pOveredScrollChild_)
00321 {
00322 pOveredScrollChild_->notify_mouse_in_frame(false, iX, iY);
00323 pOveredScrollChild_ = nullptr;
00324 }
00325 }
00326
00327 void scroll_frame::rebuild_scroll_render_target_()
00328 {
00329 if (uiAbsWidth_ == 0 || uiAbsHeight_ == 0)
00330 return;
00331
00332 if (pScrollRenderTarget_)
00333 {
00334 pScrollRenderTarget_->set_dimensions(uiAbsWidth_, uiAbsHeight_);
00335 pScrollTexture_->set_tex_coord(std::array<float,4>({{
00336 0.0f, 0.0f,
00337 float(uiAbsWidth_)/pScrollRenderTarget_->get_real_width(),
00338 float(uiAbsHeight_)/pScrollRenderTarget_->get_real_height()
00339 }}));
00340 bUpdateScrollRange_ = true;
00341 }
00342 else
00343 {
00344 pScrollRenderTarget_ = pManager_->create_render_target(uiAbsWidth_, uiAbsHeight_);
00345
00346 if (pScrollRenderTarget_)
00347 pScrollTexture_->set_texture(pScrollRenderTarget_);
00348 }
00349 }
00350
00351 void scroll_frame::rebuild_scroll_strata_list_()
00352 {
00353 lScrollStrataList_.clear();
00354
00355 std::map<uint, frame*>::iterator iterFrame;
00356 foreach (iterFrame, lScrollChildList_)
00357 {
00358 frame* pFrame = iterFrame->second;
00359 lScrollStrataList_[pFrame->get_frame_strata()].
00360 lLevelList[pFrame->get_frame_level()].
00361 lFrameList.push_back(pFrame);
00362 }
00363 }
00364
00365 void scroll_frame::render_scroll_strata_list_()
00366 {
00367 pManager_->begin(pScrollRenderTarget_);
00368 pScrollRenderTarget_->clear(color::EMPTY);
00369
00370 std::map<frame_strata, strata>::const_iterator iterStrata;
00371 foreach (iterStrata, lScrollStrataList_)
00372 {
00373 const strata& mStrata = iterStrata->second;
00374
00375 std::map<int, level>::const_iterator iterLevel;
00376 foreach (iterLevel, mStrata.lLevelList)
00377 {
00378 const level& mLevel = iterLevel->second;
00379
00380 std::vector<frame*>::const_iterator iterFrame;
00381 foreach (iterFrame, mLevel.lFrameList)
00382 {
00383 frame* pFrame = *iterFrame;
00384 if (!pFrame->is_newly_created())
00385 pFrame->render();
00386 }
00387 }
00388 }
00389
00390 pManager_->end();
00391 }
00392
00393 bool scroll_frame::is_in_frame(int iX, int iY) const
00394 {
00395 if (pScrollTexture_)
00396 return frame::is_in_frame(iX, iY) || pScrollTexture_->is_in_region(iX, iY);
00397 else
00398 return frame::is_in_frame(iX, iY);
00399 }
00400
00401 void scroll_frame::notify_mouse_in_frame(bool bMouseInFrame, int iX, int iY)
00402 {
00403 frame::notify_mouse_in_frame(bMouseInFrame, iX, iY);
00404 bMouseInScrollTexture_ = (bMouseInFrame && pScrollTexture_ && pScrollTexture_->is_in_region(iX, iY));
00405 }
00406
00407 void scroll_frame::fire_redraw() const
00408 {
00409 bRedrawScrollRenderTarget_ = true;
00410 notify_renderer_need_redraw();
00411 }
00412
00413 void scroll_frame::notify_child_strata_changed(frame* pChild)
00414 {
00415 if (pChild == pScrollChild_)
00416 bRebuildScrollStrataList_ = true;
00417 else
00418 {
00419 if (pParentFrame_)
00420 pParentFrame_->notify_child_strata_changed(this);
00421 else
00422 pManager_->fire_build_strata_list();
00423 }
00424 }
00425
00426 void scroll_frame::create_glue()
00427 {
00428 if (bVirtual_)
00429 {
00430 utils::wptr<lua::state> pLua = pManager_->get_lua();
00431 pLua->push_number(uiID_);
00432 lGlueList_.push_back(pLua->push_new<lua_virtual_glue>());
00433 pLua->set_global(sLuaName_);
00434 pLua->pop();
00435 }
00436 else
00437 {
00438 utils::wptr<lua::state> pLua = pManager_->get_lua();
00439 pLua->push_string(sLuaName_);
00440 lGlueList_.push_back(pLua->push_new<lua_scroll_frame>());
00441 pLua->set_global(sLuaName_);
00442 pLua->pop();
00443 }
00444 }
00445
00446 void scroll_frame::add_to_scroll_child_list_(frame* pChild)
00447 {
00448 lScrollChildList_[pChild->get_id()] = pChild;
00449 std::map<uint, frame*>::const_iterator iterChild;
00450 foreach (iterChild, pChild->get_children())
00451 add_to_scroll_child_list_(iterChild->second);
00452 }
00453
00454 void scroll_frame::remove_from_scroll_child_list_(frame* pChild)
00455 {
00456 lScrollChildList_.erase(pChild->get_id());
00457 std::map<uint, frame*>::const_iterator iterChild;
00458 foreach (iterChild, pChild->get_children())
00459 remove_from_scroll_child_list_(iterChild->second);
00460 }
00461
00462 void scroll_frame::notify_manually_rendered_object_(uiobject* pObject, bool bManuallyRendered)
00463 {
00464 frame* pFrame = dynamic_cast<frame*>(pObject);
00465 if (pFrame)
00466 {
00467 if (bManuallyRendered)
00468 add_to_scroll_child_list_(pFrame);
00469 else
00470 remove_from_scroll_child_list_(pFrame);
00471
00472 bRebuildScrollStrataList_ = true;
00473 }
00474 }
00475 }