/indra/llui/llmultifloater.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 512 lines · 337 code · 63 blank · 112 comment · 62 complexity · b69ceaa90608a5aff52269c410ed225c MD5 · raw file

  1. /**
  2. * @file llmultifloater.cpp
  3. * @brief LLFloater that hosts other floaters
  4. *
  5. * $LicenseInfo:firstyear=2002&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. // Floating "windows" within the GL display, like the inventory floater,
  27. // mini-map floater, etc.
  28. #include "linden_common.h"
  29. #include "llmultifloater.h"
  30. #include "llresizehandle.h"
  31. //
  32. // LLMultiFloater
  33. //
  34. LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params)
  35. : LLFloater(key),
  36. mTabContainer(NULL),
  37. mTabPos(LLTabContainer::TOP),
  38. mAutoResize(TRUE),
  39. mOrigMinWidth(0),
  40. mOrigMinHeight(0)
  41. {
  42. }
  43. void LLMultiFloater::buildTabContainer()
  44. {
  45. const LLFloater::Params& default_params = LLFloater::getDefaultParams();
  46. S32 floater_header_size = default_params.header_height;
  47. LLTabContainer::Params p;
  48. p.name(std::string("Preview Tabs"));
  49. p.rect(LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - floater_header_size, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0));
  50. p.tab_position(mTabPos);
  51. p.follows.flags(FOLLOWS_ALL);
  52. p.commit_callback.function(boost::bind(&LLMultiFloater::onTabSelected, this));
  53. mTabContainer = LLUICtrlFactory::create<LLTabContainer>(p);
  54. addChild(mTabContainer);
  55. if (isResizable())
  56. {
  57. mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
  58. }
  59. }
  60. void LLMultiFloater::onOpen(const LLSD& key)
  61. {
  62. // if (mTabContainer->getTabCount() <= 0)
  63. // {
  64. // // for now, don't allow multifloaters
  65. // // without any child floaters
  66. // closeFloater();
  67. // }
  68. }
  69. void LLMultiFloater::draw()
  70. {
  71. if (mTabContainer->getTabCount() == 0)
  72. {
  73. //RN: could this potentially crash in draw hierarchy?
  74. closeFloater();
  75. }
  76. else
  77. {
  78. LLFloater::draw();
  79. }
  80. }
  81. BOOL LLMultiFloater::closeAllFloaters()
  82. {
  83. S32 tabToClose = 0;
  84. S32 lastTabCount = mTabContainer->getTabCount();
  85. while (tabToClose < mTabContainer->getTabCount())
  86. {
  87. LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
  88. first_floater->closeFloater();
  89. if(lastTabCount == mTabContainer->getTabCount())
  90. {
  91. //Tab did not actually close, possibly due to a pending Save Confirmation dialog..
  92. //so try and close the next one in the list...
  93. tabToClose++;
  94. }
  95. else
  96. {
  97. //Tab closed ok.
  98. lastTabCount = mTabContainer->getTabCount();
  99. }
  100. }
  101. if( mTabContainer->getTabCount() != 0 )
  102. return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
  103. return TRUE; //else all tabs were successfully closed...
  104. }
  105. void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
  106. {
  107. static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
  108. const LLFloater::Params& default_params = LLFloater::getDefaultParams();
  109. S32 floater_header_size = default_params.header_height;
  110. S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
  111. S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
  112. S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height);
  113. if (isMinimized())
  114. {
  115. LLRect newrect;
  116. newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
  117. setExpandedRect(newrect);
  118. }
  119. else
  120. {
  121. S32 old_height = getRect().getHeight();
  122. reshape(new_width, new_height);
  123. // keep top left corner in same position
  124. translate(0, old_height - new_height);
  125. }
  126. }
  127. /**
  128. void addFloater(LLFloater* floaterp, BOOL select_added_floater)
  129. Adds the LLFloater pointed to by floaterp to this.
  130. If floaterp is already hosted by this, then it is re-added to get
  131. new titles, etc.
  132. If select_added_floater is true, the LLFloater pointed to by floaterp will
  133. become the selected tab in this
  134. Affects: mTabContainer, floaterp
  135. **/
  136. void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
  137. {
  138. if (!floaterp)
  139. {
  140. return;
  141. }
  142. if (!mTabContainer)
  143. {
  144. llerrs << "Tab Container used without having been initialized." << llendl;
  145. return;
  146. }
  147. if (floaterp->getHost() == this)
  148. {
  149. // already hosted by me, remove
  150. // do this so we get updated title, etc.
  151. mFloaterDataMap.erase(floaterp->getHandle());
  152. mTabContainer->removeTabPanel(floaterp);
  153. }
  154. else if (floaterp->getHost())
  155. {
  156. // floaterp is hosted by somebody else and
  157. // this is adding it, so remove it from it's old host
  158. floaterp->getHost()->removeFloater(floaterp);
  159. }
  160. else if (floaterp->getParent() == gFloaterView)
  161. {
  162. // rehost preview floater as child panel
  163. gFloaterView->removeChild(floaterp);
  164. }
  165. // store original configuration
  166. LLFloaterData floater_data;
  167. floater_data.mWidth = floaterp->getRect().getWidth();
  168. floater_data.mHeight = floaterp->getRect().getHeight();
  169. floater_data.mCanMinimize = floaterp->isMinimizeable();
  170. floater_data.mCanResize = floaterp->isResizable();
  171. // remove minimize and close buttons
  172. floaterp->setCanMinimize(FALSE);
  173. floaterp->setCanResize(FALSE);
  174. floaterp->setCanDrag(FALSE);
  175. floaterp->storeRectControl();
  176. // avoid double rendering of floater background (makes it more opaque)
  177. floaterp->setBackgroundVisible(FALSE);
  178. if (mAutoResize)
  179. {
  180. growToFit(floater_data.mWidth, floater_data.mHeight);
  181. }
  182. //add the panel, add it to proper maps
  183. mTabContainer->addTabPanel(
  184. LLTabContainer::TabPanelParams()
  185. .panel(floaterp)
  186. .label(floaterp->getShortTitle())
  187. .insert_at(insertion_point));
  188. mFloaterDataMap[floaterp->getHandle()] = floater_data;
  189. updateResizeLimits();
  190. if ( select_added_floater )
  191. {
  192. mTabContainer->selectTabPanel(floaterp);
  193. }
  194. else
  195. {
  196. // reassert visible tab (hiding new floater if necessary)
  197. mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
  198. }
  199. floaterp->setHost(this);
  200. if (isMinimized())
  201. {
  202. floaterp->setVisible(FALSE);
  203. }
  204. // Tabs sometimes overlap resize handle
  205. moveResizeHandlesToFront();
  206. }
  207. void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp)
  208. {
  209. S32 index = mTabContainer->getIndexForPanel(floaterp);
  210. if (index != -1)
  211. {
  212. mTabContainer->setPanelTitle(index, floaterp->getShortTitle());
  213. }
  214. }
  215. /**
  216. BOOL selectFloater(LLFloater* floaterp)
  217. If the LLFloater pointed to by floaterp is hosted by this,
  218. then its tab is selected and returns true. Otherwise returns false.
  219. Affects: mTabContainer
  220. **/
  221. BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
  222. {
  223. return mTabContainer->selectTabPanel(floaterp);
  224. }
  225. // virtual
  226. void LLMultiFloater::selectNextFloater()
  227. {
  228. mTabContainer->selectNextTab();
  229. }
  230. // virtual
  231. void LLMultiFloater::selectPrevFloater()
  232. {
  233. mTabContainer->selectPrevTab();
  234. }
  235. void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point)
  236. {
  237. if(!floaterp) return;
  238. // we won't select a panel that already is selected
  239. // it is hard to do this internally to tab container
  240. // as tab selection is handled via index and the tab at a given
  241. // index might have changed
  242. if (floaterp != mTabContainer->getCurrentPanel() &&
  243. !mTabContainer->selectTabPanel(floaterp))
  244. {
  245. addFloater(floaterp, TRUE, insertion_point);
  246. }
  247. }
  248. void LLMultiFloater::removeFloater(LLFloater* floaterp)
  249. {
  250. if (!floaterp || floaterp->getHost() != this )
  251. return;
  252. floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
  253. if (found_data_it != mFloaterDataMap.end())
  254. {
  255. LLFloaterData& floater_data = found_data_it->second;
  256. floaterp->setCanMinimize(floater_data.mCanMinimize);
  257. if (!floater_data.mCanResize)
  258. {
  259. // restore original size
  260. floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
  261. }
  262. floaterp->setCanResize(floater_data.mCanResize);
  263. mFloaterDataMap.erase(found_data_it);
  264. }
  265. mTabContainer->removeTabPanel(floaterp);
  266. floaterp->setBackgroundVisible(TRUE);
  267. floaterp->setCanDrag(TRUE);
  268. floaterp->setHost(NULL);
  269. floaterp->applyRectControl();
  270. updateResizeLimits();
  271. tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
  272. }
  273. void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
  274. {
  275. // default implementation does nothing
  276. }
  277. void LLMultiFloater::tabClose()
  278. {
  279. if (mTabContainer->getTabCount() == 0)
  280. {
  281. // no more children, close myself
  282. closeFloater();
  283. }
  284. }
  285. void LLMultiFloater::setVisible(BOOL visible)
  286. {
  287. // *FIX: shouldn't have to do this, fix adding to minimized multifloater
  288. LLFloater::setVisible(visible);
  289. if (mTabContainer)
  290. {
  291. LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
  292. if (cur_floaterp)
  293. {
  294. cur_floaterp->setVisible(visible);
  295. }
  296. // if no tab selected, and we're being shown,
  297. // select last tab to be added
  298. if (visible && !cur_floaterp)
  299. {
  300. mTabContainer->selectLastTab();
  301. }
  302. }
  303. }
  304. BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
  305. {
  306. if (key == 'W' && mask == (MASK_CONTROL|MASK_SHIFT))
  307. {
  308. LLFloater* floater = getActiveFloater();
  309. // is user closeable and is system closeable
  310. if (floater && floater->canClose() && floater->isCloseable())
  311. {
  312. floater->closeFloater();
  313. // EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
  314. // bring back focus on tab container if there are any tab left
  315. if(mTabContainer->getTabCount() > 0)
  316. {
  317. mTabContainer->setFocus(TRUE);
  318. }
  319. }
  320. return TRUE;
  321. }
  322. return LLFloater::handleKeyHere(key, mask);
  323. }
  324. bool LLMultiFloater::addChild(LLView* child, S32 tab_group)
  325. {
  326. LLTabContainer* tab_container = dynamic_cast<LLTabContainer*>(child);
  327. if (tab_container)
  328. {
  329. // store pointer to tab container
  330. setTabContainer(tab_container);
  331. }
  332. // then go ahead and add child as usual
  333. return LLFloater::addChild(child, tab_group);
  334. }
  335. LLFloater* LLMultiFloater::getActiveFloater()
  336. {
  337. return (LLFloater*)mTabContainer->getCurrentPanel();
  338. }
  339. S32 LLMultiFloater::getFloaterCount()
  340. {
  341. return mTabContainer->getTabCount();
  342. }
  343. /**
  344. BOOL isFloaterFlashing(LLFloater* floaterp)
  345. Returns true if the LLFloater pointed to by floaterp
  346. is currently in a flashing state and is hosted by this.
  347. False otherwise.
  348. Requires: floaterp != NULL
  349. **/
  350. BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
  351. {
  352. if ( floaterp && floaterp->getHost() == this )
  353. return mTabContainer->getTabPanelFlashing(floaterp);
  354. return FALSE;
  355. }
  356. /**
  357. BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
  358. Sets the current flashing state of the LLFloater pointed
  359. to by floaterp to be the BOOL flashing if the LLFloater pointed
  360. to by floaterp is hosted by this.
  361. Requires: floaterp != NULL
  362. **/
  363. void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
  364. {
  365. if ( floaterp && floaterp->getHost() == this )
  366. mTabContainer->setTabPanelFlashing(floaterp, flashing);
  367. }
  368. void LLMultiFloater::onTabSelected()
  369. {
  370. LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
  371. if (floaterp)
  372. {
  373. tabOpen(floaterp, true);
  374. }
  375. }
  376. void LLMultiFloater::setCanResize(BOOL can_resize)
  377. {
  378. LLFloater::setCanResize(can_resize);
  379. if (!mTabContainer) return;
  380. if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
  381. {
  382. mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
  383. }
  384. else
  385. {
  386. mTabContainer->setRightTabBtnOffset(0);
  387. }
  388. }
  389. BOOL LLMultiFloater::postBuild()
  390. {
  391. mCloseSignal.connect(boost::bind(&LLMultiFloater::closeAllFloaters, this));
  392. // remember any original xml minimum size
  393. getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
  394. if (mTabContainer)
  395. {
  396. return TRUE;
  397. }
  398. mTabContainer = getChild<LLTabContainer>("Preview Tabs");
  399. setCanResize(mResizable);
  400. return TRUE;
  401. }
  402. void LLMultiFloater::updateResizeLimits()
  403. {
  404. static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
  405. const LLFloater::Params& default_params = LLFloater::getDefaultParams();
  406. S32 floater_header_size = default_params.header_height;
  407. S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
  408. // initialize minimum size constraint to the original xml values.
  409. S32 new_min_width = mOrigMinWidth;
  410. S32 new_min_height = mOrigMinHeight;
  411. // possibly increase minimum size constraint due to children's minimums.
  412. for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
  413. {
  414. LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
  415. if (floaterp)
  416. {
  417. new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
  418. new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height);
  419. }
  420. }
  421. setResizeLimits(new_min_width, new_min_height);
  422. S32 cur_height = getRect().getHeight();
  423. S32 new_width = llmax(getRect().getWidth(), new_min_width);
  424. S32 new_height = llmax(getRect().getHeight(), new_min_height);
  425. if (isMinimized())
  426. {
  427. const LLRect& expanded = getExpandedRect();
  428. LLRect newrect;
  429. newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
  430. setExpandedRect(newrect);
  431. }
  432. else
  433. {
  434. reshape(new_width, new_height);
  435. // make sure upper left corner doesn't move
  436. translate(0, cur_height - getRect().getHeight());
  437. // make sure this window is visible on screen when it has been modified
  438. // (tab added, etc)
  439. gFloaterView->adjustToFitScreen(this, TRUE);
  440. }
  441. }