/indra/newview/llfavoritesbar.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 1393 lines · 1045 code · 200 blank · 148 comment · 182 complexity · 1607c7cf2302cd8c5029ec2ec2f63d50 MD5 · raw file

  1. /**
  2. * @file llfavoritesbar.cpp
  3. * @brief LLFavoritesBarCtrl class implementation
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llfavoritesbar.h"
  28. #include "llfloaterreg.h"
  29. #include "llfocusmgr.h"
  30. #include "llinventory.h"
  31. #include "lllandmarkactions.h"
  32. #include "lltoolbarview.h"
  33. #include "lltrans.h"
  34. #include "lluictrlfactory.h"
  35. #include "llmenugl.h"
  36. #include "lltooltip.h"
  37. #include "llagent.h"
  38. #include "llclipboard.h"
  39. #include "llinventoryclipboard.h"
  40. #include "llinventorybridge.h"
  41. #include "llinventoryfunctions.h"
  42. #include "llfloatersidepanelcontainer.h"
  43. #include "llfloaterworldmap.h"
  44. #include "lllandmarkactions.h"
  45. #include "llnotificationsutil.h"
  46. #include "lltoggleablemenu.h"
  47. #include "llviewerinventory.h"
  48. #include "llviewermenu.h"
  49. #include "llviewermenu.h"
  50. #include "lltooldraganddrop.h"
  51. static LLDefaultChildRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar");
  52. const S32 DROP_DOWN_MENU_WIDTH = 250;
  53. const S32 DROP_DOWN_MENU_TOP_PAD = 13;
  54. /**
  55. * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem.
  56. * Performing requests for SLURL for given Landmark ID
  57. */
  58. class LLLandmarkInfoGetter
  59. {
  60. public:
  61. LLLandmarkInfoGetter()
  62. : mLandmarkID(LLUUID::null),
  63. mName("(Loading...)"),
  64. mPosX(0),
  65. mPosY(0),
  66. mPosZ(0),
  67. mLoaded(false)
  68. {
  69. mHandle.bind(this);
  70. }
  71. void setLandmarkID(const LLUUID& id) { mLandmarkID = id; }
  72. const LLUUID& getLandmarkId() const { return mLandmarkID; }
  73. const std::string& getName()
  74. {
  75. if(!mLoaded)
  76. requestNameAndPos();
  77. return mName;
  78. }
  79. S32 getPosX()
  80. {
  81. if (!mLoaded)
  82. requestNameAndPos();
  83. return mPosX;
  84. }
  85. S32 getPosY()
  86. {
  87. if (!mLoaded)
  88. requestNameAndPos();
  89. return mPosY;
  90. }
  91. S32 getPosZ()
  92. {
  93. if (!mLoaded)
  94. requestNameAndPos();
  95. return mPosZ;
  96. }
  97. private:
  98. /**
  99. * Requests landmark data from server.
  100. */
  101. void requestNameAndPos()
  102. {
  103. if (mLandmarkID.isNull())
  104. return;
  105. LLVector3d g_pos;
  106. if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos))
  107. {
  108. LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos,
  109. boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, static_cast<LLHandle<LLLandmarkInfoGetter> >(mHandle), _1, _2, _3, _4));
  110. }
  111. }
  112. static void landmarkNameCallback(LLHandle<LLLandmarkInfoGetter> handle, const std::string& name, S32 x, S32 y, S32 z)
  113. {
  114. LLLandmarkInfoGetter* getter = handle.get();
  115. if (getter)
  116. {
  117. getter->mPosX = x;
  118. getter->mPosY = y;
  119. getter->mPosZ = z;
  120. getter->mName = name;
  121. getter->mLoaded = true;
  122. }
  123. }
  124. LLUUID mLandmarkID;
  125. std::string mName;
  126. S32 mPosX;
  127. S32 mPosY;
  128. S32 mPosZ;
  129. bool mLoaded;
  130. LLRootHandle<LLLandmarkInfoGetter> mHandle;
  131. };
  132. /**
  133. * This class is needed to override LLButton default handleToolTip function and
  134. * show SLURL as button tooltip.
  135. * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
  136. * in createButtons function but landmark data is not available when Favorites Bar is
  137. * created. Thats why we are requesting landmark data after
  138. */
  139. class LLFavoriteLandmarkButton : public LLButton
  140. {
  141. public:
  142. BOOL handleToolTip(S32 x, S32 y, MASK mask)
  143. {
  144. std::string region_name = mLandmarkInfoGetter.getName();
  145. if (!region_name.empty())
  146. {
  147. std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(),
  148. mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ());
  149. LLToolTip::Params params;
  150. params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str());
  151. params.max_width = 1000;
  152. params.sticky_rect = calcScreenRect();
  153. LLToolTipMgr::instance().show(params);
  154. }
  155. return TRUE;
  156. }
  157. /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask)
  158. {
  159. LLFavoritesBarCtrl* fb = dynamic_cast<LLFavoritesBarCtrl*>(getParent());
  160. if (fb)
  161. {
  162. fb->handleHover(x, y, mask);
  163. }
  164. return LLButton::handleHover(x, y, mask);
  165. }
  166. void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
  167. const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); }
  168. void onMouseEnter(S32 x, S32 y, MASK mask)
  169. {
  170. if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
  171. {
  172. LLUICtrl::onMouseEnter(x, y, mask);
  173. }
  174. else
  175. {
  176. LLButton::onMouseEnter(x, y, mask);
  177. }
  178. }
  179. protected:
  180. LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {}
  181. friend class LLUICtrlFactory;
  182. private:
  183. LLLandmarkInfoGetter mLandmarkInfoGetter;
  184. };
  185. /**
  186. * This class is needed to override LLMenuItemCallGL default handleToolTip function and
  187. * show SLURL as button tooltip.
  188. * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
  189. * in showDropDownMenu function but landmark data is not available when Favorites Bar is
  190. * created. Thats why we are requesting landmark data after
  191. */
  192. class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL
  193. {
  194. public:
  195. BOOL handleToolTip(S32 x, S32 y, MASK mask)
  196. {
  197. std::string region_name = mLandmarkInfoGetter.getName();
  198. if (!region_name.empty())
  199. {
  200. LLToolTip::Params params;
  201. params.message = llformat("%s\n%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY());
  202. params.sticky_rect = calcScreenRect();
  203. LLToolTipMgr::instance().show(params);
  204. }
  205. return TRUE;
  206. }
  207. void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
  208. virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask)
  209. {
  210. if (mMouseDownSignal)
  211. (*mMouseDownSignal)(this, x, y, mask);
  212. return LLMenuItemCallGL::handleMouseDown(x, y, mask);
  213. }
  214. virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
  215. {
  216. if (mMouseUpSignal)
  217. (*mMouseUpSignal)(this, x, y, mask);
  218. return LLMenuItemCallGL::handleMouseUp(x, y, mask);
  219. }
  220. virtual BOOL handleHover(S32 x, S32 y, MASK mask)
  221. {
  222. if (fb)
  223. {
  224. fb->handleHover(x, y, mask);
  225. }
  226. return TRUE;
  227. }
  228. void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; }
  229. protected:
  230. LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {}
  231. friend class LLUICtrlFactory;
  232. private:
  233. LLLandmarkInfoGetter mLandmarkInfoGetter;
  234. LLFavoritesBarCtrl* fb;
  235. };
  236. /**
  237. * This class was introduced just for fixing the following issue:
  238. * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through.
  239. * We must explicitly handle drag and drop event by returning TRUE
  240. * because otherwise LLToolDragAndDrop will initiate drag and drop operation
  241. * with the world.
  242. */
  243. class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu
  244. {
  245. public:
  246. virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  247. EDragAndDropType cargo_type,
  248. void* cargo_data,
  249. EAcceptance* accept,
  250. std::string& tooltip_msg)
  251. {
  252. *accept = ACCEPT_NO;
  253. return TRUE;
  254. }
  255. protected:
  256. LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p):
  257. LLToggleableMenu(p)
  258. {
  259. }
  260. friend class LLUICtrlFactory;
  261. };
  262. /**
  263. * This class is needed to update an item being copied to the favorites folder
  264. * with a sort field value (required to save favorites bar's tabs order).
  265. * See method handleNewFavoriteDragAndDrop for more details on how this class is used.
  266. */
  267. class LLItemCopiedCallback : public LLInventoryCallback
  268. {
  269. public:
  270. LLItemCopiedCallback(S32 sortField): mSortField(sortField) {}
  271. virtual void fire(const LLUUID& inv_item)
  272. {
  273. LLViewerInventoryItem* item = gInventory.getItem(inv_item);
  274. if (item)
  275. {
  276. item->setSortField(mSortField);
  277. item->setComplete(TRUE);
  278. item->updateServer(FALSE);
  279. gInventory.updateItem(item);
  280. gInventory.notifyObservers();
  281. }
  282. LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
  283. }
  284. private:
  285. S32 mSortField;
  286. };
  287. // updateButtons's helper
  288. struct LLFavoritesSort
  289. {
  290. // Sorting by creation date and name
  291. // TODO - made it customizible using gSavedSettings
  292. bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b)
  293. {
  294. S32 sortField1 = a->getSortField();
  295. S32 sortField2 = b->getSortField();
  296. if (!(sortField1 < 0 && sortField2 < 0))
  297. {
  298. return sortField2 > sortField1;
  299. }
  300. time_t first_create = a->getCreationDate();
  301. time_t second_create = b->getCreationDate();
  302. if (first_create == second_create)
  303. {
  304. return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0);
  305. }
  306. else
  307. {
  308. return (first_create > second_create);
  309. }
  310. }
  311. };
  312. LLFavoritesBarCtrl::Params::Params()
  313. : image_drag_indication("image_drag_indication"),
  314. more_button("more_button"),
  315. label("label")
  316. {
  317. }
  318. LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
  319. : LLUICtrl(p),
  320. mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
  321. mOverflowMenuHandle(),
  322. mContextMenuHandle(),
  323. mImageDragIndication(p.image_drag_indication),
  324. mShowDragMarker(FALSE),
  325. mLandingTab(NULL),
  326. mLastTab(NULL),
  327. mTabsHighlightEnabled(TRUE)
  328. , mUpdateDropDownItems(true)
  329. , mRestoreOverflowMenu(false)
  330. {
  331. // Register callback for menus with current registrar (will be parent panel's registrar)
  332. LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
  333. boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2));
  334. // Add this if we need to selectively enable items
  335. LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected",
  336. boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2));
  337. gInventory.addObserver(this);
  338. //make chevron button
  339. LLTextBox::Params more_button_params(p.more_button);
  340. mMoreTextBox = LLUICtrlFactory::create<LLTextBox> (more_button_params);
  341. mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this));
  342. addChild(mMoreTextBox);
  343. LLTextBox::Params label_param(p.label);
  344. mBarLabel = LLUICtrlFactory::create<LLTextBox> (label_param);
  345. addChild(mBarLabel);
  346. }
  347. LLFavoritesBarCtrl::~LLFavoritesBarCtrl()
  348. {
  349. gInventory.removeObserver(this);
  350. if (mOverflowMenuHandle.get()) mOverflowMenuHandle.get()->die();
  351. if (mContextMenuHandle.get()) mContextMenuHandle.get()->die();
  352. }
  353. BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  354. EDragAndDropType cargo_type,
  355. void* cargo_data,
  356. EAcceptance* accept,
  357. std::string& tooltip_msg)
  358. {
  359. *accept = ACCEPT_NO;
  360. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
  361. if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return FALSE;
  362. switch (cargo_type)
  363. {
  364. case DAD_LANDMARK:
  365. {
  366. /*
  367. * add a callback to the end drag event.
  368. * the callback will disconnet itself immediately after execution
  369. * this is done because LLToolDragAndDrop is a common tool so it shouldn't
  370. * be overloaded with redundant callbacks.
  371. */
  372. if (!mEndDragConnection.connected())
  373. {
  374. mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this));
  375. }
  376. // Copy the item into the favorites folder (if it's not already there).
  377. LLInventoryItem *item = (LLInventoryItem *)cargo_data;
  378. if (LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(findChildByLocalCoords(x, y)))
  379. {
  380. setLandingTab(dest);
  381. }
  382. else if (mLastTab && (x >= mLastTab->getRect().mRight))
  383. {
  384. /*
  385. * the condition dest == NULL can be satisfied not only in the case
  386. * of dragging to the right from the last tab of the favbar. there is a
  387. * small gap between each tab. if the user drags something exactly there
  388. * then mLandingTab will be set to NULL and the dragged item will be pushed
  389. * to the end of the favorites bar. this is incorrect behavior. that's why
  390. * we need an additional check which excludes the case described previously
  391. * making sure that the mouse pointer is beyond the last tab.
  392. */
  393. setLandingTab(NULL);
  394. }
  395. // check if we are dragging an existing item from the favorites bar
  396. if (item && mDragItemId == item->getUUID())
  397. {
  398. *accept = ACCEPT_YES_SINGLE;
  399. showDragMarker(TRUE);
  400. if (drop)
  401. {
  402. handleExistingFavoriteDragAndDrop(x, y);
  403. }
  404. }
  405. else
  406. {
  407. const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  408. if (item->getParentUUID() == favorites_id)
  409. {
  410. llwarns << "Attemt to copy a favorite item into the same folder." << llendl;
  411. break;
  412. }
  413. *accept = ACCEPT_YES_COPY_MULTI;
  414. showDragMarker(TRUE);
  415. if (drop)
  416. {
  417. if (mItems.empty())
  418. {
  419. setLandingTab(NULL);
  420. }
  421. handleNewFavoriteDragAndDrop(item, favorites_id, x, y);
  422. }
  423. }
  424. }
  425. break;
  426. default:
  427. break;
  428. }
  429. return TRUE;
  430. }
  431. void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
  432. {
  433. // Identify the button hovered and the side to drop
  434. LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
  435. bool insert_before = true;
  436. if (!dest)
  437. {
  438. insert_before = false;
  439. dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
  440. }
  441. // There is no need to handle if an item was dragged onto itself
  442. if (dest && dest->getLandmarkId() == mDragItemId)
  443. {
  444. return;
  445. }
  446. // Insert the dragged item in the right place
  447. if (dest)
  448. {
  449. LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before);
  450. }
  451. else
  452. {
  453. // This can happen when the item list is empty
  454. mItems.push_back(gInventory.getItem(mDragItemId));
  455. }
  456. gInventory.saveItemsOrder(mItems);
  457. LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
  458. if (menu && menu->getVisible())
  459. {
  460. menu->setVisible(FALSE);
  461. showDropDownMenu();
  462. }
  463. }
  464. void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y)
  465. {
  466. // Identify the button hovered and the side to drop
  467. LLFavoriteLandmarkButton* dest = NULL;
  468. bool insert_before = true;
  469. if (!mItems.empty())
  470. {
  471. dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
  472. if (!dest)
  473. {
  474. insert_before = false;
  475. dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
  476. }
  477. }
  478. // There is no need to handle if an item was dragged onto itself
  479. if (dest && dest->getLandmarkId() == mDragItemId)
  480. {
  481. return;
  482. }
  483. LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item);
  484. // Insert the dragged item in the right place
  485. if (dest)
  486. {
  487. insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before);
  488. }
  489. else
  490. {
  491. // This can happen when the item list is empty
  492. mItems.push_back(viewer_item);
  493. }
  494. int sortField = 0;
  495. LLPointer<LLItemCopiedCallback> cb;
  496. // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
  497. for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i)
  498. {
  499. LLViewerInventoryItem* currItem = *i;
  500. if (currItem->getUUID() == item->getUUID())
  501. {
  502. cb = new LLItemCopiedCallback(++sortField);
  503. }
  504. else
  505. {
  506. currItem->setSortField(++sortField);
  507. currItem->setComplete(TRUE);
  508. currItem->updateServer(FALSE);
  509. gInventory.updateItem(currItem);
  510. }
  511. }
  512. LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance();
  513. if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD)
  514. {
  515. viewer_item->setType(LLAssetType::AT_LANDMARK);
  516. copy_inventory_from_notecard(favorites_id,
  517. tool_dad->getObjectID(),
  518. tool_dad->getSourceID(),
  519. viewer_item.get(),
  520. gInventoryCallbacks.registerCB(cb));
  521. }
  522. else
  523. {
  524. copy_inventory_item(
  525. gAgent.getID(),
  526. item->getPermissions().getOwner(),
  527. item->getUUID(),
  528. favorites_id,
  529. std::string(),
  530. cb);
  531. }
  532. llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;
  533. }
  534. //virtual
  535. void LLFavoritesBarCtrl::changed(U32 mask)
  536. {
  537. if (mFavoriteFolderId.isNull())
  538. {
  539. mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  540. if (mFavoriteFolderId.notNull())
  541. {
  542. gInventory.fetchDescendentsOf(mFavoriteFolderId);
  543. }
  544. }
  545. else
  546. {
  547. LLInventoryModel::item_array_t items;
  548. LLInventoryModel::cat_array_t cats;
  549. LLIsType is_type(LLAssetType::AT_LANDMARK);
  550. gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
  551. for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
  552. {
  553. (*i)->getSLURL();
  554. }
  555. updateButtons();
  556. }
  557. }
  558. //virtual
  559. void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
  560. {
  561. LLUICtrl::reshape(width, height, called_from_parent);
  562. updateButtons();
  563. }
  564. void LLFavoritesBarCtrl::draw()
  565. {
  566. LLUICtrl::draw();
  567. if (mShowDragMarker)
  568. {
  569. S32 w = mImageDragIndication->getWidth();
  570. S32 h = mImageDragIndication->getHeight();
  571. if (mLandingTab)
  572. {
  573. // mouse pointer hovers over an existing tab
  574. LLRect rect = mLandingTab->getRect();
  575. mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h);
  576. }
  577. else if (mLastTab)
  578. {
  579. // mouse pointer hovers over the favbar empty space (right to the last tab)
  580. LLRect rect = mLastTab->getRect();
  581. mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h);
  582. }
  583. // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)
  584. mShowDragMarker = FALSE;
  585. }
  586. }
  587. const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
  588. {
  589. static LLButton::Params button_params;
  590. static bool params_initialized = false;
  591. if (!params_initialized)
  592. {
  593. LLXMLNodePtr button_xml_node;
  594. if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node))
  595. {
  596. LLXUIParser parser;
  597. parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml");
  598. }
  599. params_initialized = true;
  600. }
  601. return button_params;
  602. }
  603. void LLFavoritesBarCtrl::updateButtons()
  604. {
  605. mItems.clear();
  606. if (!collectFavoriteItems(mItems))
  607. {
  608. return;
  609. }
  610. const LLButton::Params& button_params = getButtonParams();
  611. if(mItems.empty())
  612. {
  613. mBarLabel->setVisible(TRUE);
  614. }
  615. else
  616. {
  617. mBarLabel->setVisible(FALSE);
  618. }
  619. const child_list_t* childs = getChildList();
  620. child_list_const_iter_t child_it = childs->begin();
  621. int first_changed_item_index = 0;
  622. int rightest_point = getRect().mRight - mMoreTextBox->getRect().getWidth();
  623. //lets find first changed button
  624. while (child_it != childs->end() && first_changed_item_index < mItems.count())
  625. {
  626. LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it);
  627. if (button)
  628. {
  629. const LLViewerInventoryItem *item = mItems[first_changed_item_index].get();
  630. if (item)
  631. {
  632. // an child's order and mItems should be same
  633. if (button->getLandmarkId() != item->getUUID() // sort order has been changed
  634. || button->getLabelSelected() != item->getName() // favorite's name has been changed
  635. || button->getRect().mRight < rightest_point) // favbar's width has been changed
  636. {
  637. break;
  638. }
  639. }
  640. first_changed_item_index++;
  641. }
  642. child_it++;
  643. }
  644. // now first_changed_item_index should contains a number of button that need to change
  645. if (first_changed_item_index <= mItems.count())
  646. {
  647. // Rebuild the buttons only
  648. // child_list_t is a linked list, so safe to erase from the middle if we pre-increment the iterator
  649. while (child_it != childs->end())
  650. {
  651. //lets remove other landmarks button and rebuild it
  652. child_list_const_iter_t cur_it = child_it++;
  653. LLFavoriteLandmarkButton* button =
  654. dynamic_cast<LLFavoriteLandmarkButton*> (*cur_it);
  655. if (button)
  656. {
  657. removeChild(button);
  658. delete button;
  659. }
  660. }
  661. // we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning
  662. // keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton
  663. if (mMoreTextBox->getParent() == this)
  664. {
  665. removeChild(mMoreTextBox);
  666. }
  667. int last_right_edge = 0;
  668. //calculate new buttons offset
  669. if (getChildList()->size() > 0)
  670. {
  671. //find last visible child to get the rightest button offset
  672. child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(),
  673. std::mem_fun(&LLView::getVisible));
  674. if(last_visible_it != childs->rend())
  675. {
  676. last_right_edge = (*last_visible_it)->getRect().mRight;
  677. }
  678. }
  679. //last_right_edge is saving coordinates
  680. LLButton* last_new_button = NULL;
  681. int j = first_changed_item_index;
  682. for (; j < mItems.count(); j++)
  683. {
  684. last_new_button = createButton(mItems[j], button_params, last_right_edge);
  685. if (!last_new_button)
  686. {
  687. break;
  688. }
  689. sendChildToBack(last_new_button);
  690. last_right_edge = last_new_button->getRect().mRight;
  691. mLastTab = last_new_button;
  692. }
  693. mFirstDropDownItem = j;
  694. // Chevron button
  695. if (mFirstDropDownItem < mItems.count())
  696. {
  697. // if updateButton had been called it means:
  698. //or there are some new favorites, or width had been changed
  699. // so if we need to display chevron button, we must update dropdown items too.
  700. mUpdateDropDownItems = true;
  701. S32 buttonHGap = button_params.rect.left; // default value
  702. LLRect rect;
  703. // Chevron button should stay right aligned
  704. rect.setOriginAndSize(getRect().mRight - mMoreTextBox->getRect().getWidth() - buttonHGap, 0,
  705. mMoreTextBox->getRect().getWidth(),
  706. mMoreTextBox->getRect().getHeight());
  707. addChild(mMoreTextBox);
  708. mMoreTextBox->setRect(rect);
  709. mMoreTextBox->setVisible(TRUE);
  710. }
  711. // Update overflow menu
  712. LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mOverflowMenuHandle.get());
  713. if (overflow_menu && overflow_menu->getVisible())
  714. {
  715. overflow_menu->setVisible(FALSE);
  716. if (mUpdateDropDownItems)
  717. showDropDownMenu();
  718. }
  719. }
  720. else
  721. {
  722. mUpdateDropDownItems = false;
  723. }
  724. }
  725. LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset)
  726. {
  727. S32 def_button_width = button_params.rect.width;
  728. S32 button_x_delta = button_params.rect.left; // default value
  729. S32 curr_x = x_offset;
  730. /**
  731. * WORKAROUND:
  732. * There are some problem with displaying of fonts in buttons.
  733. * Empty space or ellipsis might be displayed instead of last symbols, even though the width of the button is enough.
  734. * The problem disappears if we pad the button with 20 pixels.
  735. */
  736. int required_width = mFont->getWidth(item->getName()) + 20;
  737. int width = required_width > def_button_width? def_button_width : required_width;
  738. LLFavoriteLandmarkButton* fav_btn = NULL;
  739. // do we have a place for next button + double buttonHGap + mMoreTextBox ?
  740. if(curr_x + width + 2*button_x_delta + mMoreTextBox->getRect().getWidth() > getRect().mRight )
  741. {
  742. return NULL;
  743. }
  744. LLButton::Params fav_btn_params(button_params);
  745. fav_btn = LLUICtrlFactory::create<LLFavoriteLandmarkButton>(fav_btn_params);
  746. if (NULL == fav_btn)
  747. {
  748. llwarns << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << llendl;
  749. return NULL;
  750. }
  751. addChild(fav_btn);
  752. LLRect butt_rect (fav_btn->getRect());
  753. fav_btn->setLandmarkID(item->getUUID());
  754. butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight());
  755. fav_btn->setRect(butt_rect);
  756. // change only left and save bottom
  757. fav_btn->setFont(mFont);
  758. fav_btn->setLabel(item->getName());
  759. fav_btn->setToolTip(item->getName());
  760. fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
  761. fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 ));
  762. fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
  763. fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
  764. return fav_btn;
  765. }
  766. BOOL LLFavoritesBarCtrl::postBuild()
  767. {
  768. // make the popup menu available
  769. LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  770. if (!menu)
  771. {
  772. menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
  773. }
  774. menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
  775. mContextMenuHandle = menu->getHandle();
  776. return TRUE;
  777. }
  778. BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
  779. {
  780. if (mFavoriteFolderId.isNull())
  781. return FALSE;
  782. LLInventoryModel::cat_array_t cats;
  783. LLIsType is_type(LLAssetType::AT_LANDMARK);
  784. gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
  785. std::sort(items.begin(), items.end(), LLFavoritesSort());
  786. if (needToSaveItemsOrder(items))
  787. {
  788. S32 sortField = 0;
  789. for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
  790. {
  791. (*i)->setSortField(++sortField);
  792. }
  793. }
  794. return TRUE;
  795. }
  796. void LLFavoritesBarCtrl::showDropDownMenu()
  797. {
  798. if (mOverflowMenuHandle.isDead())
  799. {
  800. createOverflowMenu();
  801. }
  802. LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get();
  803. if (menu && menu->toggleVisibility())
  804. {
  805. if (mUpdateDropDownItems)
  806. {
  807. updateMenuItems(menu);
  808. }
  809. menu->buildDrawLabels();
  810. menu->updateParent(LLMenuGL::sMenuContainer);
  811. menu->setButtonRect(mMoreTextBox->getRect(), this);
  812. positionAndShowMenu(menu);
  813. }
  814. }
  815. void LLFavoritesBarCtrl::createOverflowMenu()
  816. {
  817. LLToggleableMenu::Params menu_p;
  818. menu_p.name("favorites menu");
  819. menu_p.can_tear_off(false);
  820. menu_p.visible(false);
  821. menu_p.scrollable(true);
  822. menu_p.max_scrollable_items = 10;
  823. menu_p.preferred_width = DROP_DOWN_MENU_WIDTH;
  824. LLToggleableMenu* menu = LLUICtrlFactory::create<LLFavoriteLandmarkToggleableMenu>(menu_p);
  825. mOverflowMenuHandle = menu->getHandle();
  826. }
  827. void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu)
  828. {
  829. menu->empty();
  830. U32 widest_item = 0;
  831. for (S32 i = mFirstDropDownItem; i < mItems.count(); i++)
  832. {
  833. LLViewerInventoryItem* item = mItems.get(i);
  834. const std::string& item_name = item->getName();
  835. LLFavoriteLandmarkMenuItem::Params item_params;
  836. item_params.name(item_name);
  837. item_params.label(item_name);
  838. item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
  839. LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params);
  840. menu_item->initFavoritesBarPointer(this);
  841. menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4));
  842. menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
  843. menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
  844. menu_item->setLandmarkID(item->getUUID());
  845. fitLabelWidth(menu_item);
  846. widest_item = llmax(widest_item, menu_item->getNominalWidth());
  847. menu->addChild(menu_item);
  848. }
  849. addOpenLandmarksMenuItem(menu);
  850. mUpdateDropDownItems = false;
  851. }
  852. void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item)
  853. {
  854. U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth());
  855. std::string item_name = menu_item->getName();
  856. // Check whether item name wider than menu
  857. if (menu_item->getNominalWidth() > max_width)
  858. {
  859. S32 chars_total = item_name.length();
  860. S32 chars_fitted = 1;
  861. menu_item->setLabel(LLStringExplicit(""));
  862. S32 label_space = max_width - menu_item->getFont()->getWidth("...") -
  863. menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels)
  864. while (chars_fitted < chars_total
  865. && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space)
  866. {
  867. chars_fitted++;
  868. }
  869. chars_fitted--; // Rolling back one char, that doesn't fit
  870. menu_item->setLabel(item_name.substr(0, chars_fitted) + "...");
  871. }
  872. }
  873. void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu)
  874. {
  875. std::string label_untrans = "Open landmarks";
  876. std::string label_transl;
  877. bool translated = LLTrans::findString(label_transl, label_untrans);
  878. LLMenuItemCallGL::Params item_params;
  879. item_params.name("open_my_landmarks");
  880. item_params.label(translated ? label_transl: label_untrans);
  881. LLSD key;
  882. key["type"] = "open_landmark_tab";
  883. item_params.on_click.function(boost::bind(&LLFloaterSidePanelContainer::showPanel, "places", key));
  884. LLMenuItemCallGL* menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
  885. fitLabelWidth(menu_item);
  886. LLMenuItemSeparatorGL::Params sep_params;
  887. sep_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor");
  888. sep_params.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
  889. sep_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
  890. sep_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
  891. LLMenuItemSeparatorGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(sep_params);
  892. menu->addChild(separator);
  893. menu->addChild(menu_item);
  894. }
  895. void LLFavoritesBarCtrl::positionAndShowMenu(LLToggleableMenu* menu)
  896. {
  897. U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth());
  898. S32 menu_x = getRect().getWidth() - max_width;
  899. S32 menu_y = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD;
  900. // the menu should be offset of the right edge of the window
  901. // so it's no covered by buttons in the right-side toolbar.
  902. LLToolBar* right_toolbar = gToolBarView->getChild<LLToolBar>("toolbar_right");
  903. if (right_toolbar && right_toolbar->hasButtons())
  904. {
  905. S32 toolbar_top = 0;
  906. if (LLView* top_border_panel = right_toolbar->getChild<LLView>("button_panel"))
  907. {
  908. toolbar_top = top_border_panel->calcScreenRect().mTop;
  909. }
  910. // Calculating the bottom (in screen coord) of the drop down menu
  911. S32 menu_top = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD;
  912. S32 menu_bottom = menu_top - menu->getRect().getHeight();
  913. S32 menu_bottom_screen = 0;
  914. localPointToScreen(0, menu_bottom, &menu_top, &menu_bottom_screen);
  915. if (menu_bottom_screen < toolbar_top)
  916. {
  917. menu_x -= right_toolbar->getRect().getWidth();
  918. }
  919. }
  920. LLMenuGL::showPopup(this, menu, menu_x, menu_y);
  921. }
  922. void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id)
  923. {
  924. // We only have one Inventory, gInventory. Some day this should be better abstracted.
  925. LLInvFVBridgeAction::doAction(item_id,&gInventory);
  926. }
  927. void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask)
  928. {
  929. mSelectedItemID = item_id;
  930. LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
  931. if (!menu)
  932. {
  933. return;
  934. }
  935. // Remember that the context menu was shown simultaneously with the overflow menu,
  936. // so that we can restore the overflow menu when user clicks a context menu item
  937. // (which hides the overflow menu).
  938. {
  939. LLView* overflow_menu = mOverflowMenuHandle.get();
  940. mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible();
  941. }
  942. // Release mouse capture so hover events go to the popup menu
  943. // because this is happening during a mouse down.
  944. gFocusMgr.setMouseCapture(NULL);
  945. menu->updateParent(LLMenuGL::sMenuContainer);
  946. LLMenuGL::showPopup(fav_button, menu, x, y);
  947. }
  948. BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
  949. {
  950. BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL;
  951. if(!handled && !gMenuHolder->hasVisibleMenu())
  952. {
  953. show_navbar_context_menu(this,x,y);
  954. handled = true;
  955. }
  956. return handled;
  957. }
  958. void copy_slurl_to_clipboard_cb(std::string& slurl)
  959. {
  960. gClipboard.copyFromString(utf8str_to_wstring(slurl));
  961. LLSD args;
  962. args["SLURL"] = slurl;
  963. LLNotificationsUtil::add("CopySLURL", args);
  964. }
  965. bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata)
  966. {
  967. std::string param = userdata.asString();
  968. if (param == std::string("can_paste"))
  969. {
  970. return isClipboardPasteable();
  971. }
  972. return false;
  973. }
  974. void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
  975. {
  976. std::string action = userdata.asString();
  977. llinfos << "Action = " << action << " Item = " << mSelectedItemID.asString() << llendl;
  978. LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID);
  979. if (!item)
  980. return;
  981. if (action == "open")
  982. {
  983. onButtonClick(item->getUUID());
  984. }
  985. else if (action == "about")
  986. {
  987. LLSD key;
  988. key["type"] = "landmark";
  989. key["id"] = mSelectedItemID;
  990. LLFloaterSidePanelContainer::showPanel("places", key);
  991. }
  992. else if (action == "copy_slurl")
  993. {
  994. LLVector3d posGlobal;
  995. LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
  996. if (!posGlobal.isExactlyZero())
  997. {
  998. LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb);
  999. }
  1000. }
  1001. else if (action == "show_on_map")
  1002. {
  1003. LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
  1004. LLVector3d posGlobal;
  1005. LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
  1006. if (!posGlobal.isExactlyZero() && worldmap_instance)
  1007. {
  1008. worldmap_instance->trackLocation(posGlobal);
  1009. LLFloaterReg::showInstance("world_map", "center");
  1010. }
  1011. }
  1012. else if (action == "cut")
  1013. {
  1014. }
  1015. else if (action == "copy")
  1016. {
  1017. LLInventoryClipboard::instance().store(mSelectedItemID);
  1018. }
  1019. else if (action == "paste")
  1020. {
  1021. pastFromClipboard();
  1022. }
  1023. else if (action == "delete")
  1024. {
  1025. gInventory.removeItem(mSelectedItemID);
  1026. }
  1027. // Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item).
  1028. // See EXT-4217 and STORM-207.
  1029. LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
  1030. if (mRestoreOverflowMenu && menu && !menu->getVisible())
  1031. {
  1032. menu->resetScrollPositionOnShow(false);
  1033. showDropDownMenu();
  1034. menu->resetScrollPositionOnShow(true);
  1035. }
  1036. }
  1037. BOOL LLFavoritesBarCtrl::isClipboardPasteable() const
  1038. {
  1039. if (!LLInventoryClipboard::instance().hasContents())
  1040. {
  1041. return FALSE;
  1042. }
  1043. LLDynamicArray<LLUUID> objects;
  1044. LLInventoryClipboard::instance().retrieve(objects);
  1045. S32 count = objects.count();
  1046. for(S32 i = 0; i < count; i++)
  1047. {
  1048. const LLUUID &item_id = objects.get(i);
  1049. // Can't paste folders
  1050. const LLInventoryCategory *cat = gInventory.getCategory(item_id);
  1051. if (cat)
  1052. {
  1053. return FALSE;
  1054. }
  1055. const LLInventoryItem *item = gInventory.getItem(item_id);
  1056. if (item && LLAssetType::AT_LANDMARK != item->getType())
  1057. {
  1058. return FALSE;
  1059. }
  1060. }
  1061. return TRUE;
  1062. }
  1063. void LLFavoritesBarCtrl::pastFromClipboard() const
  1064. {
  1065. LLInventoryModel* model = &gInventory;
  1066. if(model && isClipboardPasteable())
  1067. {
  1068. LLInventoryItem* item = NULL;
  1069. LLDynamicArray<LLUUID> objects;
  1070. LLInventoryClipboard::instance().retrieve(objects);
  1071. S32 count = objects.count();
  1072. LLUUID parent_id(mFavoriteFolderId);
  1073. for(S32 i = 0; i < count; i++)
  1074. {
  1075. item = model->getItem(objects.get(i));
  1076. if (item)
  1077. {
  1078. copy_inventory_item(
  1079. gAgent.getID(),
  1080. item->getPermissions().getOwner(),
  1081. item->getUUID(),
  1082. parent_id,
  1083. std::string(),
  1084. LLPointer<LLInventoryCallback>(NULL));
  1085. }
  1086. }
  1087. }
  1088. }
  1089. void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
  1090. {
  1091. // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away)
  1092. // mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu.
  1093. // We have to check and set visibility of pop-up menu in such a way instead of using
  1094. // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but
  1095. // we need to close only pop-up menu while dropdown one should be still opened.
  1096. LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
  1097. if(menu && menu->getVisible())
  1098. {
  1099. menu->setVisible(FALSE);
  1100. }
  1101. mDragItemId = id;
  1102. mStartDrag = TRUE;
  1103. S32 screenX, screenY;
  1104. localPointToScreen(x, y, &screenX, &screenY);
  1105. LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY);
  1106. }
  1107. void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
  1108. {
  1109. mStartDrag = FALSE;
  1110. mDragItemId = LLUUID::null;
  1111. }
  1112. void LLFavoritesBarCtrl::onEndDrag()
  1113. {
  1114. mEndDragConnection.disconnect();
  1115. showDragMarker(FALSE);
  1116. mDragItemId = LLUUID::null;
  1117. LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
  1118. }
  1119. BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask)
  1120. {
  1121. if (mDragItemId != LLUUID::null && mStartDrag)
  1122. {
  1123. S32 screenX, screenY;
  1124. localPointToScreen(x, y, &screenX, &screenY);
  1125. if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY))
  1126. {
  1127. LLToolDragAndDrop::getInstance()->beginDrag(
  1128. DAD_LANDMARK, mDragItemId,
  1129. LLToolDragAndDrop::SOURCE_LIBRARY);
  1130. mStartDrag = FALSE;
  1131. return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask);
  1132. }
  1133. }
  1134. return TRUE;
  1135. }
  1136. LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y)
  1137. {
  1138. LLUICtrl* ctrl = NULL;
  1139. const child_list_t* list = getChildList();
  1140. for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
  1141. {
  1142. // Look only for children that are favorite buttons
  1143. if ((*i)->getName() == "favorites_bar_btn")
  1144. {
  1145. LLRect rect = (*i)->getRect();
  1146. // We consider a button hit if the cursor is left of the right side
  1147. // This makes the hit a bit less finicky than hitting directly on the button itself
  1148. if (x <= rect.mRight)
  1149. {
  1150. ctrl = dynamic_cast<LLUICtrl*>(*i);
  1151. break;
  1152. }
  1153. }
  1154. }
  1155. return ctrl;
  1156. }
  1157. BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items)
  1158. {
  1159. BOOL result = FALSE;
  1160. // if there is an item without sort order field set, we need to save items order
  1161. for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
  1162. {
  1163. if ((*i)->getSortField() < 0)
  1164. {
  1165. result = TRUE;
  1166. break;
  1167. }
  1168. }
  1169. return result;
  1170. }
  1171. void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before)
  1172. {
  1173. // Get the iterator to the destination item
  1174. LLInventoryModel::item_array_t::iterator it_dest = LLInventoryModel::findItemIterByUUID(items, dest_item_id);
  1175. if (it_dest == items.end())
  1176. return;
  1177. // Go to the next element if one wishes to insert after the dest element
  1178. if (!insert_before)
  1179. {
  1180. ++it_dest;
  1181. }
  1182. // Insert the source item in the right place
  1183. if (it_dest != items.end())
  1184. {
  1185. items.insert(it_dest, insertedItem);
  1186. }
  1187. else
  1188. {
  1189. // Append to the list if it_dest reached the end
  1190. items.push_back(insertedItem);
  1191. }
  1192. }
  1193. // EOF