PageRenderTime 109ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/lltoast.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 573 lines | 418 code | 83 blank | 72 comment | 66 complexity | 746b2aa7a5cc0fcbca54cc92c74b34e8 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltoast.cpp
  3. * @brief This class implements a placeholder for any notification panel.
  4. *
  5. * $LicenseInfo:firstyear=2000&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" // must be first include
  27. #include "lltoast.h"
  28. #include "llbutton.h"
  29. #include "llfocusmgr.h"
  30. #include "llnotifications.h"
  31. #include "llviewercontrol.h"
  32. using namespace LLNotificationsUI;
  33. //--------------------------------------------------------------------------
  34. LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period)
  35. : mToast(toast),
  36. LLEventTimer(period)
  37. {
  38. }
  39. /*virtual*/
  40. BOOL LLToastLifeTimer::tick()
  41. {
  42. if (mEventTimer.hasExpired())
  43. {
  44. mToast->expire();
  45. }
  46. return FALSE;
  47. }
  48. void LLToastLifeTimer::stop()
  49. {
  50. mEventTimer.stop();
  51. }
  52. void LLToastLifeTimer::start()
  53. {
  54. mEventTimer.start();
  55. }
  56. void LLToastLifeTimer::restart()
  57. {
  58. mEventTimer.reset();
  59. }
  60. BOOL LLToastLifeTimer::getStarted()
  61. {
  62. return mEventTimer.getStarted();
  63. }
  64. void LLToastLifeTimer::setPeriod(F32 period)
  65. {
  66. mPeriod = period;
  67. }
  68. F32 LLToastLifeTimer::getRemainingTimeF32()
  69. {
  70. F32 et = mEventTimer.getElapsedTimeF32();
  71. if (!getStarted() || et > mPeriod) return 0.0f;
  72. return mPeriod - et;
  73. }
  74. //--------------------------------------------------------------------------
  75. LLToast::Params::Params()
  76. : can_fade("can_fade", true),
  77. can_be_stored("can_be_stored", true),
  78. is_modal("is_modal", false),
  79. is_tip("is_tip", false),
  80. enable_hide_btn("enable_hide_btn", true),
  81. force_show("force_show", false),
  82. force_store("force_store", false),
  83. fading_time_secs("fading_time_secs", gSavedSettings.getS32("ToastFadingTime")),
  84. lifetime_secs("lifetime_secs", gSavedSettings.getS32("NotificationToastLifeTime"))
  85. {};
  86. LLToast::LLToast(const LLToast::Params& p)
  87. : LLModalDialog(LLSD(), p.is_modal),
  88. mToastLifetime(p.lifetime_secs),
  89. mToastFadingTime(p.fading_time_secs),
  90. mNotificationID(p.notif_id),
  91. mSessionID(p.session_id),
  92. mCanFade(p.can_fade),
  93. mCanBeStored(p.can_be_stored),
  94. mHideBtnEnabled(p.enable_hide_btn),
  95. mHideBtn(NULL),
  96. mPanel(NULL),
  97. mNotification(p.notification),
  98. mIsHidden(false),
  99. mHideBtnPressed(false),
  100. mIsTip(p.is_tip),
  101. mWrapperPanel(NULL),
  102. mIsFading(false),
  103. mIsHovered(false)
  104. {
  105. mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs));
  106. buildFromFile("panel_toast.xml", NULL);
  107. setCanDrag(FALSE);
  108. mWrapperPanel = getChild<LLPanel>("wrapper_panel");
  109. setBackgroundOpaque(TRUE); // *TODO: obsolete
  110. updateTransparency();
  111. if(p.panel())
  112. {
  113. insertPanel(p.panel);
  114. }
  115. if(mHideBtnEnabled)
  116. {
  117. mHideBtn = getChild<LLButton>("hide_btn");
  118. mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this));
  119. }
  120. // init callbacks if present
  121. if(!p.on_delete_toast().empty())
  122. {
  123. mOnDeleteToastSignal.connect(p.on_delete_toast());
  124. }
  125. }
  126. void LLToast::reshape(S32 width, S32 height, BOOL called_from_parent)
  127. {
  128. // We shouldn't use reshape from LLModalDialog since it changes toasts position.
  129. // Toasts position should be controlled only by toast screen channel, see LLScreenChannelBase.
  130. // see EXT-8044
  131. LLFloater::reshape(width, height, called_from_parent);
  132. }
  133. //--------------------------------------------------------------------------
  134. BOOL LLToast::postBuild()
  135. {
  136. if(!mCanFade)
  137. {
  138. mTimer->stop();
  139. }
  140. return TRUE;
  141. }
  142. //--------------------------------------------------------------------------
  143. void LLToast::setHideButtonEnabled(bool enabled)
  144. {
  145. if(mHideBtn)
  146. mHideBtn->setEnabled(enabled);
  147. }
  148. //--------------------------------------------------------------------------
  149. LLToast::~LLToast()
  150. {
  151. mOnToastDestroyedSignal(this);
  152. }
  153. //--------------------------------------------------------------------------
  154. void LLToast::hide()
  155. {
  156. setVisible(FALSE);
  157. setFading(false);
  158. mTimer->stop();
  159. mIsHidden = true;
  160. mOnFadeSignal(this);
  161. }
  162. void LLToast::onFocusLost()
  163. {
  164. if(mWrapperPanel && !isBackgroundVisible())
  165. {
  166. // Lets make wrapper panel behave like a floater
  167. updateTransparency();
  168. }
  169. }
  170. void LLToast::onFocusReceived()
  171. {
  172. if(mWrapperPanel && !isBackgroundVisible())
  173. {
  174. // Lets make wrapper panel behave like a floater
  175. updateTransparency();
  176. }
  177. }
  178. void LLToast::setLifetime(S32 seconds)
  179. {
  180. mToastLifetime = seconds;
  181. }
  182. void LLToast::setFadingTime(S32 seconds)
  183. {
  184. mToastFadingTime = seconds;
  185. }
  186. S32 LLToast::getTopPad()
  187. {
  188. if(mWrapperPanel)
  189. {
  190. return getRect().getHeight() - mWrapperPanel->getRect().getHeight();
  191. }
  192. return 0;
  193. }
  194. S32 LLToast::getRightPad()
  195. {
  196. if(mWrapperPanel)
  197. {
  198. return getRect().getWidth() - mWrapperPanel->getRect().getWidth();
  199. }
  200. return 0;
  201. }
  202. //--------------------------------------------------------------------------
  203. void LLToast::setCanFade(bool can_fade)
  204. {
  205. mCanFade = can_fade;
  206. if(!mCanFade)
  207. {
  208. mTimer->stop();
  209. }
  210. }
  211. //--------------------------------------------------------------------------
  212. void LLToast::expire()
  213. {
  214. if (mCanFade)
  215. {
  216. if (mIsFading)
  217. {
  218. // Fade timer expired. Time to hide.
  219. hide();
  220. }
  221. else
  222. {
  223. // "Life" time has ended. Time to fade.
  224. setFading(true);
  225. mTimer->restart();
  226. }
  227. }
  228. }
  229. void LLToast::setFading(bool transparent)
  230. {
  231. mIsFading = transparent;
  232. updateTransparency();
  233. if (transparent)
  234. {
  235. mTimer->setPeriod(mToastFadingTime);
  236. }
  237. else
  238. {
  239. mTimer->setPeriod(mToastLifetime);
  240. }
  241. }
  242. F32 LLToast::getTimeLeftToLive()
  243. {
  244. F32 time_to_live = mTimer->getRemainingTimeF32();
  245. if (!mIsFading)
  246. {
  247. time_to_live += mToastFadingTime;
  248. }
  249. return time_to_live;
  250. }
  251. //--------------------------------------------------------------------------
  252. void LLToast::reshapeToPanel()
  253. {
  254. LLPanel* panel = getPanel();
  255. if(!panel)
  256. return;
  257. LLRect panel_rect = panel->getRect();
  258. panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight());
  259. panel->setShape(panel_rect);
  260. LLRect toast_rect = getRect();
  261. toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop,
  262. panel_rect.getWidth() + getRightPad(), panel_rect.getHeight() + getTopPad());
  263. setShape(toast_rect);
  264. }
  265. void LLToast::insertPanel(LLPanel* panel)
  266. {
  267. mPanel = panel;
  268. mWrapperPanel->addChild(panel);
  269. reshapeToPanel();
  270. }
  271. //--------------------------------------------------------------------------
  272. void LLToast::draw()
  273. {
  274. LLFloater::draw();
  275. if(!isBackgroundVisible())
  276. {
  277. // Floater background is invisible, lets make wrapper panel look like a
  278. // floater - draw shadow.
  279. drawShadow(mWrapperPanel);
  280. // Shadow will probably overlap close button, lets redraw the button
  281. if(mHideBtn)
  282. {
  283. drawChild(mHideBtn);
  284. }
  285. }
  286. }
  287. //--------------------------------------------------------------------------
  288. void LLToast::setVisible(BOOL show)
  289. {
  290. if(mIsHidden)
  291. {
  292. // this toast is invisible after fade until its ScreenChannel will allow it
  293. //
  294. // (EXT-1849) according to this bug a toast can be resurrected from
  295. // invisible state if it faded during a teleportation
  296. // then it fades a second time and causes a crash
  297. return;
  298. }
  299. if (show && getVisible())
  300. {
  301. return;
  302. }
  303. if(show)
  304. {
  305. if(!mTimer->getStarted() && mCanFade)
  306. {
  307. mTimer->start();
  308. }
  309. if (!getVisible())
  310. {
  311. LLModalDialog::setFrontmost(FALSE);
  312. }
  313. }
  314. else
  315. {
  316. //hide "hide" button in case toast was hidden without mouse_leave
  317. if(mHideBtn)
  318. mHideBtn->setVisible(show);
  319. }
  320. LLFloater::setVisible(show);
  321. if(mPanel)
  322. {
  323. if(!mPanel->isDead())
  324. {
  325. mPanel->setVisible(show);
  326. }
  327. }
  328. }
  329. void LLToast::updateHoveredState()
  330. {
  331. S32 x, y;
  332. LLUI::getMousePositionScreen(&x, &y);
  333. LLRect panel_rc = mWrapperPanel->calcScreenRect();
  334. LLRect button_rc;
  335. if(mHideBtn)
  336. {
  337. button_rc = mHideBtn->calcScreenRect();
  338. }
  339. if (!panel_rc.pointInRect(x, y) && !button_rc.pointInRect(x, y))
  340. {
  341. // mouse is not over this toast
  342. mIsHovered = false;
  343. }
  344. else
  345. {
  346. bool is_overlapped_by_other_floater = false;
  347. const child_list_t* child_list = gFloaterView->getChildList();
  348. // find this toast in gFloaterView child list to check whether any floater
  349. // with higher Z-order is visible under the mouse pointer overlapping this toast
  350. child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this);
  351. if (r_iter != child_list->rend())
  352. {
  353. // skip this toast and proceed to views above in Z-order
  354. for (++r_iter; r_iter != child_list->rend(); ++r_iter)
  355. {
  356. LLView* view = *r_iter;
  357. is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y);
  358. if (is_overlapped_by_other_floater)
  359. {
  360. break;
  361. }
  362. }
  363. }
  364. mIsHovered = !is_overlapped_by_other_floater;
  365. }
  366. LLToastLifeTimer* timer = getTimer();
  367. if (timer)
  368. {
  369. // Started timer means the mouse had left the toast previously.
  370. // If toast is hovered in the current frame we should handle
  371. // a mouse enter event.
  372. if(timer->getStarted() && mIsHovered)
  373. {
  374. mOnToastHoverSignal(this, MOUSE_ENTER);
  375. updateTransparency();
  376. //toasts fading is management by Screen Channel
  377. sendChildToFront(mHideBtn);
  378. if(mHideBtn && mHideBtn->getEnabled())
  379. {
  380. mHideBtn->setVisible(TRUE);
  381. }
  382. mToastMouseEnterSignal(this, getValue());
  383. }
  384. // Stopped timer means the mouse had entered the toast previously.
  385. // If the toast is not hovered in the current frame we should handle
  386. // a mouse leave event.
  387. else if(!timer->getStarted() && !mIsHovered)
  388. {
  389. mOnToastHoverSignal(this, MOUSE_LEAVE);
  390. updateTransparency();
  391. //toasts fading is management by Screen Channel
  392. if(mHideBtn && mHideBtn->getEnabled())
  393. {
  394. if( mHideBtnPressed )
  395. {
  396. mHideBtnPressed = false;
  397. return;
  398. }
  399. mHideBtn->setVisible(FALSE);
  400. }
  401. mToastMouseLeaveSignal(this, getValue());
  402. }
  403. }
  404. }
  405. void LLToast::setBackgroundOpaque(BOOL b)
  406. {
  407. if(mWrapperPanel && !isBackgroundVisible())
  408. {
  409. mWrapperPanel->setBackgroundOpaque(b);
  410. }
  411. else
  412. {
  413. LLModalDialog::setBackgroundOpaque(b);
  414. }
  415. }
  416. void LLToast::updateTransparency()
  417. {
  418. ETypeTransparency transparency_type;
  419. if (mCanFade)
  420. {
  421. // Notification toasts (including IM/chat toasts) change their transparency on hover.
  422. if (isHovered())
  423. {
  424. transparency_type = TT_ACTIVE;
  425. }
  426. else
  427. {
  428. transparency_type = mIsFading ? TT_FADING : TT_INACTIVE;
  429. }
  430. }
  431. else
  432. {
  433. // Transparency of alert toasts depends on focus.
  434. transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE;
  435. }
  436. LLFloater::updateTransparency(transparency_type);
  437. }
  438. void LLNotificationsUI::LLToast::stopTimer()
  439. {
  440. if(mCanFade)
  441. {
  442. setFading(false);
  443. mTimer->stop();
  444. }
  445. }
  446. void LLNotificationsUI::LLToast::startTimer()
  447. {
  448. if(mCanFade)
  449. {
  450. setFading(false);
  451. mTimer->start();
  452. }
  453. }
  454. //--------------------------------------------------------------------------
  455. BOOL LLToast::handleMouseDown(S32 x, S32 y, MASK mask)
  456. {
  457. if(mHideBtn && mHideBtn->getEnabled())
  458. {
  459. mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y);
  460. }
  461. return LLFloater::handleMouseDown(x, y, mask);
  462. }
  463. //--------------------------------------------------------------------------
  464. bool LLToast::isNotificationValid()
  465. {
  466. if(mNotification)
  467. {
  468. return !mNotification->isCancelled();
  469. }
  470. return false;
  471. }
  472. //--------------------------------------------------------------------------
  473. S32 LLToast::notifyParent(const LLSD& info)
  474. {
  475. if (info.has("action") && "hide_toast" == info["action"].asString())
  476. {
  477. hide();
  478. return 1;
  479. }
  480. return LLModalDialog::notifyParent(info);
  481. }
  482. //static
  483. void LLToast::updateClass()
  484. {
  485. for (LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); iter != LLInstanceTracker<LLToast>::endInstances(); )
  486. {
  487. LLToast& toast = *iter++;
  488. toast.updateHoveredState();
  489. }
  490. }