PageRenderTime 57ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/llchiclet.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2002 lines | 1540 code | 325 blank | 137 comment | 213 complexity | d63ca6a6b3fe58ce6fe91108d9d78a9c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llchiclet.cpp
  3. * @brief LLChiclet class implementation
  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. #include "llviewerprecompiledheaders.h" // must be first include
  27. #include "llchiclet.h"
  28. #include "llagent.h"
  29. #include "llavataractions.h"
  30. #include "llchicletbar.h"
  31. #include "lleventtimer.h"
  32. #include "llgroupactions.h"
  33. #include "lliconctrl.h"
  34. #include "llimfloater.h"
  35. #include "llimview.h"
  36. #include "llfloaterreg.h"
  37. #include "lllocalcliprect.h"
  38. #include "llmenugl.h"
  39. #include "llnotifications.h"
  40. #include "llnotificationsutil.h"
  41. #include "lloutputmonitorctrl.h"
  42. #include "llscriptfloater.h"
  43. #include "llspeakers.h"
  44. #include "lltextbox.h"
  45. #include "llvoiceclient.h"
  46. #include "llgroupmgr.h"
  47. #include "llnotificationmanager.h"
  48. #include "lltransientfloatermgr.h"
  49. #include "llsyswellwindow.h"
  50. static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
  51. static LLDefaultChildRegistry::Register<LLIMWellChiclet> t2_0("chiclet_im_well");
  52. static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
  53. static LLDefaultChildRegistry::Register<LLIMP2PChiclet> t3("chiclet_im_p2p");
  54. static LLDefaultChildRegistry::Register<LLIMGroupChiclet> t4("chiclet_im_group");
  55. static LLDefaultChildRegistry::Register<LLAdHocChiclet> t5("chiclet_im_adhoc");
  56. static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");
  57. static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer");
  58. boost::signals2::signal<LLChiclet* (const LLUUID&),
  59. LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > >
  60. LLIMChiclet::sFindChicletsSignal;
  61. //////////////////////////////////////////////////////////////////////////
  62. //////////////////////////////////////////////////////////////////////////
  63. //////////////////////////////////////////////////////////////////////////
  64. /**
  65. * Updates the Well's 'Lit' state to flash it when "new messages" are come.
  66. *
  67. * It gets callback which will be called 2*N times with passed period. See EXT-3147
  68. */
  69. class LLSysWellChiclet::FlashToLitTimer : public LLEventTimer
  70. {
  71. public:
  72. typedef boost::function<void()> callback_t;
  73. /**
  74. * Constructor.
  75. *
  76. * @param count - how many times callback should be called (twice to not change original state)
  77. * @param period - how frequently callback should be called
  78. * @param cb - callback to be called each tick
  79. */
  80. FlashToLitTimer(S32 count, F32 period, callback_t cb)
  81. : LLEventTimer(period)
  82. , mCallback(cb)
  83. , mFlashCount(2 * count)
  84. , mCurrentFlashCount(0)
  85. {
  86. mEventTimer.stop();
  87. }
  88. BOOL tick()
  89. {
  90. mCallback();
  91. if (++mCurrentFlashCount == mFlashCount) mEventTimer.stop();
  92. return FALSE;
  93. }
  94. void flash()
  95. {
  96. mCurrentFlashCount = 0;
  97. mEventTimer.start();
  98. }
  99. void stopFlashing()
  100. {
  101. mEventTimer.stop();
  102. }
  103. private:
  104. callback_t mCallback;
  105. /**
  106. * How many times Well will blink.
  107. */
  108. S32 mFlashCount;
  109. S32 mCurrentFlashCount;
  110. };
  111. LLSysWellChiclet::Params::Params()
  112. : button("button")
  113. , unread_notifications("unread_notifications")
  114. , max_displayed_count("max_displayed_count", 99)
  115. {
  116. button.name = "button";
  117. button.tab_stop = FALSE;
  118. button.label = LLStringUtil::null;
  119. }
  120. LLSysWellChiclet::LLSysWellChiclet(const Params& p)
  121. : LLChiclet(p)
  122. , mButton(NULL)
  123. , mCounter(0)
  124. , mMaxDisplayedCount(p.max_displayed_count)
  125. , mIsNewMessagesState(false)
  126. , mFlashToLitTimer(NULL)
  127. , mContextMenu(NULL)
  128. {
  129. LLButton::Params button_params = p.button;
  130. mButton = LLUICtrlFactory::create<LLButton>(button_params);
  131. addChild(mButton);
  132. // use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
  133. // Due to Timer is implemented as derived class from EventTimer it is impossible to change period
  134. // in runtime. So, both settings are made as required restart.
  135. static S32 flash_to_lit_count = gSavedSettings.getS32("WellIconFlashCount");
  136. static F32 flash_period = gSavedSettings.getF32("WellIconFlashPeriod");
  137. mFlashToLitTimer = new FlashToLitTimer(flash_to_lit_count, flash_period, boost::bind(&LLSysWellChiclet::changeLitState, this));
  138. }
  139. LLSysWellChiclet::~LLSysWellChiclet()
  140. {
  141. delete mFlashToLitTimer;
  142. }
  143. void LLSysWellChiclet::setCounter(S32 counter)
  144. {
  145. // do nothing if the same counter is coming. EXT-3678.
  146. if (counter == mCounter) return;
  147. // note same code in LLChicletNotificationCounterCtrl::setCounter(S32 counter)
  148. std::string s_count;
  149. if(counter != 0)
  150. {
  151. static std::string more_messages_exist("+");
  152. std::string more_messages(counter > mMaxDisplayedCount ? more_messages_exist : "");
  153. s_count = llformat("%d%s"
  154. , llmin(counter, mMaxDisplayedCount)
  155. , more_messages.c_str()
  156. );
  157. }
  158. mButton->setLabel(s_count);
  159. mCounter = counter;
  160. }
  161. boost::signals2::connection LLSysWellChiclet::setClickCallback(
  162. const commit_callback_t& cb)
  163. {
  164. return mButton->setClickedCallback(cb);
  165. }
  166. void LLSysWellChiclet::setToggleState(BOOL toggled) {
  167. mButton->setToggleState(toggled);
  168. }
  169. void LLSysWellChiclet::changeLitState()
  170. {
  171. setNewMessagesState(!mIsNewMessagesState);
  172. }
  173. void LLSysWellChiclet::setNewMessagesState(bool new_messages)
  174. {
  175. /*
  176. Emulate 4 states of button by background images, see detains in EXT-3147
  177. xml attribute Description
  178. image_unselected "Unlit" - there are no new messages
  179. image_selected "Unlit" + "Selected" - there are no new messages and the Well is open
  180. image_pressed "Lit" - there are new messages
  181. image_pressed_selected "Lit" + "Selected" - there are new messages and the Well is open
  182. */
  183. mButton->setForcePressedState(new_messages);
  184. mIsNewMessagesState = new_messages;
  185. }
  186. void LLSysWellChiclet::updateWidget(bool is_window_empty)
  187. {
  188. mButton->setEnabled(!is_window_empty);
  189. if (LLChicletBar::instanceExists())
  190. {
  191. LLChicletBar::getInstance()->showWellButton(getName(), !is_window_empty);
  192. }
  193. }
  194. // virtual
  195. BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
  196. {
  197. if(!mContextMenu)
  198. {
  199. createMenu();
  200. }
  201. if (mContextMenu)
  202. {
  203. mContextMenu->show(x, y);
  204. LLMenuGL::showPopup(this, mContextMenu, x, y);
  205. }
  206. return TRUE;
  207. }
  208. /************************************************************************/
  209. /* LLIMWellChiclet implementation */
  210. /************************************************************************/
  211. LLIMWellChiclet::LLIMWellChiclet(const Params& p)
  212. : LLSysWellChiclet(p)
  213. {
  214. LLIMModel::instance().addNewMsgCallback(boost::bind(&LLIMWellChiclet::messageCountChanged, this, _1));
  215. LLIMModel::instance().addNoUnreadMsgsCallback(boost::bind(&LLIMWellChiclet::messageCountChanged, this, _1));
  216. LLIMMgr::getInstance()->addSessionObserver(this);
  217. LLIMWellWindow::getInstance()->setSysWellChiclet(this);
  218. }
  219. LLIMWellChiclet::~LLIMWellChiclet()
  220. {
  221. LLIMWellWindow* im_well_window = LLIMWellWindow::findInstance();
  222. if (im_well_window)
  223. {
  224. im_well_window->setSysWellChiclet(NULL);
  225. }
  226. LLIMMgr::getInstance()->removeSessionObserver(this);
  227. }
  228. void LLIMWellChiclet::onMenuItemClicked(const LLSD& user_data)
  229. {
  230. std::string action = user_data.asString();
  231. if("close all" == action)
  232. {
  233. LLIMWellWindow::getInstance()->closeAll();
  234. }
  235. }
  236. bool LLIMWellChiclet::enableMenuItem(const LLSD& user_data)
  237. {
  238. std::string item = user_data.asString();
  239. if (item == "can close all")
  240. {
  241. return !LLIMWellWindow::getInstance()->isWindowEmpty();
  242. }
  243. return true;
  244. }
  245. void LLIMWellChiclet::createMenu()
  246. {
  247. if(mContextMenu)
  248. {
  249. llwarns << "Menu already exists" << llendl;
  250. return;
  251. }
  252. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  253. registrar.add("IMWellChicletMenu.Action",
  254. boost::bind(&LLIMWellChiclet::onMenuItemClicked, this, _2));
  255. LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
  256. enable_registrar.add("IMWellChicletMenu.EnableItem",
  257. boost::bind(&LLIMWellChiclet::enableMenuItem, this, _2));
  258. mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
  259. ("menu_im_well_button.xml",
  260. LLMenuGL::sMenuContainer,
  261. LLViewerMenuHolderGL::child_registry_t::instance());
  262. }
  263. void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)
  264. {
  265. // The singleton class LLChicletBar instance might be already deleted
  266. // so don't create a new one.
  267. if (!LLChicletBar::instanceExists())
  268. {
  269. return;
  270. }
  271. const LLUUID& session_id = session_data["session_id"];
  272. const S32 counter = LLChicletBar::getInstance()->getTotalUnreadIMCount();
  273. const bool im_not_visible = !LLFloaterReg::instanceVisible("im_container")
  274. && !LLFloaterReg::instanceVisible("impanel", session_id);
  275. setNewMessagesState(counter > mCounter && im_not_visible);
  276. // we have to flash to 'Lit' state each time new unread message is coming.
  277. if (counter > mCounter && im_not_visible)
  278. {
  279. mFlashToLitTimer->flash();
  280. }
  281. else if (counter == 0)
  282. {
  283. // if notification is resolved while well is flashing it can leave in the 'Lit' state
  284. // when flashing finishes itself. Let break flashing here.
  285. mFlashToLitTimer->stopFlashing();
  286. }
  287. setCounter(counter);
  288. }
  289. /************************************************************************/
  290. /* LLNotificationChiclet implementation */
  291. /************************************************************************/
  292. LLNotificationChiclet::LLNotificationChiclet(const Params& p)
  293. : LLSysWellChiclet(p)
  294. , mUreadSystemNotifications(0)
  295. {
  296. // connect counter handlers to the signals
  297. connectCounterUpdatersToSignal("notify");
  298. connectCounterUpdatersToSignal("groupnotify");
  299. connectCounterUpdatersToSignal("offer");
  300. // ensure that notification well window exists, to synchronously
  301. // handle toast add/delete events.
  302. LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
  303. }
  304. void LLNotificationChiclet::connectCounterUpdatersToSignal(const std::string& notification_type)
  305. {
  306. LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
  307. LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
  308. if(n_handler)
  309. {
  310. n_handler->setNewNotificationCallback(boost::bind(&LLNotificationChiclet::incUreadSystemNotifications, this));
  311. n_handler->setDelNotification(boost::bind(&LLNotificationChiclet::decUreadSystemNotifications, this));
  312. }
  313. }
  314. void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
  315. {
  316. std::string action = user_data.asString();
  317. if("close all" == action)
  318. {
  319. LLNotificationWellWindow::getInstance()->closeAll();
  320. }
  321. }
  322. bool LLNotificationChiclet::enableMenuItem(const LLSD& user_data)
  323. {
  324. std::string item = user_data.asString();
  325. if (item == "can close all")
  326. {
  327. return mUreadSystemNotifications != 0;
  328. }
  329. return true;
  330. }
  331. void LLNotificationChiclet::createMenu()
  332. {
  333. if(mContextMenu)
  334. {
  335. llwarns << "Menu already exists" << llendl;
  336. return;
  337. }
  338. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  339. registrar.add("NotificationWellChicletMenu.Action",
  340. boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2));
  341. LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
  342. enable_registrar.add("NotificationWellChicletMenu.EnableItem",
  343. boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2));
  344. mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
  345. ("menu_notification_well_button.xml",
  346. LLMenuGL::sMenuContainer,
  347. LLViewerMenuHolderGL::child_registry_t::instance());
  348. }
  349. /*virtual*/
  350. void LLNotificationChiclet::setCounter(S32 counter)
  351. {
  352. LLSysWellChiclet::setCounter(counter);
  353. updateWidget(getCounter() == 0);
  354. }
  355. //////////////////////////////////////////////////////////////////////////
  356. //////////////////////////////////////////////////////////////////////////
  357. //////////////////////////////////////////////////////////////////////////
  358. LLChiclet::Params::Params()
  359. : show_counter("show_counter", true)
  360. , enable_counter("enable_counter", false)
  361. {
  362. }
  363. LLChiclet::LLChiclet(const Params& p)
  364. : LLUICtrl(p)
  365. , mSessionId(LLUUID::null)
  366. , mShowCounter(p.show_counter)
  367. {
  368. }
  369. LLChiclet::~LLChiclet()
  370. {
  371. }
  372. boost::signals2::connection LLChiclet::setLeftButtonClickCallback(
  373. const commit_callback_t& cb)
  374. {
  375. return setCommitCallback(cb);
  376. }
  377. BOOL LLChiclet::handleMouseDown(S32 x, S32 y, MASK mask)
  378. {
  379. onCommit();
  380. childrenHandleMouseDown(x,y,mask);
  381. return TRUE;
  382. }
  383. boost::signals2::connection LLChiclet::setChicletSizeChangedCallback(
  384. const chiclet_size_changed_callback_t& cb)
  385. {
  386. return mChicletSizeChangedSignal.connect(cb);
  387. }
  388. void LLChiclet::onChicletSizeChanged()
  389. {
  390. mChicletSizeChangedSignal(this, getValue());
  391. }
  392. LLSD LLChiclet::getValue() const
  393. {
  394. return LLSD(getSessionId());
  395. }
  396. void LLChiclet::setValue(const LLSD& value)
  397. {
  398. if(value.isUUID())
  399. setSessionId(value.asUUID());
  400. }
  401. //////////////////////////////////////////////////////////////////////////
  402. //////////////////////////////////////////////////////////////////////////
  403. //////////////////////////////////////////////////////////////////////////
  404. LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)
  405. : LLChiclet(p)
  406. , mShowSpeaker(false)
  407. , mDefaultWidth(p.rect().getWidth())
  408. , mNewMessagesIcon(NULL)
  409. , mSpeakerCtrl(NULL)
  410. , mCounterCtrl(NULL)
  411. , mChicletButton(NULL)
  412. , mPopupMenu(NULL)
  413. {
  414. enableCounterControl(p.enable_counter);
  415. }
  416. /* virtual*/
  417. BOOL LLIMChiclet::postBuild()
  418. {
  419. mChicletButton = getChild<LLButton>("chiclet_button");
  420. mChicletButton->setCommitCallback(boost::bind(&LLIMChiclet::onMouseDown, this));
  421. mChicletButton->setDoubleClickCallback(boost::bind(&LLIMChiclet::onMouseDown, this));
  422. return TRUE;
  423. }
  424. void LLIMChiclet::setShowSpeaker(bool show)
  425. {
  426. bool needs_resize = getShowSpeaker() != show;
  427. if(needs_resize)
  428. {
  429. mShowSpeaker = show;
  430. }
  431. toggleSpeakerControl();
  432. }
  433. void LLIMChiclet::enableCounterControl(bool enable)
  434. {
  435. mCounterEnabled = enable;
  436. if(!enable)
  437. {
  438. LLChiclet::setShowCounter(false);
  439. }
  440. }
  441. void LLIMChiclet::setShowCounter(bool show)
  442. {
  443. if(!mCounterEnabled)
  444. {
  445. return;
  446. }
  447. bool needs_resize = getShowCounter() != show;
  448. if(needs_resize)
  449. {
  450. LLChiclet::setShowCounter(show);
  451. toggleCounterControl();
  452. }
  453. }
  454. void LLIMChiclet::initSpeakerControl()
  455. {
  456. // virtual
  457. }
  458. void LLIMChiclet::setRequiredWidth()
  459. {
  460. bool show_speaker = getShowSpeaker();
  461. bool show_counter = getShowCounter();
  462. S32 required_width = mDefaultWidth;
  463. if (show_counter)
  464. {
  465. required_width += mCounterCtrl->getRect().getWidth();
  466. }
  467. if (show_speaker)
  468. {
  469. required_width += mSpeakerCtrl->getRect().getWidth();
  470. }
  471. reshape(required_width, getRect().getHeight());
  472. onChicletSizeChanged();
  473. }
  474. void LLIMChiclet::toggleSpeakerControl()
  475. {
  476. if(getShowSpeaker())
  477. {
  478. // move speaker to the right of chiclet icon
  479. LLRect speaker_rc = mSpeakerCtrl->getRect();
  480. speaker_rc.setLeftTopAndSize(mDefaultWidth, speaker_rc.mTop, speaker_rc.getWidth(), speaker_rc.getHeight());
  481. mSpeakerCtrl->setRect(speaker_rc);
  482. if(getShowCounter())
  483. {
  484. // move speaker to the right of counter
  485. mSpeakerCtrl->translate(mCounterCtrl->getRect().getWidth(), 0);
  486. }
  487. initSpeakerControl();
  488. }
  489. setRequiredWidth();
  490. mSpeakerCtrl->setSpeakerId(LLUUID::null);
  491. mSpeakerCtrl->setVisible(getShowSpeaker());
  492. }
  493. void LLIMChiclet::setCounter(S32 counter)
  494. {
  495. if (mCounterCtrl->getCounter() == counter)
  496. {
  497. return;
  498. }
  499. mCounterCtrl->setCounter(counter);
  500. setShowCounter(counter);
  501. setShowNewMessagesIcon(counter);
  502. }
  503. void LLIMChiclet::toggleCounterControl()
  504. {
  505. setRequiredWidth();
  506. mCounterCtrl->setVisible(getShowCounter());
  507. }
  508. void LLIMChiclet::setShowNewMessagesIcon(bool show)
  509. {
  510. if(mNewMessagesIcon)
  511. {
  512. mNewMessagesIcon->setVisible(show);
  513. }
  514. setRequiredWidth();
  515. }
  516. bool LLIMChiclet::getShowNewMessagesIcon()
  517. {
  518. return mNewMessagesIcon->getVisible();
  519. }
  520. void LLIMChiclet::onMouseDown()
  521. {
  522. LLIMFloater::toggle(getSessionId());
  523. setCounter(0);
  524. }
  525. void LLIMChiclet::setToggleState(bool toggle)
  526. {
  527. mChicletButton->setToggleState(toggle);
  528. }
  529. void LLIMChiclet::draw()
  530. {
  531. LLUICtrl::draw();
  532. }
  533. // static
  534. LLIMChiclet::EType LLIMChiclet::getIMSessionType(const LLUUID& session_id)
  535. {
  536. EType type = TYPE_UNKNOWN;
  537. if(session_id.isNull())
  538. return type;
  539. EInstantMessage im_type = LLIMModel::getInstance()->getType(session_id);
  540. if (IM_COUNT == im_type)
  541. {
  542. llassert_always(0 && "IM session not found"); // should never happen
  543. return type;
  544. }
  545. switch(im_type)
  546. {
  547. case IM_NOTHING_SPECIAL:
  548. case IM_SESSION_P2P_INVITE:
  549. type = TYPE_IM;
  550. break;
  551. case IM_SESSION_GROUP_START:
  552. case IM_SESSION_INVITE:
  553. if (gAgent.isInGroup(session_id))
  554. {
  555. type = TYPE_GROUP;
  556. }
  557. else
  558. {
  559. type = TYPE_AD_HOC;
  560. }
  561. break;
  562. case IM_SESSION_CONFERENCE_START:
  563. type = TYPE_AD_HOC;
  564. default:
  565. break;
  566. }
  567. return type;
  568. }
  569. BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
  570. {
  571. if(!mPopupMenu)
  572. {
  573. createPopupMenu();
  574. }
  575. if (mPopupMenu)
  576. {
  577. updateMenuItems();
  578. mPopupMenu->arrangeAndClear();
  579. LLMenuGL::showPopup(this, mPopupMenu, x, y);
  580. }
  581. return TRUE;
  582. }
  583. bool LLIMChiclet::canCreateMenu()
  584. {
  585. if(mPopupMenu)
  586. {
  587. llwarns << "Menu already exists" << llendl;
  588. return false;
  589. }
  590. if(getSessionId().isNull())
  591. {
  592. return false;
  593. }
  594. return true;
  595. }
  596. //////////////////////////////////////////////////////////////////////////
  597. //////////////////////////////////////////////////////////////////////////
  598. //////////////////////////////////////////////////////////////////////////
  599. LLIMP2PChiclet::Params::Params()
  600. : avatar_icon("avatar_icon")
  601. , chiclet_button("chiclet_button")
  602. , unread_notifications("unread_notifications")
  603. , speaker("speaker")
  604. , new_message_icon("new_message_icon")
  605. , show_speaker("show_speaker")
  606. {
  607. }
  608. LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
  609. : LLIMChiclet(p)
  610. , mChicletIconCtrl(NULL)
  611. {
  612. LLButton::Params button_params = p.chiclet_button;
  613. mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
  614. addChild(mChicletButton);
  615. LLIconCtrl::Params new_msg_params = p.new_message_icon;
  616. mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
  617. addChild(mNewMessagesIcon);
  618. LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
  619. mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
  620. addChild(mChicletIconCtrl);
  621. LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications;
  622. mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params);
  623. addChild(mCounterCtrl);
  624. setCounter(getCounter());
  625. setShowCounter(getShowCounter());
  626. LLChicletSpeakerCtrl::Params speaker_params = p.speaker;
  627. mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params);
  628. addChild(mSpeakerCtrl);
  629. sendChildToFront(mNewMessagesIcon);
  630. setShowSpeaker(p.show_speaker);
  631. }
  632. void LLIMP2PChiclet::initSpeakerControl()
  633. {
  634. mSpeakerCtrl->setSpeakerId(getOtherParticipantId());
  635. }
  636. void LLIMP2PChiclet::setOtherParticipantId(const LLUUID& other_participant_id)
  637. {
  638. LLIMChiclet::setOtherParticipantId(other_participant_id);
  639. mChicletIconCtrl->setValue(getOtherParticipantId());
  640. }
  641. void LLIMP2PChiclet::updateMenuItems()
  642. {
  643. if(!mPopupMenu)
  644. return;
  645. if(getSessionId().isNull())
  646. return;
  647. LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId());
  648. bool open_window_exists = open_im_floater && open_im_floater->getVisible();
  649. mPopupMenu->getChild<LLUICtrl>("Send IM")->setEnabled(!open_window_exists);
  650. bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId());
  651. mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend);
  652. }
  653. void LLIMP2PChiclet::createPopupMenu()
  654. {
  655. if(!canCreateMenu())
  656. return;
  657. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  658. registrar.add("IMChicletMenu.Action", boost::bind(&LLIMP2PChiclet::onMenuItemClicked, this, _2));
  659. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
  660. ("menu_imchiclet_p2p.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  661. }
  662. void LLIMP2PChiclet::onMenuItemClicked(const LLSD& user_data)
  663. {
  664. std::string level = user_data.asString();
  665. LLUUID other_participant_id = getOtherParticipantId();
  666. if("profile" == level)
  667. {
  668. LLAvatarActions::showProfile(other_participant_id);
  669. }
  670. else if("im" == level)
  671. {
  672. LLAvatarActions::startIM(other_participant_id);
  673. }
  674. else if("add" == level)
  675. {
  676. LLAvatarActions::requestFriendshipDialog(other_participant_id);
  677. }
  678. else if("end" == level)
  679. {
  680. LLAvatarActions::endIM(other_participant_id);
  681. }
  682. }
  683. //////////////////////////////////////////////////////////////////////////
  684. //////////////////////////////////////////////////////////////////////////
  685. //////////////////////////////////////////////////////////////////////////
  686. LLAdHocChiclet::Params::Params()
  687. : avatar_icon("avatar_icon")
  688. , chiclet_button("chiclet_button")
  689. , unread_notifications("unread_notifications")
  690. , speaker("speaker")
  691. , new_message_icon("new_message_icon")
  692. , show_speaker("show_speaker")
  693. , avatar_icon_color("avatar_icon_color", LLColor4::green)
  694. {
  695. }
  696. LLAdHocChiclet::LLAdHocChiclet(const Params& p)
  697. : LLIMChiclet(p)
  698. , mChicletIconCtrl(NULL)
  699. {
  700. LLButton::Params button_params = p.chiclet_button;
  701. mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
  702. addChild(mChicletButton);
  703. LLIconCtrl::Params new_msg_params = p.new_message_icon;
  704. mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
  705. addChild(mNewMessagesIcon);
  706. LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
  707. mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
  708. //Make the avatar modified
  709. mChicletIconCtrl->setColor(p.avatar_icon_color);
  710. addChild(mChicletIconCtrl);
  711. LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications;
  712. mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params);
  713. addChild(mCounterCtrl);
  714. setCounter(getCounter());
  715. setShowCounter(getShowCounter());
  716. LLChicletSpeakerCtrl::Params speaker_params = p.speaker;
  717. mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params);
  718. addChild(mSpeakerCtrl);
  719. sendChildToFront(mNewMessagesIcon);
  720. setShowSpeaker(p.show_speaker);
  721. }
  722. void LLAdHocChiclet::setSessionId(const LLUUID& session_id)
  723. {
  724. LLChiclet::setSessionId(session_id);
  725. LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);
  726. mChicletIconCtrl->setValue(im_session->mOtherParticipantID);
  727. }
  728. void LLAdHocChiclet::draw()
  729. {
  730. switchToCurrentSpeaker();
  731. LLIMChiclet::draw();
  732. }
  733. void LLAdHocChiclet::initSpeakerControl()
  734. {
  735. switchToCurrentSpeaker();
  736. }
  737. void LLAdHocChiclet::switchToCurrentSpeaker()
  738. {
  739. LLUUID speaker_id;
  740. LLSpeakerMgr::speaker_list_t speaker_list;
  741. LLIMModel::getInstance()->findIMSession(getSessionId())->mSpeakers->getSpeakerList(&speaker_list, FALSE);
  742. for (LLSpeakerMgr::speaker_list_t::iterator i = speaker_list.begin(); i != speaker_list.end(); ++i)
  743. {
  744. LLPointer<LLSpeaker> s = *i;
  745. if (s->mSpeechVolume > 0 || s->mStatus == LLSpeaker::STATUS_SPEAKING)
  746. {
  747. speaker_id = s->mID;
  748. break;
  749. }
  750. }
  751. mSpeakerCtrl->setSpeakerId(speaker_id);
  752. }
  753. void LLAdHocChiclet::createPopupMenu()
  754. {
  755. if(!canCreateMenu())
  756. return;
  757. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  758. registrar.add("IMChicletMenu.Action", boost::bind(&LLAdHocChiclet::onMenuItemClicked, this, _2));
  759. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
  760. ("menu_imchiclet_adhoc.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  761. }
  762. void LLAdHocChiclet::onMenuItemClicked(const LLSD& user_data)
  763. {
  764. std::string level = user_data.asString();
  765. LLUUID group_id = getSessionId();
  766. if("end" == level)
  767. {
  768. LLGroupActions::endIM(group_id);
  769. }
  770. }
  771. //////////////////////////////////////////////////////////////////////////
  772. //////////////////////////////////////////////////////////////////////////
  773. //////////////////////////////////////////////////////////////////////////
  774. LLIMGroupChiclet::Params::Params()
  775. : group_icon("group_icon")
  776. , chiclet_button("chiclet_button")
  777. , unread_notifications("unread_notifications")
  778. , speaker("speaker")
  779. , new_message_icon("new_message_icon")
  780. , show_speaker("show_speaker")
  781. {
  782. }
  783. LLIMGroupChiclet::LLIMGroupChiclet(const Params& p)
  784. : LLIMChiclet(p)
  785. , LLGroupMgrObserver(LLUUID::null)
  786. , mChicletIconCtrl(NULL)
  787. {
  788. LLButton::Params button_params = p.chiclet_button;
  789. mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
  790. addChild(mChicletButton);
  791. LLIconCtrl::Params new_msg_params = p.new_message_icon;
  792. mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
  793. addChild(mNewMessagesIcon);
  794. LLChicletGroupIconCtrl::Params avatar_params = p.group_icon;
  795. mChicletIconCtrl = LLUICtrlFactory::create<LLChicletGroupIconCtrl>(avatar_params);
  796. addChild(mChicletIconCtrl);
  797. LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications;
  798. mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params);
  799. addChild(mCounterCtrl);
  800. setCounter(getCounter());
  801. setShowCounter(getShowCounter());
  802. LLChicletSpeakerCtrl::Params speaker_params = p.speaker;
  803. mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params);
  804. addChild(mSpeakerCtrl);
  805. sendChildToFront(mNewMessagesIcon);
  806. setShowSpeaker(p.show_speaker);
  807. }
  808. LLIMGroupChiclet::~LLIMGroupChiclet()
  809. {
  810. LLGroupMgr::getInstance()->removeObserver(this);
  811. }
  812. void LLIMGroupChiclet::draw()
  813. {
  814. if(getShowSpeaker())
  815. {
  816. switchToCurrentSpeaker();
  817. }
  818. LLIMChiclet::draw();
  819. }
  820. void LLIMGroupChiclet::initSpeakerControl()
  821. {
  822. switchToCurrentSpeaker();
  823. }
  824. void LLIMGroupChiclet::switchToCurrentSpeaker()
  825. {
  826. LLUUID speaker_id;
  827. LLSpeakerMgr::speaker_list_t speaker_list;
  828. LLIMModel::getInstance()->findIMSession(getSessionId())->mSpeakers->getSpeakerList(&speaker_list, FALSE);
  829. for (LLSpeakerMgr::speaker_list_t::iterator i = speaker_list.begin(); i != speaker_list.end(); ++i)
  830. {
  831. LLPointer<LLSpeaker> s = *i;
  832. if (s->mSpeechVolume > 0 || s->mStatus == LLSpeaker::STATUS_SPEAKING)
  833. {
  834. speaker_id = s->mID;
  835. break;
  836. }
  837. }
  838. mSpeakerCtrl->setSpeakerId(speaker_id);
  839. }
  840. void LLIMGroupChiclet::setSessionId(const LLUUID& session_id)
  841. {
  842. LLChiclet::setSessionId(session_id);
  843. LLGroupMgr* grp_mgr = LLGroupMgr::getInstance();
  844. LLGroupMgrGroupData* group_data = grp_mgr->getGroupData(session_id);
  845. if (group_data && group_data->mInsigniaID.notNull())
  846. {
  847. mChicletIconCtrl->setValue(group_data->mInsigniaID);
  848. }
  849. else
  850. {
  851. if(getSessionId() != mID)
  852. {
  853. grp_mgr->removeObserver(this);
  854. mID = getSessionId();
  855. grp_mgr->addObserver(this);
  856. }
  857. grp_mgr->sendGroupPropertiesRequest(session_id);
  858. }
  859. }
  860. void LLIMGroupChiclet::changed(LLGroupChange gc)
  861. {
  862. if (GC_PROPERTIES == gc)
  863. {
  864. LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(getSessionId());
  865. if (group_data)
  866. {
  867. mChicletIconCtrl->setValue(group_data->mInsigniaID);
  868. }
  869. }
  870. }
  871. void LLIMGroupChiclet::updateMenuItems()
  872. {
  873. if(!mPopupMenu)
  874. return;
  875. if(getSessionId().isNull())
  876. return;
  877. LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId());
  878. bool open_window_exists = open_im_floater && open_im_floater->getVisible();
  879. mPopupMenu->getChild<LLUICtrl>("Chat")->setEnabled(!open_window_exists);
  880. }
  881. void LLIMGroupChiclet::createPopupMenu()
  882. {
  883. if(!canCreateMenu())
  884. return;
  885. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  886. registrar.add("IMChicletMenu.Action", boost::bind(&LLIMGroupChiclet::onMenuItemClicked, this, _2));
  887. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
  888. ("menu_imchiclet_group.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  889. }
  890. void LLIMGroupChiclet::onMenuItemClicked(const LLSD& user_data)
  891. {
  892. std::string level = user_data.asString();
  893. LLUUID group_id = getSessionId();
  894. if("group chat" == level)
  895. {
  896. LLGroupActions::startIM(group_id);
  897. }
  898. else if("info" == level)
  899. {
  900. LLGroupActions::show(group_id);
  901. }
  902. else if("end" == level)
  903. {
  904. LLGroupActions::endIM(group_id);
  905. }
  906. }
  907. //////////////////////////////////////////////////////////////////////////
  908. //////////////////////////////////////////////////////////////////////////
  909. //////////////////////////////////////////////////////////////////////////
  910. LLChicletPanel::Params::Params()
  911. : chiclet_padding("chiclet_padding")
  912. , scrolling_offset("scrolling_offset")
  913. , scroll_button_hpad("scroll_button_hpad")
  914. , scroll_ratio("scroll_ratio")
  915. , min_width("min_width")
  916. {
  917. };
  918. LLChicletPanel::LLChicletPanel(const Params&p)
  919. : LLPanel(p)
  920. , mScrollArea(NULL)
  921. , mLeftScrollButton(NULL)
  922. , mRightScrollButton(NULL)
  923. , mChicletPadding(p.chiclet_padding)
  924. , mScrollingOffset(p.scrolling_offset)
  925. , mScrollButtonHPad(p.scroll_button_hpad)
  926. , mScrollRatio(p.scroll_ratio)
  927. , mMinWidth(p.min_width)
  928. , mShowControls(true)
  929. {
  930. LLPanel::Params panel_params;
  931. panel_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT);
  932. mScrollArea = LLUICtrlFactory::create<LLPanel>(panel_params,this);
  933. // important for Show/Hide Camera and Move controls menu in bottom tray to work properly
  934. mScrollArea->setMouseOpaque(false);
  935. addChild(mScrollArea);
  936. }
  937. LLChicletPanel::~LLChicletPanel()
  938. {
  939. if(LLTransientFloaterMgr::instanceExists())
  940. {
  941. LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton);
  942. LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton);
  943. }
  944. }
  945. void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
  946. LLUUID session_id = data["session_id"].asUUID();
  947. S32 unread = data["participant_unread"].asInteger();
  948. LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
  949. if (im_floater && im_floater->getVisible() && im_floater->hasFocus())
  950. {
  951. unread = 0;
  952. }
  953. std::list<LLChiclet*> chiclets = LLIMChiclet::sFindChicletsSignal(session_id);
  954. std::list<LLChiclet *>::iterator iter;
  955. for (iter = chiclets.begin(); iter != chiclets.end(); iter++) {
  956. LLChiclet* chiclet = *iter;
  957. if (chiclet != NULL)
  958. {
  959. chiclet->setCounter(unread);
  960. }
  961. else
  962. {
  963. llwarns << "Unable to set counter for chiclet " << session_id << llendl;
  964. }
  965. }
  966. }
  967. void object_chiclet_callback(const LLSD& data)
  968. {
  969. LLUUID notification_id = data["notification_id"];
  970. bool new_message = data["new_message"];
  971. std::list<LLChiclet*> chiclets = LLIMChiclet::sFindChicletsSignal(notification_id);
  972. std::list<LLChiclet *>::iterator iter;
  973. for (iter = chiclets.begin(); iter != chiclets.end(); iter++)
  974. {
  975. LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*iter);
  976. if (chiclet != NULL)
  977. {
  978. if(data.has("unread"))
  979. {
  980. chiclet->setCounter(data["unread"]);
  981. }
  982. chiclet->setShowNewMessagesIcon(new_message);
  983. }
  984. }
  985. }
  986. BOOL LLChicletPanel::postBuild()
  987. {
  988. LLPanel::postBuild();
  989. LLIMModel::instance().addNewMsgCallback(boost::bind(im_chiclet_callback, this, _1));
  990. LLIMModel::instance().addNoUnreadMsgsCallback(boost::bind(im_chiclet_callback, this, _1));
  991. LLScriptFloaterManager::getInstance()->addNewObjectCallback(boost::bind(object_chiclet_callback, _1));
  992. LLScriptFloaterManager::getInstance()->addToggleObjectFloaterCallback(boost::bind(object_chiclet_callback, _1));
  993. LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLChicletPanel::findChiclet<LLChiclet>, this, _1));
  994. LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLChicletPanel::onCurrentVoiceChannelChanged, this, _1));
  995. mLeftScrollButton=getChild<LLButton>("chicklet_left_scroll_button");
  996. LLTransientFloaterMgr::getInstance()->addControlView(mLeftScrollButton);
  997. mLeftScrollButton->setMouseDownCallback(boost::bind(&LLChicletPanel::onLeftScrollClick,this));
  998. mLeftScrollButton->setHeldDownCallback(boost::bind(&LLChicletPanel::onLeftScrollHeldDown,this));
  999. mLeftScrollButton->setEnabled(false);
  1000. mRightScrollButton=getChild<LLButton>("chicklet_right_scroll_button");
  1001. LLTransientFloaterMgr::getInstance()->addControlView(mRightScrollButton);
  1002. mRightScrollButton->setMouseDownCallback(boost::bind(&LLChicletPanel::onRightScrollClick,this));
  1003. mRightScrollButton->setHeldDownCallback(boost::bind(&LLChicletPanel::onRightScrollHeldDown,this));
  1004. mRightScrollButton->setEnabled(false);
  1005. return TRUE;
  1006. }
  1007. void LLChicletPanel::onCurrentVoiceChannelChanged(const LLUUID& session_id)
  1008. {
  1009. static LLUUID s_previous_active_voice_session_id;
  1010. std::list<LLChiclet*> chiclets = LLIMChiclet::sFindChicletsSignal(session_id);
  1011. for(std::list<LLChiclet *>::iterator it = chiclets.begin(); it != chiclets.end(); ++it)
  1012. {
  1013. LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it);
  1014. if(chiclet)
  1015. {
  1016. chiclet->setShowSpeaker(true);
  1017. if (gSavedSettings.getBOOL("OpenIMOnVoice"))
  1018. {
  1019. LLIMFloater::show(chiclet->getSessionId());
  1020. }
  1021. }
  1022. }
  1023. if(!s_previous_active_voice_session_id.isNull() && s_previous_active_voice_session_id != session_id)
  1024. {
  1025. chiclets = LLIMChiclet::sFindChicletsSignal(s_previous_active_voice_session_id);
  1026. for(std::list<LLChiclet *>::iterator it = chiclets.begin(); it != chiclets.end(); ++it)
  1027. {
  1028. LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it);
  1029. if(chiclet)
  1030. {
  1031. chiclet->setShowSpeaker(false);
  1032. }
  1033. }
  1034. }
  1035. s_previous_active_voice_session_id = session_id;
  1036. }
  1037. bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 index)
  1038. {
  1039. if(mScrollArea->addChild(chiclet))
  1040. {
  1041. // chiclets should be aligned to right edge of scroll panel
  1042. S32 left_shift = 0;
  1043. if (!canScrollLeft())
  1044. {
  1045. // init left shift for the first chiclet in the list...
  1046. if (mChicletList.empty())
  1047. {
  1048. // ...start from the right border of the scroll area for the first added chiclet
  1049. left_shift = mScrollArea->getRect().getWidth();
  1050. }
  1051. else
  1052. {
  1053. // ... start from the left border of the first chiclet minus padding
  1054. left_shift = getChiclet(0)->getRect().mLeft - getChicletPadding();
  1055. }
  1056. // take into account width of the being added chiclet
  1057. left_shift -= chiclet->getRequiredRect().getWidth();
  1058. // if we overflow the scroll area we do not need to shift chiclets
  1059. if (left_shift < 0)
  1060. {
  1061. left_shift = 0;
  1062. }
  1063. }
  1064. mChicletList.insert(mChicletList.begin() + index, chiclet);
  1065. // shift first chiclet to place it in correct position.
  1066. // rest ones will be placed in arrange()
  1067. if (!canScrollLeft())
  1068. {
  1069. getChiclet(0)->translate(left_shift - getChiclet(0)->getRect().mLeft, 0);
  1070. }
  1071. chiclet->setLeftButtonClickCallback(boost::bind(&LLChicletPanel::onChicletClick, this, _1, _2));
  1072. chiclet->setChicletSizeChangedCallback(boost::bind(&LLChicletPanel::onChicletSizeChanged, this, _1, index));
  1073. arrange();
  1074. LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, chiclet);
  1075. return true;
  1076. }
  1077. return false;
  1078. }
  1079. void LLChicletPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param)
  1080. {
  1081. arrange();
  1082. }
  1083. void LLChicletPanel::onChicletClick(LLUICtrl*ctrl,const LLSD&param)
  1084. {
  1085. if (mCommitSignal)
  1086. {
  1087. (*mCommitSignal)(ctrl,param);
  1088. }
  1089. }
  1090. void LLChicletPanel::removeChiclet(chiclet_list_t::iterator it)
  1091. {
  1092. LLChiclet* chiclet = *it;
  1093. mScrollArea->removeChild(chiclet);
  1094. mChicletList.erase(it);
  1095. arrange();
  1096. LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, chiclet);
  1097. chiclet->die();
  1098. }
  1099. void LLChicletPanel::removeChiclet(S32 index)
  1100. {
  1101. if(index >= 0 && index < getChicletCount())
  1102. {
  1103. removeChiclet(mChicletList.begin() + index);
  1104. }
  1105. }
  1106. S32 LLChicletPanel::getChicletIndex(const LLChiclet* chiclet)
  1107. {
  1108. if(mChicletList.empty())
  1109. return -1;
  1110. S32 size = getChicletCount();
  1111. for(int n = 0; n < size; ++n)
  1112. {
  1113. if(chiclet == mChicletList[n])
  1114. return n;
  1115. }
  1116. return -1;
  1117. }
  1118. void LLChicletPanel::removeChiclet(LLChiclet*chiclet)
  1119. {
  1120. chiclet_list_t::iterator it = mChicletList.begin();
  1121. for( ; mChicletList.end() != it; ++it)
  1122. {
  1123. LLChiclet* temp = *it;
  1124. if(temp == chiclet)
  1125. {
  1126. removeChiclet(it);
  1127. return;
  1128. }
  1129. }
  1130. }
  1131. void LLChicletPanel::removeChiclet(const LLUUID& im_session_id)
  1132. {
  1133. chiclet_list_t::iterator it = mChicletList.begin();
  1134. for( ; mChicletList.end() != it; ++it)
  1135. {
  1136. LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it);
  1137. if(chiclet->getSessionId() == im_session_id)
  1138. {
  1139. removeChiclet(it);
  1140. return;
  1141. }
  1142. }
  1143. }
  1144. void LLChicletPanel::removeAll()
  1145. {
  1146. S32 size = getChicletCount();
  1147. for(S32 n = 0; n < size; ++n)
  1148. {
  1149. mScrollArea->removeChild(mChicletList[n]);
  1150. }
  1151. mChicletList.erase(mChicletList.begin(), mChicletList.end());
  1152. showScrollButtonsIfNeeded();
  1153. }
  1154. void LLChicletPanel::scrollToChiclet(const LLChiclet* chiclet)
  1155. {
  1156. const LLRect& rect = chiclet->getRect();
  1157. if (rect.mLeft < 0)
  1158. {
  1159. scroll(llabs(rect.mLeft));
  1160. showScrollButtonsIfNeeded();
  1161. }
  1162. else
  1163. {
  1164. S32 scrollWidth = mScrollArea->getRect().getWidth();
  1165. if (rect.mRight > scrollWidth)
  1166. {
  1167. scroll(-llabs(rect.mRight - scrollWidth));
  1168. showScrollButtonsIfNeeded();
  1169. }
  1170. }
  1171. }
  1172. void LLChicletPanel::reshape(S32 width, S32 height, BOOL called_from_parent )
  1173. {
  1174. LLPanel::reshape(width,height,called_from_parent);
  1175. //Needed once- to avoid error at first call of reshape() before postBuild()
  1176. if(!mLeftScrollButton||!mRightScrollButton)
  1177. return;
  1178. LLRect scroll_button_rect = mLeftScrollButton->getRect();
  1179. mLeftScrollButton->setRect(LLRect(0,scroll_button_rect.mTop,scroll_button_rect.getWidth(),
  1180. scroll_button_rect.mBottom));
  1181. scroll_button_rect = mRightScrollButton->getRect();
  1182. mRightScrollButton->setRect(LLRect(width - scroll_button_rect.getWidth(),scroll_button_rect.mTop,
  1183. width, scroll_button_rect.mBottom));
  1184. bool need_show_scroll = needShowScroll();
  1185. if(need_show_scroll)
  1186. {
  1187. mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad,
  1188. height, width - scroll_button_rect.getWidth() - mScrollButtonHPad, 0));
  1189. }
  1190. else
  1191. {
  1192. mScrollArea->setRect(LLRect(0,height, width, 0));
  1193. }
  1194. mShowControls = width >= mMinWidth;
  1195. mScrollArea->setVisible(mShowControls);
  1196. trimChiclets();
  1197. showScrollButtonsIfNeeded();
  1198. }
  1199. S32 LLChicletPanel::notifyParent(const LLSD& info)
  1200. {
  1201. if(info.has("notification"))
  1202. {
  1203. std::string str_notification = info["notification"];
  1204. if(str_notification == "size_changes")
  1205. {
  1206. arrange();
  1207. return 1;
  1208. }
  1209. }
  1210. return LLPanel::notifyParent(info);
  1211. }
  1212. void LLChicletPanel::setChicletToggleState(const LLUUID& session_id, bool toggle)
  1213. {
  1214. if(session_id.isNull())
  1215. {
  1216. llwarns << "Null Session ID" << llendl;
  1217. }
  1218. // toggle off all chiclets, except specified
  1219. S32 size = getChicletCount();
  1220. for(int n = 0; n < size; ++n)
  1221. {
  1222. LLIMChiclet* chiclet = getChiclet<LLIMChiclet>(n);
  1223. if(chiclet && chiclet->getSessionId() != session_id)
  1224. {
  1225. chiclet->setToggleState(false);
  1226. }
  1227. }
  1228. // toggle specified chiclet
  1229. LLIMChiclet* chiclet = findChiclet<LLIMChiclet>(session_id);
  1230. if(chiclet)
  1231. {
  1232. chiclet->setToggleState(toggle);
  1233. }
  1234. }
  1235. void LLChicletPanel::arrange()
  1236. {
  1237. if(mChicletList.empty())
  1238. return;
  1239. //initial arrange of chicklets positions
  1240. S32 chiclet_left = getChiclet(0)->getRect().mLeft;
  1241. S32 size = getChicletCount();
  1242. for( int n = 0; n < size; ++n)
  1243. {
  1244. LLChiclet* chiclet = getChiclet(n);
  1245. S32 chiclet_width = chiclet->getRequiredRect().getWidth();
  1246. LLRect rect = chiclet->getRect();
  1247. rect.set(chiclet_left, rect.mTop, chiclet_left + chiclet_width, rect.mBottom);
  1248. chiclet->setRect(rect);
  1249. chiclet_left += chiclet_width + getChicletPadding();
  1250. }
  1251. //reset size and pos on mScrollArea
  1252. LLRect rect = getRect();
  1253. LLRect scroll_button_rect = mLeftScrollButton->getRect();
  1254. bool need_show_scroll = needShowScroll();
  1255. if(need_show_scroll)
  1256. {
  1257. mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad,
  1258. rect.getHeight(), rect.getWidth() - scroll_button_rect.getWidth() - mScrollButtonHPad, 0));
  1259. }
  1260. else
  1261. {
  1262. mScrollArea->setRect(LLRect(0,rect.getHeight(), rect.getWidth(), 0));
  1263. }
  1264. trimChiclets();
  1265. showScrollButtonsIfNeeded();
  1266. }
  1267. void LLChicletPanel::trimChiclets()
  1268. {
  1269. // trim right
  1270. if(!mChicletList.empty())
  1271. {
  1272. S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight;
  1273. S32 first_chiclet_left = getChiclet(0)->getRect().mLeft;
  1274. S32 scroll_width = mScrollArea->getRect().getWidth();
  1275. if(last_chiclet_right < scroll_width || first_chiclet_left > 0)
  1276. {
  1277. shiftChiclets(scroll_width - last_chiclet_right);
  1278. }
  1279. }
  1280. }
  1281. bool LLChicletPanel::needShowScroll()
  1282. {
  1283. if(mChicletList.empty())
  1284. return false;
  1285. S32 chicklet_width = (*mChicletList.rbegin())->getRect().mRight - (*mChicletList.begin())->getRect().mLeft;
  1286. return chicklet_width>getRect().getWidth();
  1287. }
  1288. void LLChicletPanel::showScrollButtonsIfNeeded()
  1289. {
  1290. bool can_scroll_left = canScrollLeft();
  1291. bool can_scroll_right = canScrollRight();
  1292. mLeftScrollButton->setEnabled(can_scroll_left);
  1293. mRightScrollButton->setEnabled(can_scroll_right);
  1294. bool show_scroll_buttons = (can_scroll_left || can_scroll_right) && mShowControls;
  1295. mLeftScrollButton->setVisible(show_scroll_buttons);
  1296. mRightScrollButton->setVisible(show_scroll_buttons);
  1297. }
  1298. void LLChicletPanel::draw()
  1299. {
  1300. child_list_const_iter_t it = getChildList()->begin();
  1301. for( ; getChildList()->end() != it; ++it)
  1302. {
  1303. LLView* child = *it;
  1304. if(child == dynamic_cast<LLView*>(mScrollArea))
  1305. {
  1306. LLLocalClipRect clip(mScrollArea->getRect());
  1307. drawChild(mScrollArea);
  1308. }
  1309. else
  1310. {
  1311. drawChild(child);
  1312. }
  1313. }
  1314. }
  1315. bool LLChicletPanel::canScrollRight()
  1316. {
  1317. if(mChicletList.empty())
  1318. return false;
  1319. S32 scroll_width = mScrollArea->getRect().getWidth();
  1320. S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight;
  1321. if(last_chiclet_right > scroll_width)
  1322. return true;
  1323. return false;
  1324. }
  1325. bool LLChicletPanel::canScrollLeft()
  1326. {
  1327. if(mChicletList.empty())
  1328. return false;
  1329. return getChiclet(0)->getRect().mLeft < 0;
  1330. }
  1331. void LLChicletPanel::scroll(S32 offset)
  1332. {
  1333. shiftChiclets(offset);
  1334. }
  1335. void LLChicletPanel::shiftChiclets(S32 offset, S32 start_index /* = 0 */)
  1336. {
  1337. if(start_index < 0 || start_index >= getChicletCount())
  1338. {
  1339. return;
  1340. }
  1341. chiclet_list_t::const_iterator it = mChicletList.begin() + start_index;
  1342. for(;mChicletList.end() != it; ++it)
  1343. {
  1344. LLChiclet* chiclet = *it;
  1345. chiclet->translate(offset,0);
  1346. }
  1347. }
  1348. void LLChicletPanel::scrollLeft()
  1349. {
  1350. if(canScrollLeft())
  1351. {
  1352. S32 offset = getScrollingOffset();
  1353. LLRect first_chiclet_rect = getChiclet(0)->getRect();
  1354. // shift chiclets in case first chiclet is partially visible
  1355. if(first_chiclet_rect.mLeft < 0 && first_chiclet_rect.mRight > 0)
  1356. {
  1357. offset = llabs(first_chiclet_rect.mLeft);
  1358. }
  1359. scroll(offset);
  1360. showScrollButtonsIfNeeded();
  1361. }
  1362. }
  1363. void LLChicletPanel::scrollRight()
  1364. {
  1365. if(canScrollRight())
  1366. {
  1367. S32 offset = - getScrollingOffset();
  1368. S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight;
  1369. S32 scroll_rect_width = mScrollArea->getRect().getWidth();
  1370. // if after scrolling, the last chiclet will not be aligned to
  1371. // scroll area right side - align it.
  1372. if( last_chiclet_right + offset < scroll_rect_width )
  1373. {
  1374. offset = scroll_rect_width - last_chiclet_right;
  1375. }
  1376. scroll(offset);
  1377. showScrollButtonsIfNeeded();
  1378. }
  1379. }
  1380. void LLChicletPanel::onLeftScrollClick()
  1381. {
  1382. scrollLeft();
  1383. }
  1384. void LLChicletPanel::onRightScrollClick()
  1385. {
  1386. scrollRight();
  1387. }
  1388. void LLChicletPanel::onLeftScrollHeldDown()
  1389. {
  1390. S32 offset = mScrollingOffset;
  1391. mScrollingOffset = mScrollingOffset / mScrollRatio;
  1392. scrollLeft();
  1393. mScrollingOffset = offset;
  1394. }
  1395. void LLChicletPanel::onRightScrollHeldDown()
  1396. {
  1397. S32 offset = mScrollingOffset;
  1398. mScrollingOffset = mScrollingOffset / mScrollRatio;
  1399. scrollRight();
  1400. mScrollingOffset = offset;
  1401. }
  1402. boost::signals2::connection LLChicletPanel::setChicletClickedCallback(
  1403. const commit_callback_t& cb)
  1404. {
  1405. return setCommitCallback(cb);
  1406. }
  1407. BOOL LLChicletPanel::handleScrollWheel(S32 x, S32 y, S32 clicks)
  1408. {
  1409. if(clicks > 0)
  1410. {
  1411. scrollRight();
  1412. }
  1413. else
  1414. {
  1415. scrollLeft();
  1416. }
  1417. return TRUE;
  1418. }
  1419. bool LLChicletPanel::isAnyIMFloaterDoked()
  1420. {
  1421. bool res = false;
  1422. for (chiclet_list_t::iterator it = mChicletList.begin(); it
  1423. != mChicletList.end(); it++)
  1424. {
  1425. LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>(
  1426. "impanel", (*it)->getSessionId());
  1427. if (im_floater != NULL && im_floater->getVisible()
  1428. && !im_floater->isMinimized() && im_floater->isDocked())
  1429. {
  1430. res = true;
  1431. break;
  1432. }
  1433. }
  1434. return res;
  1435. }
  1436. S32 LLChicletPanel::getTotalUnreadIMCount()
  1437. {
  1438. S32 count = 0;
  1439. chiclet_list_t::const_iterator it = mChicletList.begin();
  1440. for( ; mChicletList.end() != it; ++it)
  1441. {
  1442. LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it);
  1443. if(chiclet)
  1444. {
  1445. count += chiclet->getCounter();
  1446. }
  1447. }
  1448. return count;
  1449. }
  1450. //////////////////////////////////////////////////////////////////////////
  1451. //////////////////////////////////////////////////////////////////////////
  1452. //////////////////////////////////////////////////////////////////////////
  1453. LLChicletNotificationCounterCtrl::Params::Params()
  1454. : max_displayed_count("max_displayed_count", 99)
  1455. {
  1456. }
  1457. LLChicletNotificationCounterCtrl::LLChicletNotificationCounterCtrl(const Params& p)
  1458. : LLTextBox(p)
  1459. , mCounter(0)
  1460. , mInitialWidth(0)
  1461. , mMaxDisplayedCount(p.max_displayed_count)
  1462. {
  1463. mInitialWidth = getRect().getWidth();
  1464. }
  1465. void LLChicletNotificationCounterCtrl::setCounter(S32 counter)
  1466. {
  1467. mCounter = counter;
  1468. // note same code in LLSysWellChiclet::setCounter(S32 counter)
  1469. std::string s_count;
  1470. if(counter != 0)
  1471. {
  1472. static std::string more_messages_exist("+");
  1473. std::string more_messages(counter > mMaxDisplayedCount ? more_messages_exist : "");
  1474. s_count = llformat("%d%s"
  1475. , llmin(counter, mMaxDisplayedCount)
  1476. , more_messages.c_str()
  1477. );
  1478. }
  1479. if(mCounter != 0)
  1480. {
  1481. setText(s_count);
  1482. }
  1483. else
  1484. {
  1485. setText(std::string(""));
  1486. }
  1487. }
  1488. LLRect LLChicletNotificationCounterCtrl::getRequiredRect()
  1489. {
  1490. LLRect rc;
  1491. S32 text_width = getTextPixelWidth();
  1492. rc.mRight = rc.mLeft + llmax(text_width, mInitialWidth);
  1493. return rc;
  1494. }
  1495. void LLChicletNotificationCounterCtrl::setValue(const LLSD& value)
  1496. {
  1497. if(value.isInteger())
  1498. setCounter(value.asInteger());
  1499. }
  1500. LLSD LLChicletNotificationCounterCtrl::getValue() const
  1501. {
  1502. return LLSD(getCounter());
  1503. }
  1504. //////////////////////////////////////////////////////////////////////////
  1505. //////////////////////////////////////////////////////////////////////////
  1506. //////////////////////////////////////////////////////////////////////////
  1507. LLChicletAvatarIconCtrl::LLChicletAvatarIconCtrl(const Params& p)
  1508. : LLAvatarIconCtrl(p)
  1509. {
  1510. }
  1511. //////////////////////////////////////////////////////////////////////////
  1512. //////////////////////////////////////////////////////////////////////////
  1513. //////////////////////////////////////////////////////////////////////////
  1514. LLChicletGroupIconCtrl::LLChicletGroupIconCtrl(const Params& p)
  1515. : LLIconCtrl(p)
  1516. , mDefaultIcon(p.default_icon)
  1517. {
  1518. setValue(LLUUID::null);
  1519. }
  1520. void LLChicletGroupIconCtrl::setValue(const LLSD& value )
  1521. {
  1522. if(value.asUUID().isNull())
  1523. {
  1524. LLIconCtrl::setValue(mDefaultIcon);
  1525. }
  1526. else
  1527. {
  1528. LLIconCtrl::setValue(value);
  1529. }
  1530. }
  1531. //////////////////////////////////////////////////////////////////////////
  1532. //////////////////////////////////////////////////////////////////////////
  1533. //////////////////////////////////////////////////////////////////////////
  1534. LLChicletInvOfferIconCtrl::LLChicletInvOfferIconCtrl(const Params& p)
  1535. : LLChicletAvatarIconCtrl(p)
  1536. , mDefaultIcon(p.default_icon)
  1537. {
  1538. }
  1539. void LLChicletInvOfferIconCtrl::setValue(const LLSD& value )
  1540. {
  1541. if(value.asUUID().isNull())
  1542. {
  1543. LLIconCtrl::setValue(mDefaultIcon);
  1544. }
  1545. else
  1546. {
  1547. LLChicletAvatarIconCtrl::setValue(value);
  1548. }
  1549. }
  1550. //////////////////////////////////////////////////////////////////////////
  1551. //////////////////////////////////////////////////////////////////////////
  1552. //////////////////////////////////////////////////////////////////////////
  1553. LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p)
  1554. : LLOutputMonitorCtrl(p)
  1555. {
  1556. }
  1557. //////////////////////////////////////////////////////////////////////////
  1558. //////////////////////////////////////////////////////////////////////////
  1559. //////////////////////////////////////////////////////////////////////////
  1560. LLScriptChiclet::Params::Params()
  1561. : icon("icon")
  1562. , chiclet_button("chiclet_button")
  1563. , new_message_icon("new_message_icon")
  1564. {
  1565. }
  1566. LLScriptChiclet::LLScriptChiclet(const Params&p)
  1567. : LLIMChiclet(p)
  1568. , mChicletIconCtrl(NULL)
  1569. {
  1570. LLButton::Params button_params = p.chiclet_button;
  1571. mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
  1572. addChild(mChicletButton);
  1573. LLIconCtrl::Params new_msg_params = p.new_message_icon;
  1574. mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
  1575. addChild(mNewMessagesIcon);
  1576. LLIconCtrl::Params icon_params = p.icon;
  1577. mChicletIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
  1578. addChild(mChicletIconCtrl);
  1579. sendChildToFront(mNewMessagesIcon);
  1580. }
  1581. void LLScriptChiclet::setSessionId(const LLUUID& session_id)
  1582. {
  1583. setShowNewMessagesIcon( getSessionId() != session_id );
  1584. LLIMChiclet::setSessionId(session_id);
  1585. setToolTip(LLScriptFloaterManager::getObjectName(session_id));
  1586. }
  1587. void LLScriptChiclet::setCounter(S32 counter)
  1588. {
  1589. setShowNewMessagesIcon( counter > 0 );
  1590. }
  1591. void LLScriptChiclet::onMouseDown()
  1592. {
  1593. LLScriptFloaterManager::getInstance()->toggleScriptFloater(getSessionId());
  1594. }
  1595. void LLScriptChiclet::onMenuItemClicked(const LLSD& user_data)
  1596. {
  1597. std::string action = user_data.asString();
  1598. if("end" == action)
  1599. {
  1600. LLScriptFloaterManager::instance().removeNotification(getSessionId());
  1601. }
  1602. }
  1603. void LLScriptChiclet::createPopupMenu()
  1604. {
  1605. if(!canCreateMenu())
  1606. return;
  1607. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  1608. registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2));
  1609. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
  1610. ("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  1611. }
  1612. //////////////////////////////////////////////////////////////////////////
  1613. //////////////////////////////////////////////////////////////////////////
  1614. //////////////////////////////////////////////////////////////////////////
  1615. static const std::string INVENTORY_USER_OFFER ("UserGiveItem");
  1616. LLInvOfferChiclet::Params::Params()
  1617. : icon("icon")
  1618. , chiclet_button("chiclet_button")
  1619. , new_message_icon("new_message_icon")
  1620. {
  1621. }
  1622. LLInvOfferChiclet::LLInvOfferChiclet(const Params&p)
  1623. : LLIMChiclet(p)
  1624. , mChicletIconCtrl(NULL)
  1625. {
  1626. LLButton::Params button_params = p.chiclet_button;
  1627. mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
  1628. addChild(mChicletButton);
  1629. LLIconCtrl::Params new_msg_params = p.new_message_icon;
  1630. mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
  1631. addChild(mNewMessagesIcon);
  1632. LLChicletInvOfferIconCtrl::Params icon_params = p.icon;
  1633. mChicletIconCtrl = LLUICtrlFactory::create<LLChicletInvOfferIconCtrl>(icon_params);
  1634. addChild(mChicletIconCtrl);
  1635. sendChildToFront(mNewMessagesIcon);
  1636. }
  1637. void LLInvOfferChiclet::setSessionId(const LLUUID& session_id)
  1638. {
  1639. setShowNewMessagesIcon( getSessionId() != session_id );
  1640. setToolTip(LLScriptFloaterManager::getObjectName(session_id));
  1641. LLIMChiclet::setSessionId(session_id);
  1642. LLNotificationPtr notification = LLNotifications::getInstance()->find(session_id);
  1643. if ( notification && notification->getName() == INVENTORY_USER_OFFER )
  1644. {
  1645. mChicletIconCtrl->setValue(notification->getPayload()["from_id"]);
  1646. }
  1647. else
  1648. {
  1649. mChicletIconCtrl->setValue(LLUUID::null);
  1650. }
  1651. }
  1652. void LLInvOfferChiclet::setCounter(S32 counter)
  1653. {
  1654. setShowNewMessagesIcon( counter > 0 );
  1655. }
  1656. void LLInvOfferChiclet::onMouseDown()
  1657. {
  1658. LLScriptFloaterManager::instance().toggleScriptFloater(getSessionId());
  1659. }
  1660. void LLInvOfferChiclet::onMenuItemClicked(const LLSD& user_data)
  1661. {
  1662. std::string action = user_data.asString();
  1663. if("end" == action)
  1664. {
  1665. LLScriptFloaterManager::instance().removeNotification(getSessionId());
  1666. }
  1667. }
  1668. void LLInvOfferChiclet::createPopupMenu()
  1669. {
  1670. if(!canCreateMenu())
  1671. return;
  1672. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  1673. registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2));
  1674. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
  1675. ("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  1676. }
  1677. // EOF