summaryrefslogtreecommitdiff
path: root/indra/newview/llfloaterworldmap.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llfloaterworldmap.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llfloaterworldmap.cpp')
-rw-r--r--indra/newview/llfloaterworldmap.cpp1579
1 files changed, 1579 insertions, 0 deletions
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
new file mode 100644
index 0000000000..3492a36353
--- /dev/null
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -0,0 +1,1579 @@
+/**
+ * @file llfloaterworldmap.cpp
+ * @author James Cook, Tom Yedwab
+ * @brief LLFloaterWorldMap class implementation
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+/*
+ * Map of the entire world, with multiple background images,
+ * avatar tracking, teleportation by double-click, etc.
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterworldmap.h"
+
+// Library includes
+#include "llfontgl.h"
+#include "llinventory.h"
+#include "lllineeditor.h"
+#include "message.h"
+
+// Viewer includes
+#include "llagent.h"
+#include "llviewerwindow.h"
+#include "llbutton.h"
+#include "llcallingcard.h"
+#include "llcolorscheme.h"
+#include "llcombobox.h"
+#include "llviewercontrol.h"
+#include "lldraghandle.h"
+#include "lleconomy.h"
+#include "llfirstuse.h"
+#include "llfocusmgr.h"
+#include "lliconctrl.h"
+#include "llinventorymodel.h"
+#include "llinventoryview.h"
+#include "lllandmarklist.h"
+#include "llnetmap.h"
+#include "llpreviewlandmark.h"
+#include "llradiogroup.h"
+#include "llregionhandle.h"
+#include "llresizehandle.h"
+#include "llresmgr.h"
+#include "llscrolllistctrl.h"
+#include "llsliderctrl.h"
+#include "llspinctrl.h"
+#include "llstatusbar.h"
+#include "lltabcontainer.h"
+#include "lltextbox.h"
+#include "lltracker.h"
+#include "llui.h"
+#include "lluiconstants.h"
+#include "llviewercamera.h"
+#include "llviewermenu.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llworldmap.h"
+#include "llworldmapview.h"
+#include "llurl.h"
+#include "llvieweruictrlfactory.h"
+#include "viewer.h"
+#include "llmapimagetype.h"
+#include "llweb.h"
+
+#include "llglheaders.h"
+
+//---------------------------------------------------------------------------
+// Constants
+//---------------------------------------------------------------------------
+static const F32 MAP_ZOOM_TIME = 0.2f;
+
+enum EPanDirection
+{
+ PAN_UP,
+ PAN_DOWN,
+ PAN_LEFT,
+ PAN_RIGHT
+};
+
+// Values in pixels per region
+static const F32 ZOOM_MIN = -8.f; // initial value, updated by adjustZoomSlider
+static const F32 ZOOM_MAX = 0.f;
+static const F32 ZOOM_INC = 0.2f;
+
+static const F32 SIM_COORD_MIN = 0.f;
+static const F32 SIM_COORD_MAX = 255.f;
+static const F32 SIM_COORD_DEFAULT = 128.f;
+
+static const F64 MAX_FLY_DISTANCE = 363.f; // Diagonal size of one sim.
+static const F64 MAX_FLY_DISTANCE_SQUARED = MAX_FLY_DISTANCE * MAX_FLY_DISTANCE;
+
+//---------------------------------------------------------------------------
+// Globals
+//---------------------------------------------------------------------------
+
+LLFloaterWorldMap* gFloaterWorldMap = NULL;
+
+class LLMapInventoryObserver : public LLInventoryObserver
+{
+public:
+ LLMapInventoryObserver() {}
+ virtual ~LLMapInventoryObserver() {}
+ virtual void changed(U32 mask);
+};
+
+void LLMapInventoryObserver::changed(U32 mask)
+{
+ // if there's a change we're interested in.
+ if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
+ LLInventoryObserver::REMOVE)) != 0)
+ {
+ gFloaterWorldMap->inventoryChanged();
+ }
+}
+
+class LLMapFriendObserver : public LLFriendObserver
+{
+public:
+ LLMapFriendObserver() {}
+ virtual ~LLMapFriendObserver() {}
+ virtual void changed(U32 mask);
+};
+
+void LLMapFriendObserver::changed(U32 mask)
+{
+ // if there's a change we're interested in.
+ if((mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE | LLFriendObserver::POWERS)) != 0)
+ {
+ gFloaterWorldMap->friendsChanged();
+ }
+}
+
+//---------------------------------------------------------------------------
+// Statics
+//---------------------------------------------------------------------------
+
+// Used as a pretend asset and inventory id to mean "landmark at my home location."
+const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001" );
+
+//---------------------------------------------------------------------------
+// Construction and destruction
+//---------------------------------------------------------------------------
+
+
+LLFloaterWorldMap::LLFloaterWorldMap()
+: LLFloater("worldmap", "FloaterWorldMapRect", "World Map",
+ TRUE, // resize
+ 410, // min-width
+ 520, // min-height
+ FALSE, // drag on left
+ TRUE, // minimize
+ TRUE), // close
+ mInventory(NULL),
+ mInventoryObserver(NULL),
+ mFriendObserver(NULL),
+ mCompletingRegionName(""),
+ mWaitingForTracker(FALSE),
+ mExactMatch(FALSE),
+ mTrackedLocation(0,0,0),
+ mTrackedStatus(LLTracker::TRACKING_NOTHING)
+{
+ LLCallbackMap::map_t factory_map;
+ factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
+ factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL);
+ gUICtrlFactory->buildFloater(this, "floater_world_map.xml", &factory_map);
+}
+
+// static
+void* LLFloaterWorldMap::createWorldMapView(void* data)
+{
+ return new LLWorldMapView("mapview", LLRect(0,300,400,0));
+}
+
+BOOL LLFloaterWorldMap::postBuild()
+{
+ mTabs = LLUICtrlFactory::getTabContainerByName(this, "maptab");
+ if (!mTabs) return FALSE;
+
+ LLPanel *panel;
+
+ panel = LLUICtrlFactory::getPanelByName(mTabs, "objects_mapview");
+ if (panel)
+ {
+ mTabs->setTabChangeCallback(panel, onCommitBackground);
+ mTabs->setTabUserData(panel, this);
+ }
+ panel = LLUICtrlFactory::getPanelByName(mTabs, "terrain_mapview");
+ if (panel)
+ {
+ mTabs->setTabChangeCallback(panel, onCommitBackground);
+ mTabs->setTabUserData(panel, this);
+ }
+
+ onCommitBackground((void*)this, false);
+
+ childSetCommitCallback("friend combo", onAvatarComboCommit, this);
+
+ LLComboBox *avatar_combo = LLUICtrlFactory::getComboBoxByName(this, "friend combo");
+ if (avatar_combo)
+ {
+ avatar_combo->selectFirstItem();
+ avatar_combo->setPrearrangeCallback( onAvatarComboPrearrange );
+ }
+
+ childSetAction("DoSearch", onLocationCommit, this);
+
+ childSetFocusChangedCallback("location", updateSearchEnabled);
+ childSetKeystrokeCallback("location", (void (*)(LLLineEditor*,void*))updateSearchEnabled, NULL);
+
+ childSetCommitCallback("search_results", onCommitSearchResult, this);
+ childSetDoubleClickCallback("search_results", onTeleportBtn);
+ childSetCommitCallback("spin x", onCommitLocation, this);
+ childSetCommitCallback("spin y", onCommitLocation, this);
+ childSetCommitCallback("spin z", onCommitLocation, this);
+
+ childSetCommitCallback("landmark combo", onLandmarkComboCommit, this);
+
+ LLComboBox *landmark_combo = LLUICtrlFactory::getComboBoxByName(this, "landmark combo");
+ if (landmark_combo)
+ {
+ landmark_combo->selectFirstItem();
+ landmark_combo->setPrearrangeCallback( onLandmarkComboPrearrange );
+ }
+
+ childSetAction("Go Home", onGoHome, this);
+
+ childSetAction("Teleport", onTeleportBtn, this);
+
+ childSetAction("Show Destination", onShowTargetBtn, this);
+ childSetAction("Show My Location", onShowAgentBtn, this);
+ childSetAction("Clear", onClearBtn, this);
+ childSetAction("copy_slurl", onCopySLURL, this);
+
+ mCurZoomVal = log(gMapScale)/log(2.f);
+ childSetValue("zoom slider", gMapScale);
+
+ setDefaultBtn("");
+
+ if ( gAgent.mAccess <= SIM_ACCESS_PG )
+ {
+ // Hide Mature Events controls
+ childHide("events_mature_icon");
+ childHide("events_mature_label");
+ childHide("event_mature_chk");
+ }
+
+ mZoomTimer.stop();
+
+ return TRUE;
+}
+
+// virtual
+LLFloaterWorldMap::~LLFloaterWorldMap()
+{
+ // All cleaned up by LLView destructor
+ mTabs = NULL;
+
+ // Inventory deletes all observers on shutdown
+ mInventory = NULL;
+ mInventoryObserver = NULL;
+
+ // avatar tracker will delete this for us.
+ mFriendObserver = NULL;
+}
+
+
+// virtual
+void LLFloaterWorldMap::onClose(bool app_quitting)
+{
+ setVisible(FALSE);
+}
+
+// Allow us to download landmarks quickly when map is shown
+class LLLandmarkFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
+{
+public:
+ virtual void done()
+ {
+ // We need to find landmarks in all folders, so get the main
+ // background download going.
+ gInventory.startBackgroundFetch();
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+// static
+void LLFloaterWorldMap::show(void*, BOOL center_on_target)
+{
+ BOOL was_visible = gFloaterWorldMap->getVisible();
+
+ gFloaterWorldMap->mIsClosing = FALSE;
+ gFloaterWorldMap->open();
+
+ LLWorldMapView* map_panel;
+ map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
+ map_panel->clearLastClick();
+
+ if (!was_visible)
+ {
+ // reset pan on show, so it centers on you again
+ if (!center_on_target)
+ {
+ LLWorldMapView::setPan(0, 0, TRUE);
+ }
+ map_panel->updateVisibleBlocks();
+
+ // Reload the agent positions when we show the window
+ gWorldMap->eraseItems();
+
+ // Reload any maps that may have changed
+ gWorldMap->clearSimFlags();
+
+ const S32 panel_num = gFloaterWorldMap->mTabs->getCurrentPanelIndex();
+ const bool request_from_sim = true;
+ gWorldMap->setCurrentLayer(panel_num, request_from_sim);
+
+ // We may already have a bounding box for the regions of the world,
+ // so use that to adjust the view.
+ gFloaterWorldMap->adjustZoomSliderBounds();
+
+ // Could be first show
+ LLFirstUse::useMap();
+
+ // Start speculative download of landmarks
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+ LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
+ gInventory.startBackgroundFetch(landmark_folder_id);
+
+ gFloaterWorldMap->childSetFocus("location", TRUE);
+ gFocusMgr.triggerFocusFlash();
+
+ gFloaterWorldMap->buildAvatarIDList();
+ gFloaterWorldMap->buildLandmarkIDLists();
+ }
+
+ if (center_on_target)
+ {
+ gFloaterWorldMap->centerOnTarget(FALSE);
+ }
+}
+
+
+
+// static
+void LLFloaterWorldMap::reloadIcons(void*)
+{
+ gWorldMap->eraseItems();
+
+ gWorldMap->sendMapLayerRequest();
+}
+
+
+// static
+void LLFloaterWorldMap::toggle(void*)
+{
+ BOOL visible = gFloaterWorldMap->getVisible();
+
+ if (!visible)
+ {
+ show(NULL, FALSE);
+ }
+ else
+ {
+ gFloaterWorldMap->mIsClosing = TRUE;
+ gFloaterWorldMap->close();
+ }
+}
+
+
+// static
+void LLFloaterWorldMap::hide(void*)
+{
+ gFloaterWorldMap->mIsClosing = TRUE;
+ gFloaterWorldMap->close();
+}
+
+
+// virtual
+void LLFloaterWorldMap::setVisible( BOOL visible )
+{
+ LLFloater::setVisible( visible );
+
+ gSavedSettings.setBOOL( "ShowWorldMap", visible );
+
+ if( !visible )
+ {
+ // While we're not visible, discard the overlay images we're using
+ if (gWorldMap)
+ {
+ gWorldMap->clearImageRefs();
+ }
+ }
+}
+
+
+// virtual
+BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
+{
+ BOOL handled;
+ handled = LLFloater::handleHover(x, y, mask);
+ return handled;
+}
+
+BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ if (getVisible() && !isMinimized() && isFrontmost())
+ {
+ F32 slider_value = (F32)childGetValue("zoom slider").asReal();
+ slider_value += ((F32)clicks * -0.3333f);
+ childSetValue("zoom slider", LLSD(slider_value));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+// virtual
+void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent )
+{
+ LLFloater::reshape( width, height, called_from_parent );
+
+ // Might have changed size of world display area
+ // JC: Technically, this is correct, but it makes the slider "pop"
+ // if you resize the window, then draw the slider. Just leaving it
+ // the way it was when you opened the window seems better.
+ // adjustZoomSliderBounds();
+}
+
+
+// virtual
+void LLFloaterWorldMap::draw()
+{
+ if( !getVisible() )
+ {
+ return;
+ }
+
+ updateLocation();
+
+ LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
+ if (LLTracker::TRACKING_AVATAR == tracking_status)
+ {
+ childSetColor("avatar_icon", gTrackColor);
+ }
+ else
+ {
+ childSetColor("avatar_icon", gDisabledTrackColor);
+ }
+
+ if (LLTracker::TRACKING_LANDMARK == tracking_status)
+ {
+ childSetColor("landmark_icon", gTrackColor);
+ }
+ else
+ {
+ childSetColor("landmark_icon", gDisabledTrackColor);
+ }
+
+ if (LLTracker::TRACKING_LOCATION == tracking_status)
+ {
+ childSetColor("location_icon", gTrackColor);
+ }
+ else
+ {
+ if (mCompletingRegionName != "")
+ {
+ F64 seconds = LLTimer::getElapsedSeconds();
+ double value = fmod(seconds, 2);
+ value = 0.5 + 0.5*cos(value * 3.14159f);
+ LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
+ childSetColor("location_icon", loading_color);
+ }
+ else
+ {
+ childSetColor("location_icon", gDisabledTrackColor);
+ }
+ }
+
+ // check for completion of tracking data
+ if (mWaitingForTracker)
+ {
+ centerOnTarget(TRUE);
+ }
+
+ childSetEnabled("Teleport", (BOOL)tracking_status);
+// childSetEnabled("Clear", (BOOL)tracking_status);
+ childSetEnabled("Show Destination", (BOOL)tracking_status || gWorldMap->mIsTrackingUnknownLocation);
+ childSetEnabled("copy_slurl", (BOOL)tracking_status);
+
+ setMouseOpaque(TRUE);
+ mDragHandle->setMouseOpaque(TRUE);
+
+ //RN: snaps to zoom value because interpolation caused jitter in the text rendering
+ if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)childGetValue("zoom slider").asReal())
+ {
+ mZoomTimer.start();
+ }
+ F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
+ if (interp > 1.f)
+ {
+ interp = 1.f;
+ mZoomTimer.stop();
+ }
+ mCurZoomVal = lerp(mCurZoomVal, (F32)childGetValue("zoom slider").asReal(), interp);
+ F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
+ LLWorldMapView::setScale( map_scale );
+
+ LLFloater::draw();
+}
+
+
+//-------------------------------------------------------------------------
+// Internal utility functions
+//-------------------------------------------------------------------------
+
+
+void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const LLString& name )
+{
+ LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
+ if (!iface) return;
+
+ buildAvatarIDList();
+ if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
+ {
+ // *HACK: Adjust Z values automatically for liaisons & gods so
+ // we swoop down when they click on the map.
+ if(gAgent.isGodlike())
+ {
+ childSetValue("spin z", LLSD(200.f));
+ }
+ // Don't re-request info if we already have it or we won't have it in time to teleport
+ if (mTrackedStatus != LLTracker::TRACKING_AVATAR || name != mTrackedAvatarName)
+ {
+ mTrackedStatus = LLTracker::TRACKING_AVATAR;
+ mTrackedAvatarName = name;
+ LLTracker::trackAvatar(avatar_id, name);
+ }
+ }
+ else
+ {
+ LLTracker::stopTracking(NULL);
+ }
+ setDefaultBtn("Teleport");
+}
+
+void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
+{
+ LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
+ if (!iface) return;
+
+ buildLandmarkIDLists();
+ BOOL found = FALSE;
+ S32 idx;
+ for (idx = 0; idx < mLandmarkItemIDList.count(); idx++)
+ {
+ if ( mLandmarkItemIDList.get(idx) == landmark_item_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found && iface->setCurrentByID( landmark_item_id ) )
+ {
+ LLUUID asset_id = mLandmarkAssetIDList.get( idx );
+ LLString name;
+ LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(this, "landmark combo");
+ if (combo) name = combo->getSimple();
+ mTrackedStatus = LLTracker::TRACKING_LANDMARK;
+ LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ), // assetID
+ mLandmarkItemIDList.get( idx ), // itemID
+ name); // name
+
+ if( asset_id != sHomeID )
+ {
+ // start the download process
+ gLandmarkList.getAsset( asset_id);
+ }
+
+ // We have to download both region info and landmark data, so set busy. JC
+// getWindow()->incBusyCount();
+ }
+ else
+ {
+ LLTracker::stopTracking(NULL);
+ }
+ setDefaultBtn("Teleport");
+}
+
+
+void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
+{
+ mTrackedStatus = LLTracker::TRACKING_LOCATION;
+ LLTracker::trackLocation(event_info.mPosGlobal, event_info.mName, event_info.mToolTip, LLTracker::LOCATION_EVENT);
+ setDefaultBtn("Teleport");
+}
+
+void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
+{
+ mTrackedStatus = LLTracker::TRACKING_LOCATION;
+ LLTracker::trackLocation(item.mPosGlobal, item.mName, item.mToolTip, LLTracker::LOCATION_ITEM);
+ setDefaultBtn("Teleport");
+}
+
+void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
+{
+ LLSimInfo* sim_info = gWorldMap->simInfoFromPosGlobal(pos_global);
+ if (!sim_info)
+ {
+ gWorldMap->mIsTrackingUnknownLocation = TRUE;
+ gWorldMap->mInvalidLocation = FALSE;
+ gWorldMap->mUnknownLocation = pos_global;
+ LLTracker::stopTracking(NULL);
+ S32 world_x = S32(pos_global.mdV[0] / 256);
+ S32 world_y = S32(pos_global.mdV[1] / 256);
+ gWorldMap->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
+ setDefaultBtn("");
+ return;
+ }
+ if (sim_info->mAccess == SIM_ACCESS_DOWN)
+ {
+ // Down sim. Show the blue circle of death!
+ gWorldMap->mIsTrackingUnknownLocation = TRUE;
+ gWorldMap->mUnknownLocation = pos_global;
+ gWorldMap->mInvalidLocation = TRUE;
+ LLTracker::stopTracking(NULL);
+ setDefaultBtn("");
+ return;
+ }
+
+ LLString sim_name = gWorldMap->simNameFromPosGlobal( pos_global );
+ F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
+ F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
+ LLString full_name = llformat("%s (%d, %d, %d)",
+ sim_name.c_str(),
+ llround(region_x),
+ llround(region_y),
+ llround((F32)pos_global.mdV[VZ]));
+
+ LLString tooltip("");
+ mTrackedStatus = LLTracker::TRACKING_LOCATION;
+ LLTracker::trackLocation(pos_global, full_name, tooltip);
+ gWorldMap->mIsTrackingUnknownLocation = FALSE;
+ gWorldMap->mIsTrackingDoubleClick = FALSE;
+ gWorldMap->mIsTrackingCommit = FALSE;
+
+ setDefaultBtn("Teleport");
+}
+
+void LLFloaterWorldMap::updateLocation()
+{
+ // These values may get updated by a message, so need to check them every frame
+ // The fields may be changed by the user, so only update them if the data changes
+ LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
+ if (pos_global.isExactlyZero())
+ {
+ return; // invalid location
+ }
+ LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
+ LLString sim_name = gWorldMap->simNameFromPosGlobal( pos_global );
+ if ((status != LLTracker::TRACKING_NOTHING) &&
+ (status != mTrackedStatus || pos_global != mTrackedLocation || sim_name != mTrackedSimName))
+ {
+ mTrackedStatus = status;
+ mTrackedLocation = pos_global;
+ mTrackedSimName = sim_name;
+
+ if (status == LLTracker::TRACKING_AVATAR)
+ {
+ // *HACK: Adjust Z values automatically for liaisons & gods so
+ // we swoop down when they click on the map.
+ if(gAgent.isGodlike())
+ {
+ pos_global[2] = 200;
+ }
+ }
+
+ childSetValue("location", sim_name);
+
+ F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
+ F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
+ childSetValue("spin x", LLSD(region_x) );
+ childSetValue("spin y", LLSD(region_y) );
+ childSetValue("spin z", LLSD((F32)pos_global.mdV[VZ]) );
+
+ mSLURL = LLWeb::escapeURL(llformat("http://slurl.com/secondlife/%s/%d/%d/%d",
+ sim_name.c_str(), llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ])));
+ }
+}
+
+void LLFloaterWorldMap::trackURL(const LLString& region_name, S32 x_coord, S32 y_coord, S32 z_coord)
+{
+ LLSimInfo* sim_info = gWorldMap->simInfoFromName(region_name);
+ z_coord = llclamp(z_coord, 0, 1000);
+ if (sim_info)
+ {
+ LLVector3 local_pos;
+ local_pos.mV[VX] = (F32)x_coord;
+ local_pos.mV[VY] = (F32)y_coord;
+ local_pos.mV[VZ] = (F32)z_coord;
+ LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
+ trackLocation(global_pos);
+ setDefaultBtn("Teleport");
+ }
+ else
+ {
+ // fill in UI based on URL
+ gFloaterWorldMap->childSetValue("location", region_name);
+ childSetValue("spin x", LLSD((F32)x_coord));
+ childSetValue("spin y", LLSD((F32)y_coord));
+ childSetValue("spin z", LLSD((F32)z_coord));
+
+ // pass sim name to combo box
+ gFloaterWorldMap->mCompletingRegionName = region_name;
+ gWorldMap->sendNamedRegionRequest(region_name);
+ LLString::toLower(gFloaterWorldMap->mCompletingRegionName);
+ gWorldMap->mIsTrackingCommit = TRUE;
+ }
+}
+
+void LLFloaterWorldMap::observeInventory(LLInventoryModel* model)
+{
+ if(mInventory)
+ {
+ mInventory->removeObserver(mInventoryObserver);
+ delete mInventoryObserver;
+ mInventory = NULL;
+ mInventoryObserver = NULL;
+ }
+ if(model)
+ {
+ mInventory = model;
+ mInventoryObserver = new LLMapInventoryObserver;
+ // Inventory deletes all observers on shutdown
+ mInventory->addObserver(mInventoryObserver);
+ inventoryChanged();
+ }
+}
+
+void LLFloaterWorldMap::inventoryChanged()
+{
+ if(!LLTracker::getTrackedLandmarkItemID().isNull())
+ {
+ LLUUID item_id = LLTracker::getTrackedLandmarkItemID();
+ buildLandmarkIDLists();
+ trackLandmark(item_id);
+ }
+}
+
+void LLFloaterWorldMap::observeFriends()
+{
+ if(!mFriendObserver)
+ {
+ mFriendObserver = new LLMapFriendObserver;
+ LLAvatarTracker::instance().addObserver(mFriendObserver);
+ friendsChanged();
+ }
+}
+
+void LLFloaterWorldMap::friendsChanged()
+{
+ LLAvatarTracker& t = LLAvatarTracker::instance();
+ const LLUUID& avatar_id = t.getAvatarID();
+ buildAvatarIDList();
+ if(avatar_id.notNull())
+ {
+ LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
+ if(!iface || !iface->setCurrentByID(avatar_id) ||
+ !t.getBuddyInfo(avatar_id)->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) || gAgent.isGodlike())
+ {
+ LLTracker::stopTracking(NULL);
+ }
+ }
+}
+
+// No longer really builds a list. Instead, just updates mAvatarCombo.
+void LLFloaterWorldMap::buildAvatarIDList()
+{
+ LLCtrlListInterface *list = childGetListInterface("friend combo");
+ if (!list) return;
+
+ // Delete all but the "None" entry
+ S32 list_size = list->getItemCount();
+ while (list_size > 1)
+ {
+ list->selectNthItem(1);
+ list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
+ --list_size;
+ }
+
+ LLSD default_column;
+ default_column["name"] = "friend name";
+ default_column["label"] = "Friend Name";
+ default_column["width"] = 500;
+ list->addColumn(default_column);
+
+ // Get all of the calling cards for avatar that are currently online
+ LLCollectMappableBuddies collector;
+ LLAvatarTracker::instance().applyFunctor(collector);
+ LLCollectMappableBuddies::buddy_map_t::iterator it;
+ LLCollectMappableBuddies::buddy_map_t::iterator end;
+ it = collector.mMappable.begin();
+ end = collector.mMappable.end();
+ for( ; it != end; ++it)
+ {
+ list->addSimpleElement((*it).first, ADD_BOTTOM, (*it).second);
+ }
+
+ list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
+ list->selectFirstItem();
+}
+
+
+void LLFloaterWorldMap::buildLandmarkIDLists()
+{
+ LLCtrlListInterface *list = childGetListInterface("landmark combo");
+ if (!list) return;
+
+ // Delete all but the "None" entry
+ S32 list_size = list->getItemCount();
+ while (list_size > 1)
+ {
+ list->selectNthItem(1);
+ list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
+ --list_size;
+ }
+
+ mLandmarkItemIDList.reset();
+ mLandmarkAssetIDList.reset();
+
+ // Get all of the current landmarks
+ mLandmarkAssetIDList.put( LLUUID::null );
+ mLandmarkItemIDList.put( LLUUID::null );
+
+ mLandmarkAssetIDList.put( sHomeID );
+ mLandmarkItemIDList.put( sHomeID );
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLIsType is_landmark(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_landmark);
+ std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
+
+ S32 count = items.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ LLInventoryItem* item = items.get(i);
+
+ list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
+
+ mLandmarkAssetIDList.put( item->getAssetUUID() );
+ mLandmarkItemIDList.put( item->getUUID() );
+ }
+ list->sortByColumn("landmark name", TRUE);
+ list->selectFirstItem();
+}
+
+
+F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination,
+ F32 z_attenuation) const
+{
+ LLVector3d delta = destination - gAgent.getPositionGlobal();
+ // by attenuating the z-component we effectively
+ // give more weight to the x-y plane
+ delta.mdV[VZ] *= z_attenuation;
+ F32 distance = (F32)delta.magVec();
+ return distance;
+}
+
+
+void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
+{
+ LLCtrlListInterface *list = childGetListInterface("search_results");
+ if (list)
+ {
+ list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+ }
+ if (!childHasKeyboardFocus("spin x"))
+ {
+ childSetValue("spin x", SIM_COORD_DEFAULT);
+ }
+ if (!childHasKeyboardFocus("spin y"))
+ {
+ childSetValue("spin y", SIM_COORD_DEFAULT);
+ }
+ if (!childHasKeyboardFocus("spin z"))
+ {
+ childSetValue("spin z", 0);
+ }
+ gWorldMap->mIsTrackingCommit = FALSE;
+ mCompletingRegionName = "";
+ mExactMatch = FALSE;
+}
+
+
+void LLFloaterWorldMap::clearLandmarkSelection(BOOL clear_ui)
+{
+ if (clear_ui || !childHasKeyboardFocus("landmark combo"))
+ {
+ LLCtrlListInterface *list = childGetListInterface("landmark combo");
+ if (list)
+ {
+ list->selectByValue( "None" );
+ }
+ }
+}
+
+
+void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
+{
+ if (clear_ui || !childHasKeyboardFocus("friend combo"))
+ {
+ mTrackedStatus = LLTracker::TRACKING_NOTHING;
+ LLCtrlListInterface *list = childGetListInterface("friend combo");
+ if (list)
+ {
+ list->selectByValue( "None" );
+ }
+ }
+}
+
+
+// Adjust the maximally zoomed out limit of the zoom slider so you
+// can see the whole world, plus a little.
+void LLFloaterWorldMap::adjustZoomSliderBounds()
+{
+ // World size in regions
+ S32 world_width_regions = gWorldMap->getWorldWidth() / REGION_WIDTH_UNITS;
+ S32 world_height_regions = gWorldMap->getWorldHeight() / REGION_WIDTH_UNITS;
+
+ // Pad the world size a little bit, so we have a nice border on
+ // the edge
+ world_width_regions++;
+ world_height_regions++;
+
+ // Find how much space we have to display the world
+ LLWorldMapView* map_panel;
+ map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
+ LLRect view_rect = map_panel->getRect();
+
+ // View size in pixels
+ S32 view_width = view_rect.getWidth();
+ S32 view_height = view_rect.getHeight();
+
+ // Pixels per region to display entire width/height
+ F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
+ F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
+
+ F32 pixels_per_region = llmin(width_pixels_per_region,
+ height_pixels_per_region);
+
+ // Round pixels per region to an even number of slider increments
+ S32 slider_units = llfloor(pixels_per_region / 0.2f);
+ pixels_per_region = slider_units * 0.2f;
+
+ // Make sure the zoom slider can be moved at least a little bit.
+ // Likewise, less than the increment pixels per region is just silly.
+ pixels_per_region = llclamp(pixels_per_region, 1.f, (F32)(pow(2.f, ZOOM_MAX) * 128.f));
+
+ F32 min_power = log(pixels_per_region/256.f)/log(2.f);
+ childSetMinValue("zoom slider", min_power);
+}
+
+
+//-------------------------------------------------------------------------
+// User interface widget callbacks
+//-------------------------------------------------------------------------
+
+// static
+void LLFloaterWorldMap::onPanBtn( void* userdata )
+{
+ if( !gFloaterWorldMap ) return;
+
+ EPanDirection direction = (EPanDirection)(intptr_t)userdata;
+
+ S32 pan_x = 0;
+ S32 pan_y = 0;
+ switch( direction )
+ {
+ case PAN_UP: pan_y = -1; break;
+ case PAN_DOWN: pan_y = 1; break;
+ case PAN_LEFT: pan_x = 1; break;
+ case PAN_RIGHT: pan_x = -1; break;
+ default: llassert(0); return;
+ }
+
+ LLWorldMapView* map_panel;
+ map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
+ map_panel->translatePan( pan_x, pan_y );
+}
+
+// static
+void LLFloaterWorldMap::onGoHome(void*)
+{
+ gAgent.teleportHome();
+ gFloaterWorldMap->close();
+}
+
+
+// static
+void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdata )
+{
+ LLFloaterWorldMap* self = gFloaterWorldMap;
+ if( !self || self->mIsClosing )
+ {
+ return;
+ }
+
+ LLCtrlListInterface *list = self->childGetListInterface("landmark combo");
+ if (!list) return;
+
+ LLUUID current_choice = list->getCurrentID();
+
+ gFloaterWorldMap->buildLandmarkIDLists();
+
+ if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
+ {
+ LLTracker::stopTracking(NULL);
+ }
+
+}
+
+// static
+void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata )
+{
+ LLFloaterWorldMap* self = gFloaterWorldMap;
+
+ if( !self || self->mIsClosing )
+ {
+ return;
+ }
+
+ LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("landmark combo");
+ if (!list) return;
+
+ LLUUID asset_id;
+ LLUUID item_id = list->getCurrentID();
+
+ LLTracker::stopTracking(NULL);
+
+ //RN: stopTracking() clears current combobox selection, need to reassert it here
+ list->setCurrentByID(item_id);
+
+ if( item_id.isNull() )
+ {
+ }
+ else if( item_id == sHomeID )
+ {
+ asset_id = sHomeID;
+ }
+ else
+ {
+ LLInventoryItem* item = gInventory.getItem( item_id );
+ if( item )
+ {
+ asset_id = item->getAssetUUID();
+ }
+ else
+ {
+ // Something went wrong, so revert to a safe value.
+ item_id.setNull();
+ }
+ }
+
+ self->trackLandmark( item_id);
+ onShowTargetBtn(self);
+}
+
+// static
+void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata )
+{
+ LLFloaterWorldMap* self = gFloaterWorldMap;
+ if( !self || self->mIsClosing )
+ {
+ return;
+ }
+
+ LLCtrlListInterface *list = self->childGetListInterface("friend combo");
+ if (!list) return;
+
+ LLUUID current_choice;
+
+ if( LLAvatarTracker::instance().haveTrackingInfo() )
+ {
+ current_choice = LLAvatarTracker::instance().getAvatarID();
+ }
+
+ self->buildAvatarIDList();
+
+ if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
+ {
+ LLTracker::stopTracking(NULL);
+ }
+}
+
+
+// static
+void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata )
+{
+ LLFloaterWorldMap* self = gFloaterWorldMap;
+ if( !self || self->mIsClosing )
+ {
+ return;
+ }
+
+ LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("friend combo");
+ if (!list) return;
+
+ const LLUUID& new_avatar_id = list->getCurrentID();
+ if (new_avatar_id.notNull())
+ {
+ LLString name;
+ LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(gFloaterWorldMap, "friend combo");
+ if (combo) name = combo->getSimple();
+ self->trackAvatar(new_avatar_id, name);
+ onShowTargetBtn(self);
+ }
+}
+
+// static
+void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata )
+{
+ LLFloaterWorldMap *self = gFloaterWorldMap;
+ if (self->childHasKeyboardFocus("location") &&
+ self->childGetValue("location").asString().length() > 0)
+ {
+ self->setDefaultBtn("DoSearch");
+ }
+ else
+ {
+ self->setDefaultBtn("");
+ }
+}
+
+// static
+void LLFloaterWorldMap::onLocationCommit( void* userdata )
+{
+ LLFloaterWorldMap *self = gFloaterWorldMap;
+ if( !self || self->mIsClosing )
+ {
+ return;
+ }
+
+ self->clearLocationSelection(FALSE);
+ self->mCompletingRegionName = "";
+ self->mLastRegionName = "";
+
+ LLString str = self->childGetValue("location").asString();
+
+ LLString::toLower(str);
+ gFloaterWorldMap->mCompletingRegionName = str;
+ gWorldMap->mIsTrackingCommit = TRUE;
+ self->mExactMatch = FALSE;
+ if (str.length() >= 3)
+ {
+ gWorldMap->sendNamedRegionRequest(str);
+ }
+ else
+ {
+ str += "#";
+ gWorldMap->sendNamedRegionRequest(str);
+ }
+}
+
+
+// static
+void LLFloaterWorldMap::onClearBtn(void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ self->mTrackedStatus = LLTracker::TRACKING_NOTHING;
+ LLTracker::stopTracking((void *)(intptr_t)TRUE);
+ gWorldMap->mIsTrackingUnknownLocation = FALSE;
+}
+
+// static
+void LLFloaterWorldMap::onFlyBtn(void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ self->fly();
+}
+
+void LLFloaterWorldMap::onShowTargetBtn(void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ self->centerOnTarget(TRUE);
+}
+
+void LLFloaterWorldMap::onShowAgentBtn(void* data)
+{
+ LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate
+}
+
+// static
+void LLFloaterWorldMap::onTeleportBtn(void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ self->teleport();
+}
+
+// static
+void LLFloaterWorldMap::onCopySLURL(void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(self->mSLURL));
+
+ LLString::format_map_t args;
+ args["[SLURL]"] = self->mSLURL;
+
+ LLAlertDialog::showXml("CopySLURL", args);
+}
+
+void LLFloaterWorldMap::onCheckEvents(LLUICtrl*, void* data)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
+ if(!self) return;
+ self->childSetEnabled("event_mature_chk", self->childGetValue("event_chk"));
+}
+
+// protected
+void LLFloaterWorldMap::centerOnTarget(BOOL animate)
+{
+ LLVector3d pos_global;
+ if(LLTracker::getTrackingStatus() != LLTracker::TRACKING_NOTHING)
+ {
+ LLVector3d tracked_position = LLTracker::getTrackedPositionGlobal();
+ //RN: tracker doesn't allow us to query completion, so we check for a tracking position of
+ // absolute zero, and keep trying in the draw loop
+ if (tracked_position.isExactlyZero())
+ {
+ mWaitingForTracker = TRUE;
+ return;
+ }
+ else
+ {
+ // We've got the position finally, so we're no longer busy. JC
+// getWindow()->decBusyCount();
+ pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();
+ }
+ }
+ else if(gWorldMap->mIsTrackingUnknownLocation)
+ {
+ pos_global = gWorldMap->mUnknownLocation - gAgent.getCameraPositionGlobal();;
+ }
+ else
+ {
+ // default behavior = center on agent
+ pos_global.clearVec();
+ }
+
+ LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sPixelsPerMeter)),
+ -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sPixelsPerMeter)),
+ !animate);
+ mWaitingForTracker = FALSE;
+}
+
+// protected
+void LLFloaterWorldMap::fly()
+{
+ LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
+
+ // Start the autopilot and close the floater,
+ // so we can see where we're flying
+ if (!pos_global.isExactlyZero())
+ {
+ gAgent.startAutoPilotGlobal( pos_global );
+ close();
+ }
+ else
+ {
+ make_ui_sound("UISndInvalidOp");
+ }
+}
+
+
+// protected
+void LLFloaterWorldMap::teleport()
+{
+ BOOL teleport_home = FALSE;
+ LLVector3d pos_global;
+ LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
+
+ LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
+ if (LLTracker::TRACKING_AVATAR == tracking_status
+ && av_tracker.haveTrackingInfo() )
+ {
+ pos_global = av_tracker.getGlobalPos();
+ pos_global.mdV[VZ] = childGetValue("spin z");
+ }
+ else if ( LLTracker::TRACKING_LANDMARK == tracking_status)
+ {
+ if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
+ {
+ teleport_home = TRUE;
+ }
+ else
+ {
+ LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
+ LLUUID region_id;
+ if(landmark
+ && !landmark->getGlobalPos(pos_global)
+ && landmark->getRegionID(region_id))
+ {
+ LLLandmark::requestRegionHandle(
+ gMessageSystem,
+ gAgent.getRegionHost(),
+ region_id,
+ NULL);
+ }
+ }
+ }
+ else if ( LLTracker::TRACKING_LOCATION == tracking_status)
+ {
+ pos_global = LLTracker::getTrackedPositionGlobal();
+ }
+ else
+ {
+ make_ui_sound("UISndInvalidOp");
+ }
+
+ // Do the teleport, which will also close the floater
+ if (teleport_home)
+ {
+ gAgent.teleportHome();
+ }
+ else if (!pos_global.isExactlyZero())
+ {
+ if(LLTracker::TRACKING_LANDMARK == tracking_status)
+ {
+ gAgent.teleportViaLandmark(LLTracker::getTrackedLandmarkAssetID());
+ }
+ else
+ {
+ gAgent.teleportViaLocation( pos_global );
+ }
+ }
+}
+
+// static
+void LLFloaterWorldMap::onGoToLandmarkDialog( S32 option, void* userdata )
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
+ switch( option )
+ {
+ case 0:
+ self->teleportToLandmark();
+ break;
+ case 1:
+ self->flyToLandmark();
+ break;
+ default:
+ // nothing
+ break;
+ }
+}
+
+void LLFloaterWorldMap::flyToLandmark()
+{
+ LLVector3d destination_pos_global;
+ if( !LLTracker::getTrackedLandmarkAssetID().isNull() )
+ {
+ if (LLTracker::hasLandmarkPosition())
+ {
+ gAgent.startAutoPilotGlobal( LLTracker::getTrackedPositionGlobal() );
+ }
+ }
+}
+
+void LLFloaterWorldMap::teleportToLandmark()
+{
+ BOOL has_destination = FALSE;
+ LLUUID destination_id; // Null means "home"
+
+ if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
+ {
+ has_destination = TRUE;
+ }
+ else
+ {
+ LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
+ LLVector3d global_pos;
+ if(landmark && landmark->getGlobalPos(global_pos))
+ {
+ destination_id = LLTracker::getTrackedLandmarkAssetID();
+ has_destination = TRUE;
+ }
+ else if(landmark)
+ {
+ // pop up an anonymous request request.
+ LLUUID region_id;
+ if(landmark->getRegionID(region_id))
+ {
+ LLLandmark::requestRegionHandle(
+ gMessageSystem,
+ gAgent.getRegionHost(),
+ region_id,
+ NULL);
+ }
+ }
+ }
+
+ if( has_destination )
+ {
+ gAgent.teleportViaLandmark( destination_id );
+ }
+}
+
+
+void LLFloaterWorldMap::teleportToAvatar()
+{
+ LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
+ if(av_tracker.haveTrackingInfo())
+ {
+ LLVector3d pos_global = av_tracker.getGlobalPos();
+ gAgent.teleportViaLocation( pos_global );
+ }
+}
+
+
+void LLFloaterWorldMap::flyToAvatar()
+{
+ if( LLAvatarTracker::instance().haveTrackingInfo() )
+ {
+ gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
+ }
+}
+
+// static
+void LLFloaterWorldMap::onCommitBackground(void* userdata, bool from_click)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
+
+ // Find my index
+ S32 index = self->mTabs->getCurrentPanelIndex();
+
+ if (gWorldMap)
+ {
+ gWorldMap->setCurrentLayer(index);
+ }
+}
+
+void LLFloaterWorldMap::updateSims(bool found_null_sim)
+{
+ if (mCompletingRegionName == "")
+ {
+ return;
+ }
+
+ LLCtrlListInterface *list = childGetListInterface("search_results");
+ if (!list) return;
+ list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+
+ LLSD selected_value = list->getSimpleSelectedValue();
+
+ S32 name_length = mCompletingRegionName.length();
+
+ BOOL match_found = FALSE;
+ S32 num_results = 0;
+ std::map<U64, LLSimInfo*>::const_iterator it;
+ for (it = gWorldMap->mSimInfoMap.begin(); it != gWorldMap->mSimInfoMap.end(); ++it)
+ {
+ LLSimInfo* info = (*it).second;
+ LLString sim_name = info->mName;
+ LLString sim_name_lower = sim_name;
+ LLString::toLower(sim_name_lower);
+
+ if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
+ {
+ if (gWorldMap->mIsTrackingCommit)
+ {
+ if (sim_name_lower == mCompletingRegionName)
+ {
+ selected_value = sim_name;
+ match_found = TRUE;
+ }
+ }
+
+ LLSD value;
+ value["id"] = sim_name;
+ value["columns"][0]["column"] = "sim_name";
+ value["columns"][0]["value"] = sim_name;
+ list->addElement(value);
+ num_results++;
+ }
+ }
+
+ list->selectByValue(selected_value);
+
+ if (found_null_sim)
+ {
+ mCompletingRegionName = "";
+ }
+
+ if (match_found)
+ {
+ mExactMatch = TRUE;
+ childSetFocus("search_results");
+ onCommitSearchResult(NULL, this);
+ }
+ else if (!mExactMatch && num_results > 0)
+ {
+ list->selectFirstItem(); // select first item by default
+ childSetFocus("search_results");
+ onCommitSearchResult(NULL, this);
+ }
+ else
+ {
+ list->addSimpleElement("None found.");
+ list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
+ }
+}
+
+// static
+void LLFloaterWorldMap::onCommitLocation(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
+ LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
+ if ( LLTracker::TRACKING_LOCATION == tracking_status)
+ {
+ LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
+ F64 local_x = self->childGetValue("spin x");
+ F64 local_y = self->childGetValue("spin y");
+ F64 local_z = self->childGetValue("spin z");
+ pos_global.mdV[VX] += -fmod(pos_global.mdV[VX], 256.0) + local_x;
+ pos_global.mdV[VY] += -fmod(pos_global.mdV[VY], 256.0) + local_y;
+ pos_global.mdV[VZ] = local_z;
+ self->trackLocation(pos_global);
+ }
+}
+
+// static
+void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata)
+{
+ LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
+
+ LLCtrlListInterface *list = self->childGetListInterface("search_results");
+ if (!list) return;
+
+ LLSD selected_value = list->getSimpleSelectedValue();
+ LLString sim_name = selected_value.asString();
+ if (sim_name.empty())
+ {
+ return;
+ }
+ LLString::toLower(sim_name);
+
+ std::map<U64, LLSimInfo*>::const_iterator it;
+ for (it = gWorldMap->mSimInfoMap.begin(); it != gWorldMap->mSimInfoMap.end(); ++it)
+ {
+ LLSimInfo* info = (*it).second;
+ LLString info_sim_name = info->mName;
+ LLString::toLower(info_sim_name);
+
+ if (sim_name == info_sim_name)
+ {
+ LLVector3d pos_global = from_region_handle( info->mHandle );
+ F64 local_x = self->childGetValue("spin x");
+ F64 local_y = self->childGetValue("spin y");
+ F64 local_z = self->childGetValue("spin z");
+ pos_global.mdV[VX] += local_x;
+ pos_global.mdV[VY] += local_y;
+ pos_global.mdV[VZ] = local_z;
+
+ self->childSetValue("location", sim_name);
+ self->trackLocation(pos_global);
+ self->setDefaultBtn("Teleport");
+ break;
+ }
+ }
+
+ onShowTargetBtn(self);
+}