/indra/newview/llchicletbar.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 345 lines · 240 code · 56 blank · 49 comment · 34 complexity · 106c93b22bf6aff76ed1d57657e7e885 MD5 · raw file

  1. /**
  2. * @file llchicletbar.cpp
  3. * @brief LLChicletBar class implementation
  4. *
  5. * $LicenseInfo:firstyear=2011&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2011, 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 "llchicletbar.h"
  28. // library includes
  29. #include "llfloaterreg.h"
  30. #include "lllayoutstack.h"
  31. // newview includes
  32. #include "llchiclet.h"
  33. #include "llimfloater.h" // for LLIMFloater
  34. #include "llpaneltopinfobar.h"
  35. #include "llsyswellwindow.h"
  36. namespace
  37. {
  38. const std::string& PANEL_CHICLET_NAME = "chiclet_list_panel";
  39. S32 get_curr_width(LLUICtrl* ctrl)
  40. {
  41. S32 cur_width = 0;
  42. if ( ctrl && ctrl->getVisible() )
  43. {
  44. cur_width = ctrl->getRect().getWidth();
  45. }
  46. return cur_width;
  47. }
  48. }
  49. LLChicletBar::LLChicletBar(const LLSD&)
  50. : mChicletPanel(NULL),
  51. mToolbarStack(NULL)
  52. {
  53. // Firstly add our self to IMSession observers, so we catch session events
  54. // before chiclets do that.
  55. LLIMMgr::getInstance()->addSessionObserver(this);
  56. buildFromFile("panel_chiclet_bar.xml");
  57. }
  58. LLChicletBar::~LLChicletBar()
  59. {
  60. if (!LLSingleton<LLIMMgr>::destroyed())
  61. {
  62. LLIMMgr::getInstance()->removeSessionObserver(this);
  63. }
  64. }
  65. LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id)
  66. {
  67. LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);
  68. switch (im_chiclet_type)
  69. {
  70. case LLIMChiclet::TYPE_IM:
  71. return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
  72. case LLIMChiclet::TYPE_GROUP:
  73. return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
  74. case LLIMChiclet::TYPE_AD_HOC:
  75. return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
  76. case LLIMChiclet::TYPE_UNKNOWN:
  77. break;
  78. }
  79. return NULL;
  80. }
  81. //virtual
  82. void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
  83. {
  84. if (!getChicletPanel()) return;
  85. LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
  86. if (!session) return;
  87. // no need to spawn chiclets for participants in P2P calls called through Avaline
  88. if (session->isP2P() && session->isOtherParticipantAvaline()) return;
  89. if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
  90. LLIMChiclet* chiclet = createIMChiclet(session_id);
  91. if(chiclet)
  92. {
  93. chiclet->setIMSessionName(name);
  94. chiclet->setOtherParticipantId(other_participant_id);
  95. LLIMFloater::onIMChicletCreated(session_id);
  96. }
  97. else
  98. {
  99. llwarns << "Could not create chiclet" << llendl;
  100. }
  101. }
  102. //virtual
  103. void LLChicletBar::sessionRemoved(const LLUUID& session_id)
  104. {
  105. if(getChicletPanel())
  106. {
  107. // IM floater should be closed when session removed and associated chiclet closed
  108. LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
  109. if (iMfloater != NULL)
  110. {
  111. iMfloater->closeFloater();
  112. }
  113. getChicletPanel()->removeChiclet(session_id);
  114. }
  115. }
  116. void LLChicletBar::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
  117. {
  118. //this is only needed in case of outgoing ad-hoc/group chat sessions
  119. LLChicletPanel* chiclet_panel = getChicletPanel();
  120. if (chiclet_panel)
  121. {
  122. //it should be ad-hoc im chiclet or group im chiclet
  123. LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
  124. if (chiclet) chiclet->setSessionId(new_session_id);
  125. }
  126. }
  127. S32 LLChicletBar::getTotalUnreadIMCount()
  128. {
  129. return getChicletPanel()->getTotalUnreadIMCount();
  130. }
  131. BOOL LLChicletBar::postBuild()
  132. {
  133. mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
  134. mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
  135. showWellButton("im_well", !LLIMWellWindow::getInstance()->isWindowEmpty());
  136. showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
  137. LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
  138. LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
  139. return TRUE;
  140. }
  141. void LLChicletBar::showWellButton(const std::string& well_name, bool visible)
  142. {
  143. LLView * panel = findChild<LLView>(well_name + "_panel");
  144. if (!panel) return;
  145. panel->setVisible(visible);
  146. }
  147. void LLChicletBar::log(LLView* panel, const std::string& descr)
  148. {
  149. if (NULL == panel) return;
  150. LLView* layout = panel->getParent();
  151. LL_DEBUGS("Chiclet Bar Rects") << descr << ": "
  152. << "panel: " << panel->getName()
  153. << ", rect: " << panel->getRect()
  154. << " layout: " << layout->getName()
  155. << ", rect: " << layout->getRect()
  156. << LL_ENDL;
  157. }
  158. void LLChicletBar::reshape(S32 width, S32 height, BOOL called_from_parent)
  159. {
  160. static S32 debug_calling_number = 0;
  161. lldebugs << "**************************************** " << ++debug_calling_number << llendl;
  162. S32 current_width = getRect().getWidth();
  163. S32 delta_width = width - current_width;
  164. lldebugs << "Reshaping: "
  165. << ", width: " << width
  166. << ", cur width: " << current_width
  167. << ", delta_width: " << delta_width
  168. << ", called_from_parent: " << called_from_parent
  169. << llendl;
  170. if (mChicletPanel) log(mChicletPanel, "before");
  171. // Difference between chiclet bar width required to fit its children and the actual width. (see EXT-991)
  172. // Positive value means that chiclet bar is not wide enough.
  173. // Negative value means that there is free space.
  174. static S32 extra_shrink_width = 0;
  175. bool should_be_reshaped = true;
  176. if (mChicletPanel && mToolbarStack)
  177. {
  178. // Firstly, update layout stack to ensure we deal with correct panel sizes.
  179. {
  180. // Force the updating of layout to reset panels collapse factor.
  181. mToolbarStack->updateLayout();
  182. }
  183. // chiclet bar is narrowed
  184. if (delta_width < 0)
  185. {
  186. if (extra_shrink_width > 0) // not enough space
  187. {
  188. extra_shrink_width += llabs(delta_width);
  189. should_be_reshaped = false;
  190. }
  191. else
  192. {
  193. extra_shrink_width = processWidthDecreased(delta_width);
  194. // increase new width to extra_shrink_width value to not reshape less than chiclet bar minimum
  195. width += extra_shrink_width;
  196. }
  197. }
  198. // chiclet bar is widened
  199. else
  200. {
  201. if (extra_shrink_width > delta_width)
  202. {
  203. // Still not enough space.
  204. // Only subtract the delta from the required delta and don't reshape.
  205. extra_shrink_width -= delta_width;
  206. should_be_reshaped = false;
  207. }
  208. else if (extra_shrink_width > 0)
  209. {
  210. // If we have some extra shrink width let's reduce delta_width & width
  211. delta_width -= extra_shrink_width;
  212. width -= extra_shrink_width;
  213. extra_shrink_width = 0;
  214. }
  215. }
  216. }
  217. if (should_be_reshaped)
  218. {
  219. lldebugs << "Reshape all children with width: " << width << llendl;
  220. LLPanel::reshape(width, height, called_from_parent);
  221. }
  222. if (mChicletPanel) log(mChicletPanel, "after");
  223. }
  224. S32 LLChicletBar::processWidthDecreased(S32 delta_width)
  225. {
  226. bool still_should_be_processed = true;
  227. const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();
  228. // Decreasing width of chiclet panel.
  229. if (chiclet_panel_shrink_headroom > 0)
  230. {
  231. // we have some space to decrease chiclet panel
  232. S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);
  233. lldebugs << "delta_width: " << delta_width
  234. << ", panel_delta_min: " << chiclet_panel_shrink_headroom
  235. << ", shrink_by: " << shrink_by
  236. << llendl;
  237. // is chiclet panel wide enough to process resizing?
  238. delta_width += chiclet_panel_shrink_headroom;
  239. still_should_be_processed = delta_width < 0;
  240. lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
  241. mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
  242. log(mChicletPanel, "after processing panel decreasing via chiclet panel");
  243. lldebugs << "RS_CHICLET_PANEL"
  244. << ", delta_width: " << delta_width
  245. << llendl;
  246. }
  247. S32 extra_shrink_width = 0;
  248. if (still_should_be_processed)
  249. {
  250. extra_shrink_width = -delta_width;
  251. llwarns << "There is no enough width to reshape all children: "
  252. << extra_shrink_width << llendl;
  253. }
  254. return extra_shrink_width;
  255. }
  256. S32 LLChicletBar::getChicletPanelShrinkHeadroom() const
  257. {
  258. static const S32 min_width = mChicletPanel->getMinWidth();
  259. const S32 cur_width = mChicletPanel->getParent()->getRect().getWidth();
  260. S32 shrink_headroom = cur_width - min_width;
  261. llassert(shrink_headroom >= 0); // the panel cannot get narrower than the minimum
  262. return shrink_headroom;
  263. }
  264. void LLChicletBar::fitWithTopInfoBar()
  265. {
  266. LLPanelTopInfoBar& top_info_bar = LLPanelTopInfoBar::instance();
  267. LLRect rect = getRect();
  268. S32 width = rect.getWidth();
  269. if (top_info_bar.getVisible())
  270. {
  271. S32 delta = top_info_bar.calcScreenRect().mRight - calcScreenRect().mLeft;
  272. if (delta < 0 && rect.mLeft < llabs(delta))
  273. delta = -rect.mLeft;
  274. rect.setLeftTopAndSize(rect.mLeft + delta, rect.mTop, rect.getWidth(), rect.getHeight());
  275. width = rect.getWidth() - delta;
  276. }
  277. else
  278. {
  279. LLView* parent = getParent();
  280. if (parent)
  281. {
  282. LLRect parent_rect = parent->getRect();
  283. rect.setLeftTopAndSize(0, rect.mTop, rect.getWidth(), rect.getHeight());
  284. width = parent_rect.getWidth();
  285. }
  286. }
  287. setRect(rect);
  288. LLPanel::reshape(width, rect.getHeight(), false);
  289. }