llhoverview.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. /**
  2. * @file llhoverview.cpp
  3. * @brief LLHoverView class implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llhoverview.h"
  34. #include "llcachename.h"
  35. #include "llfontgl.h"
  36. #include "llgl.h"
  37. #include "llparcel.h"
  38. #include "llpermissions.h"
  39. #include "llrender.h"
  40. #include "lltrans.h"
  41. #include "llagent.h"
  42. #include "lldrawable.h"
  43. //MK
  44. #include "mkrlinterface.h"
  45. //mk
  46. #include "llselectmgr.h"
  47. #include "lltoolmgr.h"
  48. #include "lltoolpie.h"
  49. #include "lltoolselectland.h"
  50. #include "llviewercamera.h"
  51. #include "llviewercontrol.h"
  52. #include "llviewerobjectlist.h"
  53. #include "llviewerparcelmgr.h"
  54. #include "llviewerregion.h"
  55. #include "llviewertexturelist.h"
  56. //
  57. // Constants
  58. //
  59. const char* DEFAULT_DESC = "(No Description)";
  60. constexpr F32 DELAY_BEFORE_SHOW_TIP = 0.35f;
  61. constexpr F32 MAX_HOVER_DISPLAY_SECS = 5.f;
  62. // Globals
  63. // Instance created in LLViewerWindow::initWorldUI()
  64. LLHoverView* gHoverViewp = NULL;
  65. // Statics
  66. bool LLHoverView::sShowHoverTips = true;
  67. // Member functions
  68. LLHoverView::LLHoverView(const LLRect& rect)
  69. : LLView("hover view", rect, false),
  70. mLastObjectWithFullText(NULL),
  71. mLastParcelWithFullText(NULL),
  72. mDoneHoverPick(false),
  73. mStartHoverPickTimer(false),
  74. mHoverActive(false),
  75. mUseHover(false),
  76. mTyping(false)
  77. {
  78. mHoverOffset.clear();
  79. mRetrievingData = LLTrans::getString("RetrievingData");
  80. mTooltipPerson = LLTrans::getString("TooltipPerson");
  81. mTooltipNoName = LLTrans::getString("TooltipNoName");
  82. mTooltipOwner = LLTrans::getString("TooltipOwner");
  83. mTooltipPublic = LLTrans::getString("TooltipPublic");
  84. mTooltipIsGroup = LLTrans::getString("TooltipIsGroup");
  85. mTooltipFlagScript = LLTrans::getString("TooltipFlagScript");
  86. mTooltipFlagCharacter = LLTrans::getString("TooltipFlagCharacter");
  87. mTooltipFlagPhysics = LLTrans::getString("TooltipFlagPhysics");
  88. mTooltipFlagPermanent = LLTrans::getString("TooltipFlagPermanent");
  89. mTooltipFlagTouch = LLTrans::getString("TooltipFlagTouch");
  90. mTooltipFlagMoney = LLTrans::getString("TooltipFlagL$");
  91. mTooltipFlagDropInventory = LLTrans::getString("TooltipFlagDropInventory");
  92. mTooltipFlagPhantom = LLTrans::getString("TooltipFlagPhantom");
  93. mTooltipFlagTemporary = LLTrans::getString("TooltipFlagTemporary");
  94. mTooltipFlagRightClickMenu = LLTrans::getString("TooltipFlagRightClickMenu");
  95. mTooltipFreeToCopy = LLTrans::getString("TooltipFreeToCopy");
  96. mTooltipForSaleMsg = LLTrans::getString("TooltipForSaleMsg") + mRetrievingData;
  97. mTooltipLand = LLTrans::getString("TooltipLand");
  98. mTooltipFlagGroupBuild = LLTrans::getString("TooltipFlagGroupBuild");
  99. mTooltipFlagNoBuild = LLTrans::getString("TooltipFlagNoBuild");
  100. mTooltipFlagNoEdit = LLTrans::getString("TooltipFlagNoEdit");
  101. mTooltipFlagNotSafe = LLTrans::getString("TooltipFlagNotSafe");
  102. mTooltipFlagNoFly = LLTrans::getString("TooltipFlagNoFly");
  103. mTooltipFlagGroupScripts = LLTrans::getString("TooltipFlagGroupScripts");
  104. mTooltipFlagNoScripts = LLTrans::getString("TooltipFlagNoScripts");
  105. mShadowImage = LLUI::getUIImage("rounded_square_soft.tga");
  106. if (mShadowImage.isNull())
  107. {
  108. llerrs << "Missing shadow image !" << llendl;
  109. }
  110. mFont = LLFontGL::getFontSansSerifSmall();
  111. llinfos << "Hover-view initialized." << llendl;
  112. }
  113. LLHoverView::~LLHoverView()
  114. {
  115. gHoverViewp = NULL;
  116. llinfos << "Hover-view destroyed." << llendl;
  117. }
  118. void LLHoverView::updateHover(LLTool* current_tool)
  119. {
  120. bool picking_tool = current_tool == &gToolPie ||
  121. current_tool == &gToolSelectLand;
  122. mUseHover = picking_tool && !gAgent.cameraMouselook() && !mTyping;
  123. if (!mUseHover)
  124. {
  125. return;
  126. }
  127. if (LLViewerWindow::getMouseVelocityStat().getPrev(0) < 0.01f &&
  128. LLViewerCamera::getAngularVelocityStat().getPrev(0) < 0.01f &&
  129. LLViewerCamera::getVelocityStat().getPrev(0) < 0.01f)
  130. {
  131. if (!mStartHoverPickTimer)
  132. {
  133. mStartHoverTimer.reset();
  134. mStartHoverPickTimer = true;
  135. // Clear the existing text so that we do not briefly show the wrong
  136. // data.
  137. mText.clear();
  138. }
  139. if (mDoneHoverPick)
  140. {
  141. // Just update the hover data
  142. updateText();
  143. }
  144. else if (mStartHoverTimer.getElapsedTimeF32() > DELAY_BEFORE_SHOW_TIP)
  145. {
  146. gViewerWindowp->pickAsync(gViewerWindowp->getCurrentMouseX(),
  147. gViewerWindowp->getCurrentMouseY(),
  148. 0, pickCallback);
  149. }
  150. }
  151. else
  152. {
  153. cancelHover();
  154. }
  155. }
  156. void LLHoverView::pickCallback(const LLPickInfo& pick_info)
  157. {
  158. if (!gHoverViewp) return;
  159. gHoverViewp->mLastPickInfo = pick_info;
  160. LLViewerObject* hit_obj = pick_info.getObject();
  161. if (hit_obj)
  162. {
  163. gHoverViewp->setHoverActive(true);
  164. gSelectMgr.setHoverObject(hit_obj, pick_info.mObjectFace);
  165. gHoverViewp->mLastHoverObject = hit_obj;
  166. gHoverViewp->mHoverOffset = pick_info.mObjectOffset;
  167. }
  168. else
  169. {
  170. gHoverViewp->mLastHoverObject = NULL;
  171. }
  172. // We did not hit an object, but we did hit land.
  173. if (!hit_obj && pick_info.mPosGlobal != LLVector3d::zero)
  174. {
  175. gHoverViewp->setHoverActive(true);
  176. gHoverViewp->mHoverLandGlobal = pick_info.mPosGlobal;
  177. gViewerParcelMgr.setHoverParcel(gHoverViewp->mHoverLandGlobal);
  178. }
  179. else
  180. {
  181. gHoverViewp->mHoverLandGlobal.clear();
  182. }
  183. gHoverViewp->mDoneHoverPick = true;
  184. }
  185. void LLHoverView::cancelHover()
  186. {
  187. mStartHoverTimer.reset();
  188. mDoneHoverPick = false;
  189. mStartHoverPickTimer = false;
  190. gSelectMgr.setHoverObject(NULL);
  191. #if 0 // Cannot do this, some code relies on hover object still being set
  192. // after the hover is cancelled ! Dammit. JC
  193. mLastHoverObject = NULL;
  194. #endif
  195. setHoverActive(false);
  196. }
  197. void LLHoverView::resetLastHoverObject()
  198. {
  199. mLastHoverObject = NULL;
  200. mLastObjectWithFullText = NULL;
  201. mLastParcelWithFullText = NULL;
  202. }
  203. void LLHoverView::updateText()
  204. {
  205. LLViewerObject* hit_object = getLastHoverObject();
  206. if (hit_object && hit_object == mLastObjectWithFullText)
  207. {
  208. // mText is already up to date
  209. return;
  210. }
  211. mLastObjectWithFullText = NULL;
  212. std::string line;
  213. bool text_complete = true;
  214. if (hit_object)
  215. {
  216. mLastParcelWithFullText = NULL;
  217. mText.clear();
  218. if (hit_object->isHUDAttachment())
  219. {
  220. // No hover tips for HUD elements, since they can obscure what the
  221. // HUD is displaying
  222. mLastObjectWithFullText = hit_object;
  223. return;
  224. }
  225. if (hit_object->isAttachment())
  226. {
  227. // Get root of attachment then parent, which is avatar
  228. LLViewerObject* root_edit = hit_object->getRootEdit();
  229. if (!root_edit)
  230. {
  231. // Strange parenting issue, don't show any text
  232. return;
  233. }
  234. hit_object = (LLViewerObject*)root_edit->getParent();
  235. if (!hit_object)
  236. {
  237. // Another strange parenting issue, bail out
  238. return;
  239. }
  240. }
  241. line.clear();
  242. if (hit_object->isAvatar())
  243. {
  244. LLNameValue* title = hit_object->getNVPair("Title");
  245. LLNameValue* firstname = hit_object->getNVPair("FirstName");
  246. LLNameValue* lastname = hit_object->getNVPair("LastName");
  247. if (firstname && lastname)
  248. {
  249. std::string complete_name = firstname->getString();
  250. std::string last = lastname->getString();
  251. if (!LLAvatarName::sOmitResidentAsLastName ||
  252. last != "Resident")
  253. {
  254. complete_name += " " + last;
  255. }
  256. else
  257. {
  258. text_complete = false;
  259. }
  260. if (LLAvatarNameCache::useDisplayNames())
  261. {
  262. LLAvatarName avatar_name;
  263. if (LLAvatarNameCache::get(hit_object->getID(),
  264. &avatar_name))
  265. {
  266. if (LLAvatarNameCache::useDisplayNames() == 2)
  267. {
  268. complete_name = avatar_name.mDisplayName;
  269. }
  270. else
  271. {
  272. complete_name = avatar_name.getNames();
  273. }
  274. }
  275. else
  276. {
  277. text_complete = false;
  278. }
  279. }
  280. if (title)
  281. {
  282. line.append(title->getString());
  283. line.append(1, ' ');
  284. }
  285. line += complete_name;
  286. }
  287. else
  288. {
  289. line.append(mTooltipPerson);
  290. text_complete = false;
  291. }
  292. //MK
  293. if (gRLenabled &&
  294. (gRLInterface.mContainsShownames ||
  295. gRLInterface.mContainsShownametags))
  296. {
  297. line.clear();
  298. line.append(firstname->getString());
  299. line.append(1, ' ');
  300. line.append(lastname->getString());
  301. line = gRLInterface.getDummyName(line);
  302. }
  303. //mk
  304. mText.emplace_back(line);
  305. }
  306. else
  307. {
  308. // We have hit a regular object (not an avatar or attachment)
  309. // Default prefs will suppress display unless the object is
  310. // interactive
  311. static LLCachedControl<bool> show_all_tip(gSavedSettings,
  312. "ShowAllObjectHoverTip");
  313. bool suppress_tip = !show_all_tip;
  314. LLSelectNode* nodep = gSelectMgr.getHoverNode();
  315. if (nodep)
  316. {
  317. if (nodep->mName.empty())
  318. {
  319. line = mTooltipNoName;
  320. text_complete = false;
  321. }
  322. else
  323. {
  324. line = nodep->mName;
  325. }
  326. mText.emplace_back(line);
  327. if (!nodep->mDescription.empty() &&
  328. nodep->mDescription != DEFAULT_DESC)
  329. {
  330. mText.emplace_back(nodep->mDescription);
  331. }
  332. // Line: "Owner: James Linden"
  333. line = mTooltipOwner;
  334. if (nodep->mValid)
  335. {
  336. LLUUID owner;
  337. std::string name;
  338. if (!nodep->mPermissions->isGroupOwned())
  339. {
  340. owner = nodep->mPermissions->getOwner();
  341. if (LLUUID::null == owner)
  342. {
  343. line.append(" " + mTooltipPublic);
  344. }
  345. else if (gCacheNamep &&
  346. gCacheNamep->getFullName(owner, name))
  347. {
  348. //MK
  349. if (gRLenabled &&
  350. (gRLInterface.mContainsShownames ||
  351. gRLInterface.mContainsShownametags))
  352. {
  353. name = gRLInterface.getDummyName(name);
  354. }
  355. //mk
  356. line.append(" " + name);
  357. }
  358. else
  359. {
  360. line.append(" " + mRetrievingData);
  361. text_complete = false;
  362. }
  363. }
  364. else
  365. {
  366. std::string name;
  367. owner = nodep->mPermissions->getGroup();
  368. if (gCacheNamep &&
  369. gCacheNamep->getGroupName(owner, name))
  370. {
  371. line.append(" " + name + " " + mTooltipIsGroup);
  372. }
  373. else
  374. {
  375. line.append(" " + mRetrievingData);
  376. text_complete = false;
  377. }
  378. }
  379. }
  380. else
  381. {
  382. line.append(" " + mRetrievingData);
  383. text_complete = false;
  384. }
  385. mText.emplace_back(line);
  386. // Build a line describing any special properties of this object.
  387. LLViewerObject* object = hit_object;
  388. LLViewerObject* parent = object ? (LLViewerObject*)object->getParent()
  389. : NULL;
  390. if (object)
  391. {
  392. bool permanent = object->flagObjectPermanent() ||
  393. (parent && parent->flagObjectPermanent());
  394. bool character = object->flagCharacter() ||
  395. (parent && parent->flagCharacter());
  396. bool handle_touch = object->flagHandleTouch() ||
  397. (parent && parent->flagHandleTouch());
  398. bool takes_money = object->flagTakesMoney() ||
  399. (parent && parent->flagTakesMoney());
  400. if (permanent || character || handle_touch ||
  401. takes_money || object->flagUsePhysics() ||
  402. object->flagScripted() || object->flagPhantom() ||
  403. object->flagAllowInventoryAdd() ||
  404. object->flagTemporaryOnRez())
  405. {
  406. line.clear();
  407. if (object->flagScripted())
  408. {
  409. line.append(mTooltipFlagScript);
  410. }
  411. if (character)
  412. {
  413. if (!line.empty()) line.append(" ");
  414. line.append(mTooltipFlagCharacter);
  415. suppress_tip = false; // Show tip
  416. }
  417. if (object->flagUsePhysics())
  418. {
  419. if (!line.empty()) line.append(" ");
  420. line.append(mTooltipFlagPhysics);
  421. }
  422. if (permanent)
  423. {
  424. if (!line.empty()) line.append(" ");
  425. line.append(mTooltipFlagPermanent);
  426. }
  427. if (handle_touch)
  428. {
  429. if (!line.empty()) line.append(" ");
  430. line.append(mTooltipFlagTouch);
  431. suppress_tip = false; // Show tip
  432. }
  433. if (takes_money)
  434. {
  435. if (!line.empty()) line.append(" ");
  436. line.append(mTooltipFlagMoney);
  437. suppress_tip = false; // Show tip
  438. }
  439. if (object->flagAllowInventoryAdd())
  440. {
  441. if (!line.empty()) line.append(" ");
  442. line.append(mTooltipFlagDropInventory);
  443. suppress_tip = false; // Show tip
  444. }
  445. if (object->flagPhantom())
  446. {
  447. if (!line.empty()) line.append(" ");
  448. line.append(mTooltipFlagPhantom);
  449. }
  450. if (object->flagTemporaryOnRez())
  451. {
  452. if (!line.empty()) line.append(" ");
  453. line.append(mTooltipFlagTemporary);
  454. }
  455. if (!line.empty())
  456. {
  457. mText.emplace_back(line);
  458. }
  459. if (object->flagUsePhysics() || handle_touch)
  460. {
  461. line = mTooltipFlagRightClickMenu;
  462. mText.emplace_back(line);
  463. }
  464. }
  465. }
  466. else
  467. {
  468. text_complete = false;
  469. }
  470. // Free to copy / For Sale: L$
  471. line.clear();
  472. if (nodep->mValid)
  473. {
  474. bool for_copy = (nodep->mPermissions->getMaskEveryone() & PERM_COPY) &&
  475. object->permCopy();
  476. bool for_sale = nodep->mSaleInfo.isForSale() &&
  477. (nodep->mPermissions->getMaskOwner() & PERM_TRANSFER) &&
  478. ((nodep->mPermissions->getMaskOwner() & PERM_COPY) ||
  479. nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
  480. if (for_copy)
  481. {
  482. line.append(mTooltipFreeToCopy);
  483. suppress_tip = false; // Show tip
  484. }
  485. else if (for_sale)
  486. {
  487. LLStringUtil::format_map_t args;
  488. args["[AMOUNT]"] = llformat("%d",
  489. nodep->mSaleInfo.getSalePrice());
  490. line.append(LLTrans::getString("TooltipForSaleL$", args));
  491. suppress_tip = false; // Show tip
  492. }
  493. #if 0 // Nothing if not for sale
  494. else
  495. {
  496. line.append("Not for sale");
  497. }
  498. #endif
  499. }
  500. else
  501. {
  502. line.append(mTooltipForSaleMsg);
  503. text_complete = false;
  504. }
  505. if (!line.empty())
  506. {
  507. mText.emplace_back(line);
  508. }
  509. }
  510. // If the hover tip shouldn't be shown, delete all the object text
  511. if (suppress_tip)
  512. {
  513. mText.clear();
  514. }
  515. }
  516. if (text_complete)
  517. {
  518. mLastObjectWithFullText = hit_object;
  519. }
  520. }
  521. else if (!mHoverLandGlobal.isExactlyZero())
  522. {
  523. // Did not hit an object, but since we have a land point we must be
  524. // hovering over land.
  525. // Do not show hover for land unless prefs are set to allow it.
  526. static LLCachedControl<bool> show_land_hover_tip(gSavedSettings,
  527. "ShowLandHoverTip");
  528. if (!show_land_hover_tip)
  529. {
  530. mText.clear();
  531. return;
  532. }
  533. LLParcel* hover_parcel = gViewerParcelMgr.getHoverParcel();
  534. if (hover_parcel && hover_parcel == mLastParcelWithFullText)
  535. {
  536. // mText is already up to date
  537. return;
  538. }
  539. mLastParcelWithFullText = NULL;
  540. mText.clear();
  541. LLUUID owner;
  542. if (hover_parcel)
  543. {
  544. owner = hover_parcel->getOwnerID();
  545. }
  546. // Line: "Land"
  547. line = mTooltipLand;
  548. if (hover_parcel)
  549. {
  550. line.append(" " + hover_parcel->getName());
  551. mText.emplace_back(line);
  552. }
  553. // Line: "Owner: James Linden"
  554. line = mTooltipOwner + " ";
  555. if (hover_parcel)
  556. {
  557. std::string name;
  558. if (LLUUID::null == owner)
  559. {
  560. line.append(mTooltipPublic);
  561. }
  562. else if (hover_parcel->getIsGroupOwned())
  563. {
  564. if (gCacheNamep && gCacheNamep->getGroupName(owner, name))
  565. {
  566. line.append(name + mTooltipIsGroup);
  567. }
  568. else
  569. {
  570. line.append(mRetrievingData);
  571. text_complete = false;
  572. }
  573. }
  574. else if (gCacheNamep && gCacheNamep->getFullName(owner, name))
  575. {
  576. line.append(name);
  577. }
  578. else
  579. {
  580. line.append(mRetrievingData);
  581. text_complete = false;
  582. }
  583. }
  584. else
  585. {
  586. line.append(mRetrievingData);
  587. text_complete = false;
  588. }
  589. mText.emplace_back(line);
  590. // Line: "no fly, not safe, no build"
  591. // Do not display properties for your land. This is just confusing,
  592. // because you can do anything on your own land.
  593. if (hover_parcel && owner != gAgentID)
  594. {
  595. S32 words = 0;
  596. line.clear();
  597. // JC - Keep this in the same order as the checkboxes
  598. // on the land info panel
  599. if (!hover_parcel->getAllowModify())
  600. {
  601. if (hover_parcel->getAllowGroupModify())
  602. {
  603. line.append(mTooltipFlagGroupBuild);
  604. }
  605. else
  606. {
  607. line.append(mTooltipFlagNoBuild);
  608. }
  609. ++words;
  610. }
  611. if (!hover_parcel->getAllowTerraform())
  612. {
  613. if (words) line.append(", ");
  614. line.append(mTooltipFlagNoEdit);
  615. ++words;
  616. }
  617. if (hover_parcel->getAllowDamage())
  618. {
  619. if (words) line.append(", ");
  620. line.append(mTooltipFlagNotSafe);
  621. ++words;
  622. }
  623. // Maybe we should reflect the estate block fly bit here as well ?
  624. // DK 12/1/04
  625. if (!hover_parcel->getAllowFly())
  626. {
  627. if (words) line.append(", ");
  628. line.append(mTooltipFlagNoFly);
  629. ++words;
  630. }
  631. if (!hover_parcel->getAllowOtherScripts())
  632. {
  633. if (words) line.append(", ");
  634. if (hover_parcel->getAllowGroupScripts())
  635. {
  636. line.append(mTooltipFlagGroupScripts);
  637. }
  638. else
  639. {
  640. line.append(mTooltipFlagNoScripts);
  641. }
  642. ++words;
  643. }
  644. if (words)
  645. {
  646. mText.emplace_back(line);
  647. }
  648. }
  649. #if 0
  650. // Line: "Size: 1x4"
  651. // Only show for non-public land
  652. if (hover_parcel && LLUUID::null != owner)
  653. {
  654. line = llformat("Size: %dx%d", width, height);
  655. mText.emplace_back(line);
  656. }
  657. #endif
  658. if (hover_parcel && hover_parcel->getParcelFlag(PF_FOR_SALE))
  659. {
  660. LLStringUtil::format_map_t args;
  661. args["[AMOUNT]"] = llformat("%d", hover_parcel->getSalePrice());
  662. line = LLTrans::getString("TooltipForSaleL$", args);
  663. mText.emplace_back(line);
  664. }
  665. if (text_complete)
  666. {
  667. mLastParcelWithFullText = hover_parcel;
  668. }
  669. }
  670. }
  671. void LLHoverView::draw()
  672. {
  673. // To toggle off hover tips, you have to just suppress the draw. The
  674. // picking is still needed to do cursor changes over physical and scripted
  675. // objects. JC
  676. if (!isHovering() ||
  677. !sShowHoverTips ||
  678. mHoverTimer.getElapsedTimeF32() > MAX_HOVER_DISPLAY_SECS)
  679. {
  680. return;
  681. }
  682. F32 alpha = 1.f;
  683. if (mHoverActive)
  684. {
  685. if (isHoveringObject())
  686. {
  687. // Look at object
  688. LLViewerObject* hover_object = getLastHoverObject();
  689. if (hover_object->isAvatar())
  690. {
  691. gAgent.setLookAt(LOOKAT_TARGET_HOVER, getLastHoverObject(),
  692. LLVector3::zero);
  693. }
  694. else
  695. {
  696. gAgent.setLookAt(LOOKAT_TARGET_HOVER, getLastHoverObject(),
  697. mHoverOffset);
  698. }
  699. }
  700. }
  701. else
  702. {
  703. constexpr F32 MAX_ALPHA = 0.9f;
  704. alpha = llmax(0.f, MAX_ALPHA - mHoverTimer.getElapsedTimeF32() * 2.f);
  705. }
  706. // Bail out if no text to display
  707. if (mText.empty())
  708. {
  709. return;
  710. }
  711. // Don't draw if no alpha
  712. if (alpha <= 0.f)
  713. {
  714. return;
  715. }
  716. // Render text.
  717. static LLCachedControl<LLColor4U> tool_tip_text_color(gColors,
  718. "ToolTipTextColor");
  719. LLColor4 text_color = LLColor4(tool_tip_text_color);
  720. static LLCachedControl<LLColor4U> tool_tip_bg_color(gColors,
  721. "ToolTipBgColor");
  722. LLColor4 bg_color = LLColor4(tool_tip_bg_color);
  723. LLColor4 shadow_color = LLUI::sColorDropShadow;
  724. #if 0 // Could decrease the alpha here. JC
  725. static LLCachedControl<LLColor4U> border_color(gColors,
  726. "ToolTipBorderColor");
  727. text_color.mV[VALPHA] = alpha;
  728. border_color.mV[VALPHA] = alpha;
  729. bg_color.mV[VALPHA] = alpha;
  730. #endif
  731. S32 max_width = 0;
  732. S32 num_lines = mText.size();
  733. text_list_t::iterator text_end = mText.end();
  734. for (text_list_t::iterator iter = mText.begin(); iter != text_end; ++iter)
  735. {
  736. max_width = llmax(max_width, (S32)mFont->getWidth(*iter));
  737. }
  738. S32 left = mHoverPos.mX + 10;
  739. S32 top = mHoverPos.mY - 16;
  740. S32 right = mHoverPos.mX + max_width + 30;
  741. S32 bottom = mHoverPos.mY - 24 - llfloor(num_lines * mFont->getLineHeight());
  742. // Push down if there's a one-click icon
  743. if (mHoverActive && isHoveringObject() &&
  744. mLastHoverObject->getClickAction() != CLICK_ACTION_NONE)
  745. {
  746. constexpr S32 CLICK_OFFSET = 10;
  747. top -= CLICK_OFFSET;
  748. bottom -= CLICK_OFFSET;
  749. }
  750. // Make sure the rect is completely visible
  751. LLRect old_rect = getRect();
  752. setRect(LLRect(left, top, right, bottom));
  753. translateIntoRect(gViewerWindowp->getVirtualWindowRect(), false);
  754. left = getRect().mLeft;
  755. top = getRect().mTop;
  756. right = getRect().mRight;
  757. bottom = getRect().mBottom;
  758. setRect(old_rect);
  759. LLGLSUIDefault gls_ui;
  760. S32 shadow_offset = LLUI::sDropShadowTooltip;
  761. shadow_color.mV[VALPHA] = 0.7f * alpha;
  762. mShadowImage->draw(LLRect(left + shadow_offset, top - shadow_offset,
  763. right + shadow_offset, bottom - shadow_offset),
  764. shadow_color);
  765. bg_color.mV[VALPHA] = alpha;
  766. LLUIImage::sRoundedSquare->draw(LLRect(left, top, right, bottom),
  767. bg_color);
  768. S32 cur_offset = top - 4;
  769. for (text_list_t::iterator iter = mText.begin(); iter != text_end; ++iter)
  770. {
  771. mFont->renderUTF8(*iter, 0, left + 10, cur_offset,
  772. text_color, LLFontGL::LEFT, LLFontGL::TOP);
  773. cur_offset -= llfloor(mFont->getLineHeight());
  774. }
  775. }
  776. void LLHoverView::setHoverActive(bool active)
  777. {
  778. if (active != mHoverActive)
  779. {
  780. mHoverTimer.reset();
  781. }
  782. mHoverActive = active;
  783. if (active)
  784. {
  785. mHoverPos = gViewerWindowp->getCurrentMouse();
  786. }
  787. else
  788. {
  789. mLastObjectWithFullText = NULL;
  790. mLastParcelWithFullText = NULL;
  791. }
  792. }
  793. LLViewerObject* LLHoverView::getLastHoverObject() const
  794. {
  795. if (mLastHoverObject.notNull() && !mLastHoverObject->isDead())
  796. {
  797. return mLastHoverObject;
  798. }
  799. else
  800. {
  801. return NULL;
  802. }
  803. }