aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfloaterworldmap.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llfloaterworldmap.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llfloaterworldmap.cpp')
-rw-r--r--linden/indra/newview/llfloaterworldmap.cpp1600
1 files changed, 1600 insertions, 0 deletions
diff --git a/linden/indra/newview/llfloaterworldmap.cpp b/linden/indra/newview/llfloaterworldmap.cpp
new file mode 100644
index 0000000..af0e5c0
--- /dev/null
+++ b/linden/indra/newview/llfloaterworldmap.cpp
@@ -0,0 +1,1600 @@
1/**
2 * @file llfloaterworldmap.cpp
3 * @author James Cook, Tom Yedwab
4 * @brief LLFloaterWorldMap class implementation
5 *
6 * Copyright (c) 2003-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29/*
30 * Map of the entire world, with multiple background images,
31 * avatar tracking, teleportation by double-click, etc.
32 */
33
34#include "llviewerprecompiledheaders.h"
35
36#include "llfloaterworldmap.h"
37
38// Library includes
39#include "llfontgl.h"
40#include "llinventory.h"
41#include "lllineeditor.h"
42#include "message.h"
43
44// Viewer includes
45#include "llagent.h"
46#include "llviewerwindow.h"
47#include "llbutton.h"
48#include "llcallingcard.h"
49#include "llcolorscheme.h"
50#include "llcombobox.h"
51#include "llviewercontrol.h"
52#include "lldraghandle.h"
53#include "lleconomy.h"
54#include "llfirstuse.h"
55#include "llfocusmgr.h"
56#include "lliconctrl.h"
57#include "llinventorymodel.h"
58#include "llinventoryview.h"
59#include "lllandmarklist.h"
60#include "llnetmap.h"
61#include "llpreviewlandmark.h"
62#include "llradiogroup.h"
63#include "llregionhandle.h"
64#include "llresizehandle.h"
65#include "llresmgr.h"
66#include "llscrolllistctrl.h"
67#include "llsliderctrl.h"
68#include "llspinctrl.h"
69#include "llstatusbar.h"
70#include "lltabcontainer.h"
71#include "lltextbox.h"
72#include "lltracker.h"
73#include "llui.h"
74#include "lluiconstants.h"
75#include "llviewercamera.h"
76#include "llviewermenu.h"
77#include "llviewerregion.h"
78#include "llviewerstats.h"
79#include "llworldmap.h"
80#include "llworldmapview.h"
81#include "llurl.h"
82#include "llvieweruictrlfactory.h"
83#include "viewer.h"
84#include "llmapimagetype.h"
85#include "llweb.h"
86
87#include "llglheaders.h"
88
89//---------------------------------------------------------------------------
90// Constants
91//---------------------------------------------------------------------------
92static const F32 MAP_ZOOM_TIME = 0.2f;
93
94enum EPanDirection
95{
96 PAN_UP,
97 PAN_DOWN,
98 PAN_LEFT,
99 PAN_RIGHT
100};
101
102// Values in pixels per region
103static const F32 ZOOM_MIN = -8.f; // initial value, updated by adjustZoomSlider
104static const F32 ZOOM_MAX = 0.f;
105static const F32 ZOOM_INC = 0.2f;
106
107static const F32 SIM_COORD_MIN = 0.f;
108static const F32 SIM_COORD_MAX = 255.f;
109static const F32 SIM_COORD_DEFAULT = 128.f;
110
111static const F64 MAX_FLY_DISTANCE = 363.f; // Diagonal size of one sim.
112static const F64 MAX_FLY_DISTANCE_SQUARED = MAX_FLY_DISTANCE * MAX_FLY_DISTANCE;
113
114//---------------------------------------------------------------------------
115// Globals
116//---------------------------------------------------------------------------
117
118LLFloaterWorldMap* gFloaterWorldMap = NULL;
119
120class LLMapInventoryObserver : public LLInventoryObserver
121{
122public:
123 LLMapInventoryObserver() {}
124 virtual ~LLMapInventoryObserver() {}
125 virtual void changed(U32 mask);
126};
127
128void LLMapInventoryObserver::changed(U32 mask)
129{
130 // if there's a change we're interested in.
131 if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
132 LLInventoryObserver::REMOVE)) != 0)
133 {
134 gFloaterWorldMap->inventoryChanged();
135 }
136}
137
138class LLMapFriendObserver : public LLFriendObserver
139{
140public:
141 LLMapFriendObserver() {}
142 virtual ~LLMapFriendObserver() {}
143 virtual void changed(U32 mask);
144};
145
146void LLMapFriendObserver::changed(U32 mask)
147{
148 // if there's a change we're interested in.
149 if((mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE | LLFriendObserver::POWERS)) != 0)
150 {
151 gFloaterWorldMap->friendsChanged();
152 }
153}
154
155//---------------------------------------------------------------------------
156// Statics
157//---------------------------------------------------------------------------
158
159// Used as a pretend asset and inventory id to mean "landmark at my home location."
160const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001" );
161
162//---------------------------------------------------------------------------
163// Construction and destruction
164//---------------------------------------------------------------------------
165
166
167LLFloaterWorldMap::LLFloaterWorldMap()
168: LLFloater("worldmap", "FloaterWorldMapRect", "World Map",
169 TRUE, // resize
170 410, // min-width
171 520, // min-height
172 FALSE, // drag on left
173 TRUE, // minimize
174 TRUE), // close
175 mInventory(NULL),
176 mInventoryObserver(NULL),
177 mFriendObserver(NULL),
178 mCompletingRegionName(""),
179 mWaitingForTracker(FALSE),
180 mExactMatch(FALSE),
181 mTrackedLocation(0,0,0),
182 mTrackedStatus(LLTracker::TRACKING_NOTHING)
183{
184 LLCallbackMap::map_t factory_map;
185 factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
186 factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL);
187 gUICtrlFactory->buildFloater(this, "floater_world_map.xml", &factory_map);
188}
189
190// static
191void* LLFloaterWorldMap::createWorldMapView(void* data)
192{
193 return new LLWorldMapView("mapview", LLRect(0,300,400,0));
194}
195
196BOOL LLFloaterWorldMap::postBuild()
197{
198 mTabs = LLUICtrlFactory::getTabContainerByName(this, "maptab");
199 if (!mTabs) return FALSE;
200
201 LLPanel *panel;
202
203 panel = LLUICtrlFactory::getPanelByName(mTabs, "objects_mapview");
204 if (panel)
205 {
206 mTabs->setTabChangeCallback(panel, onCommitBackground);
207 mTabs->setTabUserData(panel, this);
208 }
209 panel = LLUICtrlFactory::getPanelByName(mTabs, "terrain_mapview");
210 if (panel)
211 {
212 mTabs->setTabChangeCallback(panel, onCommitBackground);
213 mTabs->setTabUserData(panel, this);
214 }
215
216 onCommitBackground((void*)this, false);
217
218 childSetCommitCallback("friend combo", onAvatarComboCommit, this);
219
220 LLComboBox *avatar_combo = LLUICtrlFactory::getComboBoxByName(this, "friend combo");
221 if (avatar_combo)
222 {
223 avatar_combo->selectFirstItem();
224 avatar_combo->setPrearrangeCallback( onAvatarComboPrearrange );
225 }
226
227 childSetAction("DoSearch", onLocationCommit, this);
228
229 childSetFocusChangedCallback("location", updateSearchEnabled);
230 childSetKeystrokeCallback("location", (void (*)(LLLineEditor*,void*))updateSearchEnabled, NULL);
231
232 childSetCommitCallback("search_results", onCommitSearchResult, this);
233 childSetDoubleClickCallback("search_results", onTeleportBtn);
234 childSetCommitCallback("spin x", onCommitLocation, this);
235 childSetCommitCallback("spin y", onCommitLocation, this);
236 childSetCommitCallback("spin z", onCommitLocation, this);
237
238 childSetCommitCallback("landmark combo", onLandmarkComboCommit, this);
239
240 LLComboBox *landmark_combo = LLUICtrlFactory::getComboBoxByName(this, "landmark combo");
241 if (landmark_combo)
242 {
243 landmark_combo->selectFirstItem();
244 landmark_combo->setPrearrangeCallback( onLandmarkComboPrearrange );
245 }
246
247 childSetAction("Go Home", onGoHome, this);
248
249 childSetAction("Teleport", onTeleportBtn, this);
250
251 childSetAction("Show Destination", onShowTargetBtn, this);
252 childSetAction("Show My Location", onShowAgentBtn, this);
253 childSetAction("Clear", onClearBtn, this);
254 childSetAction("copy_slurl", onCopySLURL, this);
255
256 mCurZoomVal = log(gMapScale)/log(2.f);
257 childSetValue("zoom slider", gMapScale);
258
259 setDefaultBtn("");
260
261 if ( gAgent.mAccess <= SIM_ACCESS_PG )
262 {
263 // Hide Mature Events controls
264 childHide("events_mature_icon");
265 childHide("events_mature_label");
266 childHide("event_mature_chk");
267 }
268
269 mZoomTimer.stop();
270
271 return TRUE;
272}
273
274// virtual
275LLFloaterWorldMap::~LLFloaterWorldMap()
276{
277 // All cleaned up by LLView destructor
278 mTabs = NULL;
279
280 // Inventory deletes all observers on shutdown
281 mInventory = NULL;
282 mInventoryObserver = NULL;
283
284 // avatar tracker will delete this for us.
285 mFriendObserver = NULL;
286}
287
288
289// virtual
290void LLFloaterWorldMap::onClose(bool app_quitting)
291{
292 setVisible(FALSE);
293}
294
295// Allow us to download landmarks quickly when map is shown
296class LLLandmarkFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
297{
298public:
299 virtual void done()
300 {
301 // We need to find landmarks in all folders, so get the main
302 // background download going.
303 gInventory.startBackgroundFetch();
304 gInventory.removeObserver(this);
305 delete this;
306 }
307};
308
309// static
310void LLFloaterWorldMap::show(void*, BOOL center_on_target)
311{
312 BOOL was_visible = gFloaterWorldMap->getVisible();
313
314 gFloaterWorldMap->mIsClosing = FALSE;
315 gFloaterWorldMap->open();
316
317 LLWorldMapView* map_panel;
318 map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
319 map_panel->clearLastClick();
320
321 if (!was_visible)
322 {
323 // reset pan on show, so it centers on you again
324 if (!center_on_target)
325 {
326 LLWorldMapView::setPan(0, 0, TRUE);
327 }
328 map_panel->updateVisibleBlocks();
329
330 // Reload the agent positions when we show the window
331 gWorldMap->eraseItems();
332
333 // Reload any maps that may have changed
334 gWorldMap->clearSimFlags();
335
336 const S32 panel_num = gFloaterWorldMap->mTabs->getCurrentPanelIndex();
337 const bool request_from_sim = true;
338 gWorldMap->setCurrentLayer(panel_num, request_from_sim);
339
340 // We may already have a bounding box for the regions of the world,
341 // so use that to adjust the view.
342 gFloaterWorldMap->adjustZoomSliderBounds();
343
344 // Could be first show
345 LLFirstUse::useMap();
346
347 // Start speculative download of landmarks
348 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
349 LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
350 gInventory.startBackgroundFetch(landmark_folder_id);
351
352 gFloaterWorldMap->childSetFocus("location", TRUE);
353 gFocusMgr.triggerFocusFlash();
354
355 gFloaterWorldMap->buildAvatarIDList();
356 gFloaterWorldMap->buildLandmarkIDLists();
357 }
358
359 if (center_on_target)
360 {
361 gFloaterWorldMap->centerOnTarget(FALSE);
362 }
363}
364
365
366
367// static
368void LLFloaterWorldMap::reloadIcons(void*)
369{
370 gWorldMap->eraseItems();
371
372 gWorldMap->sendMapLayerRequest();
373}
374
375
376// static
377void LLFloaterWorldMap::toggle(void*)
378{
379 BOOL visible = gFloaterWorldMap->getVisible();
380
381 if (!visible)
382 {
383 show(NULL, FALSE);
384 }
385 else
386 {
387 gFloaterWorldMap->mIsClosing = TRUE;
388 gFloaterWorldMap->close();
389 }
390}
391
392
393// static
394void LLFloaterWorldMap::hide(void*)
395{
396 gFloaterWorldMap->mIsClosing = TRUE;
397 gFloaterWorldMap->close();
398}
399
400
401// virtual
402void LLFloaterWorldMap::setVisible( BOOL visible )
403{
404 LLFloater::setVisible( visible );
405
406 gSavedSettings.setBOOL( "ShowWorldMap", visible );
407
408 if( !visible )
409 {
410 // While we're not visible, discard the overlay images we're using
411 if (gWorldMap)
412 {
413 gWorldMap->clearImageRefs();
414 }
415 }
416}
417
418
419// virtual
420BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
421{
422 BOOL handled;
423 handled = LLFloater::handleHover(x, y, mask);
424 return handled;
425}
426
427BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
428{
429 if (getVisible() && !isMinimized() && isFrontmost())
430 {
431 F32 slider_value = (F32)childGetValue("zoom slider").asReal();
432 slider_value += ((F32)clicks * -0.3333f);
433 childSetValue("zoom slider", LLSD(slider_value));
434 return TRUE;
435 }
436 return FALSE;
437}
438
439
440// virtual
441void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent )
442{
443 LLFloater::reshape( width, height, called_from_parent );
444
445 // Might have changed size of world display area
446 // JC: Technically, this is correct, but it makes the slider "pop"
447 // if you resize the window, then draw the slider. Just leaving it
448 // the way it was when you opened the window seems better.
449 // adjustZoomSliderBounds();
450}
451
452
453// virtual
454void LLFloaterWorldMap::draw()
455{
456 if( !getVisible() )
457 {
458 return;
459 }
460
461 updateLocation();
462
463 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
464 if (LLTracker::TRACKING_AVATAR == tracking_status)
465 {
466 childSetColor("avatar_icon", gTrackColor);
467 }
468 else
469 {
470 childSetColor("avatar_icon", gDisabledTrackColor);
471 }
472
473 if (LLTracker::TRACKING_LANDMARK == tracking_status)
474 {
475 childSetColor("landmark_icon", gTrackColor);
476 }
477 else
478 {
479 childSetColor("landmark_icon", gDisabledTrackColor);
480 }
481
482 if (LLTracker::TRACKING_LOCATION == tracking_status)
483 {
484 childSetColor("location_icon", gTrackColor);
485 }
486 else
487 {
488 if (mCompletingRegionName != "")
489 {
490 F64 seconds = LLTimer::getElapsedSeconds();
491 double value = fmod(seconds, 2);
492 value = 0.5 + 0.5*cos(value * 3.14159f);
493 LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
494 childSetColor("location_icon", loading_color);
495 }
496 else
497 {
498 childSetColor("location_icon", gDisabledTrackColor);
499 }
500 }
501
502 // check for completion of tracking data
503 if (mWaitingForTracker)
504 {
505 centerOnTarget(TRUE);
506 }
507
508 childSetEnabled("Teleport", (BOOL)tracking_status);
509// childSetEnabled("Clear", (BOOL)tracking_status);
510 childSetEnabled("Show Destination", (BOOL)tracking_status || gWorldMap->mIsTrackingUnknownLocation);
511 childSetEnabled("copy_slurl", (BOOL)tracking_status);
512
513 setMouseOpaque(TRUE);
514 mDragHandle->setMouseOpaque(TRUE);
515
516 //RN: snaps to zoom value because interpolation caused jitter in the text rendering
517 if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)childGetValue("zoom slider").asReal())
518 {
519 mZoomTimer.start();
520 }
521 F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
522 if (interp > 1.f)
523 {
524 interp = 1.f;
525 mZoomTimer.stop();
526 }
527 mCurZoomVal = lerp(mCurZoomVal, (F32)childGetValue("zoom slider").asReal(), interp);
528 F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
529 LLWorldMapView::setScale( map_scale );
530
531 LLFloater::draw();
532}
533
534
535//-------------------------------------------------------------------------
536// Internal utility functions
537//-------------------------------------------------------------------------
538
539
540void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const LLString& name )
541{
542 LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
543 if (!iface) return;
544
545 buildAvatarIDList();
546 if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
547 {
548 // *HACK: Adjust Z values automatically for liaisons & gods so
549 // they swoop down when they click on the map. Requested
550 // convenience.
551 if(gAgent.isGodlike())
552 {
553 childSetValue("spin z", LLSD(200.f));
554 }
555 // Don't re-request info if we already have it or we won't have it in time to teleport
556 if (mTrackedStatus != LLTracker::TRACKING_AVATAR || name != mTrackedAvatarName)
557 {
558 mTrackedStatus = LLTracker::TRACKING_AVATAR;
559 mTrackedAvatarName = name;
560 LLTracker::trackAvatar(avatar_id, name);
561 }
562 }
563 else
564 {
565 LLTracker::stopTracking(NULL);
566 }
567 setDefaultBtn("Teleport");
568}
569
570void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
571{
572 LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
573 if (!iface) return;
574
575 buildLandmarkIDLists();
576 BOOL found = FALSE;
577 S32 idx;
578 for (idx = 0; idx < mLandmarkItemIDList.count(); idx++)
579 {
580 if ( mLandmarkItemIDList.get(idx) == landmark_item_id)
581 {
582 found = TRUE;
583 break;
584 }
585 }
586
587 if (found && iface->setCurrentByID( landmark_item_id ) )
588 {
589 LLUUID asset_id = mLandmarkAssetIDList.get( idx );
590 LLString name;
591 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(this, "landmark combo");
592 if (combo) name = combo->getSimple();
593 mTrackedStatus = LLTracker::TRACKING_LANDMARK;
594 LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ), // assetID
595 mLandmarkItemIDList.get( idx ), // itemID
596 name); // name
597
598 if( asset_id != sHomeID )
599 {
600 // start the download process
601 gLandmarkList.getAsset( asset_id);
602 }
603
604 // We have to download both region info and landmark data, so set busy. JC
605// getWindow()->incBusyCount();
606 }
607 else
608 {
609 LLTracker::stopTracking(NULL);
610 }
611 setDefaultBtn("Teleport");
612}
613
614
615void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
616{
617 mTrackedStatus = LLTracker::TRACKING_LOCATION;
618 LLTracker::trackLocation(event_info.mPosGlobal, event_info.mName, event_info.mToolTip, LLTracker::LOCATION_EVENT);
619 setDefaultBtn("Teleport");
620}
621
622void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
623{
624 mTrackedStatus = LLTracker::TRACKING_LOCATION;
625 LLTracker::trackLocation(item.mPosGlobal, item.mName, item.mToolTip, LLTracker::LOCATION_ITEM);
626 setDefaultBtn("Teleport");
627}
628
629void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
630{
631 LLSimInfo* sim_info = gWorldMap->simInfoFromPosGlobal(pos_global);
632 if (!sim_info)
633 {
634 gWorldMap->mIsTrackingUnknownLocation = TRUE;
635 gWorldMap->mInvalidLocation = FALSE;
636 gWorldMap->mUnknownLocation = pos_global;
637 LLTracker::stopTracking(NULL);
638 S32 world_x = S32(pos_global.mdV[0] / 256);
639 S32 world_y = S32(pos_global.mdV[1] / 256);
640 gWorldMap->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
641 setDefaultBtn("");
642 return;
643 }
644 if (sim_info->mAccess == SIM_ACCESS_DOWN)
645 {
646 // Down sim. Show the blue circle of death!
647 gWorldMap->mIsTrackingUnknownLocation = TRUE;
648 gWorldMap->mUnknownLocation = pos_global;
649 gWorldMap->mInvalidLocation = TRUE;
650 LLTracker::stopTracking(NULL);
651 setDefaultBtn("");
652 return;
653 }
654
655 LLString sim_name = gWorldMap->simNameFromPosGlobal( pos_global );
656 F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
657 F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
658 LLString full_name = llformat("%s (%d, %d, %d)",
659 sim_name.c_str(),
660 llround(region_x),
661 llround(region_y),
662 llround((F32)pos_global.mdV[VZ]));
663
664 LLString tooltip("");
665 mTrackedStatus = LLTracker::TRACKING_LOCATION;
666 LLTracker::trackLocation(pos_global, full_name, tooltip);
667 gWorldMap->mIsTrackingUnknownLocation = FALSE;
668 gWorldMap->mIsTrackingDoubleClick = FALSE;
669 gWorldMap->mIsTrackingCommit = FALSE;
670
671 setDefaultBtn("Teleport");
672}
673
674void LLFloaterWorldMap::updateLocation()
675{
676 // These values may get updated by a message, so need to check them every frame
677 // The fields may be changed by the user, so only update them if the data changes
678 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
679 if (pos_global.isExactlyZero())
680 {
681 return; // invalid location
682 }
683 LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
684 LLString sim_name = gWorldMap->simNameFromPosGlobal( pos_global );
685 if ((status != LLTracker::TRACKING_NOTHING) &&
686 (status != mTrackedStatus || pos_global != mTrackedLocation || sim_name != mTrackedSimName))
687 {
688 mTrackedStatus = status;
689 mTrackedLocation = pos_global;
690 mTrackedSimName = sim_name;
691
692 if (status == LLTracker::TRACKING_AVATAR)
693 {
694 // *HACK: Adjust Z values automatically for liaisons &
695 // gods so they swoop down when they click on the
696 // map. Requested convenience.
697 if(gAgent.isGodlike())
698 {
699 pos_global[2] = 200;
700 }
701 }
702
703 childSetValue("location", sim_name);
704
705 F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
706 F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
707 childSetValue("spin x", LLSD(region_x) );
708 childSetValue("spin y", LLSD(region_y) );
709 childSetValue("spin z", LLSD((F32)pos_global.mdV[VZ]) );
710
711 mSLURL = LLWeb::escapeURL(llformat("http://slurl.com/secondlife/%s/%d/%d/%d",
712 sim_name.c_str(), llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ])));
713 }
714}
715
716void LLFloaterWorldMap::trackURL(const LLString& region_name, S32 x_coord, S32 y_coord, S32 z_coord)
717{
718 LLSimInfo* sim_info = gWorldMap->simInfoFromName(region_name);
719 z_coord = llclamp(z_coord, 0, 1000);
720 if (sim_info)
721 {
722 LLVector3 local_pos;
723 local_pos.mV[VX] = (F32)x_coord;
724 local_pos.mV[VY] = (F32)y_coord;
725 local_pos.mV[VZ] = (F32)z_coord;
726 LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
727 trackLocation(global_pos);
728 setDefaultBtn("Teleport");
729 }
730 else
731 {
732 // fill in UI based on URL
733 gFloaterWorldMap->childSetValue("location", region_name);
734 childSetValue("spin x", LLSD((F32)x_coord));
735 childSetValue("spin y", LLSD((F32)y_coord));
736 childSetValue("spin z", LLSD((F32)z_coord));
737
738 // pass sim name to combo box
739 gFloaterWorldMap->mCompletingRegionName = region_name;
740 gWorldMap->sendNamedRegionRequest(region_name);
741 LLString::toLower(gFloaterWorldMap->mCompletingRegionName);
742 gWorldMap->mIsTrackingCommit = TRUE;
743 }
744}
745
746void LLFloaterWorldMap::observeInventory(LLInventoryModel* model)
747{
748 if(mInventory)
749 {
750 mInventory->removeObserver(mInventoryObserver);
751 delete mInventoryObserver;
752 mInventory = NULL;
753 mInventoryObserver = NULL;
754 }
755 if(model)
756 {
757 mInventory = model;
758 mInventoryObserver = new LLMapInventoryObserver;
759 // Inventory deletes all observers on shutdown
760 mInventory->addObserver(mInventoryObserver);
761 inventoryChanged();
762 }
763}
764
765void LLFloaterWorldMap::inventoryChanged()
766{
767 if(!LLTracker::getTrackedLandmarkItemID().isNull())
768 {
769 LLUUID item_id = LLTracker::getTrackedLandmarkItemID();
770 buildLandmarkIDLists();
771 trackLandmark(item_id);
772 }
773}
774
775void LLFloaterWorldMap::observeFriends()
776{
777 if(!mFriendObserver)
778 {
779 mFriendObserver = new LLMapFriendObserver;
780 LLAvatarTracker::instance().addObserver(mFriendObserver);
781 friendsChanged();
782 }
783}
784
785void LLFloaterWorldMap::friendsChanged()
786{
787 LLAvatarTracker& t = LLAvatarTracker::instance();
788 const LLUUID& avatar_id = t.getAvatarID();
789 buildAvatarIDList();
790 if(avatar_id.notNull())
791 {
792 LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
793 if(!iface || !iface->setCurrentByID(avatar_id) ||
794 !t.getBuddyInfo(avatar_id)->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) || gAgent.isGodlike())
795 {
796 LLTracker::stopTracking(NULL);
797 }
798 }
799}
800
801// No longer really builds a list. Instead, just updates mAvatarCombo.
802void LLFloaterWorldMap::buildAvatarIDList()
803{
804 LLCtrlListInterface *list = childGetListInterface("friend combo");
805 if (!list) return;
806
807 // Delete all but the "None" entry
808 S32 list_size = list->getItemCount();
809 while (list_size > 1)
810 {
811 list->selectNthItem(1);
812 list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
813 --list_size;
814 }
815
816 LLSD default_column;
817 default_column["name"] = "friend name";
818 default_column["label"] = "Friend Name";
819 default_column["width"] = 500;
820 list->addColumn(default_column);
821
822 // Get all of the calling cards for avatar that are currently online
823 LLCollectMappableBuddies collector;
824 LLAvatarTracker::instance().applyFunctor(collector);
825 LLCollectMappableBuddies::buddy_map_t::iterator it;
826 LLCollectMappableBuddies::buddy_map_t::iterator end;
827 it = collector.mMappable.begin();
828 end = collector.mMappable.end();
829 for( ; it != end; ++it)
830 {
831 list->addSimpleElement((*it).first, ADD_BOTTOM, (*it).second);
832 }
833
834 list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
835 list->selectFirstItem();
836}
837
838
839void LLFloaterWorldMap::buildLandmarkIDLists()
840{
841 LLCtrlListInterface *list = childGetListInterface("landmark combo");
842 if (!list) return;
843
844 // Delete all but the "None" entry
845 S32 list_size = list->getItemCount();
846 while (list_size > 1)
847 {
848 list->selectNthItem(1);
849 list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
850 --list_size;
851 }
852
853 mLandmarkItemIDList.reset();
854 mLandmarkAssetIDList.reset();
855
856 // Get all of the current landmarks
857 mLandmarkAssetIDList.put( LLUUID::null );
858 mLandmarkItemIDList.put( LLUUID::null );
859
860 mLandmarkAssetIDList.put( sHomeID );
861 mLandmarkItemIDList.put( sHomeID );
862
863 LLInventoryModel::cat_array_t cats;
864 LLInventoryModel::item_array_t items;
865 LLIsType is_landmark(LLAssetType::AT_LANDMARK);
866 gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
867 cats,
868 items,
869 LLInventoryModel::EXCLUDE_TRASH,
870 is_landmark);
871 std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
872
873 S32 count = items.count();
874 for(S32 i = 0; i < count; ++i)
875 {
876 LLInventoryItem* item = items.get(i);
877
878 list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
879
880 mLandmarkAssetIDList.put( item->getAssetUUID() );
881 mLandmarkItemIDList.put( item->getUUID() );
882 }
883 list->sortByColumn("landmark name", TRUE);
884 list->selectFirstItem();
885}
886
887
888F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination,
889 F32 z_attenuation) const
890{
891 LLVector3d delta = destination - gAgent.getPositionGlobal();
892 // by attenuating the z-component we effectively
893 // give more weight to the x-y plane
894 delta.mdV[VZ] *= z_attenuation;
895 F32 distance = (F32)delta.magVec();
896 return distance;
897}
898
899
900void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
901{
902 LLCtrlListInterface *list = childGetListInterface("search_results");
903 if (list)
904 {
905 list->operateOnAll(LLCtrlListInterface::OP_DELETE);
906 }
907 if (!childHasKeyboardFocus("spin x"))
908 {
909 childSetValue("spin x", SIM_COORD_DEFAULT);
910 }
911 if (!childHasKeyboardFocus("spin y"))
912 {
913 childSetValue("spin y", SIM_COORD_DEFAULT);
914 }
915 if (!childHasKeyboardFocus("spin z"))
916 {
917 childSetValue("spin z", 0);
918 }
919 gWorldMap->mIsTrackingCommit = FALSE;
920 mCompletingRegionName = "";
921 mExactMatch = FALSE;
922}
923
924
925void LLFloaterWorldMap::clearLandmarkSelection(BOOL clear_ui)
926{
927 if (clear_ui || !childHasKeyboardFocus("landmark combo"))
928 {
929 LLCtrlListInterface *list = childGetListInterface("landmark combo");
930 if (list)
931 {
932 list->selectByValue( "None" );
933 }
934 }
935}
936
937
938void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
939{
940 if (clear_ui || !childHasKeyboardFocus("friend combo"))
941 {
942 mTrackedStatus = LLTracker::TRACKING_NOTHING;
943 LLCtrlListInterface *list = childGetListInterface("friend combo");
944 if (list)
945 {
946 list->selectByValue( "None" );
947 }
948 }
949}
950
951
952// Adjust the maximally zoomed out limit of the zoom slider so you
953// can see the whole world, plus a little.
954void LLFloaterWorldMap::adjustZoomSliderBounds()
955{
956 // World size in regions
957 S32 world_width_regions = gWorldMap->getWorldWidth() / REGION_WIDTH_UNITS;
958 S32 world_height_regions = gWorldMap->getWorldHeight() / REGION_WIDTH_UNITS;
959
960 // Pad the world size a little bit, so we have a nice border on
961 // the edge
962 world_width_regions++;
963 world_height_regions++;
964
965 // Find how much space we have to display the world
966 LLWorldMapView* map_panel;
967 map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
968 LLRect view_rect = map_panel->getRect();
969
970 // View size in pixels
971 S32 view_width = view_rect.getWidth();
972 S32 view_height = view_rect.getHeight();
973
974 // Pixels per region to display entire width/height
975 F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
976 F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
977
978 F32 pixels_per_region = llmin(width_pixels_per_region,
979 height_pixels_per_region);
980
981 // Round pixels per region to an even number of slider increments
982 S32 slider_units = llfloor(pixels_per_region / 0.2f);
983 pixels_per_region = slider_units * 0.2f;
984
985 // Make sure the zoom slider can be moved at least a little bit.
986 // Likewise, less than the increment pixels per region is just silly.
987 pixels_per_region = llclamp(pixels_per_region, 1.f, (F32)(pow(2.f, ZOOM_MAX) * 128.f));
988
989 F32 min_power = log(pixels_per_region/256.f)/log(2.f);
990 childSetMinValue("zoom slider", min_power);
991}
992
993
994//-------------------------------------------------------------------------
995// User interface widget callbacks
996//-------------------------------------------------------------------------
997
998// static
999void LLFloaterWorldMap::onPanBtn( void* userdata )
1000{
1001 if( !gFloaterWorldMap ) return;
1002
1003 EPanDirection direction = (EPanDirection)(intptr_t)userdata;
1004
1005 S32 pan_x = 0;
1006 S32 pan_y = 0;
1007 switch( direction )
1008 {
1009 case PAN_UP: pan_y = -1; break;
1010 case PAN_DOWN: pan_y = 1; break;
1011 case PAN_LEFT: pan_x = 1; break;
1012 case PAN_RIGHT: pan_x = -1; break;
1013 default: llassert(0); return;
1014 }
1015
1016 LLWorldMapView* map_panel;
1017 map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
1018 map_panel->translatePan( pan_x, pan_y );
1019}
1020
1021// static
1022void LLFloaterWorldMap::onGoHome(void*)
1023{
1024 gAgent.teleportHome();
1025 gFloaterWorldMap->close();
1026}
1027
1028
1029// static
1030void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdata )
1031{
1032 LLFloaterWorldMap* self = gFloaterWorldMap;
1033 if( !self || self->mIsClosing )
1034 {
1035 return;
1036 }
1037
1038 LLCtrlListInterface *list = self->childGetListInterface("landmark combo");
1039 if (!list) return;
1040
1041 LLUUID current_choice = list->getCurrentID();
1042
1043 gFloaterWorldMap->buildLandmarkIDLists();
1044
1045 if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
1046 {
1047 LLTracker::stopTracking(NULL);
1048 }
1049
1050}
1051
1052// static
1053void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata )
1054{
1055 LLFloaterWorldMap* self = gFloaterWorldMap;
1056
1057 if( !self || self->mIsClosing )
1058 {
1059 return;
1060 }
1061
1062 LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("landmark combo");
1063 if (!list) return;
1064
1065 LLUUID asset_id;
1066 LLUUID item_id = list->getCurrentID();
1067
1068 LLTracker::stopTracking(NULL);
1069
1070 //RN: stopTracking() clears current combobox selection, need to reassert it here
1071 list->setCurrentByID(item_id);
1072
1073 if( item_id.isNull() )
1074 {
1075 }
1076 else if( item_id == sHomeID )
1077 {
1078 asset_id = sHomeID;
1079 }
1080 else
1081 {
1082 LLInventoryItem* item = gInventory.getItem( item_id );
1083 if( item )
1084 {
1085 asset_id = item->getAssetUUID();
1086 }
1087 else
1088 {
1089 // Something went wrong, so revert to a safe value.
1090 item_id.setNull();
1091 }
1092 }
1093
1094 self->trackLandmark( item_id);
1095 onShowTargetBtn(self);
1096}
1097
1098// static
1099void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata )
1100{
1101 LLFloaterWorldMap* self = gFloaterWorldMap;
1102 if( !self || self->mIsClosing )
1103 {
1104 return;
1105 }
1106
1107 LLCtrlListInterface *list = self->childGetListInterface("friend combo");
1108 if (!list) return;
1109
1110 LLUUID current_choice;
1111
1112 if( LLAvatarTracker::instance().haveTrackingInfo() )
1113 {
1114 current_choice = LLAvatarTracker::instance().getAvatarID();
1115 }
1116
1117 self->buildAvatarIDList();
1118
1119 if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
1120 {
1121 LLTracker::stopTracking(NULL);
1122 }
1123}
1124
1125
1126// static
1127void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata )
1128{
1129 LLFloaterWorldMap* self = gFloaterWorldMap;
1130 if( !self || self->mIsClosing )
1131 {
1132 return;
1133 }
1134
1135 LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("friend combo");
1136 if (!list) return;
1137
1138 const LLUUID& new_avatar_id = list->getCurrentID();
1139 if (new_avatar_id.notNull())
1140 {
1141 LLString name;
1142 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(gFloaterWorldMap, "friend combo");
1143 if (combo) name = combo->getSimple();
1144 self->trackAvatar(new_avatar_id, name);
1145 onShowTargetBtn(self);
1146 }
1147}
1148
1149// static
1150void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata )
1151{
1152 LLFloaterWorldMap *self = gFloaterWorldMap;
1153 if (self->childHasKeyboardFocus("location") &&
1154 self->childGetValue("location").asString().length() > 0)
1155 {
1156 self->setDefaultBtn("DoSearch");
1157 }
1158 else
1159 {
1160 self->setDefaultBtn("");
1161 }
1162}
1163
1164// static
1165void LLFloaterWorldMap::onLocationCommit( void* userdata )
1166{
1167 LLFloaterWorldMap *self = gFloaterWorldMap;
1168 if( !self || self->mIsClosing )
1169 {
1170 return;
1171 }
1172
1173 self->clearLocationSelection(FALSE);
1174 self->mCompletingRegionName = "";
1175 self->mLastRegionName = "";
1176
1177 LLString str = self->childGetValue("location").asString();
1178
1179 LLString::toLower(str);
1180 gFloaterWorldMap->mCompletingRegionName = str;
1181 gWorldMap->mIsTrackingCommit = TRUE;
1182 self->mExactMatch = FALSE;
1183 if (str.length() >= 3)
1184 {
1185 gWorldMap->sendNamedRegionRequest(str);
1186 }
1187 else
1188 {
1189 str += "#";
1190 gWorldMap->sendNamedRegionRequest(str);
1191 }
1192}
1193
1194
1195// static
1196void LLFloaterWorldMap::onClearBtn(void* data)
1197{
1198 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1199 self->mTrackedStatus = LLTracker::TRACKING_NOTHING;
1200 LLTracker::stopTracking((void *)(intptr_t)TRUE);
1201 gWorldMap->mIsTrackingUnknownLocation = FALSE;
1202}
1203
1204// static
1205void LLFloaterWorldMap::onFlyBtn(void* data)
1206{
1207 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1208 self->fly();
1209}
1210
1211void LLFloaterWorldMap::onShowTargetBtn(void* data)
1212{
1213 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1214 self->centerOnTarget(TRUE);
1215}
1216
1217void LLFloaterWorldMap::onShowAgentBtn(void* data)
1218{
1219 LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate
1220}
1221
1222// static
1223void LLFloaterWorldMap::onTeleportBtn(void* data)
1224{
1225 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1226 self->teleport();
1227}
1228
1229// static
1230void LLFloaterWorldMap::onCopySLURL(void* data)
1231{
1232 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1233 gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(self->mSLURL));
1234
1235 LLString::format_map_t args;
1236 args["[SLURL]"] = self->mSLURL;
1237
1238 LLAlertDialog::showXml("CopySLURL", args);
1239}
1240
1241void LLFloaterWorldMap::onCheckEvents(LLUICtrl*, void* data)
1242{
1243 LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
1244 if(!self) return;
1245 self->childSetEnabled("event_mature_chk", self->childGetValue("event_chk"));
1246}
1247
1248// protected
1249void LLFloaterWorldMap::centerOnTarget(BOOL animate)
1250{
1251 LLVector3d pos_global;
1252 if(LLTracker::getTrackingStatus() != LLTracker::TRACKING_NOTHING)
1253 {
1254 LLVector3d tracked_position = LLTracker::getTrackedPositionGlobal();
1255 //RN: tracker doesn't allow us to query completion, so we check for a tracking position of
1256 // absolute zero, and keep trying in the draw loop
1257 if (tracked_position.isExactlyZero())
1258 {
1259 mWaitingForTracker = TRUE;
1260 return;
1261 }
1262 else
1263 {
1264 // We've got the position finally, so we're no longer busy. JC
1265// getWindow()->decBusyCount();
1266 pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();
1267 }
1268 }
1269 else if(gWorldMap->mIsTrackingUnknownLocation)
1270 {
1271 pos_global = gWorldMap->mUnknownLocation - gAgent.getCameraPositionGlobal();;
1272 }
1273 else
1274 {
1275 // default behavior = center on agent
1276 pos_global.clearVec();
1277 }
1278
1279 LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sPixelsPerMeter)),
1280 -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sPixelsPerMeter)),
1281 !animate);
1282 mWaitingForTracker = FALSE;
1283}
1284
1285// protected
1286void LLFloaterWorldMap::fly()
1287{
1288 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
1289
1290 // Start the autopilot and close the floater,
1291 // so we can see where we're flying
1292 if (!pos_global.isExactlyZero())
1293 {
1294 gAgent.startAutoPilotGlobal( pos_global );
1295 close();
1296 }
1297 else
1298 {
1299 make_ui_sound("UISndInvalidOp");
1300 }
1301}
1302
1303
1304// protected
1305void LLFloaterWorldMap::teleport()
1306{
1307 BOOL teleport_home = FALSE;
1308 LLVector3d pos_global;
1309 LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
1310
1311 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
1312 if (LLTracker::TRACKING_AVATAR == tracking_status
1313 && av_tracker.haveTrackingInfo() )
1314 {
1315 pos_global = av_tracker.getGlobalPos();
1316 pos_global.mdV[VZ] = childGetValue("spin z");
1317 }
1318 else if ( LLTracker::TRACKING_LANDMARK == tracking_status)
1319 {
1320 if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
1321 {
1322 teleport_home = TRUE;
1323 }
1324 else
1325 {
1326 LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
1327 LLUUID region_id;
1328 if(landmark
1329 && !landmark->getGlobalPos(pos_global)
1330 && landmark->getRegionID(region_id))
1331 {
1332 LLLandmark::requestRegionHandle(
1333 gMessageSystem,
1334 gAgent.getRegionHost(),
1335 region_id,
1336 NULL);
1337 }
1338 }
1339 }
1340 else if ( LLTracker::TRACKING_LOCATION == tracking_status)
1341 {
1342 pos_global = LLTracker::getTrackedPositionGlobal();
1343 }
1344 else
1345 {
1346 make_ui_sound("UISndInvalidOp");
1347 }
1348
1349 // Do the teleport, which will also close the floater
1350 if (teleport_home)
1351 {
1352 gAgent.teleportHome();
1353 }
1354 else if (!pos_global.isExactlyZero())
1355 {
1356 if(LLTracker::TRACKING_LANDMARK == tracking_status)
1357 {
1358 gAgent.teleportViaLandmark(LLTracker::getTrackedLandmarkAssetID());
1359 }
1360 else
1361 {
1362 gAgent.teleportViaLocation( pos_global );
1363 }
1364 }
1365}
1366
1367// static
1368void LLFloaterWorldMap::onGoToLandmarkDialog( S32 option, void* userdata )
1369{
1370 LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
1371 switch( option )
1372 {
1373 case 0:
1374 self->teleportToLandmark();
1375 break;
1376 case 1:
1377 self->flyToLandmark();
1378 break;
1379 default:
1380 // nothing
1381 break;
1382 }
1383}
1384
1385void LLFloaterWorldMap::flyToLandmark()
1386{
1387 LLVector3d destination_pos_global;
1388 if( !LLTracker::getTrackedLandmarkAssetID().isNull() )
1389 {
1390 if (LLTracker::hasLandmarkPosition())
1391 {
1392 gAgent.startAutoPilotGlobal( LLTracker::getTrackedPositionGlobal() );
1393 }
1394 }
1395}
1396
1397void LLFloaterWorldMap::teleportToLandmark()
1398{
1399 BOOL has_destination = FALSE;
1400 LLUUID destination_id; // Null means "home"
1401
1402 if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
1403 {
1404 has_destination = TRUE;
1405 }
1406 else
1407 {
1408 LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
1409 LLVector3d global_pos;
1410 if(landmark && landmark->getGlobalPos(global_pos))
1411 {
1412 destination_id = LLTracker::getTrackedLandmarkAssetID();
1413 has_destination = TRUE;
1414 }
1415 else if(landmark)
1416 {
1417 // pop up an anonymous request request.
1418 LLUUID region_id;
1419 if(landmark->getRegionID(region_id))
1420 {
1421 LLLandmark::requestRegionHandle(
1422 gMessageSystem,
1423 gAgent.getRegionHost(),
1424 region_id,
1425 NULL);
1426 }
1427 }
1428 }
1429
1430 if( has_destination )
1431 {
1432 gAgent.teleportViaLandmark( destination_id );
1433 }
1434}
1435
1436
1437void LLFloaterWorldMap::teleportToAvatar()
1438{
1439 LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
1440 if(av_tracker.haveTrackingInfo())
1441 {
1442 LLVector3d pos_global = av_tracker.getGlobalPos();
1443 gAgent.teleportViaLocation( pos_global );
1444 }
1445}
1446
1447
1448void LLFloaterWorldMap::flyToAvatar()
1449{
1450 if( LLAvatarTracker::instance().haveTrackingInfo() )
1451 {
1452 gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
1453 }
1454}
1455
1456// static
1457void LLFloaterWorldMap::onCommitBackground(void* userdata, bool from_click)
1458{
1459 LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
1460
1461 // Find my index
1462 S32 index = self->mTabs->getCurrentPanelIndex();
1463
1464 if (gWorldMap)
1465 {
1466 gWorldMap->setCurrentLayer(index);
1467 }
1468}
1469
1470void LLFloaterWorldMap::updateSims(bool found_null_sim)
1471{
1472 if (mCompletingRegionName == "")
1473 {
1474 return;
1475 }
1476
1477 LLCtrlListInterface *list = childGetListInterface("search_results");
1478 if (!list) return;
1479 list->operateOnAll(LLCtrlListInterface::OP_DELETE);
1480
1481 LLSD selected_value = list->getSimpleSelectedValue();
1482
1483 S32 name_length = mCompletingRegionName.length();
1484
1485 BOOL match_found = FALSE;
1486 S32 num_results = 0;
1487 std::map<U64, LLSimInfo*>::const_iterator it;
1488 for (it = gWorldMap->mSimInfoMap.begin(); it != gWorldMap->mSimInfoMap.end(); ++it)
1489 {
1490 LLSimInfo* info = (*it).second;
1491 LLString sim_name = info->mName;
1492 LLString sim_name_lower = sim_name;
1493 LLString::toLower(sim_name_lower);
1494
1495 if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
1496 {
1497 if (gWorldMap->mIsTrackingCommit)
1498 {
1499 if (sim_name_lower == mCompletingRegionName)
1500 {
1501 selected_value = sim_name;
1502 match_found = TRUE;
1503 }
1504 }
1505
1506 LLSD value;
1507 value["id"] = sim_name;
1508 value["columns"][0]["column"] = "sim_name";
1509 value["columns"][0]["value"] = sim_name;
1510 list->addElement(value);
1511 num_results++;
1512 }
1513 }
1514
1515 list->selectByValue(selected_value);
1516
1517 if (found_null_sim)
1518 {
1519 mCompletingRegionName = "";
1520 }
1521
1522 if (match_found)
1523 {
1524 mExactMatch = TRUE;
1525 childSetFocus("search_results");
1526 onCommitSearchResult(NULL, this);
1527 }
1528 else if (!mExactMatch && num_results > 0)
1529 {
1530 list->selectFirstItem(); // select first item by default
1531 childSetFocus("search_results");
1532 onCommitSearchResult(NULL, this);
1533 }
1534 else
1535 {
1536 list->addSimpleElement("None found.");
1537 list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
1538 }
1539}
1540
1541// static
1542void LLFloaterWorldMap::onCommitLocation(LLUICtrl* ctrl, void* userdata)
1543{
1544 LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
1545 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
1546 if ( LLTracker::TRACKING_LOCATION == tracking_status)
1547 {
1548 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
1549 F64 local_x = self->childGetValue("spin x");
1550 F64 local_y = self->childGetValue("spin y");
1551 F64 local_z = self->childGetValue("spin z");
1552 pos_global.mdV[VX] += -fmod(pos_global.mdV[VX], 256.0) + local_x;
1553 pos_global.mdV[VY] += -fmod(pos_global.mdV[VY], 256.0) + local_y;
1554 pos_global.mdV[VZ] = local_z;
1555 self->trackLocation(pos_global);
1556 }
1557}
1558
1559// static
1560void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata)
1561{
1562 LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
1563
1564 LLCtrlListInterface *list = self->childGetListInterface("search_results");
1565 if (!list) return;
1566
1567 LLSD selected_value = list->getSimpleSelectedValue();
1568 LLString sim_name = selected_value.asString();
1569 if (sim_name.empty())
1570 {
1571 return;
1572 }
1573 LLString::toLower(sim_name);
1574
1575 std::map<U64, LLSimInfo*>::const_iterator it;
1576 for (it = gWorldMap->mSimInfoMap.begin(); it != gWorldMap->mSimInfoMap.end(); ++it)
1577 {
1578 LLSimInfo* info = (*it).second;
1579 LLString info_sim_name = info->mName;
1580 LLString::toLower(info_sim_name);
1581
1582 if (sim_name == info_sim_name)
1583 {
1584 LLVector3d pos_global = from_region_handle( info->mHandle );
1585 F64 local_x = self->childGetValue("spin x");
1586 F64 local_y = self->childGetValue("spin y");
1587 F64 local_z = self->childGetValue("spin z");
1588 pos_global.mdV[VX] += local_x;
1589 pos_global.mdV[VY] += local_y;
1590 pos_global.mdV[VZ] = local_z;
1591
1592 self->childSetValue("location", sim_name);
1593 self->trackLocation(pos_global);
1594 self->setDefaultBtn("Teleport");
1595 break;
1596 }
1597 }
1598
1599 onShowTargetBtn(self);
1600}