PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llfloater.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2611 lines | 1989 code | 336 blank | 286 comment | 388 complexity | 0ec00b87906808552fa937704443b4eb MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /**
  2. * @file llfloater.cpp
  3. * @brief LLFloater base class
  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 "llfloater.h"
  30. #include "llfocusmgr.h"
  31. #include "lluictrlfactory.h"
  32. #include "llbutton.h"
  33. #include "llcheckboxctrl.h"
  34. #include "lldir.h"
  35. #include "lldraghandle.h"
  36. #include "llfloaterreg.h"
  37. #include "llfocusmgr.h"
  38. #include "llresizebar.h"
  39. #include "llresizehandle.h"
  40. #include "llkeyboard.h"
  41. #include "llmenugl.h" // MENU_BAR_HEIGHT
  42. #include "llmodaldialog.h"
  43. #include "lltextbox.h"
  44. #include "llresmgr.h"
  45. #include "llui.h"
  46. #include "llwindow.h"
  47. #include "llstl.h"
  48. #include "llcontrol.h"
  49. #include "lltabcontainer.h"
  50. #include "v2math.h"
  51. #include "lltrans.h"
  52. #include "llhelp.h"
  53. #include "llmultifloater.h"
  54. #include "llsdutil.h"
  55. #include <boost/foreach.hpp>
  56. // use this to control "jumping" behavior when Ctrl-Tabbing
  57. const S32 TABBED_FLOATER_OFFSET = 0;
  58. namespace LLInitParam
  59. {
  60. void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
  61. {
  62. declare("none", LLFloaterEnums::OPEN_POSITIONING_NONE);
  63. declare("cascading", LLFloaterEnums::OPEN_POSITIONING_CASCADING);
  64. declare("centered", LLFloaterEnums::OPEN_POSITIONING_CENTERED);
  65. declare("specified", LLFloaterEnums::OPEN_POSITIONING_SPECIFIED);
  66. }
  67. }
  68. std::string LLFloater::sButtonNames[BUTTON_COUNT] =
  69. {
  70. "llfloater_close_btn", //BUTTON_CLOSE
  71. "llfloater_restore_btn", //BUTTON_RESTORE
  72. "llfloater_minimize_btn", //BUTTON_MINIMIZE
  73. "llfloater_tear_off_btn", //BUTTON_TEAR_OFF
  74. "llfloater_dock_btn", //BUTTON_DOCK
  75. "llfloater_help_btn" //BUTTON_HELP
  76. };
  77. std::string LLFloater::sButtonToolTips[BUTTON_COUNT];
  78. std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]=
  79. {
  80. #ifdef LL_DARWIN
  81. "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE
  82. #else
  83. "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE
  84. #endif
  85. "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE
  86. "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE
  87. "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF
  88. "BUTTON_DOCK",
  89. "BUTTON_HELP"
  90. };
  91. LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
  92. {
  93. LLFloater::onClickClose, //BUTTON_CLOSE
  94. LLFloater::onClickMinimize, //BUTTON_RESTORE
  95. LLFloater::onClickMinimize, //BUTTON_MINIMIZE
  96. LLFloater::onClickTearOff, //BUTTON_TEAR_OFF
  97. LLFloater::onClickDock, //BUTTON_DOCK
  98. LLFloater::onClickHelp //BUTTON_HELP
  99. };
  100. LLMultiFloater* LLFloater::sHostp = NULL;
  101. BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting
  102. LLFloaterView* gFloaterView = NULL;
  103. /*==========================================================================*|
  104. // DEV-38598: The fundamental problem with this operation is that it can only
  105. // support a subset of LLSD values. While it's plausible to compare two arrays
  106. // lexicographically, what strict ordering can you impose on maps?
  107. // (LLFloaterTOS's current key is an LLSD map.)
  108. // Of course something like this is necessary if you want to build a std::set
  109. // or std::map with LLSD keys. Fortunately we're getting by with other
  110. // container types for now.
  111. //static
  112. bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
  113. {
  114. if (a.type() != b.type())
  115. {
  116. //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
  117. return false;
  118. }
  119. else if (a.isUndefined())
  120. return false;
  121. else if (a.isInteger())
  122. return a.asInteger() < b.asInteger();
  123. else if (a.isReal())
  124. return a.asReal() < b.asReal();
  125. else if (a.isString())
  126. return a.asString() < b.asString();
  127. else if (a.isUUID())
  128. return a.asUUID() < b.asUUID();
  129. else if (a.isDate())
  130. return a.asDate() < b.asDate();
  131. else if (a.isURI())
  132. return a.asString() < b.asString(); // compare URIs as strings
  133. else if (a.isBoolean())
  134. return a.asBoolean() < b.asBoolean();
  135. else
  136. return false; // no valid operation for Binary
  137. }
  138. |*==========================================================================*/
  139. bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
  140. {
  141. return llsd_equals(a, b);
  142. }
  143. //************************************
  144. LLFloater::Params::Params()
  145. : title("title"),
  146. short_title("short_title"),
  147. single_instance("single_instance", false),
  148. reuse_instance("reuse_instance", false),
  149. can_resize("can_resize", false),
  150. can_minimize("can_minimize", true),
  151. can_close("can_close", true),
  152. can_drag_on_left("can_drag_on_left", false),
  153. can_tear_off("can_tear_off", true),
  154. save_dock_state("save_dock_state", false),
  155. save_rect("save_rect", false),
  156. save_visibility("save_visibility", false),
  157. can_dock("can_dock", false),
  158. show_title("show_title", true),
  159. open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE),
  160. specified_left("specified_left"),
  161. specified_bottom("specified_bottom"),
  162. header_height("header_height", 0),
  163. legacy_header_height("legacy_header_height", 0),
  164. close_image("close_image"),
  165. restore_image("restore_image"),
  166. minimize_image("minimize_image"),
  167. tear_off_image("tear_off_image"),
  168. dock_image("dock_image"),
  169. help_image("help_image"),
  170. close_pressed_image("close_pressed_image"),
  171. restore_pressed_image("restore_pressed_image"),
  172. minimize_pressed_image("minimize_pressed_image"),
  173. tear_off_pressed_image("tear_off_pressed_image"),
  174. dock_pressed_image("dock_pressed_image"),
  175. help_pressed_image("help_pressed_image"),
  176. open_callback("open_callback"),
  177. close_callback("close_callback"),
  178. follows("follows")
  179. {
  180. changeDefault(visible, false);
  181. }
  182. //static
  183. const LLFloater::Params& LLFloater::getDefaultParams()
  184. {
  185. return LLUICtrlFactory::getDefaultParams<LLFloater>();
  186. }
  187. //static
  188. void LLFloater::initClass()
  189. {
  190. // translate tooltips for floater buttons
  191. for (S32 i = 0; i < BUTTON_COUNT; i++)
  192. {
  193. sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
  194. }
  195. LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
  196. if (ctrl)
  197. {
  198. ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
  199. updateActiveFloaterTransparency();
  200. }
  201. ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
  202. if (ctrl)
  203. {
  204. ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
  205. updateInactiveFloaterTransparency();
  206. }
  207. }
  208. // defaults for floater param block pulled from widgets/floater.xml
  209. static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
  210. LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
  211. : LLPanel(), // intentionally do not pass params here, see initFromParams
  212. mDragHandle(NULL),
  213. mTitle(p.title),
  214. mShortTitle(p.short_title),
  215. mSingleInstance(p.single_instance),
  216. mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default
  217. mKey(key),
  218. mCanTearOff(p.can_tear_off),
  219. mCanMinimize(p.can_minimize),
  220. mCanClose(p.can_close),
  221. mDragOnLeft(p.can_drag_on_left),
  222. mResizable(p.can_resize),
  223. mOpenPositioning(p.open_positioning),
  224. mSpecifiedLeft(p.specified_left),
  225. mSpecifiedBottom(p.specified_bottom),
  226. mMinWidth(p.min_width),
  227. mMinHeight(p.min_height),
  228. mHeaderHeight(p.header_height),
  229. mLegacyHeaderHeight(p.legacy_header_height),
  230. mMinimized(FALSE),
  231. mForeground(FALSE),
  232. mFirstLook(TRUE),
  233. mButtonScale(1.0f),
  234. mAutoFocus(TRUE), // automatically take focus when opened
  235. mCanDock(false),
  236. mDocked(false),
  237. mTornOff(false),
  238. mHasBeenDraggedWhileMinimized(FALSE),
  239. mPreviousMinimizedBottom(0),
  240. mPreviousMinimizedLeft(0),
  241. mMinimizeSignal(NULL)
  242. // mNotificationContext(NULL)
  243. {
  244. // mNotificationContext = new LLFloaterNotificationContext(getHandle());
  245. // Clicks stop here.
  246. setMouseOpaque(TRUE);
  247. // Floaters always draw their background, unlike every other panel.
  248. setBackgroundVisible(TRUE);
  249. // Floaters start not minimized. When minimized, they save their
  250. // prior rectangle to be used on restore.
  251. mExpandedRect.set(0,0,0,0);
  252. memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool));
  253. memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*));
  254. addDragHandle();
  255. addResizeCtrls();
  256. initFromParams(p);
  257. initFloater(p);
  258. }
  259. // Note: Floaters constructed from XML call init() twice!
  260. void LLFloater::initFloater(const Params& p)
  261. {
  262. // Close button.
  263. if (mCanClose)
  264. {
  265. mButtonsEnabled[BUTTON_CLOSE] = TRUE;
  266. }
  267. // Help button: '?'
  268. if ( !mHelpTopic.empty() )
  269. {
  270. mButtonsEnabled[BUTTON_HELP] = TRUE;
  271. }
  272. // Minimize button only for top draggers
  273. if ( !mDragOnLeft && mCanMinimize )
  274. {
  275. mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
  276. }
  277. if(mCanDock)
  278. {
  279. mButtonsEnabled[BUTTON_DOCK] = TRUE;
  280. }
  281. buildButtons(p);
  282. // Floaters are created in the invisible state
  283. setVisible(FALSE);
  284. if (!getParent())
  285. {
  286. gFloaterView->addChild(this);
  287. }
  288. }
  289. void LLFloater::addDragHandle()
  290. {
  291. if (!mDragHandle)
  292. {
  293. if (mDragOnLeft)
  294. {
  295. LLDragHandleLeft::Params p;
  296. p.name("drag");
  297. p.follows.flags(FOLLOWS_ALL);
  298. p.label(mTitle);
  299. mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p);
  300. }
  301. else // drag on top
  302. {
  303. LLDragHandleTop::Params p;
  304. p.name("Drag Handle");
  305. p.follows.flags(FOLLOWS_ALL);
  306. p.label(mTitle);
  307. mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p);
  308. }
  309. addChild(mDragHandle);
  310. }
  311. layoutDragHandle();
  312. applyTitle();
  313. }
  314. void LLFloater::layoutDragHandle()
  315. {
  316. static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
  317. S32 close_box_size = mCanClose ? floater_close_box_size : 0;
  318. LLRect rect;
  319. if (mDragOnLeft)
  320. {
  321. rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
  322. }
  323. else // drag on top
  324. {
  325. rect = getLocalRect();
  326. }
  327. mDragHandle->setShape(rect);
  328. updateTitleButtons();
  329. }
  330. // static
  331. void LLFloater::updateActiveFloaterTransparency()
  332. {
  333. sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
  334. }
  335. // static
  336. void LLFloater::updateInactiveFloaterTransparency()
  337. {
  338. sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
  339. }
  340. void LLFloater::addResizeCtrls()
  341. {
  342. // Resize bars (sides)
  343. LLResizeBar::Params p;
  344. p.name("resizebar_left");
  345. p.resizing_view(this);
  346. p.min_size(mMinWidth);
  347. p.side(LLResizeBar::LEFT);
  348. mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p);
  349. addChild( mResizeBar[LLResizeBar::LEFT] );
  350. p.name("resizebar_top");
  351. p.min_size(mMinHeight);
  352. p.side(LLResizeBar::TOP);
  353. mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p);
  354. addChild( mResizeBar[LLResizeBar::TOP] );
  355. p.name("resizebar_right");
  356. p.min_size(mMinWidth);
  357. p.side(LLResizeBar::RIGHT);
  358. mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p);
  359. addChild( mResizeBar[LLResizeBar::RIGHT] );
  360. p.name("resizebar_bottom");
  361. p.min_size(mMinHeight);
  362. p.side(LLResizeBar::BOTTOM);
  363. mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p);
  364. addChild( mResizeBar[LLResizeBar::BOTTOM] );
  365. // Resize handles (corners)
  366. LLResizeHandle::Params handle_p;
  367. // handles must not be mouse-opaque, otherwise they block hover events
  368. // to other buttons like the close box. JC
  369. handle_p.mouse_opaque(false);
  370. handle_p.min_width(mMinWidth);
  371. handle_p.min_height(mMinHeight);
  372. handle_p.corner(LLResizeHandle::RIGHT_BOTTOM);
  373. mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
  374. addChild(mResizeHandle[0]);
  375. handle_p.corner(LLResizeHandle::RIGHT_TOP);
  376. mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
  377. addChild(mResizeHandle[1]);
  378. handle_p.corner(LLResizeHandle::LEFT_BOTTOM);
  379. mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
  380. addChild(mResizeHandle[2]);
  381. handle_p.corner(LLResizeHandle::LEFT_TOP);
  382. mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
  383. addChild(mResizeHandle[3]);
  384. layoutResizeCtrls();
  385. }
  386. void LLFloater::layoutResizeCtrls()
  387. {
  388. LLRect rect;
  389. // Resize bars (sides)
  390. const S32 RESIZE_BAR_THICKNESS = 3;
  391. rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0);
  392. mResizeBar[LLResizeBar::LEFT]->setRect(rect);
  393. rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS);
  394. mResizeBar[LLResizeBar::TOP]->setRect(rect);
  395. rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0);
  396. mResizeBar[LLResizeBar::RIGHT]->setRect(rect);
  397. rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0);
  398. mResizeBar[LLResizeBar::BOTTOM]->setRect(rect);
  399. // Resize handles (corners)
  400. rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0);
  401. mResizeHandle[0]->setRect(rect);
  402. rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT);
  403. mResizeHandle[1]->setRect(rect);
  404. rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 );
  405. mResizeHandle[2]->setRect(rect);
  406. rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT );
  407. mResizeHandle[3]->setRect(rect);
  408. }
  409. void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
  410. {
  411. mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width);
  412. mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width);
  413. mResizeBar[LLResizeBar::TOP]->setVisible(enable && height);
  414. mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height);
  415. mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width);
  416. mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width);
  417. mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height);
  418. mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height);
  419. for (S32 i = 0; i < 4; ++i)
  420. {
  421. mResizeHandle[i]->setVisible(enable && width && height);
  422. mResizeHandle[i]->setEnabled(enable && width && height);
  423. }
  424. }
  425. void LLFloater::destroy()
  426. {
  427. // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before
  428. // it was deleted via LLMortician::updateClass(). See EXT-8458.
  429. LLFloaterReg::removeInstance(mInstanceName, mKey);
  430. die();
  431. }
  432. // virtual
  433. LLFloater::~LLFloater()
  434. {
  435. LLFloaterReg::removeInstance(mInstanceName, mKey);
  436. // delete mNotificationContext;
  437. // mNotificationContext = NULL;
  438. //// am I not hosted by another floater?
  439. //if (mHostHandle.isDead())
  440. //{
  441. // LLFloaterView* parent = (LLFloaterView*) getParent();
  442. // if( parent )
  443. // {
  444. // parent->removeChild( this );
  445. // }
  446. //}
  447. // Just in case we might still have focus here, release it.
  448. releaseFocus();
  449. // This is important so that floaters with persistent rects (i.e., those
  450. // created with rect control rather than an LLRect) are restored in their
  451. // correct, non-minimized positions.
  452. setMinimized( FALSE );
  453. delete mDragHandle;
  454. for (S32 i = 0; i < 4; i++)
  455. {
  456. delete mResizeBar[i];
  457. delete mResizeHandle[i];
  458. }
  459. setVisible(false); // We're not visible if we're destroyed
  460. storeVisibilityControl();
  461. storeDockStateControl();
  462. delete mMinimizeSignal;
  463. }
  464. void LLFloater::storeRectControl()
  465. {
  466. if( mRectControl.size() > 1 )
  467. {
  468. getControlGroup()->setRect( mRectControl, getRect() );
  469. }
  470. }
  471. void LLFloater::storeVisibilityControl()
  472. {
  473. if( !sQuitting && mVisibilityControl.size() > 1 )
  474. {
  475. getControlGroup()->setBOOL( mVisibilityControl, getVisible() );
  476. }
  477. }
  478. void LLFloater::storeDockStateControl()
  479. {
  480. if( !sQuitting && mDocStateControl.size() > 1 )
  481. {
  482. getControlGroup()->setBOOL( mDocStateControl, isDocked() );
  483. }
  484. }
  485. LLRect LLFloater::getSavedRect() const
  486. {
  487. LLRect rect;
  488. if (mRectControl.size() > 1)
  489. {
  490. rect = getControlGroup()->getRect(mRectControl);
  491. }
  492. return rect;
  493. }
  494. bool LLFloater::hasSavedRect() const
  495. {
  496. return !getSavedRect().isEmpty();
  497. }
  498. // static
  499. std::string LLFloater::getControlName(const std::string& name, const LLSD& key)
  500. {
  501. std::string ctrl_name = name;
  502. // Add the key to the control name if appropriate.
  503. if (key.isString() && !key.asString().empty())
  504. {
  505. ctrl_name += "_" + key.asString();
  506. }
  507. return ctrl_name;
  508. }
  509. // static
  510. LLControlGroup* LLFloater::getControlGroup()
  511. {
  512. // Floater size, position, visibility, etc are saved in per-account settings.
  513. return LLUI::sSettingGroups["account"];
  514. }
  515. void LLFloater::setVisible( BOOL visible )
  516. {
  517. LLPanel::setVisible(visible); // calls handleVisibilityChange()
  518. if( visible && mFirstLook )
  519. {
  520. mFirstLook = FALSE;
  521. }
  522. if( !visible )
  523. {
  524. LLUI::removePopup(this);
  525. if( gFocusMgr.childHasMouseCapture( this ) )
  526. {
  527. gFocusMgr.setMouseCapture(NULL);
  528. }
  529. }
  530. for(handle_set_iter_t dependent_it = mDependents.begin();
  531. dependent_it != mDependents.end(); )
  532. {
  533. LLFloater* floaterp = dependent_it->get();
  534. if (floaterp)
  535. {
  536. floaterp->setVisible(visible);
  537. }
  538. ++dependent_it;
  539. }
  540. storeVisibilityControl();
  541. }
  542. // virtual
  543. void LLFloater::handleVisibilityChange ( BOOL new_visibility )
  544. {
  545. if (new_visibility)
  546. {
  547. if (getHost())
  548. getHost()->setFloaterFlashing(this, FALSE);
  549. }
  550. LLPanel::handleVisibilityChange ( new_visibility );
  551. }
  552. void LLFloater::openFloater(const LLSD& key)
  553. {
  554. llinfos << "Opening floater " << getName() << llendl;
  555. mKey = key; // in case we need to open ourselves again
  556. if (getSoundFlags() != SILENT
  557. // don't play open sound for hosted (tabbed) windows
  558. && !getHost()
  559. && !getFloaterHost()
  560. && (!getVisible() || isMinimized()))
  561. {
  562. make_ui_sound("UISndWindowOpen");
  563. }
  564. //RN: for now, we don't allow rehosting from one multifloater to another
  565. // just need to fix the bugs
  566. if (getFloaterHost() != NULL && getHost() == NULL)
  567. {
  568. // needs a host
  569. // only select tabs if window they are hosted in is visible
  570. getFloaterHost()->addFloater(this, getFloaterHost()->getVisible());
  571. }
  572. if (getHost() != NULL)
  573. {
  574. getHost()->setMinimized(FALSE);
  575. getHost()->setVisibleAndFrontmost(mAutoFocus);
  576. getHost()->showFloater(this);
  577. }
  578. else
  579. {
  580. LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
  581. if (!floater_to_stack)
  582. {
  583. floater_to_stack = LLFloaterReg::getLastFloaterCascading();
  584. }
  585. applyControlsAndPosition(floater_to_stack);
  586. setMinimized(FALSE);
  587. setVisibleAndFrontmost(mAutoFocus);
  588. }
  589. mOpenSignal(this, key);
  590. onOpen(key);
  591. dirtyRect();
  592. }
  593. void LLFloater::closeFloater(bool app_quitting)
  594. {
  595. llinfos << "Closing floater " << getName() << llendl;
  596. if (app_quitting)
  597. {
  598. LLFloater::sQuitting = true;
  599. }
  600. // Always unminimize before trying to close.
  601. // Most of the time the user will never see this state.
  602. setMinimized(FALSE);
  603. if (canClose())
  604. {
  605. if (getHost())
  606. {
  607. ((LLMultiFloater*)getHost())->removeFloater(this);
  608. gFloaterView->addChild(this);
  609. }
  610. if (getSoundFlags() != SILENT
  611. && getVisible()
  612. && !getHost()
  613. && !app_quitting)
  614. {
  615. make_ui_sound("UISndWindowClose");
  616. }
  617. // now close dependent floater
  618. for(handle_set_iter_t dependent_it = mDependents.begin();
  619. dependent_it != mDependents.end(); )
  620. {
  621. LLFloater* floaterp = dependent_it->get();
  622. if (floaterp)
  623. {
  624. ++dependent_it;
  625. floaterp->closeFloater(app_quitting);
  626. }
  627. else
  628. {
  629. mDependents.erase(dependent_it++);
  630. }
  631. }
  632. cleanupHandles();
  633. gFocusMgr.clearLastFocusForGroup(this);
  634. if (hasFocus())
  635. {
  636. // Do this early, so UI controls will commit before the
  637. // window is taken down.
  638. releaseFocus();
  639. // give focus to dependee floater if it exists, and we had focus first
  640. if (isDependent())
  641. {
  642. LLFloater* dependee = mDependeeHandle.get();
  643. if (dependee && !dependee->isDead())
  644. {
  645. dependee->setFocus(TRUE);
  646. }
  647. }
  648. }
  649. dirtyRect();
  650. // Close callbacks
  651. onClose(app_quitting);
  652. mCloseSignal(this, LLSD(app_quitting));
  653. // Hide or Destroy
  654. if (mSingleInstance)
  655. {
  656. // Hide the instance
  657. if (getHost())
  658. {
  659. getHost()->setVisible(FALSE);
  660. }
  661. else
  662. {
  663. setVisible(FALSE);
  664. if (!mReuseInstance)
  665. {
  666. destroy();
  667. }
  668. }
  669. }
  670. else
  671. {
  672. setVisible(FALSE); // hide before destroying (so handleVisibilityChange() gets called)
  673. if (!mReuseInstance)
  674. {
  675. destroy();
  676. }
  677. }
  678. }
  679. }
  680. /*virtual*/
  681. void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
  682. {
  683. LLPanel::reshape(width, height, called_from_parent);
  684. }
  685. void LLFloater::releaseFocus()
  686. {
  687. LLUI::removePopup(this);
  688. setFocus(FALSE);
  689. if( gFocusMgr.childHasMouseCapture( this ) )
  690. {
  691. gFocusMgr.setMouseCapture(NULL);
  692. }
  693. }
  694. void LLFloater::setResizeLimits( S32 min_width, S32 min_height )
  695. {
  696. mMinWidth = min_width;
  697. mMinHeight = min_height;
  698. for( S32 i = 0; i < 4; i++ )
  699. {
  700. if( mResizeBar[i] )
  701. {
  702. if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
  703. {
  704. mResizeBar[i]->setResizeLimits( min_width, S32_MAX );
  705. }
  706. else
  707. {
  708. mResizeBar[i]->setResizeLimits( min_height, S32_MAX );
  709. }
  710. }
  711. if( mResizeHandle[i] )
  712. {
  713. mResizeHandle[i]->setResizeLimits( min_width, min_height );
  714. }
  715. }
  716. }
  717. void LLFloater::center()
  718. {
  719. if(getHost())
  720. {
  721. // hosted floaters can't move
  722. return;
  723. }
  724. centerWithin(gFloaterView->getRect());
  725. }
  726. LLMultiFloater* LLFloater::getHost()
  727. {
  728. return (LLMultiFloater*)mHostHandle.get();
  729. }
  730. void LLFloater::applyControlsAndPosition(LLFloater* other)
  731. {
  732. if (!applyDockState())
  733. {
  734. if (!applyRectControl())
  735. {
  736. applyPositioning(other);
  737. }
  738. }
  739. }
  740. bool LLFloater::applyRectControl()
  741. {
  742. bool saved_rect = false;
  743. LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
  744. if (last_in_group && last_in_group != this)
  745. {
  746. // other floaters in our group, position ourselves relative to them and don't save the rect
  747. mRectControl.clear();
  748. mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP;
  749. }
  750. else if (mRectControl.size() > 1)
  751. {
  752. // If we have a saved rect, use it
  753. const LLRect& rect = getControlGroup()->getRect(mRectControl);
  754. saved_rect = rect.notEmpty();
  755. if (saved_rect)
  756. {
  757. setOrigin(rect.mLeft, rect.mBottom);
  758. if (mResizable)
  759. {
  760. reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
  761. }
  762. }
  763. }
  764. return saved_rect;
  765. }
  766. bool LLFloater::applyDockState()
  767. {
  768. bool docked = false;
  769. if (mDocStateControl.size() > 1)
  770. {
  771. docked = getControlGroup()->getBOOL(mDocStateControl);
  772. setDocked(docked);
  773. }
  774. return docked;
  775. }
  776. void LLFloater::applyPositioning(LLFloater* other)
  777. {
  778. // Otherwise position according to the positioning code
  779. switch (mOpenPositioning)
  780. {
  781. case LLFloaterEnums::OPEN_POSITIONING_CENTERED:
  782. center();
  783. break;
  784. case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED:
  785. {
  786. // Translate relative to snap rect
  787. setOrigin(mSpecifiedLeft, mSpecifiedBottom);
  788. const LLRect& snap_rect = gFloaterView->getSnapRect();
  789. translate(snap_rect.mLeft, snap_rect.mBottom);
  790. translateIntoRect(snap_rect, FALSE);
  791. }
  792. break;
  793. case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP:
  794. case LLFloaterEnums::OPEN_POSITIONING_CASCADING:
  795. if (other != NULL && other != this)
  796. {
  797. stackWith(*other);
  798. }
  799. else
  800. {
  801. static const U32 CASCADING_FLOATER_HOFFSET = 0;
  802. static const U32 CASCADING_FLOATER_VOFFSET = 0;
  803. const LLRect& snap_rect = gFloaterView->getSnapRect();
  804. const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET;
  805. const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET;
  806. S32 rect_height = getRect().getHeight();
  807. setOrigin(horizontal_offset, vertical_offset - rect_height);
  808. translate(snap_rect.mLeft, snap_rect.mBottom);
  809. translateIntoRect(snap_rect, FALSE);
  810. }
  811. break;
  812. case LLFloaterEnums::OPEN_POSITIONING_NONE:
  813. default:
  814. // Do nothing
  815. break;
  816. }
  817. }
  818. void LLFloater::applyTitle()
  819. {
  820. if (!mDragHandle)
  821. {
  822. return;
  823. }
  824. if (isMinimized() && !mShortTitle.empty())
  825. {
  826. mDragHandle->setTitle( mShortTitle );
  827. }
  828. else
  829. {
  830. mDragHandle->setTitle ( mTitle );
  831. }
  832. if (getHost())
  833. {
  834. getHost()->updateFloaterTitle(this);
  835. }
  836. }
  837. std::string LLFloater::getCurrentTitle() const
  838. {
  839. return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
  840. }
  841. void LLFloater::setTitle( const std::string& title )
  842. {
  843. mTitle = title;
  844. applyTitle();
  845. }
  846. std::string LLFloater::getTitle() const
  847. {
  848. if (mTitle.empty())
  849. {
  850. return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
  851. }
  852. else
  853. {
  854. return mTitle;
  855. }
  856. }
  857. void LLFloater::setShortTitle( const std::string& short_title )
  858. {
  859. mShortTitle = short_title;
  860. applyTitle();
  861. }
  862. std::string LLFloater::getShortTitle() const
  863. {
  864. if (mShortTitle.empty())
  865. {
  866. return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
  867. }
  868. else
  869. {
  870. return mShortTitle;
  871. }
  872. }
  873. BOOL LLFloater::canSnapTo(const LLView* other_view)
  874. {
  875. if (NULL == other_view)
  876. {
  877. llwarns << "other_view is NULL" << llendl;
  878. return FALSE;
  879. }
  880. if (other_view != getParent())
  881. {
  882. const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);
  883. if (other_floaterp
  884. && other_floaterp->getSnapTarget() == getHandle()
  885. && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
  886. {
  887. // this is a dependent that is already snapped to us, so don't snap back to it
  888. return FALSE;
  889. }
  890. }
  891. return LLPanel::canSnapTo(other_view);
  892. }
  893. void LLFloater::setSnappedTo(const LLView* snap_view)
  894. {
  895. if (!snap_view || snap_view == getParent())
  896. {
  897. clearSnapTarget();
  898. }
  899. else
  900. {
  901. //RN: assume it's a floater as it must be a sibling to our parent floater
  902. const LLFloater* floaterp = dynamic_cast<const LLFloater*>(snap_view);
  903. if (floaterp)
  904. {
  905. setSnapTarget(floaterp->getHandle());
  906. }
  907. }
  908. }
  909. void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
  910. {
  911. const LLRect old_rect = getRect();
  912. LLView::handleReshape(new_rect, by_user);
  913. if (by_user && !isMinimized())
  914. {
  915. storeRectControl();
  916. mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;
  917. }
  918. // if not minimized, adjust all snapped dependents to new shape
  919. if (!isMinimized())
  920. {
  921. // gather all snapped dependents
  922. for(handle_set_iter_t dependent_it = mDependents.begin();
  923. dependent_it != mDependents.end(); ++dependent_it)
  924. {
  925. LLFloater* floaterp = dependent_it->get();
  926. // is a dependent snapped to us?
  927. if (floaterp && floaterp->getSnapTarget() == getHandle())
  928. {
  929. S32 delta_x = 0;
  930. S32 delta_y = 0;
  931. // check to see if it snapped to right or top, and move if dependee floater is resizing
  932. LLRect dependent_rect = floaterp->getRect();
  933. if (dependent_rect.mLeft - getRect().mLeft >= old_rect.getWidth() || // dependent on my right?
  934. dependent_rect.mRight == getRect().mLeft + old_rect.getWidth()) // dependent aligned with my right
  935. {
  936. // was snapped directly onto right side or aligned with it
  937. delta_x += new_rect.getWidth() - old_rect.getWidth();
  938. }
  939. if (dependent_rect.mBottom - getRect().mBottom >= old_rect.getHeight() ||
  940. dependent_rect.mTop == getRect().mBottom + old_rect.getHeight())
  941. {
  942. // was snapped directly onto top side or aligned with it
  943. delta_y += new_rect.getHeight() - old_rect.getHeight();
  944. }
  945. // take translation of dependee floater into account as well
  946. delta_x += new_rect.mLeft - old_rect.mLeft;
  947. delta_y += new_rect.mBottom - old_rect.mBottom;
  948. dependent_rect.translate(delta_x, delta_y);
  949. floaterp->setShape(dependent_rect, by_user);
  950. }
  951. }
  952. }
  953. else
  954. {
  955. // If minimized, and origin has changed, set
  956. // mHasBeenDraggedWhileMinimized to TRUE
  957. if ((new_rect.mLeft != old_rect.mLeft) ||
  958. (new_rect.mBottom != old_rect.mBottom))
  959. {
  960. mHasBeenDraggedWhileMinimized = TRUE;
  961. }
  962. }
  963. }
  964. void LLFloater::setMinimized(BOOL minimize)
  965. {
  966. const LLFloater::Params& default_params = LLFloater::getDefaultParams();
  967. S32 floater_header_size = default_params.header_height;
  968. static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
  969. if (minimize == mMinimized) return;
  970. if (mMinimizeSignal)
  971. {
  972. (*mMinimizeSignal)(this, LLSD(minimize));
  973. }
  974. if (minimize)
  975. {
  976. // minimized flag should be turned on before release focus
  977. mMinimized = TRUE;
  978. mExpandedRect = getRect();
  979. // If the floater has been dragged while minimized in the
  980. // past, then locate it at its previous minimized location.
  981. // Otherwise, ask the view for a minimize position.
  982. if (mHasBeenDraggedWhileMinimized)
  983. {
  984. setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
  985. }
  986. else
  987. {
  988. S32 left, bottom;
  989. gFloaterView->getMinimizePosition(&left, &bottom);
  990. setOrigin( left, bottom );
  991. }
  992. if (mButtonsEnabled[BUTTON_MINIMIZE])
  993. {
  994. mButtonsEnabled[BUTTON_MINIMIZE] = FALSE;
  995. mButtonsEnabled[BUTTON_RESTORE] = TRUE;
  996. }
  997. setBorderVisible(TRUE);
  998. for(handle_set_iter_t dependent_it = mDependents.begin();
  999. dependent_it != mDependents.end();
  1000. ++dependent_it)
  1001. {
  1002. LLFloater* floaterp = dependent_it->get();
  1003. if (floaterp)
  1004. {
  1005. if (floaterp->isMinimizeable())
  1006. {
  1007. floaterp->setMinimized(TRUE);
  1008. }
  1009. else if (!floaterp->isMinimized())
  1010. {
  1011. floaterp->setVisible(FALSE);
  1012. }
  1013. }
  1014. }
  1015. // Lose keyboard focus when minimized
  1016. releaseFocus();
  1017. for (S32 i = 0; i < 4; i++)
  1018. {
  1019. if (mResizeBar[i] != NULL)
  1020. {
  1021. mResizeBar[i]->setEnabled(FALSE);
  1022. }
  1023. if (mResizeHandle[i] != NULL)
  1024. {
  1025. mResizeHandle[i]->setEnabled(FALSE);
  1026. }
  1027. }
  1028. // Reshape *after* setting mMinimized
  1029. reshape( minimized_width, floater_header_size, TRUE);
  1030. }
  1031. else
  1032. {
  1033. // If this window has been dragged while minimized (at any time),
  1034. // remember its position for the next time it's minimized.
  1035. if (mHasBeenDraggedWhileMinimized)
  1036. {
  1037. const LLRect& currentRect = getRect();
  1038. mPreviousMinimizedLeft = currentRect.mLeft;
  1039. mPreviousMinimizedBottom = currentRect.mBottom;
  1040. }
  1041. setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom );
  1042. if (mButtonsEnabled[BUTTON_RESTORE])
  1043. {
  1044. mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
  1045. mButtonsEnabled[BUTTON_RESTORE] = FALSE;
  1046. }
  1047. // show dependent floater
  1048. for(handle_set_iter_t dependent_it = mDependents.begin();
  1049. dependent_it != mDependents.end();
  1050. ++dependent_it)
  1051. {
  1052. LLFloater* floaterp = dependent_it->get();
  1053. if (floaterp)
  1054. {
  1055. floaterp->setMinimized(FALSE);
  1056. floaterp->setVisible(TRUE);
  1057. }
  1058. }
  1059. for (S32 i = 0; i < 4; i++)
  1060. {
  1061. if (mResizeBar[i] != NULL)
  1062. {
  1063. mResizeBar[i]->setEnabled(isResizable());
  1064. }
  1065. if (mResizeHandle[i] != NULL)
  1066. {
  1067. mResizeHandle[i]->setEnabled(isResizable());
  1068. }
  1069. }
  1070. mMinimized = FALSE;
  1071. // Reshape *after* setting mMinimized
  1072. reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE );
  1073. }
  1074. make_ui_sound("UISndWindowClose");
  1075. updateTitleButtons();
  1076. applyTitle ();
  1077. }
  1078. void LLFloater::setFocus( BOOL b )
  1079. {
  1080. if (b && getIsChrome())
  1081. {
  1082. return;
  1083. }
  1084. LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
  1085. // a descendent already has focus
  1086. BOOL child_had_focus = hasFocus();
  1087. // give focus to first valid descendent
  1088. LLPanel::setFocus(b);
  1089. if (b)
  1090. {
  1091. // only push focused floaters to front of stack if not in midst of ctrl-tab cycle
  1092. if (!getHost() && !((LLFloaterView*)getParent())->getCycleMode())
  1093. {
  1094. if (!isFrontmost())
  1095. {
  1096. setFrontmost();
  1097. }
  1098. }
  1099. // when getting focus, delegate to last descendent which had focus
  1100. if (last_focus && !child_had_focus &&
  1101. last_focus->isInEnabledChain() &&
  1102. last_focus->isInVisibleChain())
  1103. {
  1104. // *FIX: should handle case where focus doesn't stick
  1105. last_focus->setFocus(TRUE);
  1106. }
  1107. }
  1108. updateTransparency(b ? TT_ACTIVE : TT_INACTIVE);
  1109. }
  1110. // virtual
  1111. void LLFloater::setRect(const LLRect &rect)
  1112. {
  1113. LLPanel::setRect(rect);
  1114. layoutDragHandle();
  1115. layoutResizeCtrls();
  1116. }
  1117. // virtual
  1118. void LLFloater::setIsChrome(BOOL is_chrome)
  1119. {
  1120. // chrome floaters don't take focus at all
  1121. if (is_chrome)
  1122. {
  1123. // remove focus if we're changing to chrome
  1124. setFocus(FALSE);
  1125. // can't Ctrl-Tab to "chrome" floaters
  1126. setFocusRoot(FALSE);
  1127. mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome)));
  1128. }
  1129. LLPanel::setIsChrome(is_chrome);
  1130. }
  1131. // Change the draw style to account for the foreground state.
  1132. void LLFloater::setForeground(BOOL front)
  1133. {
  1134. if (front != mForeground)
  1135. {
  1136. mForeground = front;
  1137. if (mDragHandle)
  1138. mDragHandle->setForeground( front );
  1139. if (!front)
  1140. {
  1141. releaseFocus();
  1142. }
  1143. setBackgroundOpaque( front );
  1144. }
  1145. }
  1146. void LLFloater::cleanupHandles()
  1147. {
  1148. // remove handles to non-existent dependents
  1149. for(handle_set_iter_t dependent_it = mDependents.begin();
  1150. dependent_it != mDependents.end(); )
  1151. {
  1152. LLFloater* floaterp = dependent_it->get();
  1153. if (!floaterp)
  1154. {
  1155. mDependents.erase(dependent_it++);
  1156. }
  1157. else
  1158. {
  1159. ++dependent_it;
  1160. }
  1161. }
  1162. }
  1163. void LLFloater::setHost(LLMultiFloater* host)
  1164. {
  1165. if (mHostHandle.isDead() && host)
  1166. {
  1167. // make buttons smaller for hosted windows to differentiate from parent
  1168. mButtonScale = 0.9f;
  1169. // add tear off button
  1170. if (mCanTearOff)
  1171. {
  1172. mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE;
  1173. }
  1174. }
  1175. else if (!mHostHandle.isDead() && !host)
  1176. {
  1177. mButtonScale = 1.f;
  1178. //mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE;
  1179. }
  1180. updateTitleButtons();
  1181. if (host)
  1182. {
  1183. mHostHandle = host->getHandle();
  1184. mLastHostHandle = host->getHandle();
  1185. }
  1186. else
  1187. {
  1188. mHostHandle.markDead();
  1189. }
  1190. }
  1191. void LLFloater::moveResizeHandlesToFront()
  1192. {
  1193. for( S32 i = 0; i < 4; i++ )
  1194. {
  1195. if( mResizeBar[i] )
  1196. {
  1197. sendChildToFront(mResizeBar[i]);
  1198. }
  1199. }
  1200. for( S32 i = 0; i < 4; i++ )
  1201. {
  1202. if( mResizeHandle[i] )
  1203. {
  1204. sendChildToFront(mResizeHandle[i]);
  1205. }
  1206. }
  1207. }
  1208. BOOL LLFloater::isFrontmost()
  1209. {
  1210. LLFloaterView* floater_view = getParentByType<LLFloaterView>();
  1211. return getVisible()
  1212. && (floater_view
  1213. && floater_view->getFrontmost() == this);
  1214. }
  1215. void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
  1216. {
  1217. mDependents.insert(floaterp->getHandle());
  1218. floaterp->mDependeeHandle = getHandle();
  1219. if (reposition)
  1220. {
  1221. floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
  1222. floaterp->setSnapTarget(getHandle());
  1223. }
  1224. gFloaterView->adjustToFitScreen(floaterp, FALSE);
  1225. if (floaterp->isFrontmost())
  1226. {
  1227. // make sure to bring self and sibling floaters to front
  1228. gFloaterView->bringToFront(floaterp);
  1229. }
  1230. }
  1231. void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition)
  1232. {
  1233. LLFloater* dependent_floaterp = dependent.get();
  1234. if(dependent_floaterp)
  1235. {
  1236. addDependentFloater(dependent_floaterp, reposition);
  1237. }
  1238. }
  1239. void LLFloater::removeDependentFloater(LLFloater* floaterp)
  1240. {
  1241. mDependents.erase(floaterp->getHandle());
  1242. floaterp->mDependeeHandle = LLHandle<LLFloater>();
  1243. }
  1244. BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index)
  1245. {
  1246. if( mButtonsEnabled[index] )
  1247. {
  1248. LLButton* my_butt = mButtons[index];
  1249. S32 local_x = x - my_butt->getRect().mLeft;
  1250. S32 local_y = y - my_butt->getRect().mBottom;
  1251. if (
  1252. my_butt->pointInView(local_x, local_y) &&
  1253. my_butt->handleMouseDown(local_x, local_y, mask))
  1254. {
  1255. // the button handled it
  1256. return TRUE;
  1257. }
  1258. }
  1259. return FALSE;
  1260. }
  1261. BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
  1262. {
  1263. LLPanel::handleScrollWheel(x,y,clicks);
  1264. return TRUE;//always
  1265. }
  1266. // virtual
  1267. BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
  1268. {
  1269. if( mMinimized )
  1270. {
  1271. // Offer the click to titlebar buttons.
  1272. // Note: this block and the offerClickToButton helper method can be removed
  1273. // because the parent container will handle it for us but we'll keep it here
  1274. // for safety until after reworking the panel code to manage hidden children.
  1275. if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return TRUE;
  1276. if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return TRUE;
  1277. if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE;
  1278. if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE;
  1279. // Otherwise pass to drag handle for movement
  1280. return mDragHandle->handleMouseDown(x, y, mask);
  1281. }
  1282. else
  1283. {
  1284. bringToFront( x, y );
  1285. return LLPanel::handleMouseDown( x, y, mask );
  1286. }
  1287. }
  1288. // virtual
  1289. BOOL LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
  1290. {
  1291. BOOL was_minimized = mMinimized;
  1292. bringToFront( x, y );
  1293. return was_minimized || LLPanel::handleRightMouseDown( x, y, mask );
  1294. }
  1295. BOOL LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
  1296. {
  1297. bringToFront( x, y );
  1298. return LLPanel::handleMiddleMouseDown( x, y, mask );
  1299. }
  1300. // virtual
  1301. BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
  1302. {
  1303. BOOL was_minimized = mMinimized;
  1304. setMinimized(FALSE);
  1305. return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
  1306. }
  1307. void LLFloater::bringToFront( S32 x, S32 y )
  1308. {
  1309. if (getVisible() && pointInView(x, y))
  1310. {
  1311. LLMultiFloater* hostp = getHost();
  1312. if (hostp)
  1313. {
  1314. hostp->showFloater(this);
  1315. }
  1316. else
  1317. {
  1318. LLFloaterView* parent = (LLFloaterView*) getParent();
  1319. if (parent)
  1320. {
  1321. parent->bringToFront( this );
  1322. }
  1323. }
  1324. }
  1325. }
  1326. // virtual
  1327. void LLFloater::setVisibleAndFrontmost(BOOL take_focus)
  1328. {
  1329. setVisible(TRUE);
  1330. setFrontmost(take_focus);
  1331. }
  1332. void LLFloater::setFrontmost(BOOL take_focus)
  1333. {
  1334. LLMultiFloater* hostp = getHost();
  1335. if (hostp)
  1336. {
  1337. // this will bring the host floater to the front and select
  1338. // the appropriate panel
  1339. hostp->showFloater(this);
  1340. }
  1341. else
  1342. {
  1343. // there are more than one floater view
  1344. // so we need to query our parent directly
  1345. ((LLFloaterView*)getParent())->bringToFront(this, take_focus);
  1346. // Make sure to set the appropriate transparency type (STORM-732).
  1347. updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE);
  1348. }
  1349. }
  1350. void LLFloater::setCanDock(bool b)
  1351. {
  1352. if(b != mCanDock)
  1353. {
  1354. mCanDock = b;
  1355. if(mCanDock)
  1356. {
  1357. mButtonsEnabled[BUTTON_DOCK] = !mDocked;
  1358. }
  1359. else
  1360. {
  1361. mButtonsEnabled[BUTTON_DOCK] = FALSE;
  1362. }
  1363. }
  1364. updateTitleButtons();
  1365. }
  1366. void LLFloater::setDocked(bool docked, bool pop_on_undock)
  1367. {
  1368. if(docked != mDocked && mCanDock)
  1369. {
  1370. mDocked = docked;
  1371. mButtonsEnabled[BUTTON_DOCK] = !mDocked;
  1372. if (mDocked)
  1373. {
  1374. setMinimized(FALSE);
  1375. mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;
  1376. }
  1377. updateTitleButtons();
  1378. storeDockStateControl();
  1379. }
  1380. }
  1381. // static
  1382. void LLFloater::onClickMinimize(LLFloater* self)
  1383. {
  1384. if (!self)
  1385. return;
  1386. self->setMinimized( !self->isMinimized() );
  1387. }
  1388. void LLFloater::onClickTearOff(LLFloater* self)
  1389. {
  1390. if (!self)
  1391. return;
  1392. S32 floater_header_size = self->mHeaderHeight;
  1393. LLMultiFloater* host_floater = self->getHost();
  1394. if (host_floater) //Tear off
  1395. {
  1396. LLRect new_rect;
  1397. host_floater->removeFloater(self);
  1398. // reparent to floater view
  1399. gFloaterView->addChild(self);
  1400. self->openFloater(self->getKey());
  1401. // only force position for floaters that don't have that data saved
  1402. if (self->mRectControl.size() <= 1)
  1403. {
  1404. new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight());
  1405. self->setRect(new_rect);
  1406. }
  1407. gFloaterView->adjustToFitScreen(self, FALSE);
  1408. // give focus to new window to keep continuity for the user
  1409. self->setFocus(TRUE);
  1410. self->setTornOff(true);
  1411. }
  1412. else //Attach to parent.
  1413. {
  1414. LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get();
  1415. if (new_host)
  1416. {
  1417. self->setMinimized(FALSE); // to reenable minimize button if it was minimized
  1418. new_host->showFloater(self);
  1419. // make sure host is visible
  1420. new_host->openFloater(new_host->getKey());
  1421. }
  1422. self->setTornOff(false);
  1423. }
  1424. self->updateTitleButtons();
  1425. }
  1426. // static
  1427. void LLFloater::onClickDock(LLFloater* self)
  1428. {
  1429. if(self && self->mCanDock)
  1430. {
  1431. self->setDocked(!self->mDocked, true);
  1432. }
  1433. }
  1434. // static
  1435. void LLFloater::onClickHelp( LLFloater* self )
  1436. {
  1437. if (self && LLUI::sHelpImpl)
  1438. {
  1439. // find the current help context for this floater
  1440. std::string help_topic;
  1441. if (self->findHelpTopic(help_topic))
  1442. {
  1443. LLUI::sHelpImpl->showTopic(help_topic);
  1444. }
  1445. }
  1446. }
  1447. // static
  1448. LLFloater* LLFloater::getClosableFloaterFromFocus()
  1449. {
  1450. LLFloater* focused_floater = NULL;
  1451. LLInstanceTracker<LLFloater>::instance_iter it = beginInstances();
  1452. LLInstanceTracker<LLFloater>::instance_iter end_it = endInstances();
  1453. for (; it != end_it; ++it)
  1454. {
  1455. if (it->hasFocus())
  1456. {
  1457. break;
  1458. }
  1459. }
  1460. if (it == endInstances())
  1461. {
  1462. // nothing found, return
  1463. return NULL;
  1464. }
  1465. // The focused floater may not be closable,
  1466. // Find and close a parental floater that is closeable, if any.
  1467. LLFloater* prev_floater = NULL;
  1468. for(LLFloater* floater_to_close = focused_floater;
  1469. NULL != floater_to_close;
  1470. floater_to_close = gFloaterView->getParentFloater(floater_to_close))
  1471. {
  1472. if(floater_to_close->isCloseable())
  1473. {
  1474. return floater_to_close;
  1475. }
  1476. // If floater has as parent root view
  1477. // gFloaterView->getParentFloater(floater_to_close) returns
  1478. // the same floater_to_close, so we need to check this.
  1479. if (prev_floater == floater_to_close) {
  1480. break;
  1481. }
  1482. prev_floater = floater_to_close;
  1483. }
  1484. return NULL;
  1485. }
  1486. // static
  1487. void LLFloater::closeFocusedFloater()
  1488. {
  1489. LLFloater* floater_to_close = LLFloater::getClosableFloaterFromFocus();
  1490. if(floater_to_close)
  1491. {
  1492. floater_to_close->closeFloater();
  1493. }
  1494. // if nothing took focus after closing focused floater
  1495. // give it to next floater (to allow closing multiple windows via keyboard in rapid succession)
  1496. if (gFocusMgr.getKeyboardFocus() == NULL)
  1497. {
  1498. // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window
  1499. // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view
  1500. gFloaterView->focusFrontFloater();
  1501. }
  1502. }
  1503. // static
  1504. void LLFloater::onClickClose( LLFloater* self )
  1505. {
  1506. if (!self)
  1507. return;
  1508. self->onClickCloseBtn();
  1509. }
  1510. void LLFloater::onClickCloseBtn()
  1511. {
  1512. closeFloater(false);
  1513. }
  1514. // virtual
  1515. void LLFloater::draw()
  1516. {
  1517. const F32 alpha = getCurrentTransparency();
  1518. // draw background
  1519. if( isBackgroundVisible() )
  1520. {
  1521. drawShadow(this);
  1522. S32 left = LLPANEL_BORDER_WIDTH;
  1523. S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH;
  1524. S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
  1525. S32 bottom = LLPANEL_BORDER_WIDTH;
  1526. LLUIImage* image = NULL;
  1527. LLColor4 color;
  1528. LLColor4 overlay_color;
  1529. if (isBackgroundOpaque())
  1530. {
  1531. // NOTE: image may not be set
  1532. image = getBackgroundImage();
  1533. color = getBackgroundColor();
  1534. overlay_color = getBackgroundImageOverlay();
  1535. }
  1536. else
  1537. {
  1538. image = getTransparentImage();
  1539. color = getTransparentColor();
  1540. overlay_color = getTransparentImageOverlay();
  1541. }
  1542. if (image)
  1543. {
  1544. // We're using images for this floater's backgrounds
  1545. image->draw(getLocalRect(), overlay_color % alpha);
  1546. }
  1547. else
  1548. {
  1549. // We're not using images, use old-school flat colors
  1550. gl_rect_2d( left, top, right, bottom, color % alpha );
  1551. // draw highlight on title bar to indicate focus. RDW
  1552. if(hasFocus()
  1553. && !getIsChrome()
  1554. && !getCurrentTitle().empty())
  1555. {
  1556. static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
  1557. const LLFontGL* font = LLFontGL::getFontSansSerif();
  1558. LLRect r = getRect();
  1559. gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,
  1560. titlebar_focus_color % alpha, 0, TRUE);
  1561. }
  1562. }
  1563. }
  1564. LLPanel::updateDefaultBtn();
  1565. if( getDefaultButton() )
  1566. {
  1567. if (hasFocus() && getDefaultButton()->getEnabled())
  1568. {
  1569. LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
  1570. // is this button a direct descendent and not a nested widget (e.g. checkbox)?
  1571. BOOL focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this;
  1572. // only enable default button when current focus is not a button
  1573. getDefaultButton()->setBorderEnabled(!focus_is_child_button);
  1574. }
  1575. else
  1576. {
  1577. getDefaultButton()->setBorderEnabled(FALSE);
  1578. }
  1579. }
  1580. if (isMinimized())
  1581. {
  1582. for (S32 i = 0; i < BUTTON_COUNT; i++)
  1583. {
  1584. drawChild(mButtons[i]);
  1585. }
  1586. drawChild(mDragHandle, 0, 0, TRUE);
  1587. }
  1588. else
  1589. {
  1590. // don't call LLPanel::draw() since we've implemented custom background rendering
  1591. LLView::draw();
  1592. }
  1593. // update tearoff button for torn off floaters
  1594. // when last host goes away
  1595. if (mCanTearOff && !getHost())
  1596. {
  1597. LLFloater* old_host = mLastHostHandle.get();
  1598. if (!old_host)
  1599. {
  1600. setCanTearOff(FALSE);
  1601. }
  1602. }
  1603. }
  1604. void LLFloater::drawShadow(LLPanel* panel)
  1605. {
  1606. S32 left = LLPANEL_BORDER_WIDTH;
  1607. S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
  1608. S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
  1609. S32 bottom = LLPANEL_BORDER_WIDTH;
  1610. static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0);
  1611. static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
  1612. LLColor4 shadow_color = shadow_color_cached;
  1613. F32 shadow_offset = (F32)shadow_offset_S32;
  1614. if (!panel->isBackgroundOpaque())
  1615. {
  1616. shadow_offset *= 0.2f;
  1617. shadow_color.mV[VALPHA] *= 0.5f;
  1618. }
  1619. gl_drop_shadow(left, top, right, bottom,
  1620. shadow_color % getCurrentTransparency(),
  1621. llround(shadow_offset));
  1622. }
  1623. void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
  1624. {
  1625. child_list_t children = *view->getChildList();
  1626. child_list_t::iterator it = children.begin();
  1627. LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
  1628. if (ctrl)
  1629. {
  1630. ctrl->setTransparencyType(transparency_type);
  1631. }
  1632. for(; it != children.end(); ++it)
  1633. {
  1634. updateTransparency(*it, transparency_type);
  1635. }
  1636. }
  1637. void LLFloater::updateTransparency(ETypeTransparency transparency_type)
  1638. {
  1639. updateTransparency(this, transparency_type);
  1640. }
  1641. void LLFloater::setCanMinimize(BOOL can_minimize)
  1642. {
  1643. // if removing minimize/restore button programmatically,
  1644. // go ahead and unminimize floater
  1645. mCanMinimize = can_minimize;
  1646. if (!can_minimize)
  1647. {
  1648. setMinimized(FALSE);
  1649. }
  1650. mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized();
  1651. mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized();
  1652. updateTitleButtons();
  1653. }
  1654. void LLFloater::setCanClose(BOOL can_close)
  1655. {
  1656. mCanClose = can_close;
  1657. mButtonsEnabled[BUTTON_CLOSE] = can_close;
  1658. updateTitleButtons();
  1659. }
  1660. void LLFloater::setCanTearOff(BOOL can_tear_off)
  1661. {
  1662. mCanTearOff = can_tear_off;
  1663. mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
  1664. updateTitleButtons();
  1665. }
  1666. void LLFloater::setCanResize(BOOL can_resize)
  1667. {
  1668. mResizable = can_resize;
  1669. enableResizeCtrls(can_resize);
  1670. }
  1671. void LLFloater::setCanDrag(BOOL can_drag)
  1672. {
  1673. // if we delete drag handle, we no longer have access to the floater's title
  1674. // so just enable/disable it
  1675. if (!can_drag && mDragHandle->getEnabled())
  1676. {
  1677. mDragHandle->setEnabled(FALSE);
  1678. }
  1679. else if (can_drag && !mDragHandle->getEnabled())
  1680. {
  1681. mDragHandle->setEnabled(TRUE);
  1682. }
  1683. }
  1684. bool LLFloater::getCanDrag()
  1685. {
  1686. return mDragHandle->getEnabled();
  1687. }
  1688. void LLFloater::updateTitleButtons()
  1689. {
  1690. static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
  1691. static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
  1692. LLRect buttons_rect;
  1693. S32 button_count = 0;
  1694. for (S32 i = 0; i < BUTTON_COUNT; i++)
  1695. {
  1696. if (!mButtons[i])
  1697. {
  1698. continue;
  1699. }
  1700. bool enabled = mButtonsEnabled[i];
  1701. if (i == BUTTON_HELP)
  1702. {
  1703. // don't show the help button if the floater is minimized
  1704. // or if it is a docked tear-off floater
  1705. if (isMinimized() || (mButtonsEnabled[BUTTON_TEAR_OFF] && ! mTornOff))
  1706. {
  1707. enabled = false;
  1708. }
  1709. }
  1710. if (i == BUTTON_CLOSE && mButtonScale != 1.f)
  1711. {
  1712. //*HACK: always render close button for hosted floaters so
  1713. //that users don't accidentally hit the button when
  1714. //closing multiple windows in the chatterbox
  1715. enabled = true;
  1716. }
  1717. mButtons[i]->setEnabled(enabled);
  1718. if (enabled)
  1719. {
  1720. button_count++;
  1721. LLRect btn_rect;
  1722. if (mDragOnLeft)
  1723. {
  1724. btn_rect.setLeftTopAndSize(
  1725. LLPANEL_BORDER_WIDTH,
  1726. getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count,
  1727. llround((F32)floater_close_box_size * mButtonScale),
  1728. llround((F32)floater_close_box_size * mButtonScale));
  1729. }
  1730. else
  1731. {
  1732. btn_rect.setLeftTopAndSize(
  1733. getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count,
  1734. getRect().getHeight() - close_box_from_top,
  1735. llround((F32)floater_close_box_size * mButtonScale),
  1736. llround((F32)floater_close_box_size * mButtonScale));
  1737. }
  1738. // first time here, init 'buttons_rect'
  1739. if(1 == button_count)
  1740. {
  1741. buttons_rect = btn_rect;
  1742. }
  1743. else
  1744. {
  1745. // if mDragOnLeft=true then buttons are on top-left side vertically aligned
  1746. // title is not displayed in this case, calculating 'buttons_rect' for future use
  1747. mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom :
  1748. buttons_rect.mLeft = btn_rect.mLeft;
  1749. }
  1750. mButtons[i]->setRect(btn_rect);
  1751. mButtons[i]->setVisible(TRUE);
  1752. // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater
  1753. mButtons[i]->setTabStop(i == BUTTON_RESTORE);
  1754. }
  1755. else
  1756. {
  1757. mButtons[i]->setVisible(FALSE);
  1758. }
  1759. }
  1760. if (mDragHandle)
  1761. {
  1762. localRectToOtherView(buttons_rect, &buttons_rect, mDragHandle);
  1763. mDragHandle->setButtonsRect(buttons_rect);
  1764. }
  1765. }
  1766. void LLFloater::buildButtons(const Params& floater_params)
  1767. {
  1768. static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
  1769. static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
  1770. for (S32 i = 0; i < BUTTON_COUNT; i++)
  1771. {
  1772. if (mButtons[i])
  1773. {
  1774. removeChild(mButtons[i]);
  1775. delete mButtons[i];
  1776. mButtons[i] = NULL;
  1777. }
  1778. LLRect btn_rect;
  1779. if (mDragOnLeft)
  1780. {
  1781. btn_rect.setL

Large files files are truncated, but you can click here to view the full file