/indra/newview/llhints.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 426 lines · 342 code · 47 blank · 37 comment · 25 complexity · 18cf510ce847ace020bddee34aab85ce MD5 · raw file

  1. /**
  2. * @file llhints.cpp
  3. * @brief Hint popups for displaying context sensitive help in a UI overlay
  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 "llhints.h"
  28. #include "llbutton.h"
  29. #include "lltextbox.h"
  30. #include "llviewerwindow.h"
  31. #include "llviewercontrol.h"
  32. #include "lliconctrl.h"
  33. #include "llsdparam.h"
  34. class LLHintPopup : public LLPanel
  35. {
  36. public:
  37. typedef enum e_popup_direction
  38. {
  39. LEFT,
  40. TOP,
  41. RIGHT,
  42. BOTTOM,
  43. TOP_RIGHT
  44. } EPopupDirection;
  45. struct PopupDirections : public LLInitParam::TypeValuesHelper<LLHintPopup::EPopupDirection, PopupDirections>
  46. {
  47. static void declareValues()
  48. {
  49. declare("left", LLHintPopup::LEFT);
  50. declare("right", LLHintPopup::RIGHT);
  51. declare("top", LLHintPopup::TOP);
  52. declare("bottom", LLHintPopup::BOTTOM);
  53. declare("top_right", LLHintPopup::TOP_RIGHT);
  54. }
  55. };
  56. struct TargetParams : public LLInitParam::Block<TargetParams>
  57. {
  58. Mandatory<std::string> target;
  59. Mandatory<EPopupDirection, PopupDirections> direction;
  60. TargetParams()
  61. : target("target"),
  62. direction("direction")
  63. {}
  64. };
  65. struct Params : public LLInitParam::Block<Params, LLPanel::Params>
  66. {
  67. Mandatory<LLNotificationPtr> notification;
  68. Optional<TargetParams> target_params;
  69. Optional<S32> distance;
  70. Optional<LLUIImage*> left_arrow,
  71. up_arrow,
  72. right_arrow,
  73. down_arrow,
  74. lower_left_arrow,
  75. hint_image;
  76. Optional<S32> left_arrow_offset,
  77. up_arrow_offset,
  78. right_arrow_offset,
  79. down_arrow_offset;
  80. Optional<F32> fade_in_time,
  81. fade_out_time;
  82. Params()
  83. : distance("distance"),
  84. left_arrow("left_arrow"),
  85. up_arrow("up_arrow"),
  86. right_arrow("right_arrow"),
  87. down_arrow("down_arrow"),
  88. lower_left_arrow("lower_left_arrow"),
  89. hint_image("hint_image"),
  90. left_arrow_offset("left_arrow_offset"),
  91. up_arrow_offset("up_arrow_offset"),
  92. right_arrow_offset("right_arrow_offset"),
  93. down_arrow_offset("down_arrow_offset"),
  94. fade_in_time("fade_in_time"),
  95. fade_out_time("fade_out_time")
  96. {}
  97. };
  98. LLHintPopup(const Params&);
  99. /*virtual*/ BOOL postBuild();
  100. void onClickClose()
  101. {
  102. if (!mHidden)
  103. {
  104. hide();
  105. LLNotifications::instance().cancel(mNotification);
  106. }
  107. }
  108. void draw();
  109. void hide() { if(!mHidden) {mHidden = true; mFadeTimer.reset();} }
  110. private:
  111. LLNotificationPtr mNotification;
  112. std::string mTarget;
  113. EPopupDirection mDirection;
  114. S32 mDistance;
  115. LLUIImagePtr mArrowLeft,
  116. mArrowUp,
  117. mArrowRight,
  118. mArrowDown,
  119. mArrowDownAndLeft;
  120. S32 mArrowLeftOffset,
  121. mArrowUpOffset,
  122. mArrowRightOffset,
  123. mArrowDownOffset;
  124. LLFrameTimer mFadeTimer;
  125. F32 mFadeInTime,
  126. mFadeOutTime;
  127. bool mHidden;
  128. };
  129. static LLDefaultChildRegistry::Register<LLHintPopup> r("hint_popup");
  130. LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
  131. : mNotification(p.notification),
  132. mDirection(TOP),
  133. mDistance(p.distance),
  134. mArrowLeft(p.left_arrow),
  135. mArrowUp(p.up_arrow),
  136. mArrowRight(p.right_arrow),
  137. mArrowDown(p.down_arrow),
  138. mArrowDownAndLeft(p.lower_left_arrow),
  139. mArrowLeftOffset(p.left_arrow_offset),
  140. mArrowUpOffset(p.up_arrow_offset),
  141. mArrowRightOffset(p.right_arrow_offset),
  142. mArrowDownOffset(p.down_arrow_offset),
  143. mHidden(false),
  144. mFadeInTime(p.fade_in_time),
  145. mFadeOutTime(p.fade_out_time),
  146. LLPanel(p)
  147. {
  148. if (p.target_params.isProvided())
  149. {
  150. mDirection = p.target_params.direction;
  151. mTarget = p.target_params.target;
  152. }
  153. if (p.hint_image.isProvided())
  154. {
  155. buildFromFile("panel_hint_image.xml", NULL, p);
  156. getChild<LLIconCtrl>("hint_image")->setImage(p.hint_image());
  157. }
  158. else
  159. {
  160. buildFromFile( "panel_hint.xml", NULL, p);
  161. }
  162. }
  163. BOOL LLHintPopup::postBuild()
  164. {
  165. LLTextBox& hint_text = getChildRef<LLTextBox>("hint_text");
  166. hint_text.setText(mNotification->getMessage());
  167. getChild<LLButton>("close")->setClickedCallback(boost::bind(&LLHintPopup::onClickClose, this));
  168. getChild<LLTextBox>("hint_title")->setText(mNotification->getLabel());
  169. LLRect text_bounds = hint_text.getTextBoundingRect();
  170. S32 delta_height = text_bounds.getHeight() - hint_text.getRect().getHeight();
  171. reshape(getRect().getWidth(), getRect().getHeight() + delta_height);
  172. hint_text.reshape(hint_text.getRect().getWidth(), hint_text.getRect().getHeight() + delta_height);
  173. // hint_text.translate(0, -delta_height);
  174. return TRUE;
  175. }
  176. void LLHintPopup::draw()
  177. {
  178. F32 alpha = 1.f;
  179. if (mHidden)
  180. {
  181. alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeOutTime, 1.f, 0.f);
  182. if (alpha == 0.f)
  183. {
  184. die();
  185. return;
  186. }
  187. }
  188. else
  189. {
  190. alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeInTime, 0.f, 1.f);
  191. }
  192. LLIconCtrl* hint_icon = findChild<LLIconCtrl>("hint_image");
  193. if (hint_icon)
  194. {
  195. LLUIImagePtr hint_image = hint_icon->getImage();
  196. S32 image_height = hint_image.isNull() ? 0 : hint_image->getHeight();
  197. S32 image_width = hint_image.isNull() ? 0 : hint_image->getWidth();
  198. LLView* layout_stack = hint_icon->getParent()->getParent();
  199. S32 delta_height = image_height - layout_stack->getRect().getHeight();
  200. hint_icon->getParent()->reshape(image_width, hint_icon->getParent()->getRect().getHeight());
  201. layout_stack->reshape(layout_stack->getRect().getWidth(), image_height);
  202. layout_stack->translate(0, -delta_height);
  203. LLRect hint_rect = getLocalRect();
  204. reshape(hint_rect.getWidth(), hint_rect.getHeight() + delta_height);
  205. }
  206. { LLViewDrawContext context(alpha);
  207. if (mTarget.empty())
  208. {
  209. // just draw contents, no arrow, in default position
  210. LLPanel::draw();
  211. }
  212. else
  213. {
  214. LLView* targetp = LLHints::getHintTarget(mTarget).get();
  215. if (!targetp)
  216. {
  217. // target widget is no longer valid, go away
  218. die();
  219. }
  220. else if (!targetp->isInVisibleChain())
  221. {
  222. // if target is invisible, don't draw, but keep alive in case widget comes back
  223. // but do make it so that it allows mouse events to pass through
  224. setEnabled(false);
  225. setMouseOpaque(false);
  226. }
  227. else
  228. {
  229. // revert back enabled and mouse opaque state in case we disabled it before
  230. setEnabled(true);
  231. setMouseOpaque(true);
  232. LLRect target_rect;
  233. targetp->localRectToOtherView(targetp->getLocalRect(), &target_rect, getParent());
  234. LLRect my_local_rect = getLocalRect();
  235. LLRect my_rect;
  236. LLRect arrow_rect;
  237. LLUIImagePtr arrow_imagep;
  238. switch(mDirection)
  239. {
  240. case LEFT:
  241. my_rect.setCenterAndSize( target_rect.mLeft - (my_local_rect.getWidth() / 2 + mDistance),
  242. target_rect.getCenterY(),
  243. my_local_rect.getWidth(),
  244. my_local_rect.getHeight());
  245. if (mArrowRight)
  246. {
  247. arrow_rect.setCenterAndSize(my_local_rect.mRight + mArrowRight->getWidth() / 2 + mArrowRightOffset,
  248. my_local_rect.getCenterY(),
  249. mArrowRight->getWidth(),
  250. mArrowRight->getHeight());
  251. arrow_imagep = mArrowRight;
  252. }
  253. break;
  254. case TOP:
  255. my_rect.setCenterAndSize( target_rect.getCenterX(),
  256. target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance),
  257. my_local_rect.getWidth(),
  258. my_local_rect.getHeight());
  259. if (mArrowDown)
  260. {
  261. arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
  262. my_local_rect.mBottom - mArrowDown->getHeight() / 2 + mArrowDownOffset,
  263. mArrowDown->getWidth(),
  264. mArrowDown->getHeight());
  265. arrow_imagep = mArrowDown;
  266. }
  267. break;
  268. case RIGHT:
  269. my_rect.setCenterAndSize( target_rect.mRight + (my_local_rect.getWidth() / 2 + mDistance),
  270. target_rect.getCenterY(),
  271. my_local_rect.getWidth(),
  272. my_local_rect.getHeight());
  273. if (mArrowLeft)
  274. {
  275. arrow_rect.setCenterAndSize(my_local_rect.mLeft - mArrowLeft->getWidth() / 2 + mArrowLeftOffset,
  276. my_local_rect.getCenterY(),
  277. mArrowLeft->getWidth(),
  278. mArrowLeft->getHeight());
  279. arrow_imagep = mArrowLeft;
  280. }
  281. break;
  282. case BOTTOM:
  283. my_rect.setCenterAndSize( target_rect.getCenterX(),
  284. target_rect.mBottom - (my_local_rect.getHeight() / 2 + mDistance),
  285. my_local_rect.getWidth(),
  286. my_local_rect.getHeight());
  287. if (mArrowUp)
  288. {
  289. arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
  290. my_local_rect.mTop + mArrowUp->getHeight() / 2 + mArrowUpOffset,
  291. mArrowUp->getWidth(),
  292. mArrowUp->getHeight());
  293. arrow_imagep = mArrowUp;
  294. }
  295. break;
  296. case TOP_RIGHT:
  297. my_rect.setCenterAndSize( target_rect.mRight + (my_local_rect.getWidth() / 2),
  298. target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance),
  299. my_local_rect.getWidth(),
  300. my_local_rect.getHeight());
  301. if (mArrowDownAndLeft)
  302. {
  303. arrow_rect.setCenterAndSize(my_local_rect.mLeft + mArrowDownAndLeft->getWidth() / 2 + mArrowLeftOffset,
  304. my_local_rect.mBottom - mArrowDownAndLeft->getHeight() / 2 + mArrowDownOffset,
  305. mArrowDownAndLeft->getWidth(),
  306. mArrowDownAndLeft->getHeight());
  307. arrow_imagep = mArrowDownAndLeft;
  308. }
  309. }
  310. setShape(my_rect);
  311. LLPanel::draw();
  312. if (arrow_imagep) arrow_imagep->draw(arrow_rect, LLColor4(1.f, 1.f, 1.f, alpha));
  313. }
  314. }
  315. }
  316. }
  317. LLRegistry<std::string, LLHandle<LLView> > LLHints::sTargetRegistry;
  318. std::map<LLNotificationPtr, class LLHintPopup*> LLHints::sHints;
  319. //static
  320. void LLHints::show(LLNotificationPtr hint)
  321. {
  322. LLHintPopup::Params p(LLUICtrlFactory::getDefaultParams<LLHintPopup>());
  323. LLParamSDParser parser;
  324. parser.readSD(hint->getPayload(), p, true);
  325. p.notification = hint;
  326. if (p.validateBlock())
  327. {
  328. LLHintPopup* popup = new LLHintPopup(p);
  329. sHints[hint] = popup;
  330. LLView* hint_holder = gViewerWindow->getHintHolder();
  331. if (hint_holder)
  332. {
  333. hint_holder->addChild(popup);
  334. popup->centerWithin(hint_holder->getLocalRect());
  335. }
  336. }
  337. }
  338. //static
  339. void LLHints::hide(LLNotificationPtr hint)
  340. {
  341. hint_map_t::iterator found_it = sHints.find(hint);
  342. if (found_it != sHints.end())
  343. {
  344. found_it->second->hide();
  345. sHints.erase(found_it);
  346. }
  347. }
  348. //static
  349. void LLHints::registerHintTarget(const std::string& name, LLHandle<LLView> target)
  350. {
  351. sTargetRegistry.defaultRegistrar().replace(name, target);
  352. }
  353. //static
  354. LLHandle<LLView> LLHints::getHintTarget(const std::string& name)
  355. {
  356. LLHandle<LLView>* handlep = sTargetRegistry.getValue(name);
  357. if (handlep)
  358. {
  359. return *handlep;
  360. }
  361. else
  362. {
  363. return LLHandle<LLView>();
  364. }
  365. }
  366. //static
  367. void LLHints::initClass()
  368. {
  369. sRegister.reference();
  370. LLControlVariablePtr control = gSavedSettings.getControl("EnableUIHints");
  371. control->getSignal()->connect(boost::bind(&showHints, _2));
  372. gViewerWindow->getHintHolder()->setVisible(control->getValue().asBoolean());
  373. }
  374. //staic
  375. void LLHints::showHints(const LLSD& show)
  376. {
  377. bool visible = show.asBoolean();
  378. gViewerWindow->getHintHolder()->setVisible(visible);
  379. }