llview.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:70k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llview.cpp
  3.  * @author James Cook
  4.  * @brief Container for other views, anything that draws.
  5.  *
  6.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2001-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  */
  33. #include "linden_common.h"
  34. #define LLVIEW_CPP
  35. #include "llview.h"
  36. #include <cassert>
  37. #include <boost/tokenizer.hpp>
  38. #include "llrender.h"
  39. #include "llevent.h"
  40. #include "llfocusmgr.h"
  41. #include "llrect.h"
  42. #include "llstl.h"
  43. #include "llui.h"
  44. #include "lluictrl.h"
  45. #include "llwindow.h"
  46. #include "v3color.h"
  47. #include "lluictrlfactory.h"
  48. #include "lltooltip.h"
  49. // for ui edit hack
  50. #include "llbutton.h"
  51. #include "lllineeditor.h"
  52. #include "lltexteditor.h"
  53. #include "lltextbox.h"
  54. S32 LLView::sDepth = 0;
  55. bool LLView::sDebugRects = false;
  56. bool LLView::sDebugRectsShowNames = true;
  57. bool LLView::sDebugKeys = false;
  58. bool LLView::sDebugMouseHandling = false;
  59. std::string LLView::sMouseHandlerMessage;
  60. BOOL LLView::sForceReshape = FALSE;
  61. std::set<LLView*> LLView::sPreviewHighlightedElements;
  62. BOOL LLView::sHighlightingDiffs = FALSE;
  63. LLView* LLView::sPreviewClickedElement = NULL;
  64. BOOL LLView::sDrawPreviewHighlights = FALSE;
  65. S32 LLView::sLastLeftXML = S32_MIN;
  66. S32 LLView::sLastBottomXML = S32_MIN;
  67. std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack;
  68. #if LL_DEBUG
  69. BOOL LLView::sIsDrawing = FALSE;
  70. #endif
  71. // Compiler optimization, generate extern template
  72. template class LLView* LLView::getChild<class LLView>(
  73. const std::string& name, BOOL recurse) const;
  74. static LLDefaultChildRegistry::Register<LLView> r("view");
  75. LLView::Follows::Follows()
  76. :   string(""),
  77. flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP)
  78. {}
  79. LLView::Params::Params()
  80. : name("name", std::string("unnamed")),
  81. enabled("enabled", true),
  82. visible("visible", true),
  83. mouse_opaque("mouse_opaque", true),
  84. follows("follows"),
  85. hover_cursor("hover_cursor", "UI_CURSOR_ARROW"),
  86. use_bounding_rect("use_bounding_rect", false),
  87. tab_group("tab_group", 0),
  88. default_tab_group("default_tab_group"),
  89. tool_tip("tool_tip"),
  90. sound_flags("sound_flags", MOUSE_UP),
  91. layout("layout"),
  92. rect("rect"),
  93. bottom_delta("bottom_delta", S32_MAX),
  94. top_pad("top_pad"),
  95. top_delta("top_delta", S32_MAX),
  96. left_pad("left_pad"),
  97. left_delta("left_delta", S32_MAX),
  98. center_horiz("center_horiz", false),
  99. center_vert("center_vert", false),
  100. from_xui("from_xui", false),
  101. user_resize("user_resize"),
  102. auto_resize("auto_resize"),
  103. needs_translate("translate"),
  104. xmlns("xmlns"),
  105. xmlns_xsi("xmlns:xsi"),
  106. xsi_schemaLocation("xsi:schemaLocation"),
  107. xsi_type("xsi:type")
  108. {
  109. addSynonym(rect, "");
  110. }
  111. LLView::LLView(const LLView::Params& p)
  112. : mName(p.name),
  113. mParentView(NULL),
  114. mReshapeFlags(FOLLOWS_NONE),
  115. mFromXUI(p.from_xui),
  116. mIsFocusRoot(FALSE),
  117. mLastVisible(FALSE),
  118. mNextInsertionOrdinal(0),
  119. mHoverCursor(getCursorFromString(p.hover_cursor)),
  120. mEnabled(p.enabled),
  121. mVisible(p.visible),
  122. mMouseOpaque(p.mouse_opaque),
  123. mSoundFlags(p.sound_flags),
  124. mUseBoundingRect(p.use_bounding_rect),
  125. mDefaultTabGroup(p.default_tab_group),
  126. mLastTabGroup(0),
  127. mToolTipMsg((LLStringExplicit)p.tool_tip()),
  128. mDefaultWidgets(NULL)
  129. {
  130. // create rect first, as this will supply initial follows flags
  131. setShape(p.rect);
  132. parseFollowsFlags(p);
  133. }
  134. LLView::~LLView()
  135. {
  136. dirtyRect();
  137. //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl;
  138. //  llassert(LLView::sIsDrawing == FALSE);
  139. // llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators
  140. if( hasMouseCapture() )
  141. {
  142. //llwarns << "View holding mouse capture deleted: " << getName() << ".  Mouse capture removed." << llendl;
  143. gFocusMgr.removeMouseCaptureWithoutCallback( this );
  144. }
  145. deleteAllChildren();
  146. if (mParentView != NULL)
  147. {
  148. mParentView->removeChild(this);
  149. }
  150. if (mDefaultWidgets)
  151. {
  152. std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
  153.   DeletePairedPointer());
  154. delete mDefaultWidgets;
  155. mDefaultWidgets = NULL;
  156. }
  157. }
  158. // virtual
  159. BOOL LLView::isCtrl() const
  160. {
  161. return FALSE;
  162. }
  163. // virtual
  164. BOOL LLView::isPanel() const
  165. {
  166. return FALSE;
  167. }
  168. void LLView::setToolTip(const LLStringExplicit& msg)
  169. {
  170. mToolTipMsg = msg;
  171. }
  172. BOOL LLView::setToolTipArg(const LLStringExplicit& key, const LLStringExplicit& text)
  173. {
  174. mToolTipMsg.setArg(key, text);
  175. return TRUE;
  176. }
  177. void LLView::setToolTipArgs( const LLStringUtil::format_map_t& args )
  178. {
  179. mToolTipMsg.setArgList(args);
  180. }
  181. // virtual
  182. void LLView::setRect(const LLRect& rect)
  183. {
  184. mRect = rect;
  185. updateBoundingRect();
  186. }
  187. void LLView::setUseBoundingRect( BOOL use_bounding_rect ) 
  188. {
  189. if (mUseBoundingRect != use_bounding_rect)
  190. {
  191.         mUseBoundingRect = use_bounding_rect; 
  192. updateBoundingRect();
  193. }
  194. }
  195. BOOL LLView::getUseBoundingRect()
  196. {
  197. return mUseBoundingRect;
  198. }
  199. // virtual
  200. std::string LLView::getName() const
  201. {
  202. return mName.empty() ? std::string("(no name)") : mName;
  203. }
  204. void LLView::sendChildToFront(LLView* child)
  205. {
  206. //  llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
  207. if (child && child->getParent() == this) 
  208. {
  209. // minor optimization, but more importantly,
  210. //  won't temporarily create an empty list
  211. if (child != mChildList.front())
  212. {
  213. mChildList.remove( child );
  214. mChildList.push_front(child);
  215. }
  216. }
  217. }
  218. void LLView::sendChildToBack(LLView* child)
  219. {
  220. //  llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
  221. if (child && child->getParent() == this) 
  222. {
  223. // minor optimization, but more importantly,
  224. //  won't temporarily create an empty list
  225. if (child != mChildList.back())
  226. {
  227. mChildList.remove( child );
  228. mChildList.push_back(child);
  229. }
  230. }
  231. }
  232. void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child)
  233. {
  234. if(mCtrlOrder.find(child) != mCtrlOrder.end())
  235. {
  236. mCtrlOrder[child].second = -1 * mNextInsertionOrdinal++;
  237. }
  238. }
  239. void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
  240. {
  241. if(mCtrlOrder.find(child) != mCtrlOrder.end())
  242. {
  243. mCtrlOrder[child].second = mNextInsertionOrdinal++;
  244. }
  245. }
  246. // virtual
  247. bool LLView::addChild(LLView* child, S32 tab_group)
  248. {
  249. if (!child)
  250. {
  251. return false;
  252. }
  253. if (mParentView == child) 
  254. {
  255. llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
  256. }
  257. // remove from current parent
  258. if (child->mParentView) 
  259. {
  260. child->mParentView->removeChild(child);
  261. }
  262. // add to front of child list, as normal
  263. mChildList.push_front(child);
  264. // add to ctrl list if is LLUICtrl
  265. if (child->isCtrl())
  266. {
  267. LLUICtrl* ctrl = static_cast<LLUICtrl*>(child);
  268. mCtrlOrder.insert(tab_order_pair_t(ctrl,
  269. tab_order_t(tab_group, mNextInsertionOrdinal)));
  270. mNextInsertionOrdinal++;
  271. }
  272. child->mParentView = this;
  273. updateBoundingRect();
  274. mLastTabGroup = tab_group;
  275. return true;
  276. }
  277. bool LLView::addChildInBack(LLView* child, S32 tab_group)
  278. {
  279. if(addChild(child, tab_group))
  280. {
  281. sendChildToBack(child);
  282. return true;
  283. }
  284. return false;
  285. }
  286. // remove the specified child from the view, and set it's parent to NULL.
  287. void LLView::removeChild(LLView* child)
  288. {
  289. //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
  290. if (child->mParentView == this) 
  291. {
  292. mChildList.remove( child );
  293. child->mParentView = NULL;
  294. if (child->isCtrl())
  295. {
  296. child_tab_order_t::iterator found = mCtrlOrder.find(static_cast<LLUICtrl*>(child));
  297. if(found != mCtrlOrder.end())
  298. {
  299. mCtrlOrder.erase(found);
  300. }
  301. }
  302. }
  303. else
  304. {
  305. llerrs << "LLView::removeChild called with non-child" << llendl;
  306. }
  307. updateBoundingRect();
  308. }
  309. LLView::ctrl_list_t LLView::getCtrlList() const
  310. {
  311. ctrl_list_t controls;
  312. for(child_list_const_iter_t iter = mChildList.begin();
  313. iter != mChildList.end();
  314. iter++)
  315. {
  316. if((*iter)->isCtrl())
  317. {
  318. controls.push_back(static_cast<LLUICtrl*>(*iter));
  319. }
  320. }
  321. return controls;
  322. }
  323. LLView::ctrl_list_t LLView::getCtrlListSorted() const
  324. {
  325. ctrl_list_t controls = getCtrlList();
  326. std::sort(controls.begin(), controls.end(), LLCompareByTabOrder(mCtrlOrder));
  327. return controls;
  328. }
  329. // This method compares two LLViews by the tab order specified in the comparator object.  The
  330. // code for this is a little convoluted because each argument can have four states:
  331. // 1) not a control, 2) a control but not in the tab order, 3) a control in the tab order, 4) null
  332. bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const b) const
  333. {
  334. S32 a_score = 0, b_score = 0;
  335. if(a) a_score--;
  336. if(b) b_score--;
  337. if(a && a->isCtrl()) a_score--;
  338. if(b && b->isCtrl()) b_score--;
  339. if(a_score == -2 && b_score == -2)
  340. {
  341. const LLUICtrl * const a_ctrl = static_cast<const LLUICtrl*>(a);
  342. const LLUICtrl * const b_ctrl = static_cast<const LLUICtrl*>(b);
  343. LLView::child_tab_order_const_iter_t a_found = mTabOrder.find(a_ctrl), b_found = mTabOrder.find(b_ctrl);
  344. if(a_found != mTabOrder.end()) a_score--;
  345. if(b_found != mTabOrder.end()) b_score--;
  346. if(a_score == -3 && b_score == -3)
  347. {
  348. // whew!  Once we're in here, they're both in the tab order, and we can compare based on that
  349. return compareTabOrders(a_found->second, b_found->second);
  350. }
  351. }
  352. return (a_score == b_score) ? a < b : a_score < b_score;
  353. }
  354. bool LLView::trueToRoot(const boost::function<bool (const LLView*)>& predicate) const
  355. {
  356. const LLView* cur_view = this;
  357. while(cur_view)
  358. {
  359. if(!predicate(cur_view))
  360. {
  361. return false;
  362. }
  363. cur_view = cur_view->getParent();
  364. }
  365. return true;
  366. }
  367. BOOL LLView::isInVisibleChain() const
  368. {
  369. return trueToRoot(&LLView::getVisible);
  370. }
  371. BOOL LLView::isInEnabledChain() const
  372. {
  373. return trueToRoot(&LLView::getEnabled);
  374. }
  375. // virtual
  376. BOOL LLView::canFocusChildren() const
  377. {
  378. return TRUE;
  379. }
  380. //virtual
  381. void LLView::setTentative(BOOL b)
  382. {
  383. }
  384. //virtual
  385. BOOL LLView::getTentative() const
  386. {
  387. return FALSE;
  388. }
  389. //virtual
  390. void LLView::setEnabled(BOOL enabled)
  391. {
  392. mEnabled = enabled;
  393. }
  394. //virtual
  395. bool LLView::isAvailable() const
  396. {
  397.     return isInEnabledChain() && isInVisibleChain();
  398. }
  399. //static
  400. bool LLView::isAvailable(const LLView* view)
  401. {
  402.     return view && view->isAvailable();
  403. }
  404. //virtual
  405. BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
  406. {
  407. return FALSE;
  408. }
  409. //virtual
  410. LLRect LLView::getSnapRect() const
  411. {
  412. return mRect;
  413. }
  414. //virtual
  415. LLRect LLView::getRequiredRect()
  416. {
  417. return mRect;
  418. }
  419. BOOL LLView::focusNextRoot()
  420. {
  421. LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
  422. return LLView::focusNext(result);
  423. }
  424. BOOL LLView::focusPrevRoot()
  425. {
  426. LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
  427. return LLView::focusPrev(result);
  428. }
  429. // static
  430. BOOL LLView::focusNext(LLView::child_list_t & result)
  431. {
  432. LLView::child_list_iter_t focused = result.end();
  433. for(LLView::child_list_iter_t iter = result.begin();
  434. iter != result.end();
  435. ++iter)
  436. {
  437. if(gFocusMgr.childHasKeyboardFocus(*iter))
  438. {
  439. focused = iter;
  440. break;
  441. }
  442. }
  443. LLView::child_list_iter_t next = focused;
  444. next = (next == result.end()) ? result.begin() : ++next;
  445. while(next != focused)
  446. {
  447. // wrap around to beginning if necessary
  448. if(next == result.end())
  449. {
  450. next = result.begin();
  451. }
  452. if((*next)->isCtrl())
  453. {
  454. LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next);
  455. ctrl->setFocus(TRUE);
  456. ctrl->onTabInto();  
  457. gFocusMgr.triggerFocusFlash();
  458. return TRUE;
  459. }
  460. ++next;
  461. }
  462. return FALSE;
  463. }
  464. // static
  465. BOOL LLView::focusPrev(LLView::child_list_t & result)
  466. {
  467. LLView::child_list_reverse_iter_t focused = result.rend();
  468. for(LLView::child_list_reverse_iter_t iter = result.rbegin();
  469. iter != result.rend();
  470. ++iter)
  471. {
  472. if(gFocusMgr.childHasKeyboardFocus(*iter))
  473. {
  474. focused = iter;
  475. break;
  476. }
  477. }
  478. LLView::child_list_reverse_iter_t next = focused;
  479. next = (next == result.rend()) ? result.rbegin() : ++next;
  480. while(next != focused)
  481. {
  482. // wrap around to beginning if necessary
  483. if(next == result.rend())
  484. {
  485. next = result.rbegin();
  486. }
  487. if((*next)->isCtrl())
  488. {
  489. LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next);
  490. if (!ctrl->hasFocus())
  491. {
  492. ctrl->setFocus(TRUE);
  493. ctrl->onTabInto();  
  494. gFocusMgr.triggerFocusFlash();
  495. }
  496. return TRUE;
  497. }
  498. ++next;
  499. }
  500. return FALSE;
  501. }
  502. // delete all children. Override this function if you need to
  503. // perform any extra clean up such as cached pointers to selected
  504. // children, etc.
  505. void LLView::deleteAllChildren()
  506. {
  507. // clear out the control ordering
  508. mCtrlOrder.clear();
  509. while (!mChildList.empty())
  510. {
  511. LLView* viewp = mChildList.front();
  512. delete viewp; // will remove the child from mChildList
  513. }
  514. }
  515. void LLView::setAllChildrenEnabled(BOOL b)
  516. {
  517. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  518. {
  519. LLView* viewp = *child_it;
  520. viewp->setEnabled(b);
  521. }
  522. }
  523. // virtual
  524. void LLView::setVisible(BOOL visible)
  525. {
  526. if ( mVisible != visible )
  527. {
  528. if( !visible && (gFocusMgr.getTopCtrl() == this) )
  529. {
  530. gFocusMgr.setTopCtrl( NULL );
  531. }
  532. mVisible = visible;
  533. // notify children of visibility change if root, or part of visible hierarchy
  534. if (!getParent() || getParent()->isInVisibleChain())
  535. {
  536. // tell all children of this view that the visibility may have changed
  537. dirtyRect();
  538. handleVisibilityChange( visible );
  539. }
  540. updateBoundingRect();
  541. }
  542. }
  543. // virtual
  544. void LLView::handleVisibilityChange ( BOOL new_visibility )
  545. {
  546. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  547. {
  548. LLView* viewp = *child_it;
  549. // only views that are themselves visible will have their overall visibility affected by their ancestors
  550. if (viewp->getVisible())
  551. {
  552. viewp->handleVisibilityChange ( new_visibility );
  553. }
  554. }
  555. }
  556. // virtual
  557. void LLView::translate(S32 x, S32 y)
  558. {
  559. mRect.translate(x, y);
  560. updateBoundingRect();
  561. }
  562. // virtual
  563. BOOL LLView::canSnapTo(const LLView* other_view)
  564. {
  565. return other_view != this && other_view->getVisible();
  566. }
  567. // virtual
  568. void LLView::setSnappedTo(const LLView* snap_view)
  569. {
  570. }
  571. BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
  572. {
  573. return childrenHandleHover( x, y, mask ) != NULL;
  574. }
  575. void LLView::onMouseEnter(S32 x, S32 y, MASK mask)
  576. {
  577. //llinfos << "Mouse entered " << getName() << llendl;
  578. }
  579. void LLView::onMouseLeave(S32 x, S32 y, MASK mask)
  580. {
  581. //llinfos << "Mouse left " << getName() << llendl;
  582. }
  583. LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
  584. {
  585. LLView* handled_view = NULL;
  586. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  587. {
  588. LLView* viewp = *child_it;
  589. S32 local_x = x - viewp->getRect().mLeft;
  590. S32 local_y = y - viewp->getRect().mBottom;
  591. if(!viewp->pointInView(local_x, local_y) 
  592. || !viewp->getVisible())
  593. {
  594. continue;
  595. }
  596. if (viewp->handleToolTip(local_x, local_y, mask) )
  597. {
  598. if (sDebugMouseHandling)
  599. {
  600. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  601. }
  602. handled_view = viewp;
  603. break;
  604. }
  605. if (viewp->blockMouseEvent(local_x, local_y))
  606. {
  607. handled_view = viewp;
  608. break;
  609. }
  610. }
  611. return handled_view;
  612. }
  613. LLView* LLView::childFromPoint(S32 x, S32 y)
  614. {
  615. if (!getVisible()  )
  616. return false;
  617. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  618. {
  619. LLView* viewp = *child_it;
  620. S32 local_x = x - viewp->getRect().mLeft;
  621. S32 local_y = y - viewp->getRect().mBottom;
  622. if (!viewp->pointInView(local_x, local_y) 
  623. || !viewp->getVisible() )
  624. {
  625. continue;
  626. }
  627. return viewp;
  628. }
  629. return 0;
  630. }
  631. BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
  632. {
  633. BOOL handled = FALSE;
  634. // parents provide tooltips first, which are optionally
  635. // overridden by children, in case child is mouse_opaque
  636. if (!mToolTipMsg.empty())
  637. {
  638. // allow "scrubbing" over ui by showing next tooltip immediately
  639. // if previous one was still visible
  640. F32 timeout = LLToolTipMgr::instance().toolTipVisible() 
  641. ? 0.f
  642. : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
  643. LLToolTipMgr::instance().show(LLToolTip::Params()
  644. .message(mToolTipMsg)
  645. .sticky_rect(calcScreenRect())
  646. .delay_time(timeout));
  647. handled = TRUE;
  648. }
  649. // child tooltips will override our own
  650. LLView* child_handler = childrenHandleToolTip(x, y, mask);
  651. if (child_handler)
  652. {
  653. handled = TRUE;
  654. }
  655. return handled;
  656. }
  657. BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
  658. {
  659. BOOL handled = FALSE;
  660. if (getVisible() && getEnabled())
  661. {
  662. if( called_from_parent )
  663. {
  664. // Downward traversal
  665. handled = childrenHandleKey( key, mask ) != NULL;
  666. }
  667. if (!handled)
  668. {
  669. handled = handleKeyHere( key, mask );
  670. if (handled && LLView::sDebugKeys)
  671. {
  672. llinfos << "Key handled by " << getName() << llendl;
  673. }
  674. }
  675. }
  676. if( !handled && !called_from_parent && mParentView)
  677. {
  678. // Upward traversal
  679. handled = mParentView->handleKey( key, mask, FALSE );
  680. }
  681. return handled;
  682. }
  683. // Called from handleKey()
  684. // Handles key in this object.  Checking parents and children happens in handleKey()
  685. BOOL LLView::handleKeyHere(KEY key, MASK mask)
  686. {
  687. return FALSE;
  688. }
  689. BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
  690. {
  691. BOOL handled = FALSE;
  692. if (getVisible() && getEnabled())
  693. {
  694. if( called_from_parent )
  695. {
  696. // Downward traversal
  697. handled = childrenHandleUnicodeChar( uni_char ) != NULL;
  698. }
  699. if (!handled)
  700. {
  701. handled = handleUnicodeCharHere(uni_char);
  702. if (handled && LLView::sDebugKeys)
  703. {
  704. llinfos << "Unicode key handled by " << getName() << llendl;
  705. }
  706. }
  707. }
  708. if (!handled && !called_from_parent && mParentView)
  709. {
  710. // Upward traversal
  711. handled = mParentView->handleUnicodeChar(uni_char, FALSE);
  712. }
  713. return handled;
  714. }
  715. BOOL LLView::handleUnicodeCharHere(llwchar uni_char )
  716. {
  717. return FALSE;
  718. }
  719. BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  720.    EDragAndDropType cargo_type, void* cargo_data,
  721.    EAcceptance* accept,
  722.    std::string& tooltip_msg)
  723. {
  724. return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;
  725. }
  726. LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
  727.    BOOL drop,
  728.    EDragAndDropType cargo_type,
  729.    void* cargo_data,
  730.    EAcceptance* accept,
  731.    std::string& tooltip_msg)
  732. {
  733. LLView* handled_view = NULL;
  734. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  735. {
  736. LLView* viewp = *child_it;
  737. S32 local_x = x - viewp->getRect().mLeft;
  738. S32 local_y = y - viewp->getRect().mBottom;
  739. if( !viewp->pointInView(local_x, local_y) ||
  740. !viewp->getVisible() ||
  741. !viewp->getEnabled())
  742. {
  743. continue;
  744. }
  745. if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
  746.  cargo_type,
  747.  cargo_data,
  748.  accept,
  749.  tooltip_msg))
  750. {
  751. handled_view = viewp;
  752. break;
  753. }
  754. if (viewp->blockMouseEvent(x, y))
  755. {
  756. *accept = ACCEPT_NO;
  757. handled_view = viewp;
  758. break;
  759. }
  760. }
  761. return handled_view;
  762. }
  763. void LLView::onMouseCaptureLost()
  764. {
  765. }
  766. BOOL LLView::hasMouseCapture()
  767. return gFocusMgr.getMouseCapture() == this; 
  768. }
  769. BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
  770. {
  771. return childrenHandleMouseUp( x, y, mask ) != NULL;
  772. }
  773. BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
  774. {
  775. return childrenHandleMouseDown( x, y, mask ) != NULL;
  776. }
  777. BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
  778. {
  779. return childrenHandleDoubleClick( x, y, mask ) != NULL;
  780. }
  781. BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
  782. {
  783. return childrenHandleScrollWheel( x, y, clicks ) != NULL;
  784. }
  785. BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
  786. {
  787. return childrenHandleRightMouseDown( x, y, mask ) != NULL;
  788. }
  789. BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
  790. {
  791. return childrenHandleRightMouseUp( x, y, mask ) != NULL;
  792. }
  793.  
  794. BOOL LLView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
  795. {
  796. return childrenHandleMiddleMouseDown( x, y, mask ) != NULL;
  797. }
  798. BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
  799. {
  800. return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
  801. }
  802. LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
  803. {
  804. LLView* handled_view = NULL;
  805. if (getVisible() && getEnabled() )
  806. {
  807. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  808. {
  809. LLView* viewp = *child_it;
  810. S32 local_x = x - viewp->getRect().mLeft;
  811. S32 local_y = y - viewp->getRect().mBottom;
  812. if (!viewp->pointInView(local_x, local_y) 
  813. || !viewp->getVisible()
  814. || !viewp->getEnabled())
  815. {
  816. continue;
  817. }
  818. if (viewp->handleScrollWheel( local_x, local_y, clicks ))
  819. {
  820. if (sDebugMouseHandling)
  821. {
  822. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  823. }
  824. handled_view = viewp;
  825. break;
  826. }
  827. }
  828. }
  829. return handled_view;
  830. }
  831. LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
  832. {
  833. LLView* handled_view = NULL;
  834. if (getVisible() && getEnabled() )
  835. {
  836. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  837. {
  838. LLView* viewp = *child_it;
  839. S32 local_x = x - viewp->getRect().mLeft;
  840. S32 local_y = y - viewp->getRect().mBottom;
  841. if(!viewp->pointInView(local_x, local_y) 
  842. || !viewp->getVisible() 
  843. || !viewp->getEnabled())
  844. {
  845. continue;
  846. }
  847. if (viewp->handleHover(local_x, local_y, mask) )
  848. {
  849. if (sDebugMouseHandling)
  850. {
  851. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  852. }
  853. handled_view = viewp;
  854. break;
  855. }
  856. if (viewp->blockMouseEvent(local_x, local_y))
  857. {
  858. LLUI::sWindow->setCursor(viewp->getHoverCursor());
  859. handled_view = viewp;
  860. break;
  861. }
  862. }
  863. }
  864. return handled_view;
  865. }
  866. // Called during downward traversal
  867. LLView* LLView::childrenHandleKey(KEY key, MASK mask)
  868. {
  869. LLView* handled_view = NULL;
  870. if ( getVisible() && getEnabled() )
  871. {
  872. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  873. {
  874. LLView* viewp = *child_it;
  875. if (viewp->handleKey(key, mask, TRUE))
  876. {
  877. if (LLView::sDebugKeys)
  878. {
  879. llinfos << "Key handled by " << viewp->getName() << llendl;
  880. }
  881. handled_view = viewp;
  882. break;
  883. }
  884. }
  885. }
  886. return handled_view;
  887. }
  888. // Called during downward traversal
  889. LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
  890. {
  891. LLView* handled_view = NULL;
  892. if ( getVisible() && getEnabled() )
  893. {
  894. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  895. {
  896. LLView* viewp = *child_it;
  897. if (viewp->handleUnicodeChar(uni_char, TRUE))
  898. {
  899. if (LLView::sDebugKeys)
  900. {
  901. llinfos << "Unicode character handled by " << viewp->getName() << llendl;
  902. }
  903. handled_view = viewp;
  904. break;
  905. }
  906. }
  907. }
  908. return handled_view;
  909. }
  910. LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
  911. {
  912. LLView* handled_view = NULL;
  913. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  914. {
  915. LLView* viewp = *child_it;
  916. S32 local_x = x - viewp->getRect().mLeft;
  917. S32 local_y = y - viewp->getRect().mBottom;
  918. if (!viewp->pointInView(local_x, local_y) 
  919. || !viewp->getVisible() 
  920. || !viewp->getEnabled())
  921. {
  922. continue;
  923. }
  924. if(viewp->handleMouseDown( local_x, local_y, mask ))
  925. {
  926. if (sDebugMouseHandling)
  927. {
  928. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  929. }
  930. handled_view = viewp;
  931. break;
  932. }
  933. if(viewp->blockMouseEvent(local_x, local_y))
  934. {
  935. handled_view = viewp;
  936. break;
  937. }
  938. }
  939. return handled_view;
  940. }
  941. LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
  942. {
  943. LLView* handled_view = NULL;
  944. if (getVisible() && getEnabled() )
  945. {
  946. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  947. {
  948. LLView* viewp = *child_it;
  949. S32 local_x = x - viewp->getRect().mLeft;
  950. S32 local_y = y - viewp->getRect().mBottom;
  951. if (!viewp->pointInView(local_x, local_y)
  952. || !viewp->getVisible() 
  953. || !viewp->getEnabled())
  954. {
  955. continue;
  956. }
  957. if (viewp->handleRightMouseDown( local_x, local_y, mask ))
  958. {
  959. if (sDebugMouseHandling)
  960. {
  961. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  962. }
  963. handled_view = viewp;
  964. break;
  965. }
  966. if (viewp->blockMouseEvent(local_x, local_y))
  967. {
  968. handled_view = viewp;
  969. break;
  970. }
  971. }
  972. }
  973. return handled_view;
  974. }
  975. LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
  976. {
  977. LLView* handled_view = NULL;
  978. if (getVisible() && getEnabled() )
  979. {
  980. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  981. {
  982. LLView* viewp = *child_it;
  983. S32 local_x = x - viewp->getRect().mLeft;
  984. S32 local_y = y - viewp->getRect().mBottom;
  985. if (!viewp->pointInView(local_x, local_y)
  986. || !viewp->getVisible() 
  987. || !viewp->getEnabled())
  988. {
  989. continue;
  990. }
  991. if(viewp->handleMiddleMouseDown( local_x, local_y, mask ))
  992. {
  993. if (sDebugMouseHandling)
  994. {
  995. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  996. }
  997. handled_view = viewp;
  998. break;
  999. }
  1000. if (viewp->blockMouseEvent(local_x, local_y))
  1001. {
  1002. handled_view = viewp;
  1003. break;
  1004. }
  1005. }
  1006. }
  1007. return handled_view;
  1008. }
  1009. LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
  1010. {
  1011. LLView* handled_view = NULL;
  1012. if (getVisible() && getEnabled() )
  1013. {
  1014. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1015. {
  1016. LLView* viewp = *child_it;
  1017. S32 local_x = x - viewp->getRect().mLeft;
  1018. S32 local_y = y - viewp->getRect().mBottom;
  1019. if (!viewp->pointInView(local_x, local_y) 
  1020. || !viewp->getVisible() 
  1021. || !viewp->getEnabled())
  1022. {
  1023. continue;
  1024. }
  1025. if (viewp->handleDoubleClick( local_x, local_y, mask ))
  1026. {
  1027. if (sDebugMouseHandling)
  1028. {
  1029. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  1030. }
  1031. handled_view = viewp;
  1032. break;
  1033. }
  1034. if (viewp->blockMouseEvent(local_x, local_y))
  1035. {
  1036. handled_view = viewp;
  1037. break;
  1038. }
  1039. }
  1040. }
  1041. return handled_view;
  1042. }
  1043. LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
  1044. {
  1045. LLView* handled_view = NULL;
  1046. if( getVisible() && getEnabled() )
  1047. {
  1048. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1049. {
  1050. LLView* viewp = *child_it;
  1051. S32 local_x = x - viewp->getRect().mLeft;
  1052. S32 local_y = y - viewp->getRect().mBottom;
  1053. if (!viewp->pointInView(local_x, local_y)
  1054. || !viewp->getVisible()
  1055. || !viewp->getEnabled())
  1056. {
  1057. continue;
  1058. }
  1059. if (viewp->handleMouseUp( local_x, local_y, mask ))
  1060. {
  1061. if (sDebugMouseHandling)
  1062. {
  1063. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  1064. }
  1065. handled_view = viewp;
  1066. break;
  1067. }
  1068. if (viewp->blockMouseEvent(local_x, local_y))
  1069. {
  1070. handled_view = viewp;
  1071. break;
  1072. }
  1073. }
  1074. }
  1075. return handled_view;
  1076. }
  1077. LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
  1078. {
  1079. LLView* handled_view = NULL;
  1080. if( getVisible() && getEnabled() )
  1081. {
  1082. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1083. {
  1084. LLView* viewp = *child_it;
  1085. S32 local_x = x - viewp->getRect().mLeft;
  1086. S32 local_y = y - viewp->getRect().mBottom;
  1087. if (!viewp->pointInView(local_x, local_y) 
  1088. || !viewp->getVisible() 
  1089. || !viewp->getEnabled() )
  1090. {
  1091. continue;
  1092. }
  1093. if(viewp->handleRightMouseUp( local_x, local_y, mask ))
  1094. {
  1095. if (sDebugMouseHandling)
  1096. {
  1097. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  1098. }
  1099. handled_view = viewp;
  1100. break;
  1101. }
  1102. if(viewp->blockMouseEvent(local_x, local_y))
  1103. {
  1104. handled_view = viewp;
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. return handled_view;
  1110. }
  1111. LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
  1112. {
  1113. LLView* handled_view = NULL;
  1114. if( getVisible() && getEnabled() )
  1115. {
  1116. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1117. {
  1118. LLView* viewp = *child_it;
  1119. S32 local_x = x - viewp->getRect().mLeft;
  1120. S32 local_y = y - viewp->getRect().mBottom;
  1121. if (!viewp->pointInView(local_x, local_y) 
  1122. || !viewp->getVisible() 
  1123. || !viewp->getEnabled())
  1124. {
  1125. continue;
  1126. }
  1127. if(viewp->handleMiddleMouseUp( local_x, local_y, mask ))
  1128. {
  1129. if (sDebugMouseHandling)
  1130. {
  1131. sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
  1132. }
  1133. handled_view = viewp;
  1134. break;
  1135. }
  1136. if (viewp->blockMouseEvent(local_x, local_y))
  1137. {
  1138. handled_view = viewp;
  1139. break;
  1140. }
  1141. }
  1142. }
  1143. return handled_view;
  1144. }
  1145. void LLView::draw()
  1146. {
  1147. drawChildren();
  1148. }
  1149. void LLView::drawChildren()
  1150. {
  1151. if (!mChildList.empty())
  1152. {
  1153. LLRect rootRect = getRootView()->getRect();
  1154. LLRect screenRect;
  1155. ++sDepth;
  1156. for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();)  // ++child_iter)
  1157. {
  1158. child_list_reverse_iter_t child = child_iter++;
  1159. LLView *viewp = *child;
  1160. if (viewp->getVisible() && viewp->getRect().isValid())
  1161. {
  1162. // Only draw views that are within the root view
  1163. localRectToScreen(viewp->getRect(),&screenRect);
  1164. if ( rootRect.overlaps(screenRect)  && LLUI::sDirtyRect.overlaps(screenRect))
  1165. {
  1166. glMatrixMode(GL_MODELVIEW);
  1167. LLUI::pushMatrix();
  1168. {
  1169. LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
  1170. viewp->draw();
  1171. if (sDebugRects)
  1172. {
  1173. viewp->drawDebugRect();
  1174. // Check for bogus rectangle
  1175. if (!getRect().isValid())
  1176. {
  1177. llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
  1178. }
  1179. }
  1180. }
  1181. LLUI::popMatrix();
  1182. }
  1183. }
  1184. }
  1185. --sDepth;
  1186. }
  1187. gGL.getTexUnit(0)->disable();
  1188. }
  1189. void LLView::dirtyRect()
  1190. {
  1191. LLView* child = getParent();
  1192. LLView* parent = child ? child->getParent() : NULL;
  1193. LLView* cur = this;
  1194. while (child && parent && parent->getParent())
  1195. { //find third to top-most view
  1196. cur = child;
  1197. child = parent;
  1198. parent = parent->getParent();
  1199. }
  1200. LLUI::dirtyRect(cur->calcScreenRect());
  1201. }
  1202. //Draw a box for debugging.
  1203. void LLView::drawDebugRect()
  1204. {
  1205. std::set<LLView*>::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element
  1206. LLUI::pushMatrix();
  1207. {
  1208. // drawing solids requires texturing be disabled
  1209. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  1210. if (mUseBoundingRect)
  1211. {
  1212. LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);
  1213. }
  1214. LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
  1215. // draw red rectangle for the border
  1216. LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f);
  1217. if(preview_iter != sPreviewHighlightedElements.end())
  1218. {
  1219. if(LLView::sPreviewClickedElement && this == sPreviewClickedElement)
  1220. {
  1221. border_color = LLColor4::red;
  1222. }
  1223. else
  1224. {
  1225. static LLUIColor scroll_highlighted_color = LLUIColorTable::instance().getColor("ScrollHighlightedColor");
  1226. border_color = scroll_highlighted_color;
  1227. }
  1228. }
  1229. else
  1230. {
  1231. border_color.mV[sDepth%3] = 1.f;
  1232. }
  1233. gGL.color4fv( border_color.mV );
  1234. gGL.begin(LLRender::LINES);
  1235. gGL.vertex2i(0, debug_rect.getHeight() - 1);
  1236. gGL.vertex2i(0, 0);
  1237. gGL.vertex2i(0, 0);
  1238. gGL.vertex2i(debug_rect.getWidth() - 1, 0);
  1239. gGL.vertex2i(debug_rect.getWidth() - 1, 0);
  1240. gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
  1241. gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
  1242. gGL.vertex2i(0, debug_rect.getHeight() - 1);
  1243. gGL.end();
  1244. // Draw the name if it's not a leaf node or not in editing or preview mode
  1245. if (mChildList.size()
  1246. && preview_iter == sPreviewHighlightedElements.end()
  1247. && sDebugRectsShowNames)
  1248. {
  1249. //char temp[256];
  1250. S32 x, y;
  1251. gGL.color4fv( border_color.mV );
  1252. x = debug_rect.getWidth()/2;
  1253. y = debug_rect.getHeight()/2;
  1254. std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
  1255. debug_rect.getWidth(), debug_rect.getHeight());
  1256. LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
  1257. LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
  1258. S32_MAX, S32_MAX, NULL, FALSE);
  1259. }
  1260. }
  1261. LLUI::popMatrix();
  1262. }
  1263. void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw)
  1264. {
  1265. if (childp && childp->getParent() == this)
  1266. {
  1267. ++sDepth;
  1268. if ((childp->getVisible() && childp->getRect().isValid()) 
  1269. || force_draw)
  1270. {
  1271. glMatrixMode(GL_MODELVIEW);
  1272. LLUI::pushMatrix();
  1273. {
  1274. LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset, 0.f);
  1275. childp->draw();
  1276. }
  1277. LLUI::popMatrix();
  1278. }
  1279. --sDepth;
  1280. }
  1281. }
  1282. void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
  1283. {
  1284. // compute how much things changed and apply reshape logic to children
  1285. S32 delta_width = width - getRect().getWidth();
  1286. S32 delta_height = height - getRect().getHeight();
  1287. if (delta_width || delta_height || sForceReshape)
  1288. {
  1289. // adjust our rectangle
  1290. mRect.mRight = getRect().mLeft + width;
  1291. mRect.mTop = getRect().mBottom + height;
  1292. // move child views according to reshape flags
  1293. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1294. {
  1295. LLView* viewp = *child_it;
  1296. LLRect child_rect( viewp->mRect );
  1297. if (viewp->followsRight() && viewp->followsLeft())
  1298. {
  1299. child_rect.mRight += delta_width;
  1300. }
  1301. else if (viewp->followsRight())
  1302. {
  1303. child_rect.mLeft += delta_width;
  1304. child_rect.mRight += delta_width;
  1305. }
  1306. else if (viewp->followsLeft())
  1307. {
  1308. // left is 0, don't need to adjust coords
  1309. }
  1310. else
  1311. {
  1312. // BUG what to do when we don't follow anyone?
  1313. // for now, same as followsLeft
  1314. }
  1315. if (viewp->followsTop() && viewp->followsBottom())
  1316. {
  1317. child_rect.mTop += delta_height;
  1318. }
  1319. else if (viewp->followsTop())
  1320. {
  1321. child_rect.mTop += delta_height;
  1322. child_rect.mBottom += delta_height;
  1323. }
  1324. else if (viewp->followsBottom())
  1325. {
  1326. // bottom is 0, so don't need to adjust coords
  1327. }
  1328. else
  1329. {
  1330. // BUG what to do when we don't follow?
  1331. // for now, same as bottom
  1332. }
  1333. S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft;
  1334. S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom;
  1335. viewp->translate( delta_x, delta_y );
  1336. viewp->reshape(child_rect.getWidth(), child_rect.getHeight());
  1337. }
  1338. }
  1339. if (!called_from_parent)
  1340. {
  1341. if (mParentView)
  1342. {
  1343. mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE);
  1344. }
  1345. }
  1346. updateBoundingRect();
  1347. }
  1348. LLRect LLView::calcBoundingRect()
  1349. {
  1350. LLRect local_bounding_rect = LLRect::null;
  1351. child_list_const_iter_t child_it;
  1352. for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1353. {
  1354. LLView* childp = *child_it;
  1355. // ignore invisible and "top" children when calculating bounding rect
  1356. // such as combobox popups
  1357. if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) 
  1358. {
  1359. continue;
  1360. }
  1361. LLRect child_bounding_rect = childp->getBoundingRect();
  1362. if (local_bounding_rect.isEmpty())
  1363. {
  1364. // start out with bounding rect equal to first visible child's bounding rect
  1365. local_bounding_rect = child_bounding_rect;
  1366. }
  1367. else
  1368. {
  1369. // accumulate non-null children rectangles
  1370. if (!child_bounding_rect.isEmpty())
  1371. {
  1372. local_bounding_rect.unionWith(child_bounding_rect);
  1373. }
  1374. }
  1375. }
  1376. // convert to parent-relative coordinates
  1377. local_bounding_rect.translate(mRect.mLeft, mRect.mBottom);
  1378. return local_bounding_rect;
  1379. }
  1380. void LLView::updateBoundingRect()
  1381. {
  1382. if (isDead()) return;
  1383. LLRect cur_rect = mBoundingRect;
  1384. if (mUseBoundingRect)
  1385. {
  1386. mBoundingRect = calcBoundingRect();
  1387. }
  1388. else
  1389. {
  1390. mBoundingRect = mRect;
  1391. }
  1392. // give parent view a chance to resize, in case we just moved, for example
  1393. if (getParent() && getParent()->mUseBoundingRect)
  1394. {
  1395. getParent()->updateBoundingRect();
  1396. }
  1397. if (mBoundingRect != cur_rect)
  1398. {
  1399. dirtyRect();
  1400. }
  1401. }
  1402. LLRect LLView::calcScreenRect() const
  1403. {
  1404. LLRect screen_rect;
  1405. localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom);
  1406. localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop);
  1407. return screen_rect;
  1408. }
  1409. LLRect LLView::calcScreenBoundingRect() const
  1410. {
  1411. LLRect screen_rect;
  1412. // get bounding rect, if used
  1413. LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect;
  1414. // convert to local coordinates, as defined by mRect
  1415. bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
  1416. localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom);
  1417. localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop);
  1418. return screen_rect;
  1419. }
  1420. LLRect LLView::getLocalBoundingRect() const
  1421. {
  1422. LLRect local_bounding_rect = getBoundingRect();
  1423. local_bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
  1424. return local_bounding_rect;
  1425. }
  1426. LLRect LLView::getLocalRect() const
  1427. {
  1428. LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
  1429. return local_rect;
  1430. }
  1431. LLRect LLView::getLocalSnapRect() const
  1432. {
  1433. LLRect local_snap_rect = getSnapRect();
  1434. local_snap_rect.translate(-getRect().mLeft, -getRect().mBottom);
  1435. return local_snap_rect;
  1436. }
  1437. BOOL LLView::hasAncestor(const LLView* parentp) const
  1438. {
  1439. if (!parentp)
  1440. {
  1441. return FALSE;
  1442. }
  1443. LLView* viewp = getParent();
  1444. while(viewp)
  1445. {
  1446. if (viewp == parentp)
  1447. {
  1448. return TRUE;
  1449. }
  1450. viewp = viewp->getParent();
  1451. }
  1452. return FALSE;
  1453. }
  1454. //-----------------------------------------------------------------------------
  1455. BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const
  1456. {
  1457. LLView *child = findChildView(childname, TRUE);
  1458. if (child)
  1459. {
  1460. return gFocusMgr.childHasKeyboardFocus(child);
  1461. }
  1462. else
  1463. {
  1464. return FALSE;
  1465. }
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const
  1469. {
  1470. return findChildView(childname, recurse) != NULL;
  1471. }
  1472. //-----------------------------------------------------------------------------
  1473. // getChildView()
  1474. //-----------------------------------------------------------------------------
  1475. LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
  1476. {
  1477. LLView* child = findChildView(name, recurse);
  1478. if (!child)
  1479. {
  1480. child = getDefaultWidget<LLView>(name);
  1481. if (!child)
  1482. {
  1483.  child = LLUICtrlFactory::createDefaultWidget<LLView>(name);
  1484. }
  1485. }
  1486. return child;
  1487. }
  1488. static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets");
  1489. LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
  1490. {
  1491. LLFastTimer ft(FTM_FIND_VIEWS);
  1492. //richard: should we allow empty names?
  1493. //if(name.empty())
  1494. // return NULL;
  1495. child_list_const_iter_t child_it;
  1496. // Look for direct children *first*
  1497. for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1498. {
  1499. LLView* childp = *child_it;
  1500. llassert(childp);
  1501. if (childp->getName() == name)
  1502. {
  1503. return childp;
  1504. }
  1505. }
  1506. if (recurse)
  1507. {
  1508. // Look inside each child as well.
  1509. for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  1510. {
  1511. LLView* childp = *child_it;
  1512. llassert(childp);
  1513. LLView* viewp = childp->findChildView(name, recurse);
  1514. if ( viewp )
  1515. {
  1516. return viewp;
  1517. }
  1518. }
  1519. }
  1520. return NULL;
  1521. }
  1522. BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const 
  1523. return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
  1524. ? mBoundingRect.pointInRect( x, y ) 
  1525. : mRect.pointInRect( x, y ); 
  1526. }
  1527. BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const 
  1528. return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
  1529. ? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom ) 
  1530. : mRect.localPointInRect( x, y ); 
  1531. }
  1532. BOOL LLView::blockMouseEvent(S32 x, S32 y) const
  1533. {
  1534. return mMouseOpaque && pointInView(x, y, HIT_TEST_IGNORE_BOUNDING_RECT);
  1535. }
  1536. // virtual
  1537. void LLView::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const
  1538. {
  1539. *local_x = screen_x - getRect().mLeft;
  1540. *local_y = screen_y - getRect().mBottom;
  1541. const LLView* cur = this;
  1542. while( cur->mParentView )
  1543. {
  1544. cur = cur->mParentView;
  1545. *local_x -= cur->getRect().mLeft;
  1546. *local_y -= cur->getRect().mBottom;
  1547. }
  1548. }
  1549. void LLView::localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const
  1550. {
  1551. *screen_x = local_x + getRect().mLeft;
  1552. *screen_y = local_y + getRect().mBottom;
  1553. const LLView* cur = this;
  1554. while( cur->mParentView )
  1555. {
  1556. cur = cur->mParentView;
  1557. *screen_x += cur->getRect().mLeft;
  1558. *screen_y += cur->getRect().mBottom;
  1559. }
  1560. }
  1561. void LLView::screenRectToLocal(const LLRect& screen, LLRect* local) const
  1562. {
  1563. *local = screen;
  1564. local->translate( -getRect().mLeft, -getRect().mBottom );
  1565. const LLView* cur = this;
  1566. while( cur->mParentView )
  1567. {
  1568. cur = cur->mParentView;
  1569. local->translate( -cur->getRect().mLeft, -cur->getRect().mBottom );
  1570. }
  1571. }
  1572. void LLView::localRectToScreen(const LLRect& local, LLRect* screen) const
  1573. {
  1574. *screen = local;
  1575. screen->translate( getRect().mLeft, getRect().mBottom );
  1576. const LLView* cur = this;
  1577. while( cur->mParentView )
  1578. {
  1579. cur = cur->mParentView;
  1580. screen->translate( cur->getRect().mLeft, cur->getRect().mBottom );
  1581. }
  1582. }
  1583. LLView* LLView::getRootView()
  1584. {
  1585. LLView* view = this;
  1586. while( view->mParentView )
  1587. {
  1588. view = view->mParentView;
  1589. }
  1590. return view;
  1591. }
  1592. LLView* LLView::findPrevSibling(LLView* child)
  1593. {
  1594. child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child);
  1595. if (prev_it != mChildList.end() && prev_it != mChildList.begin())
  1596. {
  1597. return *(--prev_it);
  1598. }
  1599. return NULL;
  1600. }
  1601. LLView* LLView::findNextSibling(LLView* child)
  1602. {
  1603. child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child);
  1604. if (next_it != mChildList.end())
  1605. {
  1606. next_it++;
  1607. }
  1608. return (next_it != mChildList.end()) ? *next_it : NULL;
  1609. }
  1610. void LLView::deleteViewByHandle(LLHandle<LLView> handle)
  1611. {
  1612. LLView* viewp = handle.get();
  1613. delete viewp;
  1614. }
  1615. LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BOOL allow_partial_outside)
  1616. {
  1617. LLCoordGL delta;
  1618. if (allow_partial_outside)
  1619. {
  1620. const S32 KEEP_ONSCREEN_PIXELS = 16;
  1621. if( input.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft )
  1622. {
  1623. delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS);
  1624. }
  1625. else
  1626. if( input.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight )
  1627. {
  1628. delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS);
  1629. }
  1630. if( input.mTop > constraint.mTop )
  1631. {
  1632. delta.mY = constraint.mTop - input.mTop;
  1633. }
  1634. else
  1635. if( input.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom )
  1636. {
  1637. delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS);
  1638. }
  1639. }
  1640. else
  1641. {
  1642. if( input.mLeft < constraint.mLeft )
  1643. {
  1644. delta.mX = constraint.mLeft - input.mLeft;
  1645. }
  1646. else
  1647. if( input.mRight > constraint.mRight )
  1648. {
  1649. delta.mX = constraint.mRight - input.mRight;
  1650. // compensate for left edge possible going off screen
  1651. delta.mX += llmax( 0, input.getWidth() - constraint.getWidth() );
  1652. }
  1653. if( input.mTop > constraint.mTop )
  1654. {
  1655. delta.mY = constraint.mTop - input.mTop;
  1656. }
  1657. else
  1658. if( input.mBottom < constraint.mBottom )
  1659. {
  1660. delta.mY = constraint.mBottom - input.mBottom;
  1661. // compensate for top edge possible going off screen
  1662. delta.mY -= llmax( 0, input.getHeight() - constraint.getHeight() );
  1663. }
  1664. }
  1665. return delta;
  1666. }
  1667. // Moves the view so that it is entirely inside of constraint.
  1668. // If the view will not fit because it's too big, aligns with the top and left.
  1669. // (Why top and left?  That's where the drag bars are for floaters.)
  1670. BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside )
  1671. {
  1672. LLCoordGL translation = getNeededTranslation(getRect(), constraint, allow_partial_outside);
  1673. if (translation.mX != 0 || translation.mY != 0)
  1674. {
  1675. translate(translation.mX, translation.mY);
  1676. return TRUE;
  1677. }
  1678. return FALSE;
  1679. }
  1680. // move this view into "inside" but not onto "exclude"
  1681. // NOTE: if this view is already contained in "inside", we ignore the "exclude" rect
  1682. BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside )
  1683. {
  1684. LLCoordGL translation = getNeededTranslation(getRect(), inside, allow_partial_outside);
  1685. if (translation.mX != 0 || translation.mY != 0)
  1686. {
  1687. // translate ourselves into constraint rect
  1688. translate(translation.mX, translation.mY);
  1689. // do we overlap with exclusion area?
  1690. // keep moving in the same direction to the other side of the exclusion rect
  1691. if (exclude.overlaps(getRect()))
  1692. {
  1693. // moving right
  1694. if (translation.mX > 0)
  1695. {
  1696. translate(exclude.mRight - getRect().mLeft, 0);
  1697. }
  1698. // moving left
  1699. else if (translation.mX < 0)
  1700. {
  1701. translate(exclude.mLeft - getRect().mRight, 0);
  1702. }
  1703. // moving up
  1704. if (translation.mY > 0)
  1705. {
  1706. translate(0, exclude.mTop - getRect().mBottom);
  1707. }
  1708. // moving down
  1709. else if (translation.mY < 0)
  1710. {
  1711. translate(0, exclude.mBottom - getRect().mTop);
  1712. }
  1713. }
  1714. return TRUE;
  1715. }
  1716. return FALSE;
  1717. }
  1718. void LLView::centerWithin(const LLRect& bounds)
  1719. {
  1720. S32 left   = bounds.mLeft + (bounds.getWidth() - getRect().getWidth()) / 2;
  1721. S32 bottom = bounds.mBottom + (bounds.getHeight() - getRect().getHeight()) / 2;
  1722. translate( left - getRect().mLeft, bottom - getRect().mBottom );
  1723. }
  1724. BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view) const
  1725. {
  1726. const LLView* cur_view = this;
  1727. const LLView* root_view = NULL;
  1728. while (cur_view)
  1729. {
  1730. if (cur_view == other_view)
  1731. {
  1732. *other_x = x;
  1733. *other_y = y;
  1734. return TRUE;
  1735. }
  1736. x += cur_view->getRect().mLeft;
  1737. y += cur_view->getRect().mBottom;
  1738. cur_view = cur_view->getParent();
  1739. root_view = cur_view;
  1740. }
  1741. // assuming common root between two views, chase other_view's parents up to root
  1742. cur_view = other_view;
  1743. while (cur_view)
  1744. {
  1745. x -= cur_view->getRect().mLeft;
  1746. y -= cur_view->getRect().mBottom;
  1747. cur_view = cur_view->getParent();
  1748. if (cur_view == root_view)
  1749. {
  1750. *other_x = x;
  1751. *other_y = y;
  1752. return TRUE;
  1753. }
  1754. }
  1755. *other_x = x;
  1756. *other_y = y;
  1757. return FALSE;
  1758. }
  1759. BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const
  1760. {
  1761. LLRect cur_rect = local;
  1762. const LLView* cur_view = this;
  1763. const LLView* root_view = NULL;
  1764. while (cur_view)
  1765. {
  1766. if (cur_view == other_view)
  1767. {
  1768. *other = cur_rect;
  1769. return TRUE;
  1770. }
  1771. cur_rect.translate(cur_view->getRect().mLeft, cur_view->getRect().mBottom);
  1772. cur_view = cur_view->getParent();
  1773. root_view = cur_view;
  1774. }
  1775. // assuming common root between two views, chase other_view's parents up to root
  1776. cur_view = other_view;
  1777. while (cur_view)
  1778. {
  1779. cur_rect.translate(-cur_view->getRect().mLeft, -cur_view->getRect().mBottom);
  1780. cur_view = cur_view->getParent();
  1781. if (cur_view == root_view)
  1782. {
  1783. *other = cur_rect;
  1784. return TRUE;
  1785. }
  1786. }
  1787. *other = cur_rect;
  1788. return FALSE;
  1789. }
  1790. // static
  1791. const LLCtrlQuery & LLView::getTabOrderQuery()
  1792. {
  1793. static LLCtrlQuery query;
  1794. if(query.getPreFilters().size() == 0) {
  1795. query.addPreFilter(LLVisibleFilter::getInstance());
  1796. query.addPreFilter(LLEnabledFilter::getInstance());
  1797. query.addPreFilter(LLTabStopFilter::getInstance());
  1798. query.addPostFilter(LLLeavesFilter::getInstance());
  1799. }
  1800. return query;
  1801. }
  1802. // This class is only used internally by getFocusRootsQuery below. 
  1803. class LLFocusRootsFilter : public LLQueryFilter, public LLSingleton<LLFocusRootsFilter>
  1804. {
  1805. /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const 
  1806. {
  1807. return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot());
  1808. }
  1809. };
  1810. // static
  1811. const LLCtrlQuery & LLView::getFocusRootsQuery()
  1812. {
  1813. static LLCtrlQuery query;
  1814. if(query.getPreFilters().size() == 0) {
  1815. query.addPreFilter(LLVisibleFilter::getInstance());
  1816. query.addPreFilter(LLEnabledFilter::getInstance());
  1817. query.addPreFilter(LLFocusRootsFilter::getInstance());
  1818. query.addPostFilter(LLRootsFilter::getInstance());
  1819. }
  1820. return query;
  1821. }
  1822. void LLView::setShape(const LLRect& new_rect, bool by_user)
  1823. {
  1824. handleReshape(new_rect, by_user);
  1825. }
  1826. void LLView::handleReshape(const LLRect& new_rect, bool by_user)
  1827. {
  1828. reshape(new_rect.getWidth(), new_rect.getHeight());
  1829. translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom);
  1830. }
  1831. LLView* LLView::findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir,
  1832.  LLView::ESnapType snap_type, S32 threshold, S32 padding)
  1833. {
  1834. new_rect = mRect;
  1835. LLView* snap_view = NULL;
  1836. if (!mParentView)
  1837. {
  1838. return NULL;
  1839. }
  1840. S32 delta_x = 0;
  1841. S32 delta_y = 0;
  1842. if (mouse_dir.mX >= 0)
  1843. {
  1844. S32 new_right = mRect.mRight;
  1845. LLView* view = findSnapEdge(new_right, mouse_dir, SNAP_RIGHT, snap_type, threshold, padding);
  1846. delta_x = new_right - mRect.mRight;
  1847. snap_view = view ? view : snap_view;
  1848. }
  1849. if (mouse_dir.mX <= 0)
  1850. {
  1851. S32 new_left = mRect.mLeft;
  1852. LLView* view = findSnapEdge(new_left, mouse_dir, SNAP_LEFT, snap_type, threshold, padding);
  1853. delta_x = new_left - mRect.mLeft;
  1854. snap_view = view ? view : snap_view;
  1855. }
  1856. if (mouse_dir.mY >= 0)
  1857. {
  1858. S32 new_top = mRect.mTop;
  1859. LLView* view = findSnapEdge(new_top, mouse_dir, SNAP_TOP, snap_type, threshold, padding);
  1860. delta_y = new_top - mRect.mTop;
  1861. snap_view = view ? view : snap_view;
  1862. }
  1863. if (mouse_dir.mY <= 0)
  1864. {
  1865. S32 new_bottom = mRect.mBottom;
  1866. LLView* view = findSnapEdge(new_bottom, mouse_dir, SNAP_BOTTOM, snap_type, threshold, padding);
  1867. delta_y = new_bottom - mRect.mBottom;
  1868. snap_view = view ? view : snap_view;
  1869. }
  1870. new_rect.translate(delta_x, delta_y);
  1871. return snap_view;
  1872. }
  1873. LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
  1874. {
  1875. LLRect snap_rect = getSnapRect();
  1876. S32 snap_pos = 0;
  1877. switch(snap_edge)
  1878. {
  1879. case SNAP_LEFT:
  1880. snap_pos = snap_rect.mLeft;
  1881. break;
  1882. case SNAP_RIGHT:
  1883. snap_pos = snap_rect.mRight;
  1884. break;
  1885. case SNAP_TOP:
  1886. snap_pos = snap_rect.mTop;
  1887. break;
  1888. case SNAP_BOTTOM:
  1889. snap_pos = snap_rect.mBottom;
  1890. break;
  1891. }
  1892. if (!mParentView)
  1893. {
  1894. new_edge_val = snap_pos;
  1895. return NULL;
  1896. }
  1897. LLView* snap_view = NULL;
  1898. // If the view is near the edge of its parent, snap it to
  1899. // the edge.
  1900. LLRect test_rect = snap_rect;
  1901. test_rect.stretch(padding);
  1902. S32 x_threshold = threshold;
  1903. S32 y_threshold = threshold;
  1904. LLRect parent_local_snap_rect = mParentView->getLocalSnapRect();
  1905. if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS)
  1906. {
  1907. switch(snap_edge)
  1908. {
  1909. case SNAP_RIGHT:
  1910. if (llabs(parent_local_snap_rect.mRight - test_rect.mRight) <= x_threshold 
  1911. && (parent_local_snap_rect.mRight - test_rect.mRight) * mouse_dir.mX >= 0)
  1912. {
  1913. snap_pos = parent_local_snap_rect.mRight - padding;
  1914. snap_view = mParentView;
  1915. x_threshold = llabs(parent_local_snap_rect.mRight - test_rect.mRight);
  1916. }
  1917. break;
  1918. case SNAP_LEFT:
  1919. if (llabs(test_rect.mLeft - parent_local_snap_rect.mLeft) <= x_threshold 
  1920. && test_rect.mLeft * mouse_dir.mX <= 0)
  1921. {
  1922. snap_pos = parent_local_snap_rect.mLeft + padding;
  1923. snap_view = mParentView;
  1924. x_threshold = llabs(test_rect.mLeft - parent_local_snap_rect.mLeft);
  1925. }
  1926. break;
  1927. case SNAP_BOTTOM:
  1928. if (llabs(test_rect.mBottom - parent_local_snap_rect.mBottom) <= y_threshold 
  1929. && test_rect.mBottom * mouse_dir.mY <= 0)
  1930. {
  1931. snap_pos = parent_local_snap_rect.mBottom + padding;
  1932. snap_view = mParentView;
  1933. y_threshold = llabs(test_rect.mBottom - parent_local_snap_rect.mBottom);
  1934. }
  1935. break;
  1936. case SNAP_TOP:
  1937. if (llabs(parent_local_snap_rect.mTop - test_rect.mTop) <= y_threshold && (parent_local_snap_rect.mTop - test_rect.mTop) * mouse_dir.mY >= 0)
  1938. {
  1939. snap_pos = parent_local_snap_rect.mTop - padding;
  1940. snap_view = mParentView;
  1941. y_threshold = llabs(parent_local_snap_rect.mTop - test_rect.mTop);
  1942. }
  1943. break;
  1944. default:
  1945. llerrs << "Invalid snap edge" << llendl;
  1946. }
  1947. }
  1948. if (snap_type == SNAP_SIBLINGS || snap_type == SNAP_PARENT_AND_SIBLINGS)
  1949. {
  1950. for ( child_list_const_iter_t child_it = mParentView->getChildList()->begin();
  1951.   child_it != mParentView->getChildList()->end(); ++child_it)
  1952. {
  1953. LLView* siblingp = *child_it;
  1954. if (!canSnapTo(siblingp)) continue;
  1955. LLRect sibling_rect = siblingp->getSnapRect();
  1956. switch(snap_edge)
  1957. {
  1958. case SNAP_RIGHT:
  1959. if (llabs(test_rect.mRight - sibling_rect.mLeft) <= x_threshold 
  1960. && (test_rect.mRight - sibling_rect.mLeft) * mouse_dir.mX <= 0)
  1961. {
  1962. snap_pos = sibling_rect.mLeft - padding;
  1963. snap_view = siblingp;
  1964. x_threshold = llabs(test_rect.mRight - sibling_rect.mLeft);
  1965. }
  1966. // if snapped with sibling along other axis, check for shared edge
  1967. else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold 
  1968. || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= x_threshold)
  1969. {
  1970. if (llabs(test_rect.mRight - sibling_rect.mRight) <= x_threshold 
  1971. && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0)
  1972. {
  1973. snap_pos = sibling_rect.mRight;
  1974. snap_view = siblingp;
  1975. x_threshold = llabs(test_rect.mRight - sibling_rect.mRight);
  1976. }
  1977. }
  1978. break;
  1979. case SNAP_LEFT:
  1980. if (llabs(test_rect.mLeft - sibling_rect.mRight) <= x_threshold 
  1981. && (test_rect.mLeft - sibling_rect.mRight) * mouse_dir.mX <= 0)
  1982. {
  1983. snap_pos = sibling_rect.mRight + padding;
  1984. snap_view = siblingp;
  1985. x_threshold = llabs(test_rect.mLeft - sibling_rect.mRight);
  1986. }
  1987. // if snapped with sibling along other axis, check for shared edge
  1988. else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold 
  1989. || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= y_threshold)
  1990. {
  1991. if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= x_threshold 
  1992. && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0)
  1993. {
  1994. snap_pos = sibling_rect.mLeft;
  1995. snap_view = siblingp;
  1996. x_threshold = llabs(test_rect.mLeft - sibling_rect.mLeft);
  1997. }
  1998. }
  1999. break;
  2000. case SNAP_BOTTOM:
  2001. if (llabs(test_rect.mBottom - sibling_rect.mTop) <= y_threshold 
  2002. && (test_rect.mBottom - sibling_rect.mTop) * mouse_dir.mY <= 0)
  2003. {
  2004. snap_pos = sibling_rect.mTop + padding;
  2005. snap_view = siblingp;
  2006. y_threshold = llabs(test_rect.mBottom - sibling_rect.mTop);
  2007. }
  2008. // if snapped with sibling along other axis, check for shared edge
  2009. else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold 
  2010. || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold)
  2011. {
  2012. if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= y_threshold 
  2013. && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0)
  2014. {
  2015. snap_pos = sibling_rect.mBottom;
  2016. snap_view = siblingp;
  2017. y_threshold = llabs(test_rect.mBottom - sibling_rect.mBottom);
  2018. }
  2019. }
  2020. break;
  2021. case SNAP_TOP:
  2022. if (llabs(test_rect.mTop - sibling_rect.mBottom) <= y_threshold 
  2023. && (test_rect.mTop - sibling_rect.mBottom) * mouse_dir.mY <= 0)
  2024. {
  2025. snap_pos = sibling_rect.mBottom - padding;
  2026. snap_view = siblingp;
  2027. y_threshold = llabs(test_rect.mTop - sibling_rect.mBottom);
  2028. }
  2029. // if snapped with sibling along other axis, check for shared edge
  2030. else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold 
  2031. || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold)
  2032. {
  2033. if (llabs(test_rect.mTop - sibling_rect.mTop) <= y_threshold 
  2034. && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0)
  2035. {
  2036. snap_pos = sibling_rect.mTop;
  2037. snap_view = siblingp;
  2038. y_threshold = llabs(test_rect.mTop - sibling_rect.mTop);
  2039. }
  2040. }
  2041. break;
  2042. default:
  2043. llerrs << "Invalid snap edge" << llendl;
  2044. }
  2045. }
  2046. }
  2047. new_edge_val = snap_pos;
  2048. return snap_view;
  2049. }
  2050. //-----------------------------------------------------------------------------
  2051. // Listener dispatch functions
  2052. //-----------------------------------------------------------------------------
  2053. LLControlVariable *LLView::findControl(const std::string& name)
  2054. {
  2055. // parse the name to locate which group it belongs to
  2056. std::size_t key_pos= name.find(".");
  2057. if(key_pos!=  std::string::npos )
  2058. {
  2059. std::string control_group_key = name.substr(0, key_pos);
  2060. LLControlVariable* control;
  2061. // check if it's in the control group that name indicated
  2062. if(LLUI::sSettingGroups[control_group_key])
  2063. {
  2064. control = LLUI::sSettingGroups[control_group_key]->getControl(name);
  2065. if (control)
  2066. {
  2067. return control;
  2068. }
  2069. }
  2070. }
  2071. LLControlGroup& control_group = LLUI::getControlControlGroup(name);
  2072. return control_group.getControl(name);
  2073. }
  2074. const S32 FLOATER_H_MARGIN = 15;
  2075. const S32 MIN_WIDGET_HEIGHT = 10;
  2076. const S32 VPAD = 4;
  2077. void LLView::initFromParams(const LLView::Params& params)
  2078. {
  2079. LLRect required_rect = getRequiredRect();
  2080. S32 width = llmax(getRect().getWidth(), required_rect.getWidth());
  2081. S32 height = llmax(getRect().getHeight(), required_rect.getHeight());
  2082. reshape(width, height);
  2083. // call virtual methods with most recent data
  2084. // use getters because these values might not come through parameter block
  2085. setEnabled(getEnabled());
  2086. setVisible(getVisible());
  2087. if (!params.name().empty())
  2088. {
  2089. setName(params.name());
  2090. }
  2091. mLayout = params.layout();
  2092. }
  2093. void LLView::parseFollowsFlags(const LLView::Params& params)
  2094. {
  2095. // preserve follows flags set by code if user did not override
  2096. if (!params.follows.isProvided()) 
  2097. {
  2098. return;
  2099. }
  2100. // interpret either string or bitfield version of follows
  2101. if (params.follows.string.isChosen())
  2102. {
  2103. setFollows(FOLLOWS_NONE);
  2104. std::string follows = params.follows.string;
  2105. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  2106. boost::char_separator<char> sep("|");
  2107. tokenizer tokens(follows, sep);
  2108. tokenizer::iterator token_iter = tokens.begin();
  2109. while(token_iter != tokens.end())
  2110. {
  2111. const std::string& token_str = *token_iter;
  2112. if (token_str == "left")
  2113. {
  2114. setFollowsLeft();
  2115. }
  2116. else if (token_str == "right")
  2117. {
  2118. setFollowsRight();
  2119. }
  2120. else if (token_str == "top")
  2121. {
  2122. setFollowsTop();
  2123. }
  2124. else if (token_str == "bottom")
  2125. {
  2126. setFollowsBottom();
  2127. }
  2128. else if (token_str == "all")
  2129. {
  2130. setFollowsAll();
  2131. }
  2132. ++token_iter;
  2133. }
  2134. }
  2135. else if (params.follows.flags.isChosen())
  2136. {
  2137. setFollows(params.follows.flags);
  2138. }
  2139. }
  2140. // static
  2141. //LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
  2142. //{
  2143. // LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
  2144. //
  2145. // if (node->hasAttribute("halign"))
  2146. // {
  2147. // std::string horizontal_align_name;
  2148. // node->getAttributeString("halign", horizontal_align_name);
  2149. // gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
  2150. // }
  2151. // return gl_hfont_align;
  2152. //}
  2153. // Return the rectangle of the last-constructed child,
  2154. // if present and a first-class widget (eg, not a close box or drag handle)
  2155. // Returns true if found
  2156. static bool get_last_child_rect(LLView* parent, LLRect *rect)
  2157. {
  2158. if (!parent) return false;
  2159. LLView::child_list_t::const_iterator itor = 
  2160. parent->getChildList()->begin();
  2161. for (;itor != parent->getChildList()->end(); ++itor)
  2162. {
  2163. LLView *last_view = (*itor);
  2164. if (last_view->getFromXUI())
  2165. {
  2166. *rect = last_view->getRect();
  2167. return true;
  2168. }
  2169. }
  2170. return false;
  2171. }
  2172. //static
  2173. void LLView::applyXUILayout(LLView::Params& p, LLView* parent)
  2174. {
  2175. const S32 VPAD = 4;
  2176. const S32 MIN_WIDGET_HEIGHT = 10;
  2177. // *NOTE:  This will confuse export of floater/panel coordinates unless
  2178. // the default is also "topleft".  JC
  2179. if (p.layout().empty() && parent)
  2180. {
  2181. p.layout = parent->getLayout();
  2182. }
  2183. if (parent)
  2184. {
  2185. LLRect parent_rect = parent->getLocalRect();
  2186. // overwrite uninitialized rect params, using context
  2187. LLRect last_rect = parent->getLocalRect();
  2188. bool layout_topleft = (p.layout() == "topleft");
  2189. if (layout_topleft)
  2190. {
  2191. //invert top to bottom
  2192. if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
  2193. if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
  2194. }
  2195. // convert negative or centered coordinates to parent relative values
  2196. // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock()
  2197. if (p.center_horiz)
  2198. {
  2199. if (p.rect.left.isProvided() && p.rect.right.isProvided())
  2200. {
  2201. S32 width = p.rect.right - p.rect.left;
  2202. width = llmax(width, 0);
  2203. S32 offset = parent_rect.getWidth()/2 - width/2;
  2204. p.rect.left = p.rect.left + offset;
  2205. p.rect.right = p.rect.right + offset;
  2206. }
  2207. else
  2208. {
  2209. p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2;
  2210. p.rect.right.setProvided(false); // recalculate the right
  2211. }
  2212. }
  2213. else
  2214. {
  2215. if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
  2216. if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
  2217. }
  2218. if (p.center_vert)
  2219. {
  2220. if (p.rect.bottom.isProvided() && p.rect.top.isProvided())
  2221. {
  2222. S32 height = p.rect.top - p.rect.bottom;
  2223. height = llmax(height, 0);
  2224. S32 offset = parent_rect.getHeight()/2 - height/2;
  2225. p.rect.bottom = p.rect.bottom + offset;
  2226. p.rect.top = p.rect.top + offset;
  2227. }
  2228. else
  2229. {
  2230. p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2;
  2231. p.rect.top.setProvided(false); // recalculate the top
  2232. }
  2233. }
  2234. else
  2235. {
  2236. if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
  2237. if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
  2238. }
  2239. // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
  2240. if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0)
  2241. {
  2242. p.rect.height = MIN_WIDGET_HEIGHT;
  2243. }
  2244. last_rect.translate(0, last_rect.getHeight());
  2245. // If there was a recently constructed child, use its rectangle
  2246. get_last_child_rect(parent, &last_rect);
  2247. if (layout_topleft)
  2248. {
  2249. p.bottom_delta.setIfNotProvided(0, false);
  2250. // Invert the sense of bottom_delta for topleft layout
  2251. if (p.bottom_delta.isProvided())
  2252. {
  2253. p.bottom_delta = -p.bottom_delta;
  2254. }
  2255. else if (p.top_pad.isProvided()) 
  2256. {
  2257. p.bottom_delta = -(p.rect.height + p.top_pad);
  2258. }
  2259. else if (p.top_delta.isProvided())
  2260. {
  2261. p.bottom_delta =
  2262. -(p.top_delta + p.rect.height - last_rect.getHeight());
  2263. }
  2264. else if (!p.bottom_delta.isProvided()
  2265.  && !p.left_delta.isProvided()
  2266.  && !p.top_pad.isProvided()
  2267.  && !p.left_pad.isProvided())
  2268. {
  2269. // set default position is just below last rect
  2270. p.bottom_delta.set(-(p.rect.height + VPAD), false);
  2271. }
  2272. // default to same left edge
  2273. p.left_delta.setIfNotProvided(0, false);
  2274. if (p.left_pad.isProvided())
  2275. {
  2276. // left_pad is based on prior widget's right edge
  2277. p.left_delta.set(p.left_pad + last_rect.getWidth(), false);
  2278. }
  2279. last_rect.translate(p.left_delta, p.bottom_delta);
  2280. }
  2281. else
  2282. {
  2283. // set default position is just below last rect
  2284. p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
  2285. p.left_delta.setIfNotProvided(0, false);
  2286. last_rect.translate(p.left_delta, p.bottom_delta);
  2287. }
  2288. // this handles case where *both* x and x_delta are provided
  2289. // ignore x in favor of default x + x_delta
  2290. if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false);
  2291. if (p.left_delta.isProvided()) p.rect.left.set(0, false);
  2292. // selectively apply rectangle defaults, making sure that
  2293. // params are not flagged as having been "provided"
  2294. // as rect params are overconstrained and rely on provided flags
  2295. p.rect.left.setIfNotProvided(last_rect.mLeft, false);
  2296. p.rect.bottom.setIfNotProvided(last_rect.mBottom, false);
  2297. p.rect.top.setIfNotProvided(last_rect.mTop, false);
  2298. p.rect.right.setIfNotProvided(last_rect.mRight, false);
  2299. p.rect.width.setIfNotProvided(last_rect.getWidth(), false);
  2300. p.rect.height.setIfNotProvided(last_rect.getHeight(), false);
  2301. }
  2302. }
  2303. static S32 invert_vertical(S32 y, LLView* parent)
  2304. {
  2305. if (y < 0)
  2306. {
  2307. // already based on top-left, just invert
  2308. return -y;
  2309. }
  2310. else if (parent)
  2311. {
  2312. // use parent to flip coordinate
  2313. S32 parent_height = parent->getRect().getHeight();
  2314. return parent_height - y;
  2315. }
  2316. else
  2317. {
  2318. llwarns << "Attempting to convert layout to top-left with no parent" << llendl;
  2319. return y;
  2320. }
  2321. }
  2322. // Assumes that input is in bottom-left coordinates, hence must call
  2323. // _before_ convert_coords_to_top_left().
  2324. static void convert_to_relative_layout(LLView::Params& p, LLView* parent)
  2325. {
  2326. // Use setupParams to get the final widget rectangle
  2327. // according to our wacky layout rules.
  2328. LLView::Params final = p;
  2329. LLView::applyXUILayout(final, parent);
  2330. // Must actually extract the rectangle to get consistent
  2331. // right = left+width, top = bottom+height
  2332. LLRect final_rect = final.rect;
  2333. // We prefer to write out top edge instead of bottom, regardless
  2334. // of whether we use relative positioning
  2335. bool converted_top = false;
  2336. // Look for a last rectangle
  2337. LLRect last_rect;
  2338. if (get_last_child_rect(parent, &last_rect))
  2339. {
  2340. // ...we have a previous widget to compare to
  2341. const S32 EDGE_THRESHOLD_PIXELS = 4;
  2342. S32 left_pad = final_rect.mLeft - last_rect.mRight;
  2343. S32 left_delta = final_rect.mLeft - last_rect.mLeft;
  2344. S32 top_pad = final_rect.mTop - last_rect.mBottom;
  2345. S32 top_delta = final_rect.mTop - last_rect.mTop;
  2346. // If my left edge is almost the same, or my top edge is
  2347. // almost the same...
  2348. if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS
  2349. || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS)
  2350. {
  2351. // ...use relative positioning
  2352. // prefer top_pad if widgets are stacking vertically
  2353. // (coordinate system is still bottom-left here)
  2354. if (top_pad < 0)
  2355. {
  2356. p.top_pad = top_pad;
  2357. p.top_delta.setProvided(false);
  2358. }
  2359. else
  2360. {
  2361. p.top_pad.setProvided(false);
  2362. p.top_delta = top_delta;
  2363. }
  2364. // null out other vertical specifiers
  2365. p.rect.top.setProvided(false);
  2366. p.rect.bottom.setProvided(false);
  2367. p.bottom_delta.setProvided(false);
  2368. converted_top = true;
  2369. // prefer left_pad if widgets are stacking horizontally
  2370. if (left_pad > 0)
  2371. {
  2372. p.left_pad = left_pad;
  2373. p.left_delta.setProvided(false);
  2374. }
  2375. else
  2376. {
  2377. p.left_pad.setProvided(false);
  2378. p.left_delta = left_delta;
  2379. }
  2380. p.rect.left.setProvided(false);
  2381. p.rect.right.setProvided(false);
  2382. }
  2383. }
  2384. if (!converted_top)
  2385. {
  2386. // ...this is the first widget, or one that wasn't aligned
  2387. // prefer top/left specification
  2388. p.rect.top = final_rect.mTop;
  2389. p.rect.bottom.setProvided(false);
  2390. p.bottom_delta.setProvided(false);
  2391. p.top_pad.setProvided(false);
  2392. p.top_delta.setProvided(false);
  2393. }
  2394. }
  2395. static void convert_coords_to_top_left(LLView::Params& p, LLView* parent)
  2396. {
  2397. // Convert the coordinate system to be top-left based.
  2398. if (p.rect.top.isProvided())
  2399. {
  2400. p.rect.top = invert_vertical(p.rect.top, parent);
  2401. }
  2402. if (p.rect.bottom.isProvided())
  2403. {
  2404. p.rect.bottom = invert_vertical(p.rect.bottom, parent);
  2405. }
  2406. if (p.top_pad.isProvided())
  2407. {
  2408. p.top_pad = -p.top_pad;
  2409. }
  2410. if (p.top_delta.isProvided())
  2411. {
  2412. p.top_delta = -p.top_delta;
  2413. }
  2414. if (p.bottom_delta.isProvided())
  2415. {
  2416. p.bottom_delta = -p.bottom_delta;
  2417. }
  2418. p.layout = "topleft";
  2419. }
  2420. //static
  2421. void LLView::setupParamsForExport(Params& p, LLView* parent)
  2422. {
  2423. // Don't convert if already top-left based
  2424. if (p.layout() == "topleft") 
  2425. {
  2426. return;
  2427. }
  2428. // heuristic:  Many of our floaters and panels were bulk-exported.
  2429. // These specify exactly bottom/left and height/width.
  2430. // Others were done by hand using bottom_delta and/or left_delta.
  2431. // Some rely on not specifying left to mean align with left edge.
  2432. // Try to convert both to use relative layout, but using top-left
  2433. // coordinates.
  2434. // Avoid rectangles where top/bottom/left/right was specified.
  2435. if (p.rect.height.isProvided() && p.rect.width.isProvided())
  2436. {
  2437. if (p.rect.bottom.isProvided() && p.rect.left.isProvided())
  2438. {
  2439. // standard bulk export, convert it
  2440. convert_to_relative_layout(p, parent);
  2441. }
  2442. else if (p.rect.bottom.isProvided() && p.left_delta.isProvided())
  2443. {
  2444. // hand layout with left_delta
  2445. convert_to_relative_layout(p, parent);
  2446. }
  2447. else if (p.bottom_delta.isProvided())
  2448. {
  2449. // hand layout with bottom_delta
  2450. // don't check for p.rect.left or p.left_delta because sometimes
  2451. // this layout doesn't set it for widgets that are left-aligned
  2452. convert_to_relative_layout(p, parent);
  2453. }
  2454. }
  2455. convert_coords_to_top_left(p, parent);
  2456. }
  2457. LLView::tree_iterator_t LLView::beginTreeDFS() 
  2458. return tree_iterator_t(this, 
  2459. boost::bind(boost::mem_fn(&LLView::beginChild), _1), 
  2460. boost::bind(boost::mem_fn(&LLView::endChild), _1)); 
  2461. }
  2462. LLView::tree_iterator_t LLView::endTreeDFS() 
  2463. // an empty iterator is an "end" iterator
  2464. return tree_iterator_t();
  2465. }
  2466. LLView::tree_post_iterator_t LLView::beginTreeDFSPost() 
  2467. return tree_post_iterator_t(this, 
  2468. boost::bind(boost::mem_fn(&LLView::beginChild), _1), 
  2469. boost::bind(boost::mem_fn(&LLView::endChild), _1)); 
  2470. }
  2471. LLView::tree_post_iterator_t LLView::endTreeDFSPost() 
  2472. // an empty iterator is an "end" iterator
  2473. return tree_post_iterator_t();
  2474. }
  2475. LLView::root_to_view_iterator_t LLView::beginRootToView()
  2476. {
  2477. return root_to_view_iterator_t(this, boost::bind(&LLView::getParent, _1));
  2478. }
  2479. LLView::root_to_view_iterator_t LLView::endRootToView()
  2480. {
  2481. return root_to_view_iterator_t();
  2482. }
  2483. // only create maps on demand, as they incur heap allocation/deallocation cost
  2484. // when a view is constructed/deconstructed
  2485. LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const
  2486. {
  2487. if (!mDefaultWidgets)
  2488. {
  2489. mDefaultWidgets = new default_widget_map_t();
  2490. }
  2491. return *mDefaultWidgets;
  2492. }
  2493. S32 LLView::notifyParent(const LLSD& info)
  2494. {
  2495. LLView* parent = getParent();
  2496. if(parent)
  2497. return parent->notifyParent(info);
  2498. return 0;
  2499. }
  2500. bool LLView::notifyChildren(const LLSD& info)
  2501. {
  2502. bool ret = false;
  2503. for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
  2504. {
  2505. ret |= (*child_it)->notifyChildren(info);
  2506. }
  2507. return ret;
  2508. }
  2509. // convenient accessor for draw context
  2510. const LLViewDrawContext& LLView::getDrawContext()
  2511. {
  2512. return LLViewDrawContext::getCurrentContext();
  2513. }
  2514. const LLViewDrawContext& LLViewDrawContext::getCurrentContext()
  2515. {
  2516. static LLViewDrawContext default_context;
  2517. if (sDrawContextStack.empty())
  2518. return default_context;
  2519. return *sDrawContextStack.back();
  2520. }