From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llfloaterworldmap.cpp | 3590 +++++++++++++++++------------------ 1 file changed, 1795 insertions(+), 1795 deletions(-) (limited to 'indra/newview/llfloaterworldmap.cpp') 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 - -//--------------------------------------------------------------------------- -// 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 const& _left, std::pair 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(getChild("objects_mapview")); - mMapView->setPan(0, 0, true); - - LLComboBox *avatar_combo = getChild("friend combo"); - avatar_combo->selectFirstItem(); - avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); - avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); - mListFriendCombo = dynamic_cast(avatar_combo); - - LLSearchEditor *location_editor = getChild("location"); - location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); - location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); - - getChild("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); - mListSearchResults = childGetListInterface("search_results"); - - LLComboBox *landmark_combo = getChild( "landmark combo"); - landmark_combo->selectFirstItem(); - landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); - landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); - mListLandmarkCombo = dynamic_cast(landmark_combo); - - F32 slider_zoom = mMapView->getZoom(); - getChild("zoom slider")->setValue(slider_zoom); - - getChild("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("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("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("zoom slider")->getValue().asReal(); - F32 slider_zoom = old_slider_zoom + ((F32) clicks * -0.3333f); - getChild("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("avatar_icon")->setColor( map_track_color); - } - else - { - getChild("avatar_icon")->setColor( map_track_disabled_color); - } - - if (LLTracker::TRACKING_LANDMARK == tracking_status) - { - getChild("landmark_icon")->setColor( map_track_color); - } - else - { - getChild("landmark_icon")->setColor( map_track_disabled_color); - } - - if (LLTracker::TRACKING_LOCATION == tracking_status) - { - getChild("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("location_icon")->setColor( loading_color); - } - else - { - getChild("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("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("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( "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("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("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("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("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 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("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("location")->getValue().asString().length() > 0) - { - setDefaultBtn("DoSearch"); - } - else - { - setDefaultBtn(NULL); - } -} - -void LLFloaterWorldMap::onLocationCommit() -{ - if( mIsClosing ) - { - return; - } - - clearLocationSelection(false); - mCompletingRegionName = ""; - mLastRegionName = ""; - - std::string str = getChild("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("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("floater_map_stack"); - LLLayoutPanel* controls_panel = getChild("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("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name)); - getChild("expand_collapse_icon")->setToolTip(tooltip); - getChild("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("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("search_results"); - list->operateOnAll(LLCtrlListInterface::OP_DELETE); - - S32 name_length = mCompletingRegionName.length(); - - LLSD match; - - S32 num_results = 0; - - std::vector > 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 >::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("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::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("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("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 + +//--------------------------------------------------------------------------- +// 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 const& _left, std::pair 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(getChild("objects_mapview")); + mMapView->setPan(0, 0, true); + + LLComboBox *avatar_combo = getChild("friend combo"); + avatar_combo->selectFirstItem(); + avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); + avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + mListFriendCombo = dynamic_cast(avatar_combo); + + LLSearchEditor *location_editor = getChild("location"); + location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); + location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); + + getChild("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); + mListSearchResults = childGetListInterface("search_results"); + + LLComboBox *landmark_combo = getChild( "landmark combo"); + landmark_combo->selectFirstItem(); + landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); + landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + mListLandmarkCombo = dynamic_cast(landmark_combo); + + F32 slider_zoom = mMapView->getZoom(); + getChild("zoom slider")->setValue(slider_zoom); + + getChild("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("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("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("zoom slider")->getValue().asReal(); + F32 slider_zoom = old_slider_zoom + ((F32) clicks * -0.3333f); + getChild("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("avatar_icon")->setColor( map_track_color); + } + else + { + getChild("avatar_icon")->setColor( map_track_disabled_color); + } + + if (LLTracker::TRACKING_LANDMARK == tracking_status) + { + getChild("landmark_icon")->setColor( map_track_color); + } + else + { + getChild("landmark_icon")->setColor( map_track_disabled_color); + } + + if (LLTracker::TRACKING_LOCATION == tracking_status) + { + getChild("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("location_icon")->setColor( loading_color); + } + else + { + getChild("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("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("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( "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("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("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("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("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 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("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("location")->getValue().asString().length() > 0) + { + setDefaultBtn("DoSearch"); + } + else + { + setDefaultBtn(NULL); + } +} + +void LLFloaterWorldMap::onLocationCommit() +{ + if( mIsClosing ) + { + return; + } + + clearLocationSelection(false); + mCompletingRegionName = ""; + mLastRegionName = ""; + + std::string str = getChild("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("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("floater_map_stack"); + LLLayoutPanel* controls_panel = getChild("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("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name)); + getChild("expand_collapse_icon")->setToolTip(tooltip); + getChild("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("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("search_results"); + list->operateOnAll(LLCtrlListInterface::OP_DELETE); + + S32 name_length = mCompletingRegionName.length(); + + LLSD match; + + S32 num_results = 0; + + std::vector > 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 >::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("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::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("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("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); + } +} -- cgit v1.2.3