llfloaterworldmap.cpp 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240
  1. /**
  2. * @file llfloaterworldmap.cpp
  3. * @brief LLFloaterWorldMap class implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. *
  7. * Copyright (c) 2003-2009, Linden Research, Inc.
  8. * Original authors: James Cook, Tom Yedwab
  9. * Copyright (c) 2009-2021, Henri Beauchamp.
  10. * Changes by Henri Beauchamp:
  11. * - Backported web map tiles support from v2/3 viewers while keeping the old
  12. * terrain-only map support.
  13. * - Adapted the code for OpenSim variable region size support.
  14. * - Added code to save map tiles images and their 3D terrain as scuplties.
  15. * - Allowed to keep the map tiles in memory when the floater is closed.
  16. * - Added context menu entries to reload a map given tile or all map tiles.
  17. * - Allowed to keep both objects and terrain map tiles in memory (avoids
  18. * seeing the map tiles fully reloaded at each world map tab change).
  19. *
  20. * Second Life Viewer Source Code
  21. * The source code in this file ("Source Code") is provided by Linden Lab
  22. * to you under the terms of the GNU General Public License, version 2.0
  23. * ("GPL"), unless you have obtained a separate licensing agreement
  24. * ("Other License"), formally executed by you and Linden Lab. Terms of
  25. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  26. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  27. *
  28. * There are special exceptions to the terms and conditions of the GPL as
  29. * it is applied to this Source Code. View the full text of the exception
  30. * in the file doc/FLOSS-exception.txt in this software distribution, or
  31. * online at
  32. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  33. *
  34. * By copying, modifying or distributing this software, you acknowledge
  35. * that you have read and understood your obligations described above,
  36. * and agree to abide by those obligations.
  37. *
  38. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  39. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  40. * COMPLETENESS OR PERFORMANCE.
  41. * $/LicenseInfo$
  42. */
  43. /*
  44. * Map of the entire world, with multiple background images,
  45. * avatar tracking, teleportation by double-click, etc.
  46. */
  47. #include "llviewerprecompiledheaders.h"
  48. #include "llfloaterworldmap.h"
  49. #include "llbutton.h"
  50. #include "llcachename.h"
  51. #include "llcallbacklist.h"
  52. #include "llcombobox.h"
  53. #include "lldraghandle.h"
  54. #include "llgl.h"
  55. #include "lliconctrl.h"
  56. #include "llimagetga.h"
  57. #include "lllineeditor.h"
  58. #include "llnotifications.h"
  59. #include "llscrolllistctrl.h"
  60. #include "llsliderctrl.h"
  61. #include "llspinctrl.h"
  62. #include "lltextbox.h"
  63. #include "lluictrlfactory.h"
  64. #include "llagent.h"
  65. #include "llappviewer.h"
  66. #include "llavatartracker.h"
  67. #include "llcommandhandler.h"
  68. #include "llfirstuse.h"
  69. #include "llgridmanager.h" // For gIsInSecondLife
  70. #include "llinventorymodelfetch.h"
  71. #include "lllandmarklist.h"
  72. #include "llpanelworldmap.h"
  73. #include "llpreviewlandmark.h"
  74. #include "llregionhandle.h"
  75. //MK
  76. #include "mkrlinterface.h"
  77. //mk
  78. #include "llslurl.h"
  79. #include "llsurface.h"
  80. #include "lltracker.h"
  81. #include "hbviewerautomation.h"
  82. #include "llviewercontrol.h"
  83. #include "llviewermenu.h"
  84. #include "llviewerparcelmgr.h"
  85. #include "llviewerregion.h"
  86. #include "llviewerstats.h"
  87. #include "llviewertexture.h"
  88. #include "llviewerwindow.h"
  89. #include "llweb.h"
  90. #include "llworld.h"
  91. #include "llworldmap.h"
  92. using namespace LLOldEvents;
  93. //---------------------------------------------------------------------------
  94. // Constants
  95. //---------------------------------------------------------------------------
  96. constexpr F32 MAP_ZOOM_TIME = 0.2f;
  97. enum EPanDirection
  98. {
  99. PAN_UP,
  100. PAN_DOWN,
  101. PAN_LEFT,
  102. PAN_RIGHT
  103. };
  104. constexpr F32 ZOOM_MAX = 0.f;
  105. constexpr F32 SIM_COORD_DEFAULT = 128.f;
  106. constexpr F32 GODLY_TELEPORT_HEIGHT = 200.f;
  107. //---------------------------------------------------------------------------
  108. // Globals
  109. //---------------------------------------------------------------------------
  110. // Instance created in LLViewerWindow::initWorldUI()
  111. LLFloaterWorldMap* gFloaterWorldMapp = NULL;
  112. // Handles secondlife:///app/worldmap/{NAME}/{COORDS} URLs
  113. class LLWorldMapHandler final : public LLCommandHandler
  114. {
  115. public:
  116. LLWorldMapHandler()
  117. : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE)
  118. {
  119. }
  120. bool canHandleUntrusted(const LLSD&, const LLSD&, LLMediaCtrl*,
  121. const std::string& nav_type) override
  122. {
  123. // With UNTRUSTED_THROTTLE this will cause "clicked" to pass,
  124. // "external" to be throttled, and the rest to be blocked.
  125. return nav_type == "clicked" || nav_type == "external";
  126. }
  127. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
  128. {
  129. size_t count = params.size();
  130. if (!count)
  131. {
  132. // Support the secondlife:///app/worldmap SLapp
  133. LLFloaterWorldMap::show(NULL, true);
  134. return true;
  135. }
  136. // Support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp
  137. const std::string region_name = LLURI::unescape(params[0].asString());
  138. S32 x = count > 1 ? params[1].asInteger() : 128;
  139. S32 y = count > 2 ? params[2].asInteger() : 128;
  140. S32 z = count > 3 ? params[3].asInteger() : 0;
  141. if (gFloaterWorldMapp)
  142. {
  143. gFloaterWorldMapp->trackURL(region_name, x, y, z);
  144. }
  145. LLFloaterWorldMap::show(NULL, true);
  146. return true;
  147. }
  148. };
  149. LLWorldMapHandler gWorldMapHandler;
  150. // SocialMap handler secondlife:///app/maptrackavatar/id
  151. class LLMapTrackAvatarHandler final : public LLCommandHandler
  152. {
  153. public:
  154. LLMapTrackAvatarHandler()
  155. : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)
  156. {
  157. }
  158. bool canHandleUntrusted(const LLSD& params, const LLSD&, LLMediaCtrl*,
  159. const std::string& nav_type) override
  160. {
  161. if (!params.size())
  162. {
  163. return true; // Do not block here; it will fail in handle().
  164. }
  165. // With UNTRUSTED_THROTTLE this will cause "clicked" to pass,
  166. // "external" to be throttled, and the rest to be blocked.
  167. return nav_type == "clicked" || nav_type == "external";
  168. }
  169. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
  170. {
  171. // Make sure we have some parameters
  172. if (!params.size())
  173. {
  174. return false;
  175. }
  176. // Get the ID
  177. LLUUID id;
  178. if (!id.set(params[0], false))
  179. {
  180. return false;
  181. }
  182. if (gFloaterWorldMapp && gCacheNamep)
  183. {
  184. std::string name;
  185. gCacheNamep->getFullName(id, name);
  186. gFloaterWorldMapp->trackAvatar(id, name);
  187. LLFloaterWorldMap::show(NULL, true);
  188. }
  189. return true;
  190. }
  191. };
  192. LLMapTrackAvatarHandler gMapTrackAvatar;
  193. class LLMapInventoryObserver final : public LLInventoryObserver
  194. {
  195. public:
  196. LLMapInventoryObserver() {}
  197. ~LLMapInventoryObserver() override {}
  198. void changed(U32 mask) override;
  199. };
  200. void LLMapInventoryObserver::changed(U32 mask)
  201. {
  202. // If there is a change we are interested in.
  203. constexpr U32 interests_mask = LLInventoryObserver::CALLING_CARD |
  204. LLInventoryObserver::ADD |
  205. LLInventoryObserver::REMOVE;
  206. if (gFloaterWorldMapp && (mask & interests_mask) != 0)
  207. {
  208. gFloaterWorldMapp->inventoryChanged();
  209. }
  210. }
  211. class LLMapFriendObserver final : public LLFriendObserver
  212. {
  213. public:
  214. LLMapFriendObserver() = default;
  215. void changed(U32 mask) override
  216. {
  217. // If there is a change we are interested in.
  218. if (gFloaterWorldMapp &&
  219. (mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE |
  220. LLFriendObserver::ONLINE |
  221. LLFriendObserver::POWERS)) != 0)
  222. {
  223. gFloaterWorldMapp->friendsChanged();
  224. }
  225. }
  226. };
  227. class LLMapParcelInfoObserver final : public LLParcelInfoObserver
  228. {
  229. protected:
  230. LOG_CLASS(LLMapParcelInfoObserver);
  231. public:
  232. LLMapParcelInfoObserver(const LLVector3d& pos_global)
  233. : LLParcelInfoObserver(),
  234. mPosGlobal(pos_global)
  235. {
  236. }
  237. ~LLMapParcelInfoObserver() override
  238. {
  239. // Remove old observer, if any.
  240. gViewerParcelMgr.removeInfoObserver(mParcelID, this);
  241. }
  242. void processParcelInfo(const LLParcelData& parcel_data) override
  243. {
  244. if (parcel_data.mParcelId != mParcelID) return;
  245. // Remove old observer, if any.
  246. gViewerParcelMgr.removeInfoObserver(mParcelID, this);
  247. if (gFloaterWorldMapp && !parcel_data.mName.empty() &&
  248. gTracker.getTrackedPositionGlobal() == mPosGlobal &&
  249. gTracker.getTrackedLocationType() == LLTracker::LOCATION_NOTHING &&
  250. gTracker.getTrackingStatus() == LLTracker::TRACKING_LOCATION &&
  251. !gFloaterWorldMapp->getRequestedParcelInfoGlobalPos().isExactlyZero())
  252. {
  253. gFloaterWorldMapp->trackLocation(mPosGlobal, parcel_data.mName);
  254. }
  255. }
  256. void setParcelID(const LLUUID& parcel_id) override
  257. {
  258. // Remove old observer, if any.
  259. gViewerParcelMgr.removeInfoObserver(mParcelID, this);
  260. // Set new parcel Id, observe and request info.
  261. mParcelID = parcel_id;
  262. gViewerParcelMgr.addInfoObserver(mParcelID, this);
  263. gViewerParcelMgr.sendParcelInfoRequest(mParcelID);
  264. }
  265. void setErrorStatus(S32 status, const std::string& reason) override
  266. {
  267. gViewerParcelMgr.removeInfoObserver(mParcelID, this);
  268. llwarns << "Could not retrieve parcel info. Status: " << status
  269. << " - Reason: " << reason << llendl;
  270. }
  271. private:
  272. LLVector3d mPosGlobal;
  273. LLUUID mParcelID;
  274. };
  275. //---------------------------------------------------------------------------
  276. // Statics
  277. //---------------------------------------------------------------------------
  278. LLSimInfo* LLFloaterWorldMap::sRightClickedSimInfo = NULL;
  279. LLPointer<LLViewerFetchedTexture> LLFloaterWorldMap::sImageToSave;
  280. LLSurface* LLFloaterWorldMap::sSurfaceToMap = NULL;
  281. U32 LLFloaterWorldMap::sRegionWidth = (U32)REGION_WIDTH_METERS;
  282. bool LLFloaterWorldMap::sSaveAsDecal = false;
  283. bool LLFloaterWorldMap::sSaveAsSpheric = false;
  284. std::string LLFloaterWorldMap::sSaveFileName;
  285. // Used as a pretend asset and inventory id to mean "landmark at my home
  286. // location."
  287. const LLUUID LLFloaterWorldMap::sHomeID("10000000-0000-0000-0000-000000000001");
  288. //---------------------------------------------------------------------------
  289. // Construction and destruction
  290. //---------------------------------------------------------------------------
  291. LLFloaterWorldMap::LLFloaterWorldMap()
  292. : LLFloater("map"),
  293. mFirstOpen(true),
  294. mInventory(NULL),
  295. mInventoryObserver(NULL),
  296. mFriendObserver(NULL),
  297. mParcelInfoObserver(NULL),
  298. mWaitingForTracker(false),
  299. mExactMatch(false),
  300. mIsClosing(false),
  301. mSetToUserPosition(true),
  302. mTrackedStatus(LLTracker::TRACKING_NOTHING)
  303. {
  304. LLCallbackMap::map_t factory_map;
  305. factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView,
  306. (void*)0);
  307. factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView,
  308. (void*)1);
  309. LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml",
  310. &factory_map, false);
  311. // Register event listeners for popup menu. HB
  312. (new LLReloadAllTiles())->registerListener(this,
  313. "WorldMap.ReloadAllTiles");
  314. (new LLReloadTile())->registerListener(this, "WorldMap.ReloadTile");
  315. (new LLSaveMapTile())->registerListener(this, "WorldMap.SaveMapTile");
  316. (new LLSaveSculpt())->registerListener(this, "WorldMap.SaveSculpt");
  317. LLMenuGL* menu =
  318. LLUICtrlFactory::getInstance()->buildMenu("menu_world_map.xml", this);
  319. if (!menu)
  320. {
  321. menu = new LLMenuGL(LLStringUtil::null);
  322. }
  323. menu->setVisible(false);
  324. mPopupMenuHandle = menu->getHandle();
  325. }
  326. //static
  327. void* LLFloaterWorldMap::createWorldMapView(void* data)
  328. {
  329. U32 layer = (intptr_t)data;
  330. return new LLPanelWorldMap(llformat("map layer %u", layer),
  331. LLRect(0, 300, 400, 0), layer);
  332. }
  333. bool LLFloaterWorldMap::postBuild()
  334. {
  335. mTabs = getChild<LLTabContainer>("maptab");
  336. LLPanel* panel = mTabs->getChild<LLPanel>("objects_mapview");
  337. mTabs->setTabChangeCallback(panel, onTabChanged);
  338. mTabs->setTabUserData(panel, this);
  339. panel = mTabs->getChild<LLPanel>("terrain_mapview");
  340. mTabs->setTabChangeCallback(panel, onTabChanged);
  341. mTabs->setTabUserData(panel, this);
  342. mFriendCombo = getChild<LLComboBox>("friend combo");
  343. mFriendCombo->setCommitCallback(onAvatarComboCommit);
  344. mFriendCombo->setCallbackUserData(this);
  345. mFriendCombo->selectFirstItem();
  346. mFriendCombo->setPrearrangeCallback(onAvatarComboPrearrange);
  347. mFriendCombo->setTextEntryCallback(onComboTextEntry);
  348. mEventsMatureIcon = getChild<LLIconCtrl>("events_mature_icon");
  349. mEventsAdultIcon = getChild<LLIconCtrl>("events_adult_icon");
  350. mEventsMatureCheck = getChild<LLCheckBoxCtrl>("event_mature_chk");
  351. mEventsAdultCheck = getChild<LLCheckBoxCtrl>("event_adult_chk");
  352. mAvatarIcon = getChild<LLIconCtrl>("avatar_icon");
  353. mLandmarkIcon = getChild<LLIconCtrl>("landmark_icon");
  354. mLocationIcon = getChild<LLIconCtrl>("location_icon");
  355. childSetAction("DoSearch", onLocationCommit, this);
  356. mLocationEditor = getChild<LLSearchEditor>("location");
  357. mLocationEditor->setSearchCallback(onSearchTextEntry, this);
  358. mLocationEditor->setFocusChangedCallback(onLocationFocusChanged, this);
  359. mSearchResultsList = getChild<LLScrollListCtrl>("search_results");
  360. mSearchResultsList->setCommitCallback(onCommitSearchResult);
  361. mSearchResultsList->setCallbackUserData(this);
  362. mSearchResultsList->setDoubleClickCallback(onClickTeleportBtn);
  363. mSpinX = getChild<LLSpinCtrl>("spin x");
  364. mSpinX->setCommitCallback(onCommitLocation);
  365. mSpinX->setCallbackUserData(this);
  366. mSpinY = getChild<LLSpinCtrl>("spin y");
  367. mSpinY->setCommitCallback(onCommitLocation);
  368. mSpinY->setCallbackUserData(this);
  369. mSpinZ = getChild<LLSpinCtrl>("spin z");
  370. mSpinZ->setCommitCallback(onCommitLocation);
  371. mSpinZ->setCallbackUserData(this);
  372. mLandmarkCombo = getChild<LLComboBox>("landmark combo");
  373. mLandmarkCombo->setCommitCallback(onLandmarkComboCommit);
  374. mLandmarkCombo->setCallbackUserData(this);
  375. mLandmarkCombo->selectFirstItem();
  376. mLandmarkCombo->setPrearrangeCallback(onLandmarkComboPrearrange);
  377. mLandmarkCombo->setTextEntryCallback(onComboTextEntry);
  378. mGoHomeButton = getChild<LLButton>("Go Home");
  379. mGoHomeButton->setClickedCallback(onGoHome, this);
  380. mTeleportButton = getChild<LLButton>("Teleport");
  381. mTeleportButton->setClickedCallback(onClickTeleportBtn, this);
  382. mShowDestinationButton = getChild<LLButton>("Show Destination");
  383. mShowDestinationButton->setClickedCallback(onShowTargetBtn, this);
  384. childSetAction("Show My Location", onShowAgentBtn, this);
  385. childSetAction("Clear", onClearBtn, this);
  386. mCopySLURLButton = getChild<LLButton>("copy_slurl");
  387. mCopySLURLButton->setClickedCallback(onCopySLURL, this);
  388. mCurZoomVal = logf(LLPanelWorldMap::sMapScale) / (F_LN2 * 256.f);
  389. mZoomSlider = getChild<LLSliderCtrl>("zoom slider");
  390. mZoomSlider->setValue(mCurZoomVal);
  391. setDefaultBtn((LLButton*)NULL);
  392. mZoomTimer.stop();
  393. mTeleportArrivingConnection =
  394. gViewerParcelMgr.setTPArrivingCallback(boost::bind(&LLFloaterWorldMap::onTeleportArriving));
  395. return true;
  396. }
  397. //virtual
  398. LLFloaterWorldMap::~LLFloaterWorldMap()
  399. {
  400. mTeleportArrivingConnection.disconnect();
  401. // All cleaned up by LLView destructor
  402. mTabs = NULL;
  403. clearParcelInfoRequest();
  404. // Inventory deletes all observers on shutdown
  405. mInventory = NULL;
  406. mInventoryObserver = NULL;
  407. // Avatar tracker will delete this for us.
  408. mFriendObserver = NULL;
  409. llinfos << "World map destroyed" << llendl;
  410. gFloaterWorldMapp = NULL;
  411. }
  412. //virtual
  413. void LLFloaterWorldMap::onOpen()
  414. {
  415. if (mFirstOpen)
  416. {
  417. mFirstOpen = false;
  418. // Reposition floater from saved settings
  419. LLRect rect = gSavedSettings.getRect("FloaterWorldMapRect2");
  420. reshape(rect.getWidth(), rect.getHeight(), false);
  421. setRect(rect);
  422. // Sadly, OpenSim grids do not provide terrain-only tiles. HB
  423. if (!gIsInSecondLife &&
  424. !gSavedSettings.getBool("OSWorldMapHasTerrain"))
  425. {
  426. LLPanel* panel = mTabs->getChild<LLPanel>("terrain_mapview", true,
  427. false);
  428. if (panel) // Paranoia
  429. {
  430. mTabs->removeTabPanel(panel);
  431. delete panel;
  432. }
  433. }
  434. }
  435. }
  436. //virtual
  437. void LLFloaterWorldMap::onClose(bool app_quitting)
  438. {
  439. setVisible(false);
  440. }
  441. //static
  442. void LLFloaterWorldMap::onTeleportArriving()
  443. {
  444. if (gFloaterWorldMapp && !gFloaterWorldMapp->isMinimized() &&
  445. gSavedSettings.getBool("HideFloatersOnTPSuccess"))
  446. {
  447. hide(NULL);
  448. }
  449. }
  450. //static
  451. void LLFloaterWorldMap::show(void*, bool center_on_target)
  452. {
  453. if (!gFloaterWorldMapp) return;
  454. //MK
  455. if (gRLenabled &&
  456. (gRLInterface.mContainsShowworldmap || gRLInterface.mContainsShowloc))
  457. {
  458. return;
  459. }
  460. //mk
  461. bool was_visible = gFloaterWorldMapp->getVisible();
  462. gFloaterWorldMapp->mIsClosing = false;
  463. gFloaterWorldMapp->open();
  464. LLPanelWorldMap* panelp =
  465. (LLPanelWorldMap*)gFloaterWorldMapp->mTabs->getCurrentPanel();
  466. if (!panelp) return; // Paranoia (or bad world map menu XML...)
  467. panelp->clearLastClick();
  468. if (!was_visible)
  469. {
  470. // Reset pan on show, so it centers on you again
  471. if (!center_on_target)
  472. {
  473. LLPanelWorldMap::setPan(0, 0, true);
  474. }
  475. // Reload the agent positions when we show the window
  476. gWorldMap.eraseItems();
  477. // Reload any maps that may have changed
  478. gWorldMap.clearSimFlags();
  479. const U32 panel_num = gFloaterWorldMapp->mTabs->getCurrentPanelIndex();
  480. constexpr bool request_from_sim = true;
  481. gWorldMap.setCurrentLayer(panel_num, request_from_sim);
  482. // We may already have a bounding box for the regions of the world, so
  483. // use that to adjust the view.
  484. gFloaterWorldMapp->adjustZoomSliderBounds();
  485. // Could be first show
  486. LLFirstUse::useMap();
  487. // Start speculative download of landmarks
  488. const LLUUID& lm_folder_id =
  489. gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
  490. LLInventoryModelFetch::getInstance()->start(lm_folder_id);
  491. gFloaterWorldMapp->mLocationEditor->setFocus(true);
  492. gFocusMgr.triggerFocusFlash();
  493. gFloaterWorldMapp->buildAvatarIDList();
  494. gFloaterWorldMapp->buildLandmarkIDLists();
  495. // If nothing is being tracked, set flag so the user position will be
  496. // found
  497. gFloaterWorldMapp->mSetToUserPosition =
  498. (gTracker.getTrackingStatus() == LLTracker::TRACKING_NOTHING);
  499. panelp->updateVisibleBlocks();
  500. }
  501. if (center_on_target)
  502. {
  503. gFloaterWorldMapp->centerOnTarget(false);
  504. }
  505. }
  506. //static
  507. void LLFloaterWorldMap::reloadIcons(void*)
  508. {
  509. gWorldMap.eraseItems();
  510. gWorldMap.sendMapLayerRequest();
  511. }
  512. //static
  513. void LLFloaterWorldMap::toggle(void*)
  514. {
  515. if (!gFloaterWorldMapp) return;
  516. bool visible = gFloaterWorldMapp->getVisible();
  517. if (!visible)
  518. {
  519. show(NULL, false);
  520. }
  521. else
  522. {
  523. gFloaterWorldMapp->mIsClosing = true;
  524. gFloaterWorldMapp->close();
  525. }
  526. }
  527. //static
  528. void LLFloaterWorldMap::hide(void*)
  529. {
  530. if (gFloaterWorldMapp)
  531. {
  532. gFloaterWorldMapp->mIsClosing = true;
  533. gFloaterWorldMapp->close();
  534. }
  535. }
  536. //virtual
  537. void LLFloaterWorldMap::setVisible(bool visible)
  538. {
  539. LLFloater::setVisible(visible);
  540. gSavedSettings.setBool("ShowWorldMap", visible);
  541. if (!visible && !gSavedSettings.getBool("KeepWorldMapTilesOnClose"))
  542. {
  543. // While we are not visible, discard the overlay images we are using
  544. gWorldMap.clearImageRefs();
  545. }
  546. }
  547. bool LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
  548. {
  549. if (!isMinimized() && isFrontmost())
  550. {
  551. LLRect area = mSearchResultsList->getRect();
  552. if (!area.pointInRect(x, y))
  553. {
  554. F32 slider_value = mZoomSlider->getValue().asReal();
  555. slider_value += ((F32)clicks * -0.3333f);
  556. mZoomSlider->setValue(LLSD(slider_value));
  557. return true;
  558. }
  559. }
  560. return LLFloater::handleScrollWheel(x, y, clicks);
  561. }
  562. //virtual
  563. bool LLFloaterWorldMap::handleMouseUp(S32 x, S32 y, MASK mask)
  564. {
  565. if (hasMouseCapture())
  566. {
  567. gViewerWindowp->showCursor();
  568. gFocusMgr.setMouseCapture(NULL);
  569. return true;
  570. }
  571. return false;
  572. }
  573. //virtual
  574. bool LLFloaterWorldMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
  575. {
  576. LLPanelWorldMap* panelp =
  577. (LLPanelWorldMap*)gFloaterWorldMapp->mTabs->getCurrentPanel();
  578. if (!panelp) // No panel... Bad floater UI xml ?
  579. {
  580. return LLFloater::handleRightMouseDown(x, y, mask);
  581. }
  582. // When the click is out of the map panel, let the UI handle it
  583. LLRect panel_rect = panelp->getRect();
  584. if (x > panel_rect.mRight + panel_rect.mLeft)
  585. {
  586. return LLFloater::handleRightMouseDown(x, y, mask);
  587. }
  588. if (sImageToSave.notNull() || sSurfaceToMap)
  589. {
  590. // There is already a tile being saved, ignore this event
  591. return true;
  592. }
  593. // Find the clicked global position in the grid
  594. LLVector3d loc = panelp->viewPosToGlobal(x, y);
  595. // Find and save the sim info for the right-clicked tile
  596. sRightClickedSimInfo = gWorldMap.simInfoFromPosGlobal(loc);
  597. if (!sRightClickedSimInfo)
  598. {
  599. return false; // No sim here: abort
  600. }
  601. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
  602. if (menu)
  603. {
  604. menu->buildDrawLabels();
  605. menu->updateParent(gMenuHolderp);
  606. LLMenuGL::showPopup(this, menu, x, y);
  607. }
  608. return true;
  609. }
  610. //static
  611. bool LLFloaterWorldMap::LLReloadAllTiles::handleEvent(LLPointer<LLEvent>,
  612. const LLSD&)
  613. {
  614. gWorldMap.clearImageRefs(gWorldMap.getCurrentLayer());
  615. gWorldMap.clearSimFlags();
  616. return true;
  617. }
  618. //static
  619. bool LLFloaterWorldMap::LLReloadTile::handleEvent(LLPointer<LLEvent>,
  620. const LLSD&)
  621. {
  622. if (LLFloaterWorldMap::sRightClickedSimInfo)
  623. {
  624. U64 handle = LLFloaterWorldMap::sRightClickedSimInfo->mHandle;
  625. gWorldMap.forceUpdateRegion(handle);
  626. }
  627. return true;
  628. }
  629. //static
  630. void LLFloaterWorldMap::saveTileCallback(HBFileSelector::ESaveFilter type,
  631. std::string& filename, void*)
  632. {
  633. if (filename.empty())
  634. {
  635. sImageToSave = NULL;
  636. return;
  637. }
  638. if (sImageToSave.isNull())
  639. {
  640. return;
  641. }
  642. sSaveFileName = filename;
  643. LLStringUtil::toLower(filename);
  644. if (filename.rfind(".tga") != filename.length() - 4)
  645. {
  646. sSaveFileName += ".tga";
  647. }
  648. // Re-fetch the raw image if the old one is removed.
  649. sImageToSave->forceToSaveRawImage(0);
  650. sImageToSave->setLoadedCallback(onTileLoadedForSave, 0, true, false, NULL,
  651. NULL);
  652. }
  653. //static
  654. void LLFloaterWorldMap::onTileLoadedForSave(bool success,
  655. LLViewerFetchedTexture* src_vi,
  656. LLImageRaw* src, LLImageRaw*,
  657. S32 discard_level, bool is_final,
  658. void*)
  659. {
  660. if (is_final && success)
  661. {
  662. // This is needed to avoid seeing the raw image vanishing on us !
  663. LLPointer<LLImageRaw> source = src;
  664. if (sSaveAsDecal)
  665. {
  666. // Make a duplicate to keep the original raw image untouched:
  667. source = source->duplicate();
  668. LLPointer<LLImageRaw> decal;
  669. bool success = source->scale(240, 240, true);
  670. if (success)
  671. {
  672. decal = new LLImageRaw(256, 256, source->getComponents());
  673. if (decal.isNull())
  674. {
  675. success = false;
  676. }
  677. }
  678. if (success)
  679. {
  680. decal->fill(LLColor4U(0, 0, 0, 1));
  681. success = decal->setSubImage(8, 8, 240, 240,
  682. source->getData());
  683. source = decal.get();
  684. }
  685. if (!success)
  686. {
  687. gNotifications.add("CannotRescaleImage");
  688. sImageToSave = NULL;
  689. return;
  690. }
  691. }
  692. LLSD args;
  693. args["FILE"] = sSaveFileName;
  694. LLPointer<LLImageTGA> image_tga = new LLImageTGA;
  695. if (!image_tga->encode(source))
  696. {
  697. gNotifications.add("CannotEncodeFile", args);
  698. }
  699. else if (!image_tga->save(sSaveFileName))
  700. {
  701. gNotifications.add("CannotWriteFile", args);
  702. }
  703. else
  704. {
  705. gNotifications.add("FileSaved", args);
  706. }
  707. sImageToSave = NULL;
  708. }
  709. else if (!success)
  710. {
  711. gNotifications.add("CannotDownloadFile");
  712. sImageToSave = NULL;
  713. }
  714. }
  715. //static
  716. bool LLFloaterWorldMap::LLSaveMapTile::handleEvent(LLPointer<LLEvent>,
  717. const LLSD& userdata)
  718. {
  719. LLSimInfo* infop = LLFloaterWorldMap::sRightClickedSimInfo;
  720. if (!infop) return true;
  721. // Get the image for that sim
  722. LLFloaterWorldMap::sImageToSave =
  723. infop->mCurrentImage[gWorldMap.getCurrentLayer()];
  724. if (!LLFloaterWorldMap::sImageToSave) return true;
  725. // Call the file selector
  726. std::string suggestion = infop->mName;
  727. LLFloaterWorldMap::sSaveAsDecal = userdata.asInteger() > 0;
  728. if (LLFloaterWorldMap::sSaveAsDecal)
  729. {
  730. suggestion += "Decal";
  731. }
  732. HBFileSelector::saveFile(HBFileSelector::FFSAVE_TGA, suggestion,
  733. saveTileCallback);
  734. return true;
  735. }
  736. //static
  737. void LLFloaterWorldMap::saveSculptCallback(HBFileSelector::ESaveFilter type,
  738. std::string& filename, void*)
  739. {
  740. if (filename.empty())
  741. {
  742. sSurfaceToMap = NULL;
  743. return;
  744. }
  745. if (!sSurfaceToMap)
  746. {
  747. return;
  748. }
  749. constexpr S32 SCULPT_PIXELS = 64;
  750. LLPointer<LLImageRaw> sculpt = new LLImageRaw(SCULPT_PIXELS,
  751. SCULPT_PIXELS, 3);
  752. if (sculpt.isNull())
  753. {
  754. llwarns << "Out of memory creating a 64x64 sculpt map !" << llendl;
  755. return;
  756. }
  757. U8* data = sculpt->getData();
  758. // Get the region height data to compute bottom altitude and Z scale
  759. S32 min_z = sSurfaceToMap->getMinZ();
  760. S32 max_z = sSurfaceToMap->getMaxZ();
  761. S32 scale = (max_z - min_z) / 256 + 1;
  762. if (max_z <= 255)
  763. {
  764. min_z = 0;
  765. }
  766. // Construct the final filename
  767. sSaveFileName = filename;
  768. // remove the .tga extension, if any
  769. LLStringUtil::toLower(filename);
  770. size_t i = filename.rfind(".tga");
  771. if (i == filename.length() - 4)
  772. {
  773. sSaveFileName = sSaveFileName.substr(0, i);
  774. }
  775. // Adjust the name to add the scale and minimum Z data
  776. if (scale != 1)
  777. {
  778. sSaveFileName += llformat("_S%d", scale);
  779. }
  780. if (min_z != 0)
  781. {
  782. sSaveFileName += llformat("_B%d", min_z);
  783. }
  784. // Add the .tga extension
  785. sSaveFileName += ".tga";
  786. // Fill-up the sculpt map
  787. S32 increment = sRegionWidth / SCULPT_PIXELS;
  788. // To get the altitude at the center of each land patch:
  789. S32 delta = increment / 2;
  790. for (S32 y = 0; y < (S32)sRegionWidth - 1; y += increment)
  791. {
  792. for (S32 x = 0; x < (S32)sRegionWidth - 1; x += increment)
  793. {
  794. *data++ = (U8)x;
  795. *data++ = (U8)y;
  796. if (sSaveAsSpheric &&
  797. (x < 2 || y < 2 || x >= (S32)sRegionWidth - 2 * increment ||
  798. y >= (S32)sRegionWidth - 2 * increment))
  799. {
  800. *data++ = 0;
  801. }
  802. else
  803. {
  804. S32 height = sSurfaceToMap->resolveHeightRegion(x + delta,
  805. y + delta);
  806. *data++ = (U8)((height - min_z) / scale);
  807. }
  808. }
  809. }
  810. // Save the sculpt map now...
  811. LLSD args;
  812. args["FILE"] = sSaveFileName;
  813. LLPointer<LLImageTGA> image_tga = new LLImageTGA;
  814. if (!image_tga->encode(sculpt))
  815. {
  816. gNotifications.add("CannotEncodeFile", args);
  817. }
  818. else if (!image_tga->save(sSaveFileName))
  819. {
  820. gNotifications.add("CannotWriteFile", args);
  821. }
  822. else
  823. {
  824. gNotifications.add("FileSaved", args);
  825. }
  826. sSurfaceToMap = NULL;
  827. }
  828. //static
  829. bool LLFloaterWorldMap::LLSaveSculpt::handleEvent(LLPointer<LLEvent>,
  830. const LLSD& userdata)
  831. {
  832. LLSimInfo* infop = LLFloaterWorldMap::sRightClickedSimInfo;
  833. if (!infop) return true;
  834. // Get the surface for that sim
  835. U64 handle = infop->mHandle;
  836. LLViewerRegion* regionp = gWorld.getRegionFromHandle(handle);
  837. if (!regionp)
  838. {
  839. gNotifications.add("NoDataForRegion");
  840. return true;
  841. }
  842. LLFloaterWorldMap::sSurfaceToMap = &regionp->getLand();
  843. if (!LLFloaterWorldMap::sSurfaceToMap)
  844. {
  845. gNotifications.add("NoDataForRegion");
  846. return true;
  847. }
  848. LLFloaterWorldMap::sRegionWidth = (U32)regionp->getWidth();
  849. LLFloaterWorldMap::sSaveAsSpheric = userdata.asInteger() > 0;
  850. // Call the file selector
  851. std::string suggestion = infop->mName + "Sculpt";
  852. HBFileSelector::saveFile(HBFileSelector::FFSAVE_TGA, suggestion,
  853. saveSculptCallback);
  854. return true;
  855. }
  856. //virtual
  857. void LLFloaterWorldMap::draw()
  858. {
  859. //MK
  860. // Fast enough that it can be kept here
  861. if (gRLenabled &&
  862. (gRLInterface.mContainsShowworldmap || gRLInterface.mContainsShowloc))
  863. {
  864. setVisible(false);
  865. return;
  866. }
  867. //mk
  868. // Hide/Show Mature Events controls
  869. bool can_access_mature = gAgent.canAccessMature();
  870. bool adult_enabled = gAgent.canAccessAdult();
  871. mEventsMatureIcon->setVisible(can_access_mature);
  872. mEventsAdultIcon->setVisible(can_access_mature);
  873. mEventsMatureCheck->setVisible(can_access_mature);
  874. mEventsAdultCheck->setVisible(can_access_mature);
  875. mEventsAdultCheck->setEnabled(adult_enabled);
  876. if (!adult_enabled)
  877. {
  878. mEventsAdultCheck->setValue(false);
  879. }
  880. // On orientation island, users do not have a home location yet, so
  881. // do not let them teleport "home". It dumps them in an often-crowed
  882. // welcome area (infohub) and they get confused. JC
  883. LLViewerRegion* regionp = gAgent.getRegion();
  884. bool agent_on_prelude = regionp && regionp->isPrelude();
  885. bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude;
  886. mGoHomeButton->setEnabled(enable_go_home);
  887. updateLocation();
  888. LLTracker::ETrackingStatus tracking_status = gTracker.getTrackingStatus();
  889. if (tracking_status == LLTracker::TRACKING_AVATAR)
  890. {
  891. mAvatarIcon->setColor(LLUI::sTrackColor);
  892. }
  893. else
  894. {
  895. mAvatarIcon->setColor(LLUI::sDisabledTrackColor);
  896. }
  897. if (tracking_status == LLTracker::TRACKING_LANDMARK)
  898. {
  899. mLandmarkIcon->setColor(LLUI::sTrackColor);
  900. }
  901. else
  902. {
  903. mLandmarkIcon->setColor(LLUI::sDisabledTrackColor);
  904. }
  905. if (tracking_status == LLTracker::TRACKING_LOCATION)
  906. {
  907. mLocationIcon->setColor(LLUI::sTrackColor);
  908. }
  909. else if (!mCompletingRegionName.empty())
  910. {
  911. F32 seconds = LLTimer::getElapsedSeconds();
  912. F32 value = fmodf(seconds, 2);
  913. value = 0.5f + 0.5f * cosf(value * F_PI);
  914. LLColor4 loading_color(0.f, value * 0.5f, value, 1.f);
  915. mLocationIcon->setColor(loading_color);
  916. }
  917. else
  918. {
  919. mLocationIcon->setColor(LLUI::sDisabledTrackColor);
  920. }
  921. // check for completion of tracking data
  922. if (mWaitingForTracker)
  923. {
  924. centerOnTarget(true);
  925. }
  926. bool is_tracking = tracking_status != LLTracker::TRACKING_NOTHING;
  927. mTeleportButton->setEnabled(is_tracking);
  928. #if 0
  929. childSetEnabled("Clear", is_tracking);
  930. #endif
  931. mShowDestinationButton->setEnabled(is_tracking ||
  932. gWorldMap.mIsTrackingUnknownLocation);
  933. mCopySLURLButton->setEnabled(mSLURL.size() > 0);
  934. setMouseOpaque(true);
  935. getDragHandle()->setMouseOpaque(true);
  936. // RN: snaps to zoom value because interpolation caused jitter in the text
  937. // rendering
  938. if (!mZoomTimer.getStarted() &&
  939. mCurZoomVal != (F32)mZoomSlider->getValue().asReal())
  940. {
  941. mZoomTimer.start();
  942. }
  943. F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
  944. if (interp > 1.f)
  945. {
  946. interp = 1.f;
  947. mZoomTimer.stop();
  948. }
  949. mCurZoomVal = lerp(mCurZoomVal, (F32)mZoomSlider->getValue().asReal(),
  950. interp);
  951. F32 map_scale = 256.f * powf(2.f, mCurZoomVal);
  952. LLPanelWorldMap::setScale(map_scale);
  953. LLFloater::draw();
  954. }
  955. //-------------------------------------------------------------------------
  956. // Internal utility functions
  957. //-------------------------------------------------------------------------
  958. void LLFloaterWorldMap::trackAvatar(const LLUUID& avatar_id,
  959. const std::string& name)
  960. {
  961. clearParcelInfoRequest();
  962. buildAvatarIDList();
  963. if (mFriendCombo->setCurrentByID(avatar_id) || gAgent.isGodlike())
  964. {
  965. // *HACK: Adjust Z values automatically for liaisons & gods so
  966. // they swoop down when they click on the map. Requested
  967. // convenience.
  968. if (gAgent.isGodlike())
  969. {
  970. mSpinZ->setValue(GODLY_TELEPORT_HEIGHT);
  971. }
  972. // Do not re-request info if we already have it or we would not have it
  973. // in time to teleport
  974. if (mTrackedStatus != LLTracker::TRACKING_AVATAR ||
  975. mTrackedAvatarId != avatar_id)
  976. {
  977. mTrackedStatus = LLTracker::TRACKING_AVATAR;
  978. mTrackedAvatarId = avatar_id;
  979. gTracker.trackAvatar(avatar_id, name);
  980. }
  981. }
  982. else
  983. {
  984. gTracker.stopTracking();
  985. }
  986. setDefaultBtn(mTeleportButton);
  987. }
  988. void LLFloaterWorldMap::trackLandmark(const LLUUID& landmark_item_id)
  989. {
  990. clearParcelInfoRequest();
  991. buildLandmarkIDLists();
  992. bool found = false;
  993. S32 idx;
  994. S32 count = mLandmarkItemIDList.size();
  995. for (idx = 0; idx < count; ++idx)
  996. {
  997. if (mLandmarkItemIDList[idx] == landmark_item_id)
  998. {
  999. found = true;
  1000. break;
  1001. }
  1002. }
  1003. if (found && mLandmarkCombo->setCurrentByID(landmark_item_id))
  1004. {
  1005. const LLUUID& asset_id = mLandmarkAssetIDList[idx];
  1006. mTrackedStatus = LLTracker::TRACKING_LANDMARK;
  1007. gTracker.trackLandmark(asset_id, mLandmarkItemIDList[idx],
  1008. mLandmarkCombo->getSimple()); // Name
  1009. if (asset_id != sHomeID)
  1010. {
  1011. // Start the download process
  1012. gLandmarkList.getAsset(asset_id);
  1013. }
  1014. }
  1015. else
  1016. {
  1017. gTracker.stopTracking();
  1018. }
  1019. setDefaultBtn(mTeleportButton);
  1020. }
  1021. void LLFloaterWorldMap::trackEvent(const LLItemInfo& event_info)
  1022. {
  1023. clearParcelInfoRequest();
  1024. mTrackedStatus = LLTracker::TRACKING_LOCATION;
  1025. gTracker.trackLocation(event_info.mPosGlobal, event_info.mName,
  1026. event_info.mToolTip, LLTracker::LOCATION_EVENT);
  1027. setDefaultBtn(mTeleportButton);
  1028. }
  1029. void LLFloaterWorldMap::trackGenericItem(const LLItemInfo& item)
  1030. {
  1031. clearParcelInfoRequest();
  1032. mTrackedStatus = LLTracker::TRACKING_LOCATION;
  1033. gTracker.trackLocation(item.mPosGlobal, item.mName, item.mToolTip,
  1034. LLTracker::LOCATION_ITEM);
  1035. setDefaultBtn(mTeleportButton);
  1036. }
  1037. void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global,
  1038. const std::string& tooltip)
  1039. {
  1040. LLPanelWorldMap::setDefaultZ(pos_global.mdV[VZ]);
  1041. LLSimInfo* sim_info = gWorldMap.simInfoFromPosGlobal(pos_global);
  1042. if (!sim_info)
  1043. {
  1044. gTracker.stopTracking();
  1045. gWorldMap.mInvalidLocation = false;
  1046. gWorldMap.mIsTrackingUnknownLocation = true;
  1047. gWorldMap.mUnknownLocation = pos_global;
  1048. S32 world_x = S32(pos_global.mdV[VX] / (F64)REGION_WIDTH_METERS);
  1049. S32 world_y = S32(pos_global.mdV[VY] / (F64)REGION_WIDTH_METERS);
  1050. gWorldMap.sendMapBlockRequest(world_x, world_y, world_x, world_y,
  1051. true);
  1052. setDefaultBtn("");
  1053. return;
  1054. }
  1055. if (sim_info->mAccess == SIM_ACCESS_DOWN)
  1056. {
  1057. // Down sim. Show the blue circle of death !
  1058. gTracker.stopTracking();
  1059. gWorldMap.mInvalidLocation = true;
  1060. gWorldMap.mIsTrackingUnknownLocation = true;
  1061. gWorldMap.mUnknownLocation = pos_global;
  1062. setDefaultBtn("");
  1063. return;
  1064. }
  1065. // Force an update of the number of agents in this sim
  1066. sim_info->mAgentsUpdateTime = 0.0;
  1067. std::string sim_name;
  1068. gWorldMap.simNameFromPosGlobal(pos_global, sim_name);
  1069. // Variable region size support
  1070. U32 locX, locY;
  1071. from_region_handle(sim_info->getHandle(), &locX, &locY);
  1072. F32 region_x = pos_global.mdV[VX] - locX;
  1073. F32 region_y = pos_global.mdV[VY] - locY;
  1074. std::string full_name = llformat("%s (%d, %d, %d)", sim_name.c_str(),
  1075. ll_round(region_x), ll_round(region_y),
  1076. ll_round((F32)pos_global.mdV[VZ]));
  1077. mTrackedStatus = LLTracker::TRACKING_LOCATION;
  1078. gTracker.trackLocation(pos_global, full_name, tooltip);
  1079. gWorldMap.mIsTrackingUnknownLocation = false;
  1080. gWorldMap.mIsTrackingDoubleClick = false;
  1081. gWorldMap.mIsTrackingCommit = false;
  1082. requestParcelInfo(pos_global);
  1083. setDefaultBtn(mTeleportButton);
  1084. }
  1085. void LLFloaterWorldMap::requestParcelInfo(const LLVector3d& pos_global)
  1086. {
  1087. if (pos_global == mRequestedGlobalPos) return;
  1088. LLViewerRegion* regionp = gAgent.getRegion();
  1089. if (!regionp) return;
  1090. const std::string& url = regionp->getCapability("RemoteParcelRequest");
  1091. if (url.empty()) return;
  1092. mRequestedGlobalPos = pos_global;
  1093. if (mParcelInfoObserver)
  1094. {
  1095. delete mParcelInfoObserver;
  1096. }
  1097. mParcelInfoObserver = new LLMapParcelInfoObserver(pos_global);
  1098. LLVector3 pos_region((F32)fmod(pos_global.mdV[VX],
  1099. (F64)REGION_WIDTH_METERS),
  1100. (F32)fmod(pos_global.mdV[VY],
  1101. (F64)REGION_WIDTH_METERS),
  1102. (F32)pos_global.mdV[VZ]);
  1103. gViewerParcelMgr.requestRegionParcelInfo(url, regionp->getRegionID(),
  1104. pos_region, pos_global,
  1105. mParcelInfoObserver->getObserverHandle());
  1106. }
  1107. void LLFloaterWorldMap::clearParcelInfoRequest()
  1108. {
  1109. mRequestedGlobalPos.clear();
  1110. if (mParcelInfoObserver)
  1111. {
  1112. delete mParcelInfoObserver;
  1113. mParcelInfoObserver = NULL;
  1114. }
  1115. }
  1116. void LLFloaterWorldMap::updateLocationSpinners(const LLVector3d& pos,
  1117. LLVector3* local_pos)
  1118. {
  1119. // Convert global specified position to a local one
  1120. F32 region_local_x = (F32)fmod(pos.mdV[VX], (F64)REGION_WIDTH_METERS);
  1121. F32 region_local_y = (F32)fmod(pos.mdV[VY], (F64)REGION_WIDTH_METERS);
  1122. F32 region_local_z = (F32)pos.mdV[VZ];
  1123. // Support for variable size regions
  1124. LLSimInfo* sim_info = gWorldMap.simInfoFromPosGlobal(pos);
  1125. if (sim_info)
  1126. {
  1127. U32 loc_x, loc_y;
  1128. from_region_handle(sim_info->getHandle(), &loc_x, &loc_y);
  1129. region_local_x = pos.mdV[VX] - loc_x;
  1130. region_local_y = pos.mdV[VY] - loc_y;
  1131. }
  1132. mSpinX->setValue(LLSD(region_local_x));
  1133. mSpinY->setValue(LLSD(region_local_y));
  1134. mSpinZ->setValue(LLSD(region_local_z));
  1135. if (local_pos)
  1136. {
  1137. *local_pos = LLVector3(region_local_x, region_local_y, region_local_z);
  1138. }
  1139. }
  1140. void LLFloaterWorldMap::updateLocation()
  1141. {
  1142. bool got_sim_name;
  1143. LLTracker::ETrackingStatus status = gTracker.getTrackingStatus();
  1144. // These values may get updated by a message, so need to check them every
  1145. // frame. The fields may be changed by the user, so only update them if the
  1146. // data changes
  1147. LLVector3d pos_global = gTracker.getTrackedPositionGlobal();
  1148. if (pos_global.isExactlyZero())
  1149. {
  1150. LLVector3d agent_global_pos = gAgent.getPositionGlobal();
  1151. // Set to avatar's current postion if nothing is selected
  1152. if (status == LLTracker::TRACKING_NOTHING && mSetToUserPosition)
  1153. {
  1154. // Make sure we know where we are before setting the current user
  1155. // position
  1156. std::string agent_sim_name;
  1157. got_sim_name = gWorldMap.simNameFromPosGlobal(agent_global_pos,
  1158. agent_sim_name);
  1159. if (got_sim_name)
  1160. {
  1161. mSetToUserPosition = false;
  1162. // Fill out the location field
  1163. mLocationEditor->setValue(agent_sim_name);
  1164. // Figure out where user is
  1165. LLVector3 agent_pos;
  1166. updateLocationSpinners(agent_global_pos, &agent_pos);
  1167. LLPanelWorldMap::setDefaultZ(agent_pos.mV[VZ]);
  1168. // Set the current SLURL
  1169. mSLURL = LLSLURL(agent_sim_name, agent_pos).getSLURLString();
  1170. }
  1171. }
  1172. return; // Invalid location
  1173. }
  1174. std::string sim_name;
  1175. got_sim_name = gWorldMap.simNameFromPosGlobal(pos_global, sim_name);
  1176. if (status != LLTracker::TRACKING_NOTHING &&
  1177. (status != mTrackedStatus || pos_global != mTrackedLocation ||
  1178. sim_name != mTrackedSimName))
  1179. {
  1180. mTrackedStatus = status;
  1181. mTrackedLocation = pos_global;
  1182. mTrackedSimName = sim_name;
  1183. if (status == LLTracker::TRACKING_AVATAR)
  1184. {
  1185. // *HACK: adjust Z values automatically for liaisons & gods so they
  1186. // swoop down when they click on the map. Requested convenience.
  1187. if (gAgent.isGodlike())
  1188. {
  1189. pos_global[2] = 200;
  1190. }
  1191. }
  1192. mLocationEditor->setValue(sim_name);
  1193. LLVector3 local_pos;
  1194. updateLocationSpinners(pos_global, &local_pos);
  1195. LLPanelWorldMap::setDefaultZ(local_pos.mV[VZ]);
  1196. // simNameFromPosGlobal can fail, so do not give the user an invalid
  1197. // SLURL
  1198. if (got_sim_name)
  1199. {
  1200. mSLURL = LLSLURL(sim_name, local_pos).getSLURLString();
  1201. }
  1202. else
  1203. {
  1204. // Empty SLURL will disable the "Copy SLURL to clipboard" button
  1205. mSLURL.clear();
  1206. }
  1207. }
  1208. }
  1209. void LLFloaterWorldMap::trackURL(const std::string& region_name,
  1210. S32 x_coord, S32 y_coord, S32 z_coord)
  1211. {
  1212. if (!gFloaterWorldMapp) return;
  1213. LLSimInfo* sim_info = gWorldMap.simInfoFromName(region_name);
  1214. z_coord = llclamp(z_coord, 0, 4096);
  1215. if (sim_info)
  1216. {
  1217. LLVector3 local_pos;
  1218. local_pos.mV[VX] = (F32)x_coord;
  1219. local_pos.mV[VY] = (F32)y_coord;
  1220. local_pos.mV[VZ] = (F32)z_coord;
  1221. LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
  1222. trackLocation(global_pos);
  1223. setDefaultBtn(mTeleportButton);
  1224. // Force an update of the number of agents in this sim
  1225. sim_info->mAgentsUpdateTime = 0.0;
  1226. }
  1227. else
  1228. {
  1229. // Fill in UI based on URL
  1230. gFloaterWorldMapp->mLocationEditor->setValue(region_name);
  1231. mSpinX->setValue(LLSD((F32)x_coord));
  1232. mSpinY->setValue(LLSD((F32)y_coord));
  1233. mSpinZ->setValue(LLSD((F32)z_coord));
  1234. LLPanelWorldMap::setDefaultZ((F32)z_coord);
  1235. // pass sim name to combo box
  1236. gFloaterWorldMapp->mCompletingRegionName = region_name;
  1237. gWorldMap.sendNamedRegionRequest(region_name);
  1238. LLStringUtil::toLower(gFloaterWorldMapp->mCompletingRegionName);
  1239. gWorldMap.mIsTrackingCommit = true;
  1240. }
  1241. }
  1242. void LLFloaterWorldMap::observeInventory(LLInventoryModel* model)
  1243. {
  1244. if (mInventory)
  1245. {
  1246. mInventory->removeObserver(mInventoryObserver);
  1247. delete mInventoryObserver;
  1248. mInventory = NULL;
  1249. mInventoryObserver = NULL;
  1250. }
  1251. if (model)
  1252. {
  1253. mInventory = model;
  1254. mInventoryObserver = new LLMapInventoryObserver;
  1255. // Inventory deletes all observers on shutdown
  1256. mInventory->addObserver(mInventoryObserver);
  1257. inventoryChanged();
  1258. }
  1259. }
  1260. void LLFloaterWorldMap::inventoryChanged()
  1261. {
  1262. if (gTracker.getTrackedLandmarkItemID().notNull())
  1263. {
  1264. LLUUID item_id = gTracker.getTrackedLandmarkItemID();
  1265. buildLandmarkIDLists();
  1266. trackLandmark(item_id);
  1267. }
  1268. }
  1269. void LLFloaterWorldMap::observeFriends()
  1270. {
  1271. if (!mFriendObserver)
  1272. {
  1273. mFriendObserver = new LLMapFriendObserver;
  1274. gAvatarTracker.addObserver(mFriendObserver);
  1275. friendsChanged();
  1276. }
  1277. }
  1278. void LLFloaterWorldMap::friendsChanged()
  1279. {
  1280. const LLUUID& avatar_id = gAvatarTracker.getAvatarID();
  1281. buildAvatarIDList();
  1282. if (avatar_id.notNull())
  1283. {
  1284. const LLRelationship* buddy = gAvatarTracker.getBuddyInfo(avatar_id);
  1285. if (!buddy || !mFriendCombo || gAgent.isGodlike() ||
  1286. !mFriendCombo->setCurrentByID(avatar_id) ||
  1287. !buddy->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION))
  1288. {
  1289. gTracker.stopTracking();
  1290. }
  1291. }
  1292. }
  1293. // No longer really builds a list. Instead, just updates mAvatarCombo.
  1294. void LLFloaterWorldMap::buildAvatarIDList()
  1295. {
  1296. if (!mFriendCombo) return;
  1297. // Delete all but the "None" entry
  1298. S32 list_size = mFriendCombo->getItemCount();
  1299. while (list_size > 1)
  1300. {
  1301. mFriendCombo->selectNthItem(1);
  1302. mFriendCombo->operateOnSelection(LLComboBox::OP_DELETE);
  1303. --list_size;
  1304. }
  1305. LLSD default_column;
  1306. default_column["name"] = "friend name";
  1307. default_column["label"] = "Friend Name";
  1308. default_column["width"] = 500;
  1309. mFriendCombo->addColumn(default_column);
  1310. // Get all of the calling cards for avatar that are currently online
  1311. LLCollectMappableBuddies collector;
  1312. gAvatarTracker.applyFunctor(collector);
  1313. LLCollectMappableBuddies::buddy_map_t::iterator it;
  1314. LLCollectMappableBuddies::buddy_map_t::iterator end;
  1315. it = collector.mMappable.begin();
  1316. end = collector.mMappable.end();
  1317. for ( ; it != end; ++it)
  1318. {
  1319. mFriendCombo->addSimpleElement(it->first, ADD_BOTTOM, it->second);
  1320. }
  1321. mFriendCombo->setCurrentByID(gAvatarTracker.getAvatarID());
  1322. mFriendCombo->selectFirstItem();
  1323. }
  1324. void LLFloaterWorldMap::buildLandmarkIDLists()
  1325. {
  1326. if (!mLandmarkCombo)
  1327. {
  1328. return;
  1329. }
  1330. // Delete all but the "None" entry
  1331. S32 list_size = mLandmarkCombo->getItemCount();
  1332. if (list_size > 1)
  1333. {
  1334. mLandmarkCombo->selectItemRange(1, -1);
  1335. mLandmarkCombo->operateOnSelection(LLComboBox::OP_DELETE);
  1336. }
  1337. mLandmarkItemIDList.clear();
  1338. mLandmarkAssetIDList.clear();
  1339. // Get all of the current landmarks
  1340. mLandmarkAssetIDList.emplace_back(LLUUID::null);
  1341. mLandmarkItemIDList.emplace_back(LLUUID::null);
  1342. mLandmarkAssetIDList.emplace_back(sHomeID);
  1343. mLandmarkItemIDList.emplace_back(sHomeID);
  1344. LLInventoryModel::cat_array_t cats;
  1345. LLInventoryModel::item_array_t items;
  1346. LLIsType is_landmark(LLAssetType::AT_LANDMARK);
  1347. gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items,
  1348. LLInventoryModel::EXCLUDE_TRASH,
  1349. is_landmark);
  1350. std::sort(items.begin(), items.end(),
  1351. LLViewerInventoryItem::comparePointers());
  1352. for (S32 i = 0, count = items.size(); i < count; ++i)
  1353. {
  1354. LLInventoryItem* item = items[i];
  1355. if (!item) continue; // Paranoia
  1356. mLandmarkCombo->addSimpleElement(item->getName(), ADD_BOTTOM,
  1357. item->getUUID());
  1358. mLandmarkAssetIDList.emplace_back(item->getAssetUUID());
  1359. mLandmarkItemIDList.emplace_back(item->getUUID());
  1360. }
  1361. mLandmarkCombo->sortByColumn("landmark name", true);
  1362. mLandmarkCombo->selectFirstItem();
  1363. }
  1364. F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d& destination,
  1365. F32 z_attenuation) const
  1366. {
  1367. LLVector3d delta = destination - gAgent.getPositionGlobal();
  1368. // by attenuating the z-component we effectively
  1369. // give more weight to the x-y plane
  1370. delta.mdV[VZ] *= z_attenuation;
  1371. F32 distance = (F32)delta.length();
  1372. return distance;
  1373. }
  1374. void LLFloaterWorldMap::clearLocationSelection(bool clear_ui)
  1375. {
  1376. if (mSearchResultsList)
  1377. {
  1378. mSearchResultsList->operateOnAll(LLScrollListCtrl::OP_DELETE);
  1379. }
  1380. if (!gFocusMgr.childHasKeyboardFocus(mSpinX))
  1381. {
  1382. mSpinX->setValue(SIM_COORD_DEFAULT);
  1383. }
  1384. if (!gFocusMgr.childHasKeyboardFocus(mSpinY))
  1385. {
  1386. mSpinY->setValue(SIM_COORD_DEFAULT);
  1387. }
  1388. if (!gFocusMgr.childHasKeyboardFocus(mSpinZ))
  1389. {
  1390. mSpinZ->setValue(0);
  1391. LLPanelWorldMap::setDefaultZ(-1.f); // reset default Z
  1392. }
  1393. gWorldMap.mIsTrackingCommit = false;
  1394. mCompletingRegionName.clear();
  1395. mExactMatch = false;
  1396. }
  1397. void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui)
  1398. {
  1399. if (clear_ui || !gFocusMgr.childHasKeyboardFocus(mLandmarkCombo))
  1400. {
  1401. if (mLandmarkCombo)
  1402. {
  1403. mLandmarkCombo->selectByValue("None");
  1404. }
  1405. }
  1406. }
  1407. void LLFloaterWorldMap::clearAvatarSelection(bool clear_ui)
  1408. {
  1409. if (clear_ui || !gFocusMgr.childHasKeyboardFocus(mFriendCombo))
  1410. {
  1411. mTrackedStatus = LLTracker::TRACKING_NOTHING;
  1412. if (mFriendCombo)
  1413. {
  1414. mFriendCombo->selectByValue("None");
  1415. }
  1416. }
  1417. }
  1418. // Adjust the maximally zoomed out limit of the zoom slider so you
  1419. // can see the whole world, plus a little.
  1420. void LLFloaterWorldMap::adjustZoomSliderBounds()
  1421. {
  1422. // World size in regions
  1423. S32 world_width_regions = gWorldMap.getWorldWidth() / REGION_WIDTH_UNITS;
  1424. S32 world_height_regions = gWorldMap.getWorldHeight() / REGION_WIDTH_UNITS;
  1425. // Pad the world size a little bit, so we have a nice border on the edge
  1426. ++world_width_regions;
  1427. ++world_height_regions;
  1428. // Find how much space we have to display the world
  1429. LLPanelWorldMap* panelp = (LLPanelWorldMap*)mTabs->getCurrentPanel();
  1430. LLRect view_rect = panelp->getRect();
  1431. // View size in pixels
  1432. S32 view_width = view_rect.getWidth();
  1433. S32 view_height = view_rect.getHeight();
  1434. // Pixels per region to display entire width/height
  1435. F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
  1436. F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
  1437. F32 pixels_per_region = llmin(width_pixels_per_region,
  1438. height_pixels_per_region);
  1439. // Round pixels per region to an even number of slider increments
  1440. S32 slider_units = llfloor(pixels_per_region / 0.2f);
  1441. pixels_per_region = slider_units * 0.2f;
  1442. // Make sure the zoom slider can be moved at least a little bit.
  1443. // Likewise, less than the increment pixels per region is just silly.
  1444. pixels_per_region = llclamp(pixels_per_region, 1.f,
  1445. powf(2.f, ZOOM_MAX) * 128.f);
  1446. F32 min_power = logf(pixels_per_region / 256.f) / F_LN2;
  1447. mZoomSlider->setMinValue(min_power);
  1448. }
  1449. //static
  1450. void LLFloaterWorldMap::onGoHome(void*)
  1451. {
  1452. gAgent.teleportHome();
  1453. }
  1454. //static
  1455. void LLFloaterWorldMap::onLandmarkComboPrearrange(LLUICtrl*, void* userdata)
  1456. {
  1457. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1458. if (!self || self->mIsClosing)
  1459. {
  1460. return;
  1461. }
  1462. LLComboBox* combop = self->mLandmarkCombo;
  1463. if (!combop) return;
  1464. LLUUID current_choice;
  1465. if (combop->getFirstSelectedIndex()) // If not "None" selected
  1466. {
  1467. current_choice = combop->getCurrentID();
  1468. }
  1469. self->buildLandmarkIDLists();
  1470. if (current_choice.isNull() || !combop->setCurrentByID(current_choice))
  1471. {
  1472. gTracker.stopTracking();
  1473. }
  1474. }
  1475. //static
  1476. void LLFloaterWorldMap::onLocationFocusChanged(LLFocusableElement* focus,
  1477. void* userdata)
  1478. {
  1479. updateSearchEnabled();
  1480. }
  1481. //static
  1482. void LLFloaterWorldMap::onComboTextEntry(LLLineEditor*, void*)
  1483. {
  1484. // Reset the tracking whenever we start typing into any of the search
  1485. // fields, so that hitting <enter> does an auto-complete versus teleporting
  1486. // us to the previously selected landmark/friend.
  1487. gTracker.clearFocus();
  1488. }
  1489. //static
  1490. void LLFloaterWorldMap::onSearchTextEntry(const std::string&, void*)
  1491. {
  1492. // Reset the tracking whenever we start typing into any of the search
  1493. // fields, so that hitting <enter> does an auto-complete versus teleporting
  1494. // us to the previously selected landmark/friend.
  1495. gTracker.clearFocus();
  1496. updateSearchEnabled();
  1497. }
  1498. //static
  1499. void LLFloaterWorldMap::onLandmarkComboCommit(LLUICtrl*, void* userdata)
  1500. {
  1501. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1502. if (!self || self->mIsClosing)
  1503. {
  1504. return;
  1505. }
  1506. LLComboBox* combop = self->mLandmarkCombo;
  1507. if (!combop) return;
  1508. // If "None" is selected, we are done.
  1509. if (!combop->getFirstSelectedIndex())
  1510. {
  1511. return;
  1512. }
  1513. LLUUID asset_id;
  1514. LLUUID item_id = combop->getCurrentID();
  1515. gTracker.stopTracking();
  1516. // RN: stopTracking() clears current combobox selection, need to reassert
  1517. // it here
  1518. combop->setCurrentByID(item_id);
  1519. if (item_id.isNull())
  1520. {
  1521. }
  1522. else if (item_id == sHomeID)
  1523. {
  1524. asset_id = sHomeID;
  1525. }
  1526. else
  1527. {
  1528. LLInventoryItem* item = gInventory.getItem(item_id);
  1529. if (item)
  1530. {
  1531. asset_id = item->getAssetUUID();
  1532. }
  1533. else
  1534. {
  1535. // Something went wrong, so revert to a safe value.
  1536. item_id.setNull();
  1537. }
  1538. }
  1539. self->trackLandmark(item_id);
  1540. onShowTargetBtn(self);
  1541. // Reset to user postion if nothing is tracked
  1542. self->mSetToUserPosition =
  1543. (gTracker.getTrackingStatus() == LLTracker::TRACKING_NOTHING);
  1544. }
  1545. //static
  1546. void LLFloaterWorldMap::onAvatarComboPrearrange(LLUICtrl*, void* userdata)
  1547. {
  1548. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1549. if (!self || self->mIsClosing)
  1550. {
  1551. return;
  1552. }
  1553. LLComboBox* combop = self->mFriendCombo;
  1554. if (!combop) return;
  1555. LLUUID current_choice;
  1556. if (gAvatarTracker.haveTrackingInfo())
  1557. {
  1558. current_choice = gAvatarTracker.getAvatarID();
  1559. }
  1560. self->buildAvatarIDList();
  1561. if (!combop->setCurrentByID(current_choice) || current_choice.isNull())
  1562. {
  1563. gTracker.stopTracking();
  1564. }
  1565. }
  1566. //static
  1567. void LLFloaterWorldMap::onAvatarComboCommit(LLUICtrl*, void* userdata)
  1568. {
  1569. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1570. if (!self || self->mIsClosing)
  1571. {
  1572. return;
  1573. }
  1574. LLComboBox* combop = self->mFriendCombo;
  1575. if (!combop) return;
  1576. const LLUUID& new_avatar_id = combop->getCurrentID();
  1577. if (new_avatar_id.notNull())
  1578. {
  1579. std::string name = self->mFriendCombo->getSimple();
  1580. self->trackAvatar(new_avatar_id, name);
  1581. onShowTargetBtn(self);
  1582. }
  1583. else
  1584. {
  1585. // Reset to user postion if nothing is tracked
  1586. self->mSetToUserPosition =
  1587. gTracker.getTrackingStatus() == LLTracker::TRACKING_NOTHING;
  1588. }
  1589. }
  1590. //static
  1591. void LLFloaterWorldMap::updateSearchEnabled()
  1592. {
  1593. if (!gFloaterWorldMapp || gFloaterWorldMapp->mIsClosing)
  1594. {
  1595. return;
  1596. }
  1597. if (gFocusMgr.childHasKeyboardFocus(gFloaterWorldMapp->mLocationEditor) &&
  1598. gFloaterWorldMapp->mLocationEditor->getValue().asString().length() > 0)
  1599. {
  1600. gFloaterWorldMapp->setDefaultBtn("DoSearch");
  1601. }
  1602. else
  1603. {
  1604. gFloaterWorldMapp->setDefaultBtn((LLButton*)NULL);
  1605. }
  1606. }
  1607. //static
  1608. void LLFloaterWorldMap::onLocationCommit(void* userdata)
  1609. {
  1610. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1611. if (!self || self->mIsClosing)
  1612. {
  1613. return;
  1614. }
  1615. self->clearLocationSelection(false);
  1616. self->mCompletingRegionName.clear();
  1617. self->mLastRegionName.clear();
  1618. std::string str = self->mLocationEditor->getValue().asString();
  1619. // Trim any leading and trailing spaces in the search target
  1620. std::string saved_str = str;
  1621. LLStringUtil::trim(str);
  1622. if (str != saved_str)
  1623. {
  1624. // Set the value in the UI if any spaces were removed
  1625. self->mLocationEditor->setValue(str);
  1626. }
  1627. LLStringUtil::toLower(str);
  1628. self->mCompletingRegionName = str;
  1629. gWorldMap.mIsTrackingCommit = true;
  1630. self->mExactMatch = false;
  1631. if (str.length() >= 3)
  1632. {
  1633. gWorldMap.sendNamedRegionRequest(str);
  1634. }
  1635. else
  1636. {
  1637. str += "#";
  1638. gWorldMap.sendNamedRegionRequest(str);
  1639. }
  1640. }
  1641. //static
  1642. void LLFloaterWorldMap::onClearBtn(void* data)
  1643. {
  1644. LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
  1645. if (self)
  1646. {
  1647. LLPanelWorldMap::setDefaultZ(-1.f); // reset default Z
  1648. self->mTrackedStatus = LLTracker::TRACKING_NOTHING;
  1649. gTracker.stopTracking(true);
  1650. gWorldMap.mIsTrackingUnknownLocation = false;
  1651. // Clear the SLURL since it's invalid
  1652. self->mSLURL.clear();
  1653. // Revert back to the current user position
  1654. self->mSetToUserPosition = true;
  1655. }
  1656. }
  1657. //static
  1658. void LLFloaterWorldMap::onShowTargetBtn(void* data)
  1659. {
  1660. LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
  1661. if (self)
  1662. {
  1663. self->centerOnTarget(true);
  1664. }
  1665. }
  1666. //static
  1667. void LLFloaterWorldMap::onShowAgentBtn(void* data)
  1668. {
  1669. LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
  1670. if (self)
  1671. {
  1672. LLPanelWorldMap::setPan(0, 0, false); // false == animate
  1673. // Set flag so user's location will be displayed if not tracking
  1674. // anything else
  1675. self->mSetToUserPosition = true;
  1676. }
  1677. }
  1678. //static
  1679. void LLFloaterWorldMap::onClickTeleportBtn(void* data)
  1680. {
  1681. LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
  1682. if (self)
  1683. {
  1684. self->teleport();
  1685. }
  1686. }
  1687. //static
  1688. void LLFloaterWorldMap::onCopySLURL(void* data)
  1689. {
  1690. LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
  1691. if (self)
  1692. {
  1693. gWindowp->copyTextToClipboard(utf8str_to_wstring(self->mSLURL));
  1694. LLSD args;
  1695. args["SLURL"] = self->mSLURL;
  1696. gNotifications.add("CopySLURL", args);
  1697. }
  1698. }
  1699. void LLFloaterWorldMap::centerOnTarget(bool animate)
  1700. {
  1701. LLVector3d pos_global;
  1702. if (gTracker.getTrackingStatus() != LLTracker::TRACKING_NOTHING)
  1703. {
  1704. LLVector3d tracked_position = gTracker.getTrackedPositionGlobal();
  1705. // RN: tracker does not allow us to query completion, so we check for a
  1706. // tracking position of absolute zero, and keep trying in the draw loop
  1707. if (tracked_position.isExactlyZero())
  1708. {
  1709. mWaitingForTracker = true;
  1710. return;
  1711. }
  1712. pos_global = gTracker.getTrackedPositionGlobal() -
  1713. gAgent.getCameraPositionGlobal();
  1714. }
  1715. else if (gWorldMap.mIsTrackingUnknownLocation)
  1716. {
  1717. pos_global = gWorldMap.mUnknownLocation -
  1718. gAgent.getCameraPositionGlobal();;
  1719. }
  1720. else
  1721. {
  1722. // Default behavior = center on agent
  1723. pos_global.clear();
  1724. }
  1725. LLPanelWorldMap::setPan(-llfloor((F32)(pos_global.mdV[VX] *
  1726. (F64)LLPanelWorldMap::sPixelsPerMeter)),
  1727. -llfloor((F32)(pos_global.mdV[VY] *
  1728. (F64)LLPanelWorldMap::sPixelsPerMeter)),
  1729. !animate);
  1730. mWaitingForTracker = false;
  1731. }
  1732. void LLFloaterWorldMap::teleport()
  1733. {
  1734. bool teleport_home = false;
  1735. LLUUID lm_asset_id;
  1736. LLVector3d pos_global;
  1737. LLAvatarTracker& av_tracker = gAvatarTracker;
  1738. LLTracker::ETrackingStatus tracking_status = gTracker.getTrackingStatus();
  1739. if (tracking_status == LLTracker::TRACKING_AVATAR &&
  1740. av_tracker.haveTrackingInfo())
  1741. {
  1742. pos_global = av_tracker.getGlobalPos();
  1743. pos_global.mdV[VZ] = mSpinZ->getValue();
  1744. }
  1745. else if (tracking_status == LLTracker::TRACKING_LANDMARK)
  1746. {
  1747. lm_asset_id = gTracker.getTrackedLandmarkAssetID();
  1748. if (lm_asset_id == sHomeID)
  1749. {
  1750. teleport_home = true;
  1751. }
  1752. else
  1753. {
  1754. LLLandmark* landmark = gLandmarkList.getAsset(lm_asset_id);
  1755. LLUUID region_id;
  1756. if (landmark && !landmark->getGlobalPos(pos_global) &&
  1757. landmark->getRegionID(region_id))
  1758. {
  1759. LLLandmark::requestRegionHandle(gMessageSystemp,
  1760. gAgent.getRegionHost(),
  1761. region_id, NULL);
  1762. }
  1763. }
  1764. }
  1765. else if (tracking_status == LLTracker::TRACKING_LOCATION)
  1766. {
  1767. // Make sure any change to spinners is committed:
  1768. onCommitLocation(NULL, this);
  1769. pos_global = gTracker.getTrackedPositionGlobal();
  1770. }
  1771. else
  1772. {
  1773. make_ui_sound("UISndInvalidOp");
  1774. }
  1775. // Do the teleport, which will also close the floater
  1776. if (teleport_home)
  1777. {
  1778. gAgent.teleportHome();
  1779. }
  1780. else if (!pos_global.isExactlyZero())
  1781. {
  1782. if (lm_asset_id.notNull())
  1783. {
  1784. gAgent.teleportViaLandmark(lm_asset_id);
  1785. }
  1786. else
  1787. {
  1788. gAgent.teleportViaLocation(pos_global);
  1789. }
  1790. }
  1791. }
  1792. // *HACK: to work around non loading tiles on first tab change. HB
  1793. static void force_reload_tiles(U32 layer)
  1794. {
  1795. gWorldMap.clearImageRefs(layer);
  1796. gWorldMap.clearSimFlags();
  1797. }
  1798. //static
  1799. void LLFloaterWorldMap::onTabChanged(void* userdata, bool from_click)
  1800. {
  1801. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1802. if (self)
  1803. {
  1804. // Find my index
  1805. U32 index = self->mTabs->getCurrentPanelIndex();
  1806. gWorldMap.setCurrentLayer(index);
  1807. // *HACK: to work around non loading tiles on first tab change. HB
  1808. static bool first_tab_change = true;
  1809. if (first_tab_change)
  1810. {
  1811. first_tab_change = false;
  1812. constexpr F32 delay = 2.f; // In seconds
  1813. doAfterInterval(boost::bind(&force_reload_tiles, index), delay);
  1814. }
  1815. }
  1816. }
  1817. void LLFloaterWorldMap::updateSims(bool found_null_sim)
  1818. {
  1819. if (mCompletingRegionName.empty())
  1820. {
  1821. return;
  1822. }
  1823. mSearchResultsList->operateOnAll(LLScrollListCtrl::OP_DELETE);
  1824. LLSD selected_value = mSearchResultsList->getSelectedValue();
  1825. S32 name_length = mCompletingRegionName.length();
  1826. bool match_found = false;
  1827. S32 num_results = 0;
  1828. for (LLWorldMap::sim_info_map_t::const_iterator
  1829. it = gWorldMap.mSimInfoMap.begin(),
  1830. end = gWorldMap.mSimInfoMap.end();
  1831. it != end; ++it)
  1832. {
  1833. LLSimInfo* info = it->second;
  1834. std::string sim_name = info->mName;
  1835. std::string sim_name_lower = sim_name;
  1836. LLStringUtil::toLower(sim_name_lower);
  1837. if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
  1838. {
  1839. if (gWorldMap.mIsTrackingCommit)
  1840. {
  1841. if (sim_name_lower == mCompletingRegionName)
  1842. {
  1843. selected_value = sim_name;
  1844. match_found = true;
  1845. // Force an update of the number of agents in this sim
  1846. info->mAgentsUpdateTime = 0.0;
  1847. }
  1848. }
  1849. LLSD value;
  1850. value["id"] = sim_name;
  1851. value["columns"][0]["column"] = "sim_name";
  1852. value["columns"][0]["value"] = sim_name;
  1853. mSearchResultsList->addElement(value);
  1854. ++num_results;
  1855. }
  1856. }
  1857. mSearchResultsList->selectByValue(selected_value);
  1858. if (found_null_sim)
  1859. {
  1860. mCompletingRegionName.clear();
  1861. }
  1862. if (match_found)
  1863. {
  1864. mExactMatch = true;
  1865. mSearchResultsList->setFocus(true);
  1866. onCommitSearchResult(mSearchResultsList, this);
  1867. }
  1868. else if (!mExactMatch && num_results > 0)
  1869. {
  1870. mSearchResultsList->selectFirstItem(); // select first item by default
  1871. mSearchResultsList->setFocus(true);
  1872. onCommitSearchResult(mSearchResultsList, this);
  1873. }
  1874. else
  1875. {
  1876. mSearchResultsList->addCommentText("None found.");
  1877. mSearchResultsList->operateOnAll(LLScrollListCtrl::OP_DESELECT);
  1878. }
  1879. }
  1880. //static
  1881. void LLFloaterWorldMap::onCommitLocation(LLUICtrl*, void* userdata)
  1882. {
  1883. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1884. if (self)
  1885. {
  1886. S32 local_x = self->mSpinX->getValue();
  1887. S32 local_y = self->mSpinY->getValue();
  1888. S32 local_z = self->mSpinZ->getValue();
  1889. std::string region_name = self->mLocationEditor->getValue().asString();
  1890. self->trackURL(region_name, local_x, local_y, local_z);
  1891. }
  1892. }
  1893. //static
  1894. void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata)
  1895. {
  1896. LLFloaterWorldMap* self = (LLFloaterWorldMap*)userdata;
  1897. if (!self) return;
  1898. LLScrollListCtrl* listp = self->mSearchResultsList;
  1899. if (!listp) return;
  1900. LLSD selected_value = listp->getSelectedValue();
  1901. std::string sim_name = selected_value.asString();
  1902. if (sim_name.empty())
  1903. {
  1904. return;
  1905. }
  1906. LLStringUtil::toLower(sim_name);
  1907. for (LLWorldMap::sim_info_map_t::const_iterator
  1908. it = gWorldMap.mSimInfoMap.begin(),
  1909. end = gWorldMap.mSimInfoMap.end();
  1910. it != end; ++it)
  1911. {
  1912. LLSimInfo* info = it->second;
  1913. std::string info_sim_name = info->mName;
  1914. LLStringUtil::toLower(info_sim_name);
  1915. if (sim_name == info_sim_name)
  1916. {
  1917. LLVector3d pos_global = from_region_handle(info->mHandle);
  1918. F64 local_x = self->mSpinX->getValue();
  1919. F64 local_y = self->mSpinY->getValue();
  1920. F64 local_z = self->mSpinZ->getValue();
  1921. pos_global.mdV[VX] += local_x;
  1922. pos_global.mdV[VY] += local_y;
  1923. pos_global.mdV[VZ] = local_z;
  1924. self->mLocationEditor->setValue(sim_name);
  1925. self->trackLocation(pos_global);
  1926. self->setDefaultBtn(self->mTeleportButton);
  1927. // Force an update of the number of agents in this sim
  1928. info->mAgentsUpdateTime = 0.0;
  1929. break;
  1930. }
  1931. }
  1932. onShowTargetBtn(self);
  1933. }