diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llfloaterworldmap.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llfloaterworldmap.cpp')
-rwxr-xr-x | indra/newview/llfloaterworldmap.cpp | 3590 |
1 files changed, 1795 insertions, 1795 deletions
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 9cc0b873b2..2c28e80995 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -1,1795 +1,1795 @@ -/**
- * @file llfloaterworldmap.cpp
- * @author James Cook, Tom Yedwab
- * @brief LLFloaterWorldMap class implementation
- *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-/*
- * Map of the entire world, with multiple background images,
- * avatar tracking, teleportation by double-click, etc.
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterworldmap.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llbutton.h"
-#include "llcallingcard.h"
-#include "llcombobox.h"
-#include "llviewercontrol.h"
-#include "llcommandhandler.h"
-#include "lldraghandle.h"
-//#include "llfirstuse.h"
-#include "llfloaterreg.h" // getTypedInstance()
-#include "llfocusmgr.h"
-#include "lliconctrl.h"
-#include "llinventoryfunctions.h"
-#include "llinventorymodel.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llinventoryobserver.h"
-#include "lllandmarklist.h"
-#include "llsearcheditor.h"
-#include "llnotificationsutil.h"
-#include "llregionhandle.h"
-#include "llscrolllistctrl.h"
-#include "llslurl.h"
-#include "lltextbox.h"
-#include "lltoolbarview.h"
-#include "lltracker.h"
-#include "lltrans.h"
-#include "llviewerinventory.h" // LLViewerInventoryItem
-#include "llviewermenu.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewertexture.h"
-#include "llviewerwindow.h"
-#include "llworldmap.h"
-#include "llworldmapmessage.h"
-#include "llworldmapview.h"
-#include "lluictrlfactory.h"
-#include "llappviewer.h"
-#include "llmapimagetype.h"
-#include "llweb.h"
-#include "llsliderctrl.h"
-#include "message.h"
-#include "llwindow.h" // copyTextToClipboard()
-#include <algorithm>
-
-//---------------------------------------------------------------------------
-// Constants
-//---------------------------------------------------------------------------
-
-// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
-// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
-// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
-// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
-static const S32 MAX_VISIBLE_REGIONS = 512;
-
-
-const S32 HIDE_BEACON_PAD = 133;
-
-// It would be more logical to have this inside the method where it is used but to compile under gcc this
-// struct has to be here.
-struct SortRegionNames
-{
- inline bool operator ()(std::pair <U64, LLSimInfo*> const& _left, std::pair <U64, LLSimInfo*> const& _right)
- {
- return(LLStringUtil::compareInsensitive(_left.second->getName(), _right.second->getName()) < 0);
- }
-};
-
-enum EPanDirection
-{
- PAN_UP,
- PAN_DOWN,
- PAN_LEFT,
- PAN_RIGHT
-};
-
-// Values in pixels per region
-static const F32 ZOOM_MAX = 128.f;
-
-//---------------------------------------------------------------------------
-// Globals
-//---------------------------------------------------------------------------
-
-// handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs
-class LLWorldMapHandler : public LLCommandHandler
-{
-public:
- LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE)
- {
- }
-
- virtual bool canHandleUntrusted(
- const LLSD& params,
- const LLSD& query_map,
- LLMediaCtrl* web,
- const std::string& nav_type)
- {
- if (nav_type == NAV_TYPE_CLICKED
- || nav_type == NAV_TYPE_EXTERNAL)
- {
- // NAV_TYPE_EXTERNAL will be throttled
- return true;
- }
-
- return false;
- }
-
- bool handle(const LLSD& params,
- const LLSD& query_map,
- const std::string& grid,
- LLMediaCtrl* web)
- {
- if (params.size() == 0)
- {
- // support the secondlife:///app/worldmap SLapp
- LLFloaterReg::showInstance("world_map", "center");
- return true;
- }
-
- // support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp
- const std::string region_name = LLURI::unescape(params[0].asString());
- S32 x = (params.size() > 1) ? params[1].asInteger() : 128;
- S32 y = (params.size() > 2) ? params[2].asInteger() : 128;
- S32 z = (params.size() > 3) ? params[3].asInteger() : 0;
-
- LLFloaterWorldMap::getInstance()->trackURL(region_name, x, y, z);
- LLFloaterReg::showInstance("world_map", "center");
-
- return true;
- }
-};
-LLWorldMapHandler gWorldMapHandler;
-
-// SocialMap handler secondlife:///app/maptrackavatar/id
-class LLMapTrackAvatarHandler : public LLCommandHandler
-{
-public:
- LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)
- {
- }
-
- virtual bool canHandleUntrusted(
- const LLSD& params,
- const LLSD& query_map,
- LLMediaCtrl* web,
- const std::string& nav_type)
- {
- if (params.size() < 1)
- {
- return true; // don't block, will fail later
- }
-
- if (nav_type == NAV_TYPE_CLICKED
- || nav_type == NAV_TYPE_EXTERNAL)
- {
- // NAV_TYPE_EXTERNAL will be throttled
- return true;
- }
-
- return false;
- }
-
- bool handle(const LLSD& params,
- const LLSD& query_map,
- const std::string& grid,
- LLMediaCtrl* web)
- {
- //Make sure we have some parameters
- if (params.size() == 0)
- {
- return false;
- }
-
- //Get the ID
- LLUUID id;
- if (!id.set( params[0], false ))
- {
- return false;
- }
-
- LLFloaterWorldMap::getInstance()->avatarTrackFromSlapp( id );
- LLFloaterReg::showInstance( "world_map", "center" );
-
- return true;
- }
-};
-LLMapTrackAvatarHandler gMapTrackAvatar;
-
-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(const LLSD& key)
-: LLFloater(key),
- mInventory(NULL),
- mInventoryObserver(NULL),
- mFriendObserver(NULL),
- mCompletingRegionName(),
- mCompletingRegionPos(),
- mWaitingForTracker(false),
- mIsClosing(false),
- mSetToUserPosition(true),
- mTrackedLocation(0,0,0),
- mTrackedStatus(LLTracker::TRACKING_NOTHING),
- mListFriendCombo(NULL),
- mListLandmarkCombo(NULL),
- mListSearchResults(NULL)
-{
- gFloaterWorldMap = this;
-
- mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
-
- mCommitCallbackRegistrar.add("WMap.Coordinates", boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this));
- mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this));
- mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this));
- mCommitCallbackRegistrar.add("WMap.Landmark", boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this));
- mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this));
- mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this));
- mCommitCallbackRegistrar.add("WMap.Teleport", boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
- mCommitCallbackRegistrar.add("WMap.ShowTarget", boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this));
- mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this));
- mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this));
- mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this));
-
- gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this));
-}
-
-// static
-void* LLFloaterWorldMap::createWorldMapView(void* data)
-{
- return new LLWorldMapView();
-}
-
-bool LLFloaterWorldMap::postBuild()
-{
- mMapView = dynamic_cast<LLWorldMapView*>(getChild<LLPanel>("objects_mapview"));
- mMapView->setPan(0, 0, true);
-
- LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
- avatar_combo->selectFirstItem();
- avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
- avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
- mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
-
- LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
- location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
- location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
-
- getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
- mListSearchResults = childGetListInterface("search_results");
-
- LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
- landmark_combo->selectFirstItem();
- landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
- landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
- mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
-
- F32 slider_zoom = mMapView->getZoom();
- getChild<LLUICtrl>("zoom slider")->setValue(slider_zoom);
-
- getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this));
-
- setDefaultBtn(NULL);
-
- onChangeMaturity();
-
- return true;
-}
-
-// virtual
-LLFloaterWorldMap::~LLFloaterWorldMap()
-{
- // All cleaned up by LLView destructor
- mMapView = NULL;
-
- // Inventory deletes all observers on shutdown
- mInventory = NULL;
- mInventoryObserver = NULL;
-
- // avatar tracker will delete this for us.
- mFriendObserver = NULL;
-
- gFloaterWorldMap = NULL;
-
- mTeleportFinishConnection.disconnect();
-}
-
-//static
-LLFloaterWorldMap* LLFloaterWorldMap::getInstance()
-{
- return LLFloaterReg::getTypedInstance<LLFloaterWorldMap>("world_map");
-}
-
-// virtual
-void LLFloaterWorldMap::onClose(bool app_quitting)
-{
- // While we're not visible, discard the overlay images we're using
- LLWorldMap::getInstance()->clearImageRefs();
- mTeleportFinishConnection.disconnect();
-}
-
-// virtual
-void LLFloaterWorldMap::onOpen(const LLSD& key)
-{
- mTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
- setTeleportFinishedCallback(boost::bind(&LLFloaterWorldMap::onTeleportFinished, this));
-
- bool center_on_target = (key.asString() == "center");
-
- mIsClosing = false;
-
- mMapView->clearLastClick();
-
- {
- // reset pan on show, so it centers on you again
- if (!center_on_target)
- {
- mMapView->setPan(0, 0, true);
- }
- mMapView->updateVisibleBlocks();
-
- // Reload items as they may have changed
- LLWorldMap::getInstance()->reloadItems();
-
- // We may already have a bounding box for the regions of the world,
- // so use that to adjust the view.
- adjustZoomSliderBounds();
-
- // Could be first show
- //LLFirstUse::useMap();
-
- // Start speculative download of landmarks
- const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
- LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);
-
- getChild<LLUICtrl>("location")->setFocus( true);
- gFocusMgr.triggerFocusFlash();
-
- buildAvatarIDList();
- buildLandmarkIDLists();
-
- // If nothing is being tracked, set flag so the user position will be found
- mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
- }
-
- if (center_on_target)
- {
- centerOnTarget(false);
- }
-}
-
-// static
-void LLFloaterWorldMap::reloadIcons(void*)
-{
- LLWorldMap::getInstance()->reloadItems();
-}
-
-// 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 (!isMinimized() && isFrontmost())
- {
- S32 map_x = x - mMapView->getRect().mLeft;
- S32 map_y = y - mMapView->getRect().mBottom;
- if (mMapView->pointInView(map_x, map_y))
- {
- F32 old_slider_zoom = (F32) getChild<LLUICtrl>("zoom slider")->getValue().asReal();
- F32 slider_zoom = old_slider_zoom + ((F32) clicks * -0.3333f);
- getChild<LLUICtrl>("zoom slider")->setValue(LLSD(slider_zoom));
- mMapView->zoomWithPivot(slider_zoom, map_x, map_y);
- return true;
- }
- }
-
- return LLFloater::handleScrollWheel(x, y, clicks);
-}
-
-
-// virtual
-void LLFloaterWorldMap::reshape( S32 width, S32 height, bool called_from_parent )
-{
- LLFloater::reshape( width, height, called_from_parent );
-}
-
-
-// virtual
-void LLFloaterWorldMap::draw()
-{
- static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
- static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white);
-
- // On orientation island, users don't have a home location yet, so don't
- // let them teleport "home". It dumps them in an often-crowed welcome
- // area (infohub) and they get confused. JC
- LLViewerRegion* regionp = gAgent.getRegion();
- bool agent_on_prelude = (regionp && regionp->isPrelude());
- bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude;
- getChildView("Go Home")->setEnabled(enable_go_home);
-
- updateLocation();
-
- LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
- if (LLTracker::TRACKING_AVATAR == tracking_status)
- {
- getChild<LLUICtrl>("avatar_icon")->setColor( map_track_color);
- }
- else
- {
- getChild<LLUICtrl>("avatar_icon")->setColor( map_track_disabled_color);
- }
-
- if (LLTracker::TRACKING_LANDMARK == tracking_status)
- {
- getChild<LLUICtrl>("landmark_icon")->setColor( map_track_color);
- }
- else
- {
- getChild<LLUICtrl>("landmark_icon")->setColor( map_track_disabled_color);
- }
-
- if (LLTracker::TRACKING_LOCATION == tracking_status)
- {
- getChild<LLUICtrl>("location_icon")->setColor( map_track_color);
- }
- else
- {
- if (mCompletingRegionName != "")
- {
- F64 seconds = LLTimer::getElapsedSeconds();
- double value = fmod(seconds, 2);
- value = 0.5 + 0.5*cos(value * F_PI);
- LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
- getChild<LLUICtrl>("location_icon")->setColor( loading_color);
- }
- else
- {
- getChild<LLUICtrl>("location_icon")->setColor( map_track_disabled_color);
- }
- }
-
- // check for completion of tracking data
- if (mWaitingForTracker)
- {
- centerOnTarget(true);
- }
-
- getChildView("Teleport")->setEnabled((bool)tracking_status);
- // getChildView("Clear")->setEnabled((bool)tracking_status);
- getChildView("Show Destination")->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking());
- getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) );
-
- setMouseOpaque(true);
- getDragHandle()->setMouseOpaque(true);
-
- mMapView->zoom((F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal());
-
- // Enable/disable checkboxes depending on the zoom level
- // If above threshold level (i.e. low res) -> Disable all checkboxes
- // If under threshold level (i.e. high res) -> Enable all checkboxes
- bool enable = mMapView->showRegionInfo();
- getChildView("people_chk")->setEnabled(enable);
- getChildView("infohub_chk")->setEnabled(enable);
- getChildView("telehub_chk")->setEnabled(enable);
- getChildView("land_for_sale_chk")->setEnabled(enable);
- getChildView("event_chk")->setEnabled(enable);
- getChildView("events_mature_chk")->setEnabled(enable);
- getChildView("events_adult_chk")->setEnabled(enable);
-
- LLFloater::draw();
-}
-
-
-//-------------------------------------------------------------------------
-// Internal utility functions
-//-------------------------------------------------------------------------
-
-
-void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& 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
- // they swoop down when they click on the map. Requested
- // convenience.
- if(gAgent.isGodlike())
- {
- getChild<LLUICtrl>("teleport_coordinate_z")->setValue(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 || avatar_id != mTrackedAvatarID)
- {
- mTrackedStatus = LLTracker::TRACKING_AVATAR;
- mTrackedAvatarID = avatar_id;
- LLTracker::trackAvatar(avatar_id, name);
- }
- }
- else
- {
- LLTracker::stopTracking(false);
- }
- 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.size(); idx++)
- {
- if ( mLandmarkItemIDList.at(idx) == landmark_item_id)
- {
- found = true;
- break;
- }
- }
-
- if (found && iface->setCurrentByID( landmark_item_id ) )
- {
- LLUUID asset_id = mLandmarkAssetIDList.at( idx );
- std::string name;
- LLComboBox* combo = getChild<LLComboBox>( "landmark combo");
- if (combo) name = combo->getSimple();
- mTrackedStatus = LLTracker::TRACKING_LANDMARK;
- LLTracker::trackLandmark(mLandmarkAssetIDList.at( idx ), // assetID
- mLandmarkItemIDList.at( 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(false);
- }
- setDefaultBtn("Teleport");
-}
-
-
-void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
-{
- mTrackedStatus = LLTracker::TRACKING_LOCATION;
- LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT);
- setDefaultBtn("Teleport");
-}
-
-void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
-{
- mTrackedStatus = LLTracker::TRACKING_LOCATION;
- LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM);
- setDefaultBtn("Teleport");
-}
-
-void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
-{
- LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
- if (!sim_info)
- {
- // We haven't found a region for that point yet, leave the tracking to the world map
- LLTracker::stopTracking(false);
- LLWorldMap::getInstance()->setTracking(pos_global);
- S32 world_x = S32(pos_global.mdV[0] / 256);
- S32 world_y = S32(pos_global.mdV[1] / 256);
- LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
- setDefaultBtn("");
-
- // clicked on a non-region - turn off coord display
- enableTeleportCoordsDisplay( false );
-
- return;
- }
- if (sim_info->isDown())
- {
- // Down region. Show the blue circle of death!
- // i.e. let the world map that this and tell it it's invalid
- LLTracker::stopTracking(false);
- LLWorldMap::getInstance()->setTracking(pos_global);
- LLWorldMap::getInstance()->setTrackingInvalid();
- setDefaultBtn("");
-
- // clicked on a down region - turn off coord display
- enableTeleportCoordsDisplay( false );
-
- return;
- }
-
- std::string sim_name = sim_info->getName();
- 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 );
- std::string full_name = llformat("%s (%d, %d, %d)",
- sim_name.c_str(),
- ll_round(region_x),
- ll_round(region_y),
- ll_round((F32)pos_global.mdV[VZ]));
-
- std::string tooltip("");
- mTrackedStatus = LLTracker::TRACKING_LOCATION;
- LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking
- LLTracker::trackLocation(pos_global, full_name, tooltip);
-
- LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
- updateTeleportCoordsDisplay( coord_pos );
-
- // we have a valid region - turn on coord display
- enableTeleportCoordsDisplay( true );
-
- setDefaultBtn("Teleport");
-}
-
-// enable/disable teleport destination coordinates
-void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled )
-{
- childSetEnabled("teleport_coordinate_x", enabled );
- childSetEnabled("teleport_coordinate_y", enabled );
- childSetEnabled("teleport_coordinate_z", enabled );
-}
-
-// update display of teleport destination coordinates - pos is in global coordinates
-void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos )
-{
- // if we're going to update their value, we should also enable them
- enableTeleportCoordsDisplay( true );
-
- // convert global specified position to a local one
- F32 region_local_x = (F32)fmod( pos.mdV[VX], (F64)REGION_WIDTH_METERS );
- F32 region_local_y = (F32)fmod( pos.mdV[VY], (F64)REGION_WIDTH_METERS );
- F32 region_local_z = (F32)llclamp( pos.mdV[VZ], 0.0, (F64)REGION_HEIGHT_METERS );
-
- // write in the values
- childSetValue("teleport_coordinate_x", region_local_x );
- childSetValue("teleport_coordinate_y", region_local_y );
- childSetValue("teleport_coordinate_z", region_local_z );
-}
-
-void LLFloaterWorldMap::updateLocation()
-{
- bool gotSimName;
-
- LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
-
- // 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())
- {
- LLVector3d agentPos = gAgent.getPositionGlobal();
-
- // Set to avatar's current postion if nothing is selected
- if ( status == LLTracker::TRACKING_NOTHING && mSetToUserPosition )
- {
- // Make sure we know where we are before setting the current user position
- std::string agent_sim_name;
- gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name );
- if ( gotSimName )
- {
- mSetToUserPosition = false;
-
- // Fill out the location field
- getChild<LLUICtrl>("location")->setValue(agent_sim_name);
-
- // update the coordinate display with location of avatar in region
- updateTeleportCoordsDisplay( agentPos );
-
- // Figure out where user is
- // Set the current SLURL
- mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal());
- }
- }
-
- return; // invalid location
- }
- std::string sim_name;
- gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name );
- 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 they swoop down when they click on the
- // map. Requested convenience.
- if(gAgent.isGodlike())
- {
- pos_global[2] = 200;
- }
- }
-
- getChild<LLUICtrl>("location")->setValue(sim_name);
-
- // refresh coordinate display to reflect where user clicked.
- LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
- updateTeleportCoordsDisplay( coord_pos );
-
- // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
- if ( gotSimName )
- {
- mSLURL = LLSLURL(sim_name, pos_global);
- }
- else
- { // Empty SLURL will disable the "Copy SLURL to clipboard" button
- mSLURL = LLSLURL();
- }
- }
-}
-
-void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S32 y_coord, S32 z_coord)
-{
- LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromName(region_name);
- z_coord = llclamp(z_coord, 0, 4096);
- 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->getChild<LLUICtrl>("location")->setValue(region_name);
-
- // Save local coords to highlight position after region global
- // position is returned.
- gFloaterWorldMap->mCompletingRegionPos.set(
- (F32)x_coord, (F32)y_coord, (F32)z_coord);
-
- // pass sim name to combo box
- gFloaterWorldMap->mCompletingRegionName = region_name;
- LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name);
- LLStringUtil::toLower(gFloaterWorldMap->mCompletingRegionName);
- LLWorldMap::getInstance()->setTrackingCommit();
- }
-}
-
-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");
- const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id);
- if(!iface ||
- !iface->setCurrentByID(avatar_id) ||
- (buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) ||
- gAgent.isGodlike())
- {
- LLTracker::stopTracking(false);
- }
- }
-}
-
-// No longer really builds a list. Instead, just updates mAvatarCombo.
-void LLFloaterWorldMap::buildAvatarIDList()
-{
- LLCtrlListInterface *list = mListFriendCombo;
- if (!list) return;
-
- // Delete all but the "None" entry
- S32 list_size = list->getItemCount();
- if (list_size > 1)
- {
- list->selectItemRange(1, -1);
- list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
- }
-
- // 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).second, ADD_BOTTOM, (*it).first);
- }
-
- list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
- list->selectFirstItem();
-}
-
-
-void LLFloaterWorldMap::buildLandmarkIDLists()
-{
- LLCtrlListInterface *list = mListLandmarkCombo;
- if (!list) return;
-
- // Delete all but the "None" entry
- S32 list_size = list->getItemCount();
- if (list_size > 1)
- {
- list->selectItemRange(1, -1);
- list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
- }
-
- mLandmarkItemIDList.clear();
- mLandmarkAssetIDList.clear();
-
- // Get all of the current landmarks
- mLandmarkAssetIDList.push_back( LLUUID::null );
- mLandmarkItemIDList.push_back( LLUUID::null );
-
- mLandmarkAssetIDList.push_back( sHomeID );
- mLandmarkItemIDList.push_back( sHomeID );
-
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- LLIsType is_landmark(LLAssetType::AT_LANDMARK);
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_landmark);
-
- std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
-
- mLandmarkAssetIDList.reserve(mLandmarkAssetIDList.size() + items.size());
- mLandmarkItemIDList.reserve(mLandmarkItemIDList.size() + items.size());
-
- S32 count = items.size();
- for(S32 i = 0; i < count; ++i)
- {
- LLInventoryItem* item = items.at(i);
-
- list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
-
- mLandmarkAssetIDList.push_back( item->getAssetUUID() );
- mLandmarkItemIDList.push_back( item->getUUID() );
- }
-
- 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, bool dest_reached)
-{
- LLCtrlListInterface *list = mListSearchResults;
- if (list && (!dest_reached || (list->getItemCount() == 1)))
- {
- list->operateOnAll(LLCtrlListInterface::OP_DELETE);
- }
- LLWorldMap::getInstance()->cancelTracking();
- mCompletingRegionName = "";
-}
-
-
-void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui)
-{
- if (clear_ui || !childHasKeyboardFocus("landmark combo"))
- {
- LLCtrlListInterface *list = mListLandmarkCombo;
- if (list)
- {
- list->selectByValue( "None" );
- }
- }
-}
-
-
-void LLFloaterWorldMap::clearAvatarSelection(bool clear_ui)
-{
- if (clear_ui || !childHasKeyboardFocus("friend combo"))
- {
- mTrackedStatus = LLTracker::TRACKING_NOTHING;
- LLCtrlListInterface *list = mListFriendCombo;
- if (list && list->getSelectedValue().asString() != "None")
- {
- 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()
-{
- // Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
- // width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
- // sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
- // Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
- S32 world_width_regions = MAX_VISIBLE_REGIONS;
- S32 world_height_regions = MAX_VISIBLE_REGIONS;
-
- // Find how much space we have to display the world
- LLRect view_rect = mMapView->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, ZOOM_MAX);
-
- F32 min_power = log(pixels_per_region/256.f)/log(2.f);
-
- getChild<LLSliderCtrl>("zoom slider")->setMinValue(min_power);
-}
-
-
-//-------------------------------------------------------------------------
-// User interface widget callbacks
-//-------------------------------------------------------------------------
-
-void LLFloaterWorldMap::onGoHome()
-{
- gAgent.teleportHome();
- closeFloater();
-}
-
-
-void LLFloaterWorldMap::onLandmarkComboPrearrange( )
-{
- if( mIsClosing )
- {
- return;
- }
-
- LLCtrlListInterface *list = mListLandmarkCombo;
- if (!list) return;
-
- LLUUID current_choice = list->getCurrentID();
-
- buildLandmarkIDLists();
-
- if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
- {
- LLTracker::stopTracking(false);
- }
-
-}
-
-void LLFloaterWorldMap::onComboTextEntry()
-{
- // Reset the tracking whenever we start typing into any of the search fields,
- // so that hitting <enter> does an auto-complete versus teleporting us to the
- // previously selected landmark/friend.
- LLTracker::stopTracking(false);
-}
-
-void LLFloaterWorldMap::onSearchTextEntry( )
-{
- onComboTextEntry();
- updateSearchEnabled();
-}
-
-
-void LLFloaterWorldMap::onLandmarkComboCommit()
-{
- if( mIsClosing )
- {
- return;
- }
-
- LLCtrlListInterface *list = mListLandmarkCombo;
- if (!list) return;
-
- LLUUID asset_id;
- LLUUID item_id = list->getCurrentID();
-
- LLTracker::stopTracking(false);
-
- //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();
- }
- }
-
- trackLandmark( item_id);
- onShowTargetBtn();
-
- // Reset to user postion if nothing is tracked
- mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
-}
-
-// static
-void LLFloaterWorldMap::onAvatarComboPrearrange( )
-{
- if( mIsClosing )
- {
- return;
- }
-
- LLCtrlListInterface *list = mListFriendCombo;
- if (!list) return;
-
- LLUUID current_choice;
-
- if( LLAvatarTracker::instance().haveTrackingInfo() )
- {
- current_choice = LLAvatarTracker::instance().getAvatarID();
- }
-
- buildAvatarIDList();
-
- if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
- {
- LLTracker::stopTracking(false);
- }
-}
-
-void LLFloaterWorldMap::onAvatarComboCommit()
-{
- if( mIsClosing )
- {
- return;
- }
-
- LLCtrlListInterface *list = mListFriendCombo;
- if (!list) return;
-
- const LLUUID& new_avatar_id = list->getCurrentID();
- if (new_avatar_id.notNull())
- {
- std::string name;
- LLComboBox* combo = getChild<LLComboBox>("friend combo");
- if (combo) name = combo->getSimple();
- trackAvatar(new_avatar_id, name);
- onShowTargetBtn();
- }
- else
- { // Reset to user postion if nothing is tracked
- mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
- }
-}
-
-void LLFloaterWorldMap::avatarTrackFromSlapp( const LLUUID& id )
-{
- trackAvatar( id, "av" );
- onShowTargetBtn();
-}
-
-void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus )
-{
- updateSearchEnabled();
-}
-
-void LLFloaterWorldMap::updateSearchEnabled()
-{
- if (childHasKeyboardFocus("location") &&
- getChild<LLUICtrl>("location")->getValue().asString().length() > 0)
- {
- setDefaultBtn("DoSearch");
- }
- else
- {
- setDefaultBtn(NULL);
- }
-}
-
-void LLFloaterWorldMap::onLocationCommit()
-{
- if( mIsClosing )
- {
- return;
- }
-
- clearLocationSelection(false);
- mCompletingRegionName = "";
- mLastRegionName = "";
-
- std::string str = getChild<LLUICtrl>("location")->getValue().asString();
-
- // Trim any leading and trailing spaces in the search target
- std::string saved_str = str;
- LLStringUtil::trim( str );
- if ( str != saved_str )
- { // Set the value in the UI if any spaces were removed
- getChild<LLUICtrl>("location")->setValue(str);
- }
-
- // Don't try completing empty name (STORM-1427).
- if (str.empty())
- {
- return;
- }
-
- LLStringUtil::toLower(str);
- mCompletingRegionName = str;
- LLWorldMap::getInstance()->setTrackingCommit();
- if (str.length() >= 3)
- {
- LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
- }
- else
- {
- str += "#";
- LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
- }
-}
-
-void LLFloaterWorldMap::onCoordinatesCommit()
-{
- if( mIsClosing )
- {
- return;
- }
-
- S32 x_coord = (S32)childGetValue("teleport_coordinate_x").asReal();
- S32 y_coord = (S32)childGetValue("teleport_coordinate_y").asReal();
- S32 z_coord = (S32)childGetValue("teleport_coordinate_z").asReal();
-
- const std::string region_name = childGetValue("location").asString();
-
- trackURL( region_name, x_coord, y_coord, z_coord );
-}
-
-void LLFloaterWorldMap::onClearBtn()
-{
- mTrackedStatus = LLTracker::TRACKING_NOTHING;
- LLTracker::stopTracking(true);
- LLWorldMap::getInstance()->cancelTracking();
- mSLURL = LLSLURL(); // Clear the SLURL since it's invalid
- mSetToUserPosition = true; // Revert back to the current user position
-}
-
-void LLFloaterWorldMap::onShowTargetBtn()
-{
- centerOnTarget(true);
-}
-
-void LLFloaterWorldMap::onShowAgentBtn()
-{
- mMapView->setPanWithInterpTime(0, 0, false, 0.1f); // false == animate
- // Set flag so user's location will be displayed if not tracking anything else
- mSetToUserPosition = true;
-}
-
-void LLFloaterWorldMap::onClickTeleportBtn()
-{
- teleport();
-}
-
-void LLFloaterWorldMap::onCopySLURL()
-{
- getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString()));
-
- LLSD args;
- args["SLURL"] = mSLURL.getSLURLString();
-
- LLNotificationsUtil::add("CopySLURL", args);
-}
-
-void LLFloaterWorldMap::onExpandCollapseBtn()
-{
- LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack");
- LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp");
-
- bool toggle_collapse = !controls_panel->isCollapsed();
- floater_stack->collapsePanel(controls_panel, toggle_collapse);
- floater_stack->updateLayout();
-
- std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
- std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
- getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
- getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
- getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
-}
-
-// 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() - gAgentCamera.getCameraPositionGlobal();
- }
- }
- else if(LLWorldMap::getInstance()->isTracking())
- {
- pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();;
-
-
-
- }
- else
- {
- // default behavior = center on agent
- pos_global.clearVec();
- }
-
- F64 map_scale = (F64)mMapView->getScale();
- mMapView->setPanWithInterpTime(-llfloor((F32)(pos_global.mdV[VX] * map_scale / REGION_WIDTH_METERS)),
- -llfloor((F32)(pos_global.mdV[VY] * map_scale / REGION_WIDTH_METERS)),
- !animate, 0.1f);
- 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 );
- closeFloater();
- }
- 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] = getChild<LLUICtrl>("teleport_coordinate_z")->getValue();
- }
- 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 );
- }
- }
-}
-
-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() );
- }
-}
-
-void LLFloaterWorldMap::updateSims(bool found_null_sim)
-{
- if (mCompletingRegionName == "")
- {
- return;
- }
-
- LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
- list->operateOnAll(LLCtrlListInterface::OP_DELETE);
-
- S32 name_length = mCompletingRegionName.length();
-
- LLSD match;
-
- S32 num_results = 0;
-
- std::vector<std::pair <U64, LLSimInfo*> > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end());
- std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames());
-
- for (std::vector<std::pair <U64, LLSimInfo*> >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it)
- {
- LLSimInfo* info = it->second;
- std::string sim_name_lower = info->getName();
- LLStringUtil::toLower(sim_name_lower);
-
- if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
- {
- if (sim_name_lower == mCompletingRegionName)
- {
- match = info->getName();
- }
-
- LLSD value;
- value["id"] = info->getName();
- value["columns"][0]["column"] = "sim_name";
- value["columns"][0]["value"] = info->getName();
- list->addElement(value);
- num_results++;
- }
- }
-
- if (found_null_sim)
- {
- mCompletingRegionName = "";
- }
-
- if (num_results > 0)
- {
- // if match found, highlight it and go
- if (!match.isUndefined())
- {
- list->selectByValue(match);
- }
- // else select first found item
- else
- {
- list->selectFirstItem();
- }
- getChild<LLUICtrl>("search_results")->setFocus(true);
- onCommitSearchResult();
- }
- else
- {
- // if we found nothing, say "none"
- list->setCommentText(LLTrans::getString("worldmap_results_none_found"));
- list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
- }
-}
-
-void LLFloaterWorldMap::onTeleportFinished()
-{
- if(isInVisibleChain())
- {
- mMapView->setPan(0, 0, true);
- }
-}
-
-void LLFloaterWorldMap::onCommitSearchResult()
-{
- LLCtrlListInterface *list = mListSearchResults;
- if (!list) return;
-
- LLSD selected_value = list->getSelectedValue();
- std::string sim_name = selected_value.asString();
- if (sim_name.empty())
- {
- return;
- }
- LLStringUtil::toLower(sim_name);
-
- std::map<U64, LLSimInfo*>::const_iterator it;
- for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
- {
- LLSimInfo* info = it->second;
-
- if (info->isName(sim_name))
- {
- LLVector3d pos_global = info->getGlobalOrigin();
-
- const F64 SIM_COORD_DEFAULT = 128.0;
- LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f);
-
- // Did this value come from a trackURL() request?
- if (!mCompletingRegionPos.isExactlyZero())
- {
- pos_local = mCompletingRegionPos;
- mCompletingRegionPos.clear();
- }
- pos_global.mdV[VX] += (F64)pos_local.mV[VX];
- pos_global.mdV[VY] += (F64)pos_local.mV[VY];
- pos_global.mdV[VZ] = (F64)pos_local.mV[VZ];
-
- getChild<LLUICtrl>("location")->setValue(sim_name);
- trackLocation(pos_global);
- setDefaultBtn("Teleport");
- break;
- }
- }
-
- onShowTargetBtn();
-}
-
-void LLFloaterWorldMap::onChangeMaturity()
-{
- bool can_access_mature = gAgent.canAccessMature();
- bool can_access_adult = gAgent.canAccessAdult();
-
- getChildView("events_mature_icon")->setVisible( can_access_mature);
- getChildView("events_mature_label")->setVisible( can_access_mature);
- getChildView("events_mature_chk")->setVisible( can_access_mature);
-
- getChildView("events_adult_icon")->setVisible( can_access_adult);
- getChildView("events_adult_label")->setVisible( can_access_adult);
- getChildView("events_adult_chk")->setVisible( can_access_adult);
-
- // disable mature / adult events.
- if (!can_access_mature)
- {
- gSavedSettings.setBOOL("ShowMatureEvents", false);
- }
- if (!can_access_adult)
- {
- gSavedSettings.setBOOL("ShowAdultEvents", false);
- }
-}
-
-void LLFloaterWorldMap::onFocusLost()
-{
- gViewerWindow->showCursor();
- mMapView->mPanning = false;
-}
-
-LLPanelHideBeacon::LLPanelHideBeacon() :
- mHideButton(NULL)
-{
-}
-
-// static
-LLPanelHideBeacon* LLPanelHideBeacon::getInstance()
-{
- static LLPanelHideBeacon* panel = getPanelHideBeacon();
- return panel;
-}
-
-
-bool LLPanelHideBeacon::postBuild()
-{
- mHideButton = getChild<LLButton>("hide_beacon_btn");
- mHideButton->setCommitCallback(boost::bind(&LLPanelHideBeacon::onHideButtonClick, this));
-
- gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelHideBeacon::updatePosition, this));
-
- return true;
-}
-
-//virtual
-void LLPanelHideBeacon::draw()
-{
- if (!LLTracker::isTracking(NULL))
- {
- mHideButton->setVisible(false);
- return;
- }
- mHideButton->setVisible(true);
- updatePosition();
- LLPanel::draw();
-}
-
-//virtual
-void LLPanelHideBeacon::setVisible(bool visible)
-{
- if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) visible = false;
-
- if (visible)
- {
- updatePosition();
- }
-
- LLPanel::setVisible(visible);
-}
-
-
-//static
-LLPanelHideBeacon* LLPanelHideBeacon::getPanelHideBeacon()
-{
- LLPanelHideBeacon* panel = new LLPanelHideBeacon();
- panel->buildFromFile("panel_hide_beacon.xml");
-
- LL_INFOS() << "Build LLPanelHideBeacon panel" << LL_ENDL;
-
- panel->updatePosition();
- return panel;
-}
-
-void LLPanelHideBeacon::onHideButtonClick()
-{
- LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
- if (instance)
- {
- instance->onClearBtn();
- }
-}
-
-/**
-* Updates position of the panel (similar to Stand & Stop Flying panel).
-*/
-void LLPanelHideBeacon::updatePosition()
-{
- S32 bottom_tb_center = 0;
- if (LLToolBar* toolbar_bottom = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_BOTTOM))
- {
- bottom_tb_center = toolbar_bottom->getRect().getCenterX();
- }
-
- S32 left_tb_width = 0;
- if (LLToolBar* toolbar_left = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT))
- {
- left_tb_width = toolbar_left->getRect().getWidth();
- }
-
- if (gToolBarView != NULL && gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)->hasButtons())
- {
- S32 x_pos = bottom_tb_center - getRect().getWidth() / 2 - left_tb_width;
- setOrigin( x_pos + HIDE_BEACON_PAD, 0);
- }
- else
- {
- S32 x_pos = bottom_tb_center - getRect().getWidth() / 2;
- setOrigin( x_pos + HIDE_BEACON_PAD, 0);
- }
-}
+/** + * @file llfloaterworldmap.cpp + * @author James Cook, Tom Yedwab + * @brief LLFloaterWorldMap class implementation + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/* + * Map of the entire world, with multiple background images, + * avatar tracking, teleportation by double-click, etc. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterworldmap.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llviewercontrol.h" +#include "llcommandhandler.h" +#include "lldraghandle.h" +//#include "llfirstuse.h" +#include "llfloaterreg.h" // getTypedInstance() +#include "llfocusmgr.h" +#include "lliconctrl.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "lllandmarklist.h" +#include "llsearcheditor.h" +#include "llnotificationsutil.h" +#include "llregionhandle.h" +#include "llscrolllistctrl.h" +#include "llslurl.h" +#include "lltextbox.h" +#include "lltoolbarview.h" +#include "lltracker.h" +#include "lltrans.h" +#include "llviewerinventory.h" // LLViewerInventoryItem +#include "llviewermenu.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewertexture.h" +#include "llviewerwindow.h" +#include "llworldmap.h" +#include "llworldmapmessage.h" +#include "llworldmapview.h" +#include "lluictrlfactory.h" +#include "llappviewer.h" +#include "llmapimagetype.h" +#include "llweb.h" +#include "llsliderctrl.h" +#include "message.h" +#include "llwindow.h" // copyTextToClipboard() +#include <algorithm> + +//--------------------------------------------------------------------------- +// Constants +//--------------------------------------------------------------------------- + +// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed +// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across +// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit. +// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window. +static const S32 MAX_VISIBLE_REGIONS = 512; + + +const S32 HIDE_BEACON_PAD = 133; + +// It would be more logical to have this inside the method where it is used but to compile under gcc this +// struct has to be here. +struct SortRegionNames +{ + inline bool operator ()(std::pair <U64, LLSimInfo*> const& _left, std::pair <U64, LLSimInfo*> const& _right) + { + return(LLStringUtil::compareInsensitive(_left.second->getName(), _right.second->getName()) < 0); + } +}; + +enum EPanDirection +{ + PAN_UP, + PAN_DOWN, + PAN_LEFT, + PAN_RIGHT +}; + +// Values in pixels per region +static const F32 ZOOM_MAX = 128.f; + +//--------------------------------------------------------------------------- +// Globals +//--------------------------------------------------------------------------- + +// handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs +class LLWorldMapHandler : public LLCommandHandler +{ +public: + LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE) + { + } + + virtual bool canHandleUntrusted( + const LLSD& params, + const LLSD& query_map, + LLMediaCtrl* web, + const std::string& nav_type) + { + if (nav_type == NAV_TYPE_CLICKED + || nav_type == NAV_TYPE_EXTERNAL) + { + // NAV_TYPE_EXTERNAL will be throttled + return true; + } + + return false; + } + + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) + { + if (params.size() == 0) + { + // support the secondlife:///app/worldmap SLapp + LLFloaterReg::showInstance("world_map", "center"); + return true; + } + + // support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp + const std::string region_name = LLURI::unescape(params[0].asString()); + S32 x = (params.size() > 1) ? params[1].asInteger() : 128; + S32 y = (params.size() > 2) ? params[2].asInteger() : 128; + S32 z = (params.size() > 3) ? params[3].asInteger() : 0; + + LLFloaterWorldMap::getInstance()->trackURL(region_name, x, y, z); + LLFloaterReg::showInstance("world_map", "center"); + + return true; + } +}; +LLWorldMapHandler gWorldMapHandler; + +// SocialMap handler secondlife:///app/maptrackavatar/id +class LLMapTrackAvatarHandler : public LLCommandHandler +{ +public: + LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE) + { + } + + virtual bool canHandleUntrusted( + const LLSD& params, + const LLSD& query_map, + LLMediaCtrl* web, + const std::string& nav_type) + { + if (params.size() < 1) + { + return true; // don't block, will fail later + } + + if (nav_type == NAV_TYPE_CLICKED + || nav_type == NAV_TYPE_EXTERNAL) + { + // NAV_TYPE_EXTERNAL will be throttled + return true; + } + + return false; + } + + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) + { + //Make sure we have some parameters + if (params.size() == 0) + { + return false; + } + + //Get the ID + LLUUID id; + if (!id.set( params[0], false )) + { + return false; + } + + LLFloaterWorldMap::getInstance()->avatarTrackFromSlapp( id ); + LLFloaterReg::showInstance( "world_map", "center" ); + + return true; + } +}; +LLMapTrackAvatarHandler gMapTrackAvatar; + +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(const LLSD& key) +: LLFloater(key), + mInventory(NULL), + mInventoryObserver(NULL), + mFriendObserver(NULL), + mCompletingRegionName(), + mCompletingRegionPos(), + mWaitingForTracker(false), + mIsClosing(false), + mSetToUserPosition(true), + mTrackedLocation(0,0,0), + mTrackedStatus(LLTracker::TRACKING_NOTHING), + mListFriendCombo(NULL), + mListLandmarkCombo(NULL), + mListSearchResults(NULL) +{ + gFloaterWorldMap = this; + + mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL); + + mCommitCallbackRegistrar.add("WMap.Coordinates", boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this)); + mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this)); + mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this)); + mCommitCallbackRegistrar.add("WMap.Landmark", boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this)); + mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this)); + mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this)); + mCommitCallbackRegistrar.add("WMap.Teleport", boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); + mCommitCallbackRegistrar.add("WMap.ShowTarget", boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this)); + mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this)); + mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this)); + mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this)); + + gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this)); +} + +// static +void* LLFloaterWorldMap::createWorldMapView(void* data) +{ + return new LLWorldMapView(); +} + +bool LLFloaterWorldMap::postBuild() +{ + mMapView = dynamic_cast<LLWorldMapView*>(getChild<LLPanel>("objects_mapview")); + mMapView->setPan(0, 0, true); + + LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo"); + avatar_combo->selectFirstItem(); + avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); + avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo); + + LLSearchEditor *location_editor = getChild<LLSearchEditor>("location"); + location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); + location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); + + getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); + mListSearchResults = childGetListInterface("search_results"); + + LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo"); + landmark_combo->selectFirstItem(); + landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); + landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo); + + F32 slider_zoom = mMapView->getZoom(); + getChild<LLUICtrl>("zoom slider")->setValue(slider_zoom); + + getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this)); + + setDefaultBtn(NULL); + + onChangeMaturity(); + + return true; +} + +// virtual +LLFloaterWorldMap::~LLFloaterWorldMap() +{ + // All cleaned up by LLView destructor + mMapView = NULL; + + // Inventory deletes all observers on shutdown + mInventory = NULL; + mInventoryObserver = NULL; + + // avatar tracker will delete this for us. + mFriendObserver = NULL; + + gFloaterWorldMap = NULL; + + mTeleportFinishConnection.disconnect(); +} + +//static +LLFloaterWorldMap* LLFloaterWorldMap::getInstance() +{ + return LLFloaterReg::getTypedInstance<LLFloaterWorldMap>("world_map"); +} + +// virtual +void LLFloaterWorldMap::onClose(bool app_quitting) +{ + // While we're not visible, discard the overlay images we're using + LLWorldMap::getInstance()->clearImageRefs(); + mTeleportFinishConnection.disconnect(); +} + +// virtual +void LLFloaterWorldMap::onOpen(const LLSD& key) +{ + mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLFloaterWorldMap::onTeleportFinished, this)); + + bool center_on_target = (key.asString() == "center"); + + mIsClosing = false; + + mMapView->clearLastClick(); + + { + // reset pan on show, so it centers on you again + if (!center_on_target) + { + mMapView->setPan(0, 0, true); + } + mMapView->updateVisibleBlocks(); + + // Reload items as they may have changed + LLWorldMap::getInstance()->reloadItems(); + + // We may already have a bounding box for the regions of the world, + // so use that to adjust the view. + adjustZoomSliderBounds(); + + // Could be first show + //LLFirstUse::useMap(); + + // Start speculative download of landmarks + const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id); + + getChild<LLUICtrl>("location")->setFocus( true); + gFocusMgr.triggerFocusFlash(); + + buildAvatarIDList(); + buildLandmarkIDLists(); + + // If nothing is being tracked, set flag so the user position will be found + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); + } + + if (center_on_target) + { + centerOnTarget(false); + } +} + +// static +void LLFloaterWorldMap::reloadIcons(void*) +{ + LLWorldMap::getInstance()->reloadItems(); +} + +// 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 (!isMinimized() && isFrontmost()) + { + S32 map_x = x - mMapView->getRect().mLeft; + S32 map_y = y - mMapView->getRect().mBottom; + if (mMapView->pointInView(map_x, map_y)) + { + F32 old_slider_zoom = (F32) getChild<LLUICtrl>("zoom slider")->getValue().asReal(); + F32 slider_zoom = old_slider_zoom + ((F32) clicks * -0.3333f); + getChild<LLUICtrl>("zoom slider")->setValue(LLSD(slider_zoom)); + mMapView->zoomWithPivot(slider_zoom, map_x, map_y); + return true; + } + } + + return LLFloater::handleScrollWheel(x, y, clicks); +} + + +// virtual +void LLFloaterWorldMap::reshape( S32 width, S32 height, bool called_from_parent ) +{ + LLFloater::reshape( width, height, called_from_parent ); +} + + +// virtual +void LLFloaterWorldMap::draw() +{ + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white); + + // On orientation island, users don't have a home location yet, so don't + // let them teleport "home". It dumps them in an often-crowed welcome + // area (infohub) and they get confused. JC + LLViewerRegion* regionp = gAgent.getRegion(); + bool agent_on_prelude = (regionp && regionp->isPrelude()); + bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude; + getChildView("Go Home")->setEnabled(enable_go_home); + + updateLocation(); + + LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); + if (LLTracker::TRACKING_AVATAR == tracking_status) + { + getChild<LLUICtrl>("avatar_icon")->setColor( map_track_color); + } + else + { + getChild<LLUICtrl>("avatar_icon")->setColor( map_track_disabled_color); + } + + if (LLTracker::TRACKING_LANDMARK == tracking_status) + { + getChild<LLUICtrl>("landmark_icon")->setColor( map_track_color); + } + else + { + getChild<LLUICtrl>("landmark_icon")->setColor( map_track_disabled_color); + } + + if (LLTracker::TRACKING_LOCATION == tracking_status) + { + getChild<LLUICtrl>("location_icon")->setColor( map_track_color); + } + else + { + if (mCompletingRegionName != "") + { + F64 seconds = LLTimer::getElapsedSeconds(); + double value = fmod(seconds, 2); + value = 0.5 + 0.5*cos(value * F_PI); + LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0); + getChild<LLUICtrl>("location_icon")->setColor( loading_color); + } + else + { + getChild<LLUICtrl>("location_icon")->setColor( map_track_disabled_color); + } + } + + // check for completion of tracking data + if (mWaitingForTracker) + { + centerOnTarget(true); + } + + getChildView("Teleport")->setEnabled((bool)tracking_status); + // getChildView("Clear")->setEnabled((bool)tracking_status); + getChildView("Show Destination")->setEnabled((bool)tracking_status || LLWorldMap::getInstance()->isTracking()); + getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) ); + + setMouseOpaque(true); + getDragHandle()->setMouseOpaque(true); + + mMapView->zoom((F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal()); + + // Enable/disable checkboxes depending on the zoom level + // If above threshold level (i.e. low res) -> Disable all checkboxes + // If under threshold level (i.e. high res) -> Enable all checkboxes + bool enable = mMapView->showRegionInfo(); + getChildView("people_chk")->setEnabled(enable); + getChildView("infohub_chk")->setEnabled(enable); + getChildView("telehub_chk")->setEnabled(enable); + getChildView("land_for_sale_chk")->setEnabled(enable); + getChildView("event_chk")->setEnabled(enable); + getChildView("events_mature_chk")->setEnabled(enable); + getChildView("events_adult_chk")->setEnabled(enable); + + LLFloater::draw(); +} + + +//------------------------------------------------------------------------- +// Internal utility functions +//------------------------------------------------------------------------- + + +void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& 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 + // they swoop down when they click on the map. Requested + // convenience. + if(gAgent.isGodlike()) + { + getChild<LLUICtrl>("teleport_coordinate_z")->setValue(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 || avatar_id != mTrackedAvatarID) + { + mTrackedStatus = LLTracker::TRACKING_AVATAR; + mTrackedAvatarID = avatar_id; + LLTracker::trackAvatar(avatar_id, name); + } + } + else + { + LLTracker::stopTracking(false); + } + 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.size(); idx++) + { + if ( mLandmarkItemIDList.at(idx) == landmark_item_id) + { + found = true; + break; + } + } + + if (found && iface->setCurrentByID( landmark_item_id ) ) + { + LLUUID asset_id = mLandmarkAssetIDList.at( idx ); + std::string name; + LLComboBox* combo = getChild<LLComboBox>( "landmark combo"); + if (combo) name = combo->getSimple(); + mTrackedStatus = LLTracker::TRACKING_LANDMARK; + LLTracker::trackLandmark(mLandmarkAssetIDList.at( idx ), // assetID + mLandmarkItemIDList.at( 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(false); + } + setDefaultBtn("Teleport"); +} + + +void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info) +{ + mTrackedStatus = LLTracker::TRACKING_LOCATION; + LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT); + setDefaultBtn("Teleport"); +} + +void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item) +{ + mTrackedStatus = LLTracker::TRACKING_LOCATION; + LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM); + setDefaultBtn("Teleport"); +} + +void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) +{ + LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); + if (!sim_info) + { + // We haven't found a region for that point yet, leave the tracking to the world map + LLTracker::stopTracking(false); + LLWorldMap::getInstance()->setTracking(pos_global); + S32 world_x = S32(pos_global.mdV[0] / 256); + S32 world_y = S32(pos_global.mdV[1] / 256); + LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true); + setDefaultBtn(""); + + // clicked on a non-region - turn off coord display + enableTeleportCoordsDisplay( false ); + + return; + } + if (sim_info->isDown()) + { + // Down region. Show the blue circle of death! + // i.e. let the world map that this and tell it it's invalid + LLTracker::stopTracking(false); + LLWorldMap::getInstance()->setTracking(pos_global); + LLWorldMap::getInstance()->setTrackingInvalid(); + setDefaultBtn(""); + + // clicked on a down region - turn off coord display + enableTeleportCoordsDisplay( false ); + + return; + } + + std::string sim_name = sim_info->getName(); + 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 ); + std::string full_name = llformat("%s (%d, %d, %d)", + sim_name.c_str(), + ll_round(region_x), + ll_round(region_y), + ll_round((F32)pos_global.mdV[VZ])); + + std::string tooltip(""); + mTrackedStatus = LLTracker::TRACKING_LOCATION; + LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking + LLTracker::trackLocation(pos_global, full_name, tooltip); + + LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal(); + updateTeleportCoordsDisplay( coord_pos ); + + // we have a valid region - turn on coord display + enableTeleportCoordsDisplay( true ); + + setDefaultBtn("Teleport"); +} + +// enable/disable teleport destination coordinates +void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled ) +{ + childSetEnabled("teleport_coordinate_x", enabled ); + childSetEnabled("teleport_coordinate_y", enabled ); + childSetEnabled("teleport_coordinate_z", enabled ); +} + +// update display of teleport destination coordinates - pos is in global coordinates +void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos ) +{ + // if we're going to update their value, we should also enable them + enableTeleportCoordsDisplay( true ); + + // convert global specified position to a local one + F32 region_local_x = (F32)fmod( pos.mdV[VX], (F64)REGION_WIDTH_METERS ); + F32 region_local_y = (F32)fmod( pos.mdV[VY], (F64)REGION_WIDTH_METERS ); + F32 region_local_z = (F32)llclamp( pos.mdV[VZ], 0.0, (F64)REGION_HEIGHT_METERS ); + + // write in the values + childSetValue("teleport_coordinate_x", region_local_x ); + childSetValue("teleport_coordinate_y", region_local_y ); + childSetValue("teleport_coordinate_z", region_local_z ); +} + +void LLFloaterWorldMap::updateLocation() +{ + bool gotSimName; + + LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus(); + + // 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()) + { + LLVector3d agentPos = gAgent.getPositionGlobal(); + + // Set to avatar's current postion if nothing is selected + if ( status == LLTracker::TRACKING_NOTHING && mSetToUserPosition ) + { + // Make sure we know where we are before setting the current user position + std::string agent_sim_name; + gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name ); + if ( gotSimName ) + { + mSetToUserPosition = false; + + // Fill out the location field + getChild<LLUICtrl>("location")->setValue(agent_sim_name); + + // update the coordinate display with location of avatar in region + updateTeleportCoordsDisplay( agentPos ); + + // Figure out where user is + // Set the current SLURL + mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal()); + } + } + + return; // invalid location + } + std::string sim_name; + gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name ); + 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 they swoop down when they click on the + // map. Requested convenience. + if(gAgent.isGodlike()) + { + pos_global[2] = 200; + } + } + + getChild<LLUICtrl>("location")->setValue(sim_name); + + // refresh coordinate display to reflect where user clicked. + LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal(); + updateTeleportCoordsDisplay( coord_pos ); + + // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL + if ( gotSimName ) + { + mSLURL = LLSLURL(sim_name, pos_global); + } + else + { // Empty SLURL will disable the "Copy SLURL to clipboard" button + mSLURL = LLSLURL(); + } + } +} + +void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S32 y_coord, S32 z_coord) +{ + LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromName(region_name); + z_coord = llclamp(z_coord, 0, 4096); + 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->getChild<LLUICtrl>("location")->setValue(region_name); + + // Save local coords to highlight position after region global + // position is returned. + gFloaterWorldMap->mCompletingRegionPos.set( + (F32)x_coord, (F32)y_coord, (F32)z_coord); + + // pass sim name to combo box + gFloaterWorldMap->mCompletingRegionName = region_name; + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name); + LLStringUtil::toLower(gFloaterWorldMap->mCompletingRegionName); + LLWorldMap::getInstance()->setTrackingCommit(); + } +} + +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"); + const LLRelationship* buddy_info = t.getBuddyInfo(avatar_id); + if(!iface || + !iface->setCurrentByID(avatar_id) || + (buddy_info && !buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) || + gAgent.isGodlike()) + { + LLTracker::stopTracking(false); + } + } +} + +// No longer really builds a list. Instead, just updates mAvatarCombo. +void LLFloaterWorldMap::buildAvatarIDList() +{ + LLCtrlListInterface *list = mListFriendCombo; + if (!list) return; + + // Delete all but the "None" entry + S32 list_size = list->getItemCount(); + if (list_size > 1) + { + list->selectItemRange(1, -1); + list->operateOnSelection(LLCtrlListInterface::OP_DELETE); + } + + // 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).second, ADD_BOTTOM, (*it).first); + } + + list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() ); + list->selectFirstItem(); +} + + +void LLFloaterWorldMap::buildLandmarkIDLists() +{ + LLCtrlListInterface *list = mListLandmarkCombo; + if (!list) return; + + // Delete all but the "None" entry + S32 list_size = list->getItemCount(); + if (list_size > 1) + { + list->selectItemRange(1, -1); + list->operateOnSelection(LLCtrlListInterface::OP_DELETE); + } + + mLandmarkItemIDList.clear(); + mLandmarkAssetIDList.clear(); + + // Get all of the current landmarks + mLandmarkAssetIDList.push_back( LLUUID::null ); + mLandmarkItemIDList.push_back( LLUUID::null ); + + mLandmarkAssetIDList.push_back( sHomeID ); + mLandmarkItemIDList.push_back( sHomeID ); + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_landmark(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_landmark); + + std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers()); + + mLandmarkAssetIDList.reserve(mLandmarkAssetIDList.size() + items.size()); + mLandmarkItemIDList.reserve(mLandmarkItemIDList.size() + items.size()); + + S32 count = items.size(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryItem* item = items.at(i); + + list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID()); + + mLandmarkAssetIDList.push_back( item->getAssetUUID() ); + mLandmarkItemIDList.push_back( item->getUUID() ); + } + + 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, bool dest_reached) +{ + LLCtrlListInterface *list = mListSearchResults; + if (list && (!dest_reached || (list->getItemCount() == 1))) + { + list->operateOnAll(LLCtrlListInterface::OP_DELETE); + } + LLWorldMap::getInstance()->cancelTracking(); + mCompletingRegionName = ""; +} + + +void LLFloaterWorldMap::clearLandmarkSelection(bool clear_ui) +{ + if (clear_ui || !childHasKeyboardFocus("landmark combo")) + { + LLCtrlListInterface *list = mListLandmarkCombo; + if (list) + { + list->selectByValue( "None" ); + } + } +} + + +void LLFloaterWorldMap::clearAvatarSelection(bool clear_ui) +{ + if (clear_ui || !childHasKeyboardFocus("friend combo")) + { + mTrackedStatus = LLTracker::TRACKING_NOTHING; + LLCtrlListInterface *list = mListFriendCombo; + if (list && list->getSelectedValue().asString() != "None") + { + 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() +{ + // Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed + // width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across + // sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit. + // Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window. + S32 world_width_regions = MAX_VISIBLE_REGIONS; + S32 world_height_regions = MAX_VISIBLE_REGIONS; + + // Find how much space we have to display the world + LLRect view_rect = mMapView->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, ZOOM_MAX); + + F32 min_power = log(pixels_per_region/256.f)/log(2.f); + + getChild<LLSliderCtrl>("zoom slider")->setMinValue(min_power); +} + + +//------------------------------------------------------------------------- +// User interface widget callbacks +//------------------------------------------------------------------------- + +void LLFloaterWorldMap::onGoHome() +{ + gAgent.teleportHome(); + closeFloater(); +} + + +void LLFloaterWorldMap::onLandmarkComboPrearrange( ) +{ + if( mIsClosing ) + { + return; + } + + LLCtrlListInterface *list = mListLandmarkCombo; + if (!list) return; + + LLUUID current_choice = list->getCurrentID(); + + buildLandmarkIDLists(); + + if( current_choice.isNull() || !list->setCurrentByID( current_choice ) ) + { + LLTracker::stopTracking(false); + } + +} + +void LLFloaterWorldMap::onComboTextEntry() +{ + // Reset the tracking whenever we start typing into any of the search fields, + // so that hitting <enter> does an auto-complete versus teleporting us to the + // previously selected landmark/friend. + LLTracker::stopTracking(false); +} + +void LLFloaterWorldMap::onSearchTextEntry( ) +{ + onComboTextEntry(); + updateSearchEnabled(); +} + + +void LLFloaterWorldMap::onLandmarkComboCommit() +{ + if( mIsClosing ) + { + return; + } + + LLCtrlListInterface *list = mListLandmarkCombo; + if (!list) return; + + LLUUID asset_id; + LLUUID item_id = list->getCurrentID(); + + LLTracker::stopTracking(false); + + //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(); + } + } + + trackLandmark( item_id); + onShowTargetBtn(); + + // Reset to user postion if nothing is tracked + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); +} + +// static +void LLFloaterWorldMap::onAvatarComboPrearrange( ) +{ + if( mIsClosing ) + { + return; + } + + LLCtrlListInterface *list = mListFriendCombo; + if (!list) return; + + LLUUID current_choice; + + if( LLAvatarTracker::instance().haveTrackingInfo() ) + { + current_choice = LLAvatarTracker::instance().getAvatarID(); + } + + buildAvatarIDList(); + + if( !list->setCurrentByID( current_choice ) || current_choice.isNull() ) + { + LLTracker::stopTracking(false); + } +} + +void LLFloaterWorldMap::onAvatarComboCommit() +{ + if( mIsClosing ) + { + return; + } + + LLCtrlListInterface *list = mListFriendCombo; + if (!list) return; + + const LLUUID& new_avatar_id = list->getCurrentID(); + if (new_avatar_id.notNull()) + { + std::string name; + LLComboBox* combo = getChild<LLComboBox>("friend combo"); + if (combo) name = combo->getSimple(); + trackAvatar(new_avatar_id, name); + onShowTargetBtn(); + } + else + { // Reset to user postion if nothing is tracked + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); + } +} + +void LLFloaterWorldMap::avatarTrackFromSlapp( const LLUUID& id ) +{ + trackAvatar( id, "av" ); + onShowTargetBtn(); +} + +void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus ) +{ + updateSearchEnabled(); +} + +void LLFloaterWorldMap::updateSearchEnabled() +{ + if (childHasKeyboardFocus("location") && + getChild<LLUICtrl>("location")->getValue().asString().length() > 0) + { + setDefaultBtn("DoSearch"); + } + else + { + setDefaultBtn(NULL); + } +} + +void LLFloaterWorldMap::onLocationCommit() +{ + if( mIsClosing ) + { + return; + } + + clearLocationSelection(false); + mCompletingRegionName = ""; + mLastRegionName = ""; + + std::string str = getChild<LLUICtrl>("location")->getValue().asString(); + + // Trim any leading and trailing spaces in the search target + std::string saved_str = str; + LLStringUtil::trim( str ); + if ( str != saved_str ) + { // Set the value in the UI if any spaces were removed + getChild<LLUICtrl>("location")->setValue(str); + } + + // Don't try completing empty name (STORM-1427). + if (str.empty()) + { + return; + } + + LLStringUtil::toLower(str); + mCompletingRegionName = str; + LLWorldMap::getInstance()->setTrackingCommit(); + if (str.length() >= 3) + { + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str); + } + else + { + str += "#"; + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str); + } +} + +void LLFloaterWorldMap::onCoordinatesCommit() +{ + if( mIsClosing ) + { + return; + } + + S32 x_coord = (S32)childGetValue("teleport_coordinate_x").asReal(); + S32 y_coord = (S32)childGetValue("teleport_coordinate_y").asReal(); + S32 z_coord = (S32)childGetValue("teleport_coordinate_z").asReal(); + + const std::string region_name = childGetValue("location").asString(); + + trackURL( region_name, x_coord, y_coord, z_coord ); +} + +void LLFloaterWorldMap::onClearBtn() +{ + mTrackedStatus = LLTracker::TRACKING_NOTHING; + LLTracker::stopTracking(true); + LLWorldMap::getInstance()->cancelTracking(); + mSLURL = LLSLURL(); // Clear the SLURL since it's invalid + mSetToUserPosition = true; // Revert back to the current user position +} + +void LLFloaterWorldMap::onShowTargetBtn() +{ + centerOnTarget(true); +} + +void LLFloaterWorldMap::onShowAgentBtn() +{ + mMapView->setPanWithInterpTime(0, 0, false, 0.1f); // false == animate + // Set flag so user's location will be displayed if not tracking anything else + mSetToUserPosition = true; +} + +void LLFloaterWorldMap::onClickTeleportBtn() +{ + teleport(); +} + +void LLFloaterWorldMap::onCopySLURL() +{ + getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString())); + + LLSD args; + args["SLURL"] = mSLURL.getSLURLString(); + + LLNotificationsUtil::add("CopySLURL", args); +} + +void LLFloaterWorldMap::onExpandCollapseBtn() +{ + LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack"); + LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp"); + + bool toggle_collapse = !controls_panel->isCollapsed(); + floater_stack->collapsePanel(controls_panel, toggle_collapse); + floater_stack->updateLayout(); + + std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon"); + std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip"); + getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name)); + getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip); + getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip); +} + +// 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() - gAgentCamera.getCameraPositionGlobal(); + } + } + else if(LLWorldMap::getInstance()->isTracking()) + { + pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();; + + + + } + else + { + // default behavior = center on agent + pos_global.clearVec(); + } + + F64 map_scale = (F64)mMapView->getScale(); + mMapView->setPanWithInterpTime(-llfloor((F32)(pos_global.mdV[VX] * map_scale / REGION_WIDTH_METERS)), + -llfloor((F32)(pos_global.mdV[VY] * map_scale / REGION_WIDTH_METERS)), + !animate, 0.1f); + 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 ); + closeFloater(); + } + 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] = getChild<LLUICtrl>("teleport_coordinate_z")->getValue(); + } + 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 ); + } + } +} + +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() ); + } +} + +void LLFloaterWorldMap::updateSims(bool found_null_sim) +{ + if (mCompletingRegionName == "") + { + return; + } + + LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results"); + list->operateOnAll(LLCtrlListInterface::OP_DELETE); + + S32 name_length = mCompletingRegionName.length(); + + LLSD match; + + S32 num_results = 0; + + std::vector<std::pair <U64, LLSimInfo*> > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end()); + std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames()); + + for (std::vector<std::pair <U64, LLSimInfo*> >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it) + { + LLSimInfo* info = it->second; + std::string sim_name_lower = info->getName(); + LLStringUtil::toLower(sim_name_lower); + + if (sim_name_lower.substr(0, name_length) == mCompletingRegionName) + { + if (sim_name_lower == mCompletingRegionName) + { + match = info->getName(); + } + + LLSD value; + value["id"] = info->getName(); + value["columns"][0]["column"] = "sim_name"; + value["columns"][0]["value"] = info->getName(); + list->addElement(value); + num_results++; + } + } + + if (found_null_sim) + { + mCompletingRegionName = ""; + } + + if (num_results > 0) + { + // if match found, highlight it and go + if (!match.isUndefined()) + { + list->selectByValue(match); + } + // else select first found item + else + { + list->selectFirstItem(); + } + getChild<LLUICtrl>("search_results")->setFocus(true); + onCommitSearchResult(); + } + else + { + // if we found nothing, say "none" + list->setCommentText(LLTrans::getString("worldmap_results_none_found")); + list->operateOnAll(LLCtrlListInterface::OP_DESELECT); + } +} + +void LLFloaterWorldMap::onTeleportFinished() +{ + if(isInVisibleChain()) + { + mMapView->setPan(0, 0, true); + } +} + +void LLFloaterWorldMap::onCommitSearchResult() +{ + LLCtrlListInterface *list = mListSearchResults; + if (!list) return; + + LLSD selected_value = list->getSelectedValue(); + std::string sim_name = selected_value.asString(); + if (sim_name.empty()) + { + return; + } + LLStringUtil::toLower(sim_name); + + std::map<U64, LLSimInfo*>::const_iterator it; + for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) + { + LLSimInfo* info = it->second; + + if (info->isName(sim_name)) + { + LLVector3d pos_global = info->getGlobalOrigin(); + + const F64 SIM_COORD_DEFAULT = 128.0; + LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f); + + // Did this value come from a trackURL() request? + if (!mCompletingRegionPos.isExactlyZero()) + { + pos_local = mCompletingRegionPos; + mCompletingRegionPos.clear(); + } + pos_global.mdV[VX] += (F64)pos_local.mV[VX]; + pos_global.mdV[VY] += (F64)pos_local.mV[VY]; + pos_global.mdV[VZ] = (F64)pos_local.mV[VZ]; + + getChild<LLUICtrl>("location")->setValue(sim_name); + trackLocation(pos_global); + setDefaultBtn("Teleport"); + break; + } + } + + onShowTargetBtn(); +} + +void LLFloaterWorldMap::onChangeMaturity() +{ + bool can_access_mature = gAgent.canAccessMature(); + bool can_access_adult = gAgent.canAccessAdult(); + + getChildView("events_mature_icon")->setVisible( can_access_mature); + getChildView("events_mature_label")->setVisible( can_access_mature); + getChildView("events_mature_chk")->setVisible( can_access_mature); + + getChildView("events_adult_icon")->setVisible( can_access_adult); + getChildView("events_adult_label")->setVisible( can_access_adult); + getChildView("events_adult_chk")->setVisible( can_access_adult); + + // disable mature / adult events. + if (!can_access_mature) + { + gSavedSettings.setBOOL("ShowMatureEvents", false); + } + if (!can_access_adult) + { + gSavedSettings.setBOOL("ShowAdultEvents", false); + } +} + +void LLFloaterWorldMap::onFocusLost() +{ + gViewerWindow->showCursor(); + mMapView->mPanning = false; +} + +LLPanelHideBeacon::LLPanelHideBeacon() : + mHideButton(NULL) +{ +} + +// static +LLPanelHideBeacon* LLPanelHideBeacon::getInstance() +{ + static LLPanelHideBeacon* panel = getPanelHideBeacon(); + return panel; +} + + +bool LLPanelHideBeacon::postBuild() +{ + mHideButton = getChild<LLButton>("hide_beacon_btn"); + mHideButton->setCommitCallback(boost::bind(&LLPanelHideBeacon::onHideButtonClick, this)); + + gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelHideBeacon::updatePosition, this)); + + return true; +} + +//virtual +void LLPanelHideBeacon::draw() +{ + if (!LLTracker::isTracking(NULL)) + { + mHideButton->setVisible(false); + return; + } + mHideButton->setVisible(true); + updatePosition(); + LLPanel::draw(); +} + +//virtual +void LLPanelHideBeacon::setVisible(bool visible) +{ + if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) visible = false; + + if (visible) + { + updatePosition(); + } + + LLPanel::setVisible(visible); +} + + +//static +LLPanelHideBeacon* LLPanelHideBeacon::getPanelHideBeacon() +{ + LLPanelHideBeacon* panel = new LLPanelHideBeacon(); + panel->buildFromFile("panel_hide_beacon.xml"); + + LL_INFOS() << "Build LLPanelHideBeacon panel" << LL_ENDL; + + panel->updatePosition(); + return panel; +} + +void LLPanelHideBeacon::onHideButtonClick() +{ + LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); + if (instance) + { + instance->onClearBtn(); + } +} + +/** +* Updates position of the panel (similar to Stand & Stop Flying panel). +*/ +void LLPanelHideBeacon::updatePosition() +{ + S32 bottom_tb_center = 0; + if (LLToolBar* toolbar_bottom = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_BOTTOM)) + { + bottom_tb_center = toolbar_bottom->getRect().getCenterX(); + } + + S32 left_tb_width = 0; + if (LLToolBar* toolbar_left = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)) + { + left_tb_width = toolbar_left->getRect().getWidth(); + } + + if (gToolBarView != NULL && gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)->hasButtons()) + { + S32 x_pos = bottom_tb_center - getRect().getWidth() / 2 - left_tb_width; + setOrigin( x_pos + HIDE_BEACON_PAD, 0); + } + else + { + S32 x_pos = bottom_tb_center - getRect().getWidth() / 2; + setOrigin( x_pos + HIDE_BEACON_PAD, 0); + } +} |