llfloaterworldmap.cpp

Go to the documentation of this file.
00001 
00033 /*
00034  * Map of the entire world, with multiple background images,
00035  * avatar tracking, teleportation by double-click, etc.
00036  */
00037 
00038 #include "llviewerprecompiledheaders.h"
00039 
00040 #include "llfloaterworldmap.h"
00041 
00042 #include "llagent.h"
00043 #include "llviewerwindow.h"
00044 #include "llbutton.h"
00045 #include "llcallingcard.h"
00046 #include "llcolorscheme.h"
00047 #include "llcombobox.h"
00048 #include "llviewercontrol.h"
00049 #include "lldraghandle.h"
00050 #include "llfirstuse.h"
00051 #include "llfocusmgr.h"
00052 #include "llinventorymodel.h"
00053 #include "lllandmarklist.h"
00054 #include "lllineeditor.h"
00055 #include "llnetmap.h"
00056 #include "llpreviewlandmark.h"
00057 #include "llregionhandle.h"
00058 #include "llscrolllistctrl.h"
00059 #include "lltextbox.h"
00060 #include "lltracker.h"
00061 #include "llurldispatcher.h"
00062 #include "llviewermenu.h"
00063 #include "llviewerregion.h"
00064 #include "llviewerstats.h"
00065 #include "llworldmap.h"
00066 #include "llworldmapview.h"
00067 #include "lluictrlfactory.h"
00068 #include "llappviewer.h"
00069 #include "llmapimagetype.h"
00070 #include "llweb.h"
00071 
00072 #include "llglheaders.h"
00073 
00074 //---------------------------------------------------------------------------
00075 // Constants
00076 //---------------------------------------------------------------------------
00077 static const F32 MAP_ZOOM_TIME = 0.2f;
00078 
00079 enum EPanDirection
00080 {
00081         PAN_UP,
00082         PAN_DOWN,
00083         PAN_LEFT,
00084         PAN_RIGHT
00085 };
00086 
00087 // Values in pixels per region
00088 static const F32 ZOOM_MIN = -8.f;       // initial value, updated by adjustZoomSlider
00089 static const F32 ZOOM_MAX = 0.f;
00090 static const F32 ZOOM_INC = 0.2f;
00091 
00092 static const F32 SIM_COORD_MIN   = 0.f;
00093 static const F32 SIM_COORD_MAX   = 255.f;
00094 static const F32 SIM_COORD_DEFAULT = 128.f;
00095 
00096 static const F64 MAX_FLY_DISTANCE = 363.f;  // Diagonal size of one sim.
00097 static const F64 MAX_FLY_DISTANCE_SQUARED = MAX_FLY_DISTANCE * MAX_FLY_DISTANCE;
00098 
00099 //---------------------------------------------------------------------------
00100 // Globals
00101 //---------------------------------------------------------------------------
00102 
00103 LLFloaterWorldMap* gFloaterWorldMap = NULL;
00104 
00105 class LLMapInventoryObserver : public LLInventoryObserver
00106 {
00107 public:
00108         LLMapInventoryObserver() {}
00109         virtual ~LLMapInventoryObserver() {}
00110         virtual void changed(U32 mask);
00111 };
00112   
00113 void LLMapInventoryObserver::changed(U32 mask)
00114 {
00115         // if there's a change we're interested in.
00116         if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
00117                                 LLInventoryObserver::REMOVE)) != 0)
00118         {
00119                 gFloaterWorldMap->inventoryChanged();
00120         }
00121 }
00122 
00123 class LLMapFriendObserver : public LLFriendObserver
00124 {
00125 public:
00126         LLMapFriendObserver() {}
00127         virtual ~LLMapFriendObserver() {}
00128         virtual void changed(U32 mask);
00129 };
00130 
00131 void LLMapFriendObserver::changed(U32 mask)
00132 {
00133         // if there's a change we're interested in.
00134         if((mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE | LLFriendObserver::POWERS)) != 0)
00135         {
00136                 gFloaterWorldMap->friendsChanged();
00137         }
00138 }
00139 
00140 //---------------------------------------------------------------------------
00141 // Statics
00142 //---------------------------------------------------------------------------
00143 
00144 // Used as a pretend asset and inventory id to mean "landmark at my home location."
00145 const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001" );
00146 
00147 //---------------------------------------------------------------------------
00148 // Construction and destruction
00149 //---------------------------------------------------------------------------
00150 
00151 
00152 LLFloaterWorldMap::LLFloaterWorldMap()
00153 :       LLFloater("worldmap"),
00154         mInventory(NULL),
00155         mInventoryObserver(NULL),
00156         mFriendObserver(NULL),
00157         mCompletingRegionName(""),
00158         mWaitingForTracker(FALSE),
00159         mExactMatch(FALSE),
00160         mIsClosing(FALSE),
00161         mSetToUserPosition(TRUE),
00162         mTrackedLocation(0,0,0),
00163         mTrackedStatus(LLTracker::TRACKING_NOTHING)
00164 {
00165         LLCallbackMap::map_t factory_map;
00166         factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
00167         factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL);
00168         LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", &factory_map);
00169 }
00170 
00171 // static
00172 void* LLFloaterWorldMap::createWorldMapView(void* data)
00173 {
00174         return new LLWorldMapView("mapview", LLRect(0,300,400,0));
00175 }
00176 
00177 BOOL LLFloaterWorldMap::postBuild()
00178 {
00179         mTabs = getChild<LLTabContainer>("maptab");
00180         if (!mTabs) return FALSE;
00181 
00182         LLPanel *panel;
00183 
00184         panel = mTabs->getChild<LLPanel>("objects_mapview");
00185         if (panel)
00186         {
00187                 mTabs->setTabChangeCallback(panel, onCommitBackground);
00188                 mTabs->setTabUserData(panel, this);
00189         }
00190         panel = mTabs->getChild<LLPanel>("terrain_mapview");
00191         if (panel)
00192         {
00193                 mTabs->setTabChangeCallback(panel, onCommitBackground);
00194                 mTabs->setTabUserData(panel, this);
00195         }
00196 
00197         // The following callback syncs the worlmap tabs with the images.
00198         // Commented out since it was crashing when LLWorldMap became a singleton.
00199         // We should be fine without it but override the onOpen method and put it 
00200         // there if it turns out to be needed. -MG
00201         //
00202         //onCommitBackground((void*)this, false);
00203 
00204         childSetCommitCallback("friend combo", onAvatarComboCommit, this);
00205 
00206         LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
00207         if (avatar_combo)
00208         {
00209                 avatar_combo->selectFirstItem();
00210                 avatar_combo->setPrearrangeCallback( onAvatarComboPrearrange );
00211                 avatar_combo->setTextEntryCallback( onComboTextEntry );
00212         }
00213 
00214         childSetAction("DoSearch", onLocationCommit, this);
00215 
00216         childSetFocusChangedCallback("location", onLocationFocusChanged, this);
00217 
00218         LLLineEditor *location_editor = getChild<LLLineEditor>("location");
00219         if (location_editor)
00220         {
00221                 location_editor->setKeystrokeCallback( onSearchTextEntry );
00222         }
00223         
00224         childSetCommitCallback("search_results", onCommitSearchResult, this);
00225         childSetDoubleClickCallback("search_results", onClickTeleportBtn);
00226         childSetCommitCallback("spin x", onCommitLocation, this);
00227         childSetCommitCallback("spin y", onCommitLocation, this);
00228         childSetCommitCallback("spin z", onCommitLocation, this);
00229 
00230         childSetCommitCallback("landmark combo", onLandmarkComboCommit, this);
00231 
00232         LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
00233         if (landmark_combo)
00234         {
00235                 landmark_combo->selectFirstItem();
00236                 landmark_combo->setPrearrangeCallback( onLandmarkComboPrearrange );
00237                 landmark_combo->setTextEntryCallback( onComboTextEntry );
00238         }
00239 
00240         childSetAction("Go Home", onGoHome, this);
00241 
00242         childSetAction("Teleport", onClickTeleportBtn, this);
00243 
00244         childSetAction("Show Destination", onShowTargetBtn, this);
00245         childSetAction("Show My Location", onShowAgentBtn, this);
00246         childSetAction("Clear", onClearBtn, this);
00247         childSetAction("copy_slurl", onCopySLURL, this);
00248 
00249         mCurZoomVal = log(gMapScale)/log(2.f);
00250         childSetValue("zoom slider", gMapScale);
00251 
00252         setDefaultBtn(NULL);
00253 
00254         mZoomTimer.stop();
00255 
00256         return TRUE;
00257 }
00258 
00259 // virtual
00260 LLFloaterWorldMap::~LLFloaterWorldMap()
00261 {
00262         // All cleaned up by LLView destructor
00263         mTabs = NULL;
00264 
00265         // Inventory deletes all observers on shutdown
00266         mInventory = NULL;
00267         mInventoryObserver = NULL;
00268 
00269         // avatar tracker will delete this for us.
00270         mFriendObserver = NULL;
00271 }
00272 
00273 
00274 // virtual
00275 void LLFloaterWorldMap::onClose(bool app_quitting)
00276 {
00277         setVisible(FALSE);
00278 }
00279 
00280 // static
00281 void LLFloaterWorldMap::show(void*, BOOL center_on_target)
00282 {
00283         BOOL was_visible = gFloaterWorldMap->getVisible();
00284 
00285         gFloaterWorldMap->mIsClosing = FALSE;
00286         gFloaterWorldMap->open();               /* Flawfinder: ignore */
00287 
00288         LLWorldMapView* map_panel;
00289         map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
00290         map_panel->clearLastClick();
00291 
00292         if (!was_visible)
00293         {
00294                 // reset pan on show, so it centers on you again
00295                 if (!center_on_target)
00296                 {
00297                         LLWorldMapView::setPan(0, 0, TRUE);
00298                 }
00299                 map_panel->updateVisibleBlocks();
00300 
00301                 // Reload the agent positions when we show the window
00302                 LLWorldMap::getInstance()->eraseItems();
00303 
00304                 // Reload any maps that may have changed
00305                 LLWorldMap::getInstance()->clearSimFlags();
00306 
00307                 const S32 panel_num = gFloaterWorldMap->mTabs->getCurrentPanelIndex();
00308                 const bool request_from_sim = true;
00309                 LLWorldMap::getInstance()->setCurrentLayer(panel_num, request_from_sim);
00310 
00311                 // We may already have a bounding box for the regions of the world,
00312                 // so use that to adjust the view.
00313                 gFloaterWorldMap->adjustZoomSliderBounds();
00314 
00315                 // Could be first show
00316                 LLFirstUse::useMap();
00317 
00318                 // Start speculative download of landmarks
00319                 LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
00320                 gInventory.startBackgroundFetch(landmark_folder_id);
00321 
00322                 gFloaterWorldMap->childSetFocus("location", TRUE);
00323                 gFocusMgr.triggerFocusFlash();
00324 
00325                 gFloaterWorldMap->buildAvatarIDList();
00326                 gFloaterWorldMap->buildLandmarkIDLists();
00327 
00328                 // If nothing is being tracked, set flag so the user position will be found
00329                 gFloaterWorldMap->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
00330         }
00331         
00332         if (center_on_target)
00333         {
00334                 gFloaterWorldMap->centerOnTarget(FALSE);
00335         }
00336 }
00337 
00338 
00339 
00340 // static
00341 void LLFloaterWorldMap::reloadIcons(void*)
00342 {
00343         LLWorldMap::getInstance()->eraseItems();
00344 
00345         LLWorldMap::getInstance()->sendMapLayerRequest();
00346 }
00347 
00348 
00349 // static
00350 void LLFloaterWorldMap::toggle(void*)
00351 {
00352         BOOL visible = gFloaterWorldMap->getVisible();
00353 
00354         if (!visible)
00355         {
00356                 show(NULL, FALSE);
00357         }
00358         else
00359         {
00360                 gFloaterWorldMap->mIsClosing = TRUE;
00361                 gFloaterWorldMap->close();
00362         }
00363 }
00364 
00365 
00366 // static
00367 void LLFloaterWorldMap::hide(void*)
00368 {
00369         gFloaterWorldMap->mIsClosing = TRUE;
00370         gFloaterWorldMap->close();
00371 }
00372 
00373 
00374 // virtual
00375 void LLFloaterWorldMap::setVisible( BOOL visible )
00376 {
00377         LLFloater::setVisible( visible );
00378 
00379         gSavedSettings.setBOOL( "ShowWorldMap", visible );
00380 
00381         if( !visible )
00382         {
00383                 // While we're not visible, discard the overlay images we're using
00384                 LLWorldMap::getInstance()->clearImageRefs();
00385         }
00386 }
00387 
00388 
00389 // virtual
00390 BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
00391 {
00392         BOOL handled;
00393         handled = LLFloater::handleHover(x, y, mask);
00394         return handled;
00395 }
00396 
00397 BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
00398 {
00399         if (!isMinimized() && isFrontmost())
00400         {
00401                 F32 slider_value = (F32)childGetValue("zoom slider").asReal();
00402                 slider_value += ((F32)clicks * -0.3333f);
00403                 childSetValue("zoom slider", LLSD(slider_value));
00404                 return TRUE;
00405         }
00406         return FALSE;
00407 }
00408 
00409 
00410 // virtual
00411 void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent )
00412 {
00413         LLFloater::reshape( width, height, called_from_parent );
00414 
00415         // Might have changed size of world display area
00416         // JC: Technically, this is correct, but it makes the slider "pop"
00417         // if you resize the window, then draw the slider.  Just leaving it
00418         // the way it was when you opened the window seems better.
00419         // adjustZoomSliderBounds();
00420 }
00421 
00422 
00423 // virtual
00424 void LLFloaterWorldMap::draw()
00425 {
00426         // Hide/Show Mature Events controls
00427         childSetVisible("events_mature_icon", !gAgent.isTeen());
00428         childSetVisible("events_mature_label", !gAgent.isTeen());
00429         childSetVisible("event_mature_chk", !gAgent.isTeen());
00430 
00431         // On orientation island, users don't have a home location yet, so don't
00432         // let them teleport "home".  It dumps them in an often-crowed welcome
00433         // area (infohub) and they get confused. JC
00434         LLViewerRegion* regionp = gAgent.getRegion();
00435         bool agent_on_prelude = (regionp && regionp->isPrelude());
00436         bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude;
00437         childSetEnabled("Go Home", enable_go_home);
00438 
00439         updateLocation();
00440         
00441         LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); 
00442         if (LLTracker::TRACKING_AVATAR == tracking_status)
00443         {
00444                 childSetColor("avatar_icon", gTrackColor);
00445         }
00446         else
00447         {
00448                 childSetColor("avatar_icon", gDisabledTrackColor);
00449         }
00450 
00451         if (LLTracker::TRACKING_LANDMARK == tracking_status)
00452         {
00453                 childSetColor("landmark_icon", gTrackColor);
00454         }
00455         else
00456         {
00457                 childSetColor("landmark_icon", gDisabledTrackColor);
00458         }
00459 
00460         if (LLTracker::TRACKING_LOCATION == tracking_status)
00461         {
00462                 childSetColor("location_icon", gTrackColor);
00463         }
00464         else
00465         {
00466                 if (mCompletingRegionName != "")
00467                 {
00468                         F64 seconds = LLTimer::getElapsedSeconds();
00469                         double value = fmod(seconds, 2);
00470                         value = 0.5 + 0.5*cos(value * 3.14159f);
00471                         LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
00472                         childSetColor("location_icon", loading_color);
00473                 }
00474                 else
00475                 {
00476                         childSetColor("location_icon", gDisabledTrackColor);
00477                 }
00478         }
00479 
00480         // check for completion of tracking data
00481         if (mWaitingForTracker)
00482         {
00483                 centerOnTarget(TRUE);
00484         }
00485 
00486         childSetEnabled("Teleport", (BOOL)tracking_status);
00487 //      childSetEnabled("Clear", (BOOL)tracking_status);
00488         childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->mIsTrackingUnknownLocation);
00489         childSetEnabled("copy_slurl", (mSLURL.size() > 0) );
00490 
00491         setMouseOpaque(TRUE);
00492         getDragHandle()->setMouseOpaque(TRUE);
00493 
00494         //RN: snaps to zoom value because interpolation caused jitter in the text rendering
00495         if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)childGetValue("zoom slider").asReal())
00496         {
00497                 mZoomTimer.start();
00498         }
00499         F32 interp = mZoomTimer.getElapsedTimeF32() / MAP_ZOOM_TIME;
00500         if (interp > 1.f)
00501         {
00502                 interp = 1.f;
00503                 mZoomTimer.stop();
00504         }
00505         mCurZoomVal = lerp(mCurZoomVal, (F32)childGetValue("zoom slider").asReal(), interp);
00506         F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
00507         LLWorldMapView::setScale( map_scale );
00508         
00509         LLFloater::draw();
00510 }
00511 
00512 
00513 //-------------------------------------------------------------------------
00514 // Internal utility functions
00515 //-------------------------------------------------------------------------
00516 
00517 
00518 void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const LLString& name )
00519 {
00520         LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
00521         if (!iface) return;
00522 
00523         buildAvatarIDList();
00524         if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
00525         {
00526                 // *HACK: Adjust Z values automatically for liaisons & gods so
00527                 // they swoop down when they click on the map. Requested
00528                 // convenience.
00529                 if(gAgent.isGodlike())
00530                 {
00531                         childSetValue("spin z", LLSD(200.f));
00532                 }
00533                 // Don't re-request info if we already have it or we won't have it in time to teleport
00534                 if (mTrackedStatus != LLTracker::TRACKING_AVATAR || name != mTrackedAvatarName)
00535                 {
00536                         mTrackedStatus = LLTracker::TRACKING_AVATAR;
00537                         mTrackedAvatarName = name;
00538                         LLTracker::trackAvatar(avatar_id, name);
00539                 }
00540         }
00541         else
00542         {
00543                 LLTracker::stopTracking(NULL);
00544         }
00545         setDefaultBtn("Teleport");
00546 }
00547 
00548 void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
00549 {
00550         LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
00551         if (!iface) return;
00552 
00553         buildLandmarkIDLists();
00554         BOOL found = FALSE;
00555         S32 idx;
00556         for (idx = 0; idx < mLandmarkItemIDList.count(); idx++)
00557         {
00558                 if ( mLandmarkItemIDList.get(idx) == landmark_item_id)
00559                 {
00560                         found = TRUE;
00561                         break;
00562                 }
00563         }
00564 
00565         if (found && iface->setCurrentByID( landmark_item_id ) ) 
00566         {
00567                 LLUUID asset_id = mLandmarkAssetIDList.get( idx );
00568                 LLString name;
00569                 LLComboBox* combo = getChild<LLComboBox>( "landmark combo");
00570                 if (combo) name = combo->getSimple();
00571                 mTrackedStatus = LLTracker::TRACKING_LANDMARK;
00572                 LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ),       // assetID
00573                                                                 mLandmarkItemIDList.get( idx ), // itemID
00574                                                                 name);                  // name
00575 
00576                 if( asset_id != sHomeID )
00577                 {
00578                         // start the download process
00579                         gLandmarkList.getAsset( asset_id);
00580                 }
00581 
00582                 // We have to download both region info and landmark data, so set busy. JC
00583 //              getWindow()->incBusyCount();
00584         }
00585         else
00586         {
00587                 LLTracker::stopTracking(NULL);
00588         }
00589         setDefaultBtn("Teleport");
00590 }
00591 
00592 
00593 void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
00594 {
00595         mTrackedStatus = LLTracker::TRACKING_LOCATION;
00596         LLTracker::trackLocation(event_info.mPosGlobal, event_info.mName, event_info.mToolTip, LLTracker::LOCATION_EVENT);
00597         setDefaultBtn("Teleport");
00598 }
00599 
00600 void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
00601 {
00602         mTrackedStatus = LLTracker::TRACKING_LOCATION;
00603         LLTracker::trackLocation(item.mPosGlobal, item.mName, item.mToolTip, LLTracker::LOCATION_ITEM);
00604         setDefaultBtn("Teleport");
00605 }
00606 
00607 void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
00608 {
00609         LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
00610         if (!sim_info)
00611         {
00612                 LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE;
00613                 LLWorldMap::getInstance()->mInvalidLocation = FALSE;
00614                 LLWorldMap::getInstance()->mUnknownLocation = pos_global;
00615                 LLTracker::stopTracking(NULL);
00616                 S32 world_x = S32(pos_global.mdV[0] / 256);
00617                 S32 world_y = S32(pos_global.mdV[1] / 256);
00618                 LLWorldMap::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
00619                 setDefaultBtn("");
00620                 return;
00621         }
00622         if (sim_info->mAccess == SIM_ACCESS_DOWN)
00623         {
00624                 // Down sim. Show the blue circle of death!
00625                 LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE;
00626                 LLWorldMap::getInstance()->mUnknownLocation = pos_global;
00627                 LLWorldMap::getInstance()->mInvalidLocation = TRUE;
00628                 LLTracker::stopTracking(NULL);
00629                 setDefaultBtn("");
00630                 return;
00631         }
00632 
00633         LLString sim_name;
00634         LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name );
00635         F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
00636         F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
00637         LLString full_name = llformat("%s (%d, %d, %d)", 
00638                                                                   sim_name.c_str(), 
00639                                                                   llround(region_x), 
00640                                                                   llround(region_y),
00641                                                                   llround((F32)pos_global.mdV[VZ]));
00642 
00643         LLString tooltip("");
00644         mTrackedStatus = LLTracker::TRACKING_LOCATION;
00645         LLTracker::trackLocation(pos_global, full_name, tooltip);
00646         LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
00647         LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE;
00648         LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
00649 
00650         setDefaultBtn("Teleport");
00651 }
00652 
00653 void LLFloaterWorldMap::updateLocation()
00654 {
00655         bool gotSimName;
00656 
00657         LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
00658 
00659         // These values may get updated by a message, so need to check them every frame
00660         // The fields may be changed by the user, so only update them if the data changes
00661         LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
00662         if (pos_global.isExactlyZero())
00663         {
00664                 LLVector3d agentPos = gAgent.getPositionGlobal();
00665 
00666                 // Set to avatar's current postion if nothing is selected
00667                 if ( status == LLTracker::TRACKING_NOTHING && mSetToUserPosition )
00668                 {
00669                         // Make sure we know where we are before setting the current user position
00670                         LLString agent_sim_name;
00671                         gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name );
00672                         if ( gotSimName )
00673                         {
00674                                 mSetToUserPosition = FALSE;
00675 
00676                                 // Fill out the location field
00677                                 childSetValue("location", agent_sim_name);
00678 
00679                                 // Figure out where user is
00680                                 LLVector3d agentPos = gAgent.getPositionGlobal();
00681 
00682                                 S32 agent_x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
00683                                 S32 agent_y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
00684                                 S32 agent_z = llround( (F32)agentPos.mdV[VZ] );
00685 
00686                                 childSetValue("spin x", LLSD(agent_x) );
00687                                 childSetValue("spin y", LLSD(agent_y) );
00688                                 childSetValue("spin z", LLSD(agent_z) );
00689 
00690                                 // Set the current SLURL
00691                                 mSLURL = LLURLDispatcher::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z);
00692                         }
00693                 }
00694 
00695                 return; // invalid location
00696         }
00697         LLString sim_name;
00698         gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name );
00699         if ((status != LLTracker::TRACKING_NOTHING) &&
00700                 (status != mTrackedStatus || pos_global != mTrackedLocation || sim_name != mTrackedSimName))
00701         {
00702                 mTrackedStatus = status;
00703                 mTrackedLocation = pos_global;
00704                 mTrackedSimName = sim_name;
00705                 
00706                 if (status == LLTracker::TRACKING_AVATAR)
00707                 {
00708                         // *HACK: Adjust Z values automatically for liaisons &
00709                         // gods so they swoop down when they click on the
00710                         // map. Requested convenience.
00711                         if(gAgent.isGodlike())
00712                         {
00713                                 pos_global[2] = 200;
00714                         }
00715                 }
00716 
00717                 childSetValue("location", sim_name);
00718                 
00719                 F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
00720                 F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
00721                 childSetValue("spin x", LLSD(region_x) );
00722                 childSetValue("spin y", LLSD(region_y) );
00723                 childSetValue("spin z", LLSD((F32)pos_global.mdV[VZ]) );
00724 
00725                 // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
00726                 if ( gotSimName )
00727                 {
00728                         mSLURL = LLURLDispatcher::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ]));
00729                 }
00730                 else
00731                 {       // Empty SLURL will disable the "Copy SLURL to clipboard" button
00732                         mSLURL = "";
00733                 }
00734         }
00735 }
00736 
00737 void LLFloaterWorldMap::trackURL(const LLString& region_name, S32 x_coord, S32 y_coord, S32 z_coord)
00738 {
00739         LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromName(region_name);
00740         z_coord = llclamp(z_coord, 0, 1000);
00741         if (sim_info)
00742         {
00743                 LLVector3 local_pos;
00744                 local_pos.mV[VX] = (F32)x_coord;
00745                 local_pos.mV[VY] = (F32)y_coord;
00746                 local_pos.mV[VZ] = (F32)z_coord;
00747                 LLVector3d global_pos = sim_info->getGlobalPos(local_pos);
00748                 trackLocation(global_pos);
00749                 setDefaultBtn("Teleport");
00750         }
00751         else
00752         {
00753                 // fill in UI based on URL
00754                 gFloaterWorldMap->childSetValue("location", region_name);
00755                 childSetValue("spin x", LLSD((F32)x_coord));
00756                 childSetValue("spin y", LLSD((F32)y_coord));
00757                 childSetValue("spin z", LLSD((F32)z_coord));
00758 
00759                 // pass sim name to combo box
00760                 gFloaterWorldMap->mCompletingRegionName = region_name;
00761                 LLWorldMap::getInstance()->sendNamedRegionRequest(region_name);
00762                 LLString::toLower(gFloaterWorldMap->mCompletingRegionName);
00763                 LLWorldMap::getInstance()->mIsTrackingCommit = TRUE;
00764         }
00765 }
00766 
00767 void LLFloaterWorldMap::observeInventory(LLInventoryModel* model)
00768 {
00769         if(mInventory)
00770         {
00771                 mInventory->removeObserver(mInventoryObserver);
00772                 delete mInventoryObserver;
00773                 mInventory = NULL;
00774                 mInventoryObserver = NULL;
00775         }
00776         if(model)
00777         {
00778                 mInventory = model;
00779                 mInventoryObserver = new LLMapInventoryObserver;
00780                 // Inventory deletes all observers on shutdown
00781                 mInventory->addObserver(mInventoryObserver);
00782                 inventoryChanged();
00783         }
00784 }
00785 
00786 void LLFloaterWorldMap::inventoryChanged()
00787 {
00788         if(!LLTracker::getTrackedLandmarkItemID().isNull())
00789         {
00790                 LLUUID item_id = LLTracker::getTrackedLandmarkItemID();
00791                 buildLandmarkIDLists();
00792                 trackLandmark(item_id);
00793         }
00794 }
00795 
00796 void LLFloaterWorldMap::observeFriends()
00797 {
00798         if(!mFriendObserver)
00799         {
00800                 mFriendObserver = new LLMapFriendObserver;
00801                 LLAvatarTracker::instance().addObserver(mFriendObserver);
00802                 friendsChanged();
00803         }
00804 }
00805 
00806 void LLFloaterWorldMap::friendsChanged()
00807 {
00808         LLAvatarTracker& t = LLAvatarTracker::instance();
00809         const LLUUID& avatar_id = t.getAvatarID();
00810         buildAvatarIDList();
00811         if(avatar_id.notNull())
00812         {
00813                 LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
00814                 if(!iface || !iface->setCurrentByID(avatar_id) || 
00815                         !t.getBuddyInfo(avatar_id)->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) || gAgent.isGodlike())
00816                 {
00817                         LLTracker::stopTracking(NULL);
00818                 }
00819         }
00820 }
00821 
00822 // No longer really builds a list.  Instead, just updates mAvatarCombo.
00823 void LLFloaterWorldMap::buildAvatarIDList()
00824 {
00825         LLCtrlListInterface *list = childGetListInterface("friend combo");
00826         if (!list) return;
00827 
00828     // Delete all but the "None" entry
00829         S32 list_size = list->getItemCount();
00830         while (list_size > 1)
00831         {
00832                 list->selectNthItem(1);
00833                 list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
00834                 --list_size;
00835         }
00836 
00837         LLSD default_column;
00838         default_column["name"] = "friend name";
00839         default_column["label"] = "Friend Name";
00840         default_column["width"] = 500;
00841         list->addColumn(default_column);
00842 
00843         // Get all of the calling cards for avatar that are currently online
00844         LLCollectMappableBuddies collector;
00845         LLAvatarTracker::instance().applyFunctor(collector);
00846         LLCollectMappableBuddies::buddy_map_t::iterator it;
00847         LLCollectMappableBuddies::buddy_map_t::iterator end;
00848         it = collector.mMappable.begin();
00849         end = collector.mMappable.end();
00850         for( ; it != end; ++it)
00851         {
00852                 list->addSimpleElement((*it).first, ADD_BOTTOM, (*it).second);
00853         }
00854 
00855         list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
00856         list->selectFirstItem();
00857 }
00858 
00859 
00860 void LLFloaterWorldMap::buildLandmarkIDLists()
00861 {
00862         LLCtrlListInterface *list = childGetListInterface("landmark combo");
00863         if (!list)
00864         {
00865                 return;
00866         }
00867 
00868     // Delete all but the "None" entry
00869         S32 list_size = list->getItemCount();
00870         if (list_size > 1)
00871         {
00872                 list->selectItemRange(1, -1);
00873                 list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
00874         }
00875 
00876         mLandmarkItemIDList.reset();
00877         mLandmarkAssetIDList.reset();
00878 
00879         // Get all of the current landmarks
00880         mLandmarkAssetIDList.put( LLUUID::null );
00881         mLandmarkItemIDList.put( LLUUID::null );
00882 
00883         mLandmarkAssetIDList.put( sHomeID );
00884         mLandmarkItemIDList.put( sHomeID );
00885 
00886         LLInventoryModel::cat_array_t cats;
00887         LLInventoryModel::item_array_t items;
00888         LLIsType is_landmark(LLAssetType::AT_LANDMARK);
00889         gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
00890                                                                         cats,
00891                                                                         items,
00892                                                                         LLInventoryModel::EXCLUDE_TRASH,
00893                                                                         is_landmark);
00894 
00895         std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
00896         
00897         S32 count = items.count();
00898         for(S32 i = 0; i < count; ++i)
00899         {
00900                 LLInventoryItem* item = items.get(i);
00901 
00902                 list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
00903 
00904                 mLandmarkAssetIDList.put( item->getAssetUUID() );
00905                 mLandmarkItemIDList.put( item->getUUID() );
00906         }
00907         
00908         list->sortByColumn("landmark name", TRUE);
00909 
00910         list->selectFirstItem();
00911 }
00912 
00913 
00914 F32 LLFloaterWorldMap::getDistanceToDestination(const LLVector3d &destination, 
00915                                                                                                 F32 z_attenuation) const
00916 {
00917         LLVector3d delta = destination - gAgent.getPositionGlobal();
00918         // by attenuating the z-component we effectively 
00919         // give more weight to the x-y plane
00920         delta.mdV[VZ] *= z_attenuation;
00921         F32 distance = (F32)delta.magVec();
00922         return distance;
00923 }
00924 
00925 
00926 void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
00927 {
00928         LLCtrlListInterface *list = childGetListInterface("search_results");
00929         if (list)
00930         {
00931                 list->operateOnAll(LLCtrlListInterface::OP_DELETE);
00932         }
00933         if (!childHasKeyboardFocus("spin x"))
00934         {
00935                 childSetValue("spin x", SIM_COORD_DEFAULT);
00936         }
00937         if (!childHasKeyboardFocus("spin y"))
00938         {
00939                 childSetValue("spin y", SIM_COORD_DEFAULT);
00940         }
00941         if (!childHasKeyboardFocus("spin z"))
00942         {
00943                 childSetValue("spin z", 0);
00944         }
00945         LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
00946         mCompletingRegionName = "";
00947         mExactMatch = FALSE;
00948 }
00949 
00950 
00951 void LLFloaterWorldMap::clearLandmarkSelection(BOOL clear_ui)
00952 {
00953         if (clear_ui || !childHasKeyboardFocus("landmark combo"))
00954         {
00955                 LLCtrlListInterface *list = childGetListInterface("landmark combo");
00956                 if (list)
00957                 {
00958                         list->selectByValue( "None" );
00959                 }
00960         }
00961 }
00962 
00963 
00964 void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
00965 {
00966         if (clear_ui || !childHasKeyboardFocus("friend combo"))
00967         {
00968                 mTrackedStatus = LLTracker::TRACKING_NOTHING;
00969                 LLCtrlListInterface *list = childGetListInterface("friend combo");
00970                 if (list)
00971                 {
00972                         list->selectByValue( "None" );
00973                 }
00974         }
00975 }
00976 
00977 
00978 // Adjust the maximally zoomed out limit of the zoom slider so you
00979 // can see the whole world, plus a little.
00980 void LLFloaterWorldMap::adjustZoomSliderBounds()
00981 {
00982         // World size in regions
00983         S32 world_width_regions  = LLWorldMap::getInstance()->getWorldWidth() / REGION_WIDTH_UNITS;
00984         S32 world_height_regions = LLWorldMap::getInstance()->getWorldHeight() / REGION_WIDTH_UNITS;
00985 
00986         // Pad the world size a little bit, so we have a nice border on
00987         // the edge
00988         world_width_regions++;
00989         world_height_regions++;
00990 
00991         // Find how much space we have to display the world
00992         LLWorldMapView* map_panel;
00993         map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
00994         LLRect view_rect = map_panel->getRect();
00995 
00996         // View size in pixels
00997         S32 view_width = view_rect.getWidth();
00998         S32 view_height = view_rect.getHeight();
00999 
01000         // Pixels per region to display entire width/height
01001         F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
01002         F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
01003 
01004         F32 pixels_per_region = llmin(width_pixels_per_region,
01005                                                                   height_pixels_per_region);
01006 
01007         // Round pixels per region to an even number of slider increments
01008         S32 slider_units = llfloor(pixels_per_region / 0.2f);
01009         pixels_per_region = slider_units * 0.2f;
01010 
01011         // Make sure the zoom slider can be moved at least a little bit.
01012         // Likewise, less than the increment pixels per region is just silly.
01013         pixels_per_region = llclamp(pixels_per_region, 1.f, (F32)(pow(2.f, ZOOM_MAX) * 128.f));
01014 
01015         F32 min_power = log(pixels_per_region/256.f)/log(2.f);
01016         childSetMinValue("zoom slider", min_power);
01017 }
01018 
01019 
01020 //-------------------------------------------------------------------------
01021 // User interface widget callbacks
01022 //-------------------------------------------------------------------------
01023 
01024 // static
01025 void LLFloaterWorldMap::onPanBtn( void* userdata )
01026 {
01027         if( !gFloaterWorldMap ) return;
01028 
01029         EPanDirection direction = (EPanDirection)(intptr_t)userdata;
01030 
01031         S32 pan_x = 0;
01032         S32 pan_y = 0;
01033         switch( direction )
01034         {
01035         case PAN_UP:    pan_y = -1;     break;
01036         case PAN_DOWN:  pan_y = 1;      break;
01037         case PAN_LEFT:  pan_x = 1;      break;
01038         case PAN_RIGHT: pan_x = -1;     break;
01039         default:                llassert(0);    return;
01040         }
01041 
01042         LLWorldMapView* map_panel;
01043         map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel();
01044         map_panel->translatePan( pan_x, pan_y );
01045 }
01046 
01047 // static
01048 void LLFloaterWorldMap::onGoHome(void*)
01049 {
01050         gAgent.teleportHome();
01051         gFloaterWorldMap->close();
01052 }
01053 
01054 
01055 // static 
01056 void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdata )
01057 {
01058         LLFloaterWorldMap* self = gFloaterWorldMap;
01059         if( !self || self->mIsClosing )
01060         {
01061                 return;
01062         }
01063 
01064         LLCtrlListInterface *list = self->childGetListInterface("landmark combo");
01065         if (!list) return;
01066 
01067         LLUUID current_choice = list->getCurrentID();
01068 
01069         gFloaterWorldMap->buildLandmarkIDLists();
01070 
01071         if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
01072         {
01073                 LLTracker::stopTracking(NULL);
01074         }
01075 
01076 }
01077 
01078 void LLFloaterWorldMap::onComboTextEntry( LLLineEditor* ctrl, void* userdata )
01079 {
01080         // Reset the tracking whenever we start typing into any of the search fields,
01081         // so that hitting <enter> does an auto-complete versus teleporting us to the
01082         // previously selected landmark/friend.
01083         LLTracker::clearFocus();
01084 }
01085 
01086 // static
01087 void LLFloaterWorldMap::onSearchTextEntry( LLLineEditor* ctrl, void* userdata )
01088 {
01089         onComboTextEntry(ctrl, userdata);
01090         updateSearchEnabled(ctrl, userdata);
01091 }
01092 
01093 // static 
01094 void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata )
01095 {
01096         LLFloaterWorldMap* self = gFloaterWorldMap;
01097 
01098         if( !self || self->mIsClosing )
01099         {
01100                 return;
01101         }
01102 
01103         LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("landmark combo");
01104         if (!list) return;
01105 
01106         LLUUID asset_id;
01107         LLUUID item_id = list->getCurrentID();
01108 
01109         LLTracker::stopTracking(NULL);
01110 
01111         //RN: stopTracking() clears current combobox selection, need to reassert it here
01112         list->setCurrentByID(item_id);
01113 
01114         if( item_id.isNull() )
01115         {
01116         }
01117         else if( item_id == sHomeID )
01118         {
01119                 asset_id = sHomeID;
01120         }
01121         else
01122         {
01123                 LLInventoryItem* item = gInventory.getItem( item_id );
01124                 if( item )
01125                 {
01126                         asset_id = item->getAssetUUID();
01127                 }
01128                 else
01129                 {
01130                         // Something went wrong, so revert to a safe value.
01131                         item_id.setNull();
01132                 }
01133         }
01134         
01135         self->trackLandmark( item_id);
01136         onShowTargetBtn(self);
01137 
01138         // Reset to user postion if nothing is tracked
01139         self->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
01140 }
01141 
01142 // static 
01143 void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata )
01144 {
01145         LLFloaterWorldMap* self = gFloaterWorldMap;
01146         if( !self || self->mIsClosing )
01147         {
01148                 return;
01149         }
01150 
01151         LLCtrlListInterface *list = self->childGetListInterface("friend combo");
01152         if (!list) return;
01153 
01154         LLUUID current_choice;
01155 
01156         if( LLAvatarTracker::instance().haveTrackingInfo() )
01157         {
01158                 current_choice = LLAvatarTracker::instance().getAvatarID();
01159         }
01160 
01161         self->buildAvatarIDList();
01162 
01163         if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
01164         {
01165                 LLTracker::stopTracking(NULL);
01166         }
01167 }
01168 
01169 
01170 // static 
01171 void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata )
01172 {
01173         LLFloaterWorldMap* self = gFloaterWorldMap;
01174         if( !self || self->mIsClosing )
01175         {
01176                 return;
01177         }
01178 
01179         LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("friend combo");
01180         if (!list) return;
01181 
01182         const LLUUID& new_avatar_id = list->getCurrentID();
01183         if (new_avatar_id.notNull())
01184         {
01185                 LLString name;
01186                 LLComboBox* combo = gFloaterWorldMap->getChild<LLComboBox>("friend combo");
01187                 if (combo) name = combo->getSimple();
01188                 self->trackAvatar(new_avatar_id, name);
01189                 onShowTargetBtn(self);
01190         }
01191         else
01192         {       // Reset to user postion if nothing is tracked
01193                 self->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
01194         }
01195 }
01196 
01197 //static 
01198 void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus, void* userdata )
01199 {
01200         updateSearchEnabled((LLUICtrl*)focus, userdata);
01201 }
01202 
01203 // static 
01204 void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata )
01205 {
01206         LLFloaterWorldMap *self = gFloaterWorldMap;
01207         if (self->childHasKeyboardFocus("location") && 
01208                 self->childGetValue("location").asString().length() > 0)
01209         {
01210                 self->setDefaultBtn("DoSearch");
01211         }
01212         else
01213         {
01214                 self->setDefaultBtn(NULL);
01215         }
01216 }
01217 
01218 // static 
01219 void LLFloaterWorldMap::onLocationCommit( void* userdata )
01220 {
01221         LLFloaterWorldMap *self = gFloaterWorldMap;
01222         if( !self || self->mIsClosing )
01223         {
01224                 return;
01225         }
01226 
01227         self->clearLocationSelection(FALSE);
01228         self->mCompletingRegionName = "";
01229         self->mLastRegionName = "";
01230 
01231         LLString str = self->childGetValue("location").asString();
01232 
01233         // Trim any leading and trailing spaces in the search target
01234         LLString saved_str = str;
01235         LLString::trim( str );
01236         if ( str != saved_str )
01237         {       // Set the value in the UI if any spaces were removed
01238                 self->childSetValue("location", str);
01239         }
01240 
01241         LLString::toLower(str);
01242         gFloaterWorldMap->mCompletingRegionName = str;
01243         LLWorldMap::getInstance()->mIsTrackingCommit = TRUE;
01244         self->mExactMatch = FALSE;
01245         if (str.length() >= 3)
01246         {
01247                 LLWorldMap::getInstance()->sendNamedRegionRequest(str);
01248         }
01249         else
01250         {
01251                 str += "#";
01252                 LLWorldMap::getInstance()->sendNamedRegionRequest(str);
01253         }
01254 }
01255 
01256 
01257 // static
01258 void LLFloaterWorldMap::onClearBtn(void* data)
01259 {
01260         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01261         self->mTrackedStatus = LLTracker::TRACKING_NOTHING;
01262         LLTracker::stopTracking((void *)(intptr_t)TRUE);
01263         LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
01264         self->mSLURL = "";                              // Clear the SLURL since it's invalid
01265         self->mSetToUserPosition = TRUE;        // Revert back to the current user position
01266 }
01267 
01268 // static
01269 void LLFloaterWorldMap::onFlyBtn(void* data)
01270 {
01271         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01272         self->fly();
01273 }
01274 
01275 void LLFloaterWorldMap::onShowTargetBtn(void* data)
01276 {
01277         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01278         self->centerOnTarget(TRUE);
01279 }
01280 
01281 void LLFloaterWorldMap::onShowAgentBtn(void* data)
01282 {
01283         LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate
01284 
01285         // Set flag so user's location will be displayed if not tracking anything else
01286         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01287         self->mSetToUserPosition = TRUE;        
01288 }
01289 
01290 // static
01291 void LLFloaterWorldMap::onClickTeleportBtn(void* data)
01292 {
01293         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01294         self->teleport();
01295 }
01296 
01297 // static
01298 void LLFloaterWorldMap::onCopySLURL(void* data)
01299 {
01300         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01301         gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(self->mSLURL));
01302         
01303         LLString::format_map_t args;
01304         args["[SLURL]"] = self->mSLURL;
01305 
01306         LLAlertDialog::showXml("CopySLURL", args);
01307 }
01308 
01309 void LLFloaterWorldMap::onCheckEvents(LLUICtrl*, void* data)
01310 {
01311         LLFloaterWorldMap* self = (LLFloaterWorldMap*)data;
01312         if(!self) return;
01313         self->childSetEnabled("event_mature_chk", self->childGetValue("event_chk"));
01314 }
01315 
01316 // protected
01317 void LLFloaterWorldMap::centerOnTarget(BOOL animate)
01318 {
01319         LLVector3d pos_global;
01320         if(LLTracker::getTrackingStatus() != LLTracker::TRACKING_NOTHING)
01321         {
01322                 LLVector3d tracked_position = LLTracker::getTrackedPositionGlobal();
01323                 //RN: tracker doesn't allow us to query completion, so we check for a tracking position of
01324                 // absolute zero, and keep trying in the draw loop
01325                 if (tracked_position.isExactlyZero())
01326                 {
01327                         mWaitingForTracker = TRUE;
01328                         return;
01329                 }
01330                 else
01331                 {
01332                         // We've got the position finally, so we're no longer busy. JC
01333 //                      getWindow()->decBusyCount();
01334                         pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();
01335                 }
01336         }
01337         else if(LLWorldMap::getInstance()->mIsTrackingUnknownLocation)
01338         {
01339                 pos_global = LLWorldMap::getInstance()->mUnknownLocation - gAgent.getCameraPositionGlobal();;
01340         }
01341         else
01342         {
01343                 // default behavior = center on agent
01344                 pos_global.clearVec();
01345         }
01346 
01347         LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sPixelsPerMeter)), 
01348                                                         -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sPixelsPerMeter)),
01349                                                         !animate);
01350         mWaitingForTracker = FALSE;
01351 }
01352 
01353 // protected
01354 void LLFloaterWorldMap::fly()
01355 {
01356         LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
01357 
01358         // Start the autopilot and close the floater, 
01359         // so we can see where we're flying
01360         if (!pos_global.isExactlyZero())
01361         {
01362                 gAgent.startAutoPilotGlobal( pos_global );
01363                 close();
01364         }
01365         else
01366         {
01367                 make_ui_sound("UISndInvalidOp");
01368         }
01369 }
01370 
01371 
01372 // protected
01373 void LLFloaterWorldMap::teleport()
01374 {
01375         BOOL teleport_home = FALSE;
01376         LLVector3d pos_global;
01377         LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
01378 
01379         LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
01380         if (LLTracker::TRACKING_AVATAR == tracking_status
01381                 && av_tracker.haveTrackingInfo() )
01382         {
01383                 pos_global = av_tracker.getGlobalPos();
01384                 pos_global.mdV[VZ] = childGetValue("spin z");
01385         }
01386         else if ( LLTracker::TRACKING_LANDMARK == tracking_status)
01387         {
01388                 if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
01389                 {
01390                         teleport_home = TRUE;
01391                 }
01392                 else
01393                 {
01394                         LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
01395                         LLUUID region_id;
01396                         if(landmark
01397                            && !landmark->getGlobalPos(pos_global)
01398                            && landmark->getRegionID(region_id))
01399                         {
01400                                 LLLandmark::requestRegionHandle(
01401                                         gMessageSystem,
01402                                         gAgent.getRegionHost(),
01403                                         region_id,
01404                                         NULL);
01405                         }
01406                 }
01407         }
01408         else if ( LLTracker::TRACKING_LOCATION == tracking_status)
01409         {
01410                 pos_global = LLTracker::getTrackedPositionGlobal();
01411         }
01412         else
01413         {
01414                 make_ui_sound("UISndInvalidOp");
01415         }
01416 
01417         // Do the teleport, which will also close the floater
01418         if (teleport_home)
01419         {
01420                 gAgent.teleportHome();
01421         }
01422         else if (!pos_global.isExactlyZero())
01423         {
01424                 if(LLTracker::TRACKING_LANDMARK == tracking_status)
01425                 {
01426                         gAgent.teleportViaLandmark(LLTracker::getTrackedLandmarkAssetID());
01427                 }
01428                 else
01429                 {
01430                         gAgent.teleportViaLocation( pos_global );
01431                 }
01432         }
01433 }
01434 
01435 // static
01436 void LLFloaterWorldMap::onGoToLandmarkDialog( S32 option, void* userdata )
01437 {
01438         LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
01439         switch( option )
01440         {
01441         case 0:
01442                 self->teleportToLandmark();
01443                 break;
01444         case 1:
01445                 self->flyToLandmark();
01446                 break;
01447         default:
01448                 // nothing
01449                 break;
01450         }
01451 }
01452 
01453 void LLFloaterWorldMap::flyToLandmark()
01454 {
01455         LLVector3d destination_pos_global;
01456         if( !LLTracker::getTrackedLandmarkAssetID().isNull() )
01457         {
01458                 if (LLTracker::hasLandmarkPosition())
01459                 {
01460                         gAgent.startAutoPilotGlobal( LLTracker::getTrackedPositionGlobal() );
01461                 }
01462         }
01463 }
01464 
01465 void LLFloaterWorldMap::teleportToLandmark()
01466 {
01467         BOOL has_destination = FALSE;
01468         LLUUID destination_id; // Null means "home"
01469 
01470         if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
01471         {
01472                 has_destination = TRUE;
01473         }
01474         else
01475         {
01476                 LLLandmark* landmark = gLandmarkList.getAsset( LLTracker::getTrackedLandmarkAssetID() );
01477                 LLVector3d global_pos;
01478                 if(landmark && landmark->getGlobalPos(global_pos))
01479                 {
01480                         destination_id = LLTracker::getTrackedLandmarkAssetID();
01481                         has_destination = TRUE;
01482                 }
01483                 else if(landmark)
01484                 {
01485                         // pop up an anonymous request request.
01486                         LLUUID region_id;
01487                         if(landmark->getRegionID(region_id))
01488                         {
01489                                 LLLandmark::requestRegionHandle(
01490                                         gMessageSystem,
01491                                         gAgent.getRegionHost(),
01492                                         region_id,
01493                                         NULL);
01494                         }
01495                 }
01496         }
01497 
01498         if( has_destination )
01499         {
01500                 gAgent.teleportViaLandmark( destination_id );
01501         }
01502 }
01503 
01504 
01505 void LLFloaterWorldMap::teleportToAvatar()
01506 {
01507         LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
01508         if(av_tracker.haveTrackingInfo())
01509         {
01510                 LLVector3d pos_global = av_tracker.getGlobalPos();
01511                 gAgent.teleportViaLocation( pos_global );
01512         }
01513 }
01514 
01515 
01516 void LLFloaterWorldMap::flyToAvatar()
01517 {
01518         if( LLAvatarTracker::instance().haveTrackingInfo() )
01519         {
01520                 gAgent.startAutoPilotGlobal( LLAvatarTracker::instance().getGlobalPos() );
01521         }
01522 }
01523 
01524 // static
01525 void LLFloaterWorldMap::onCommitBackground(void* userdata, bool from_click)
01526 {
01527         LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
01528 
01529         // Find my index
01530         S32 index = self->mTabs->getCurrentPanelIndex();
01531 
01532         LLWorldMap::getInstance()->setCurrentLayer(index);
01533 }
01534 
01535 void LLFloaterWorldMap::updateSims(bool found_null_sim)
01536 {
01537         if (mCompletingRegionName == "")
01538         {
01539                 return;
01540         }
01541 
01542         LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
01543         list->operateOnAll(LLCtrlListInterface::OP_DELETE);
01544 
01545         LLSD selected_value = list->getSelectedValue();
01546 
01547         S32 name_length = mCompletingRegionName.length();
01548 
01549         BOOL match_found = FALSE;
01550         S32 num_results = 0;
01551         std::map<U64, LLSimInfo*>::const_iterator it;
01552         for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
01553         {
01554                 LLSimInfo* info = (*it).second;
01555                 LLString sim_name = info->mName;
01556                 LLString sim_name_lower = sim_name;
01557                 LLString::toLower(sim_name_lower);
01558 
01559                 if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
01560                 {
01561                         if (LLWorldMap::getInstance()->mIsTrackingCommit)
01562                         {
01563                                 if (sim_name_lower == mCompletingRegionName)
01564                                 {
01565                                         selected_value = sim_name;
01566                                         match_found = TRUE;
01567                                 }
01568                         }
01569 
01570                         LLSD value;
01571                         value["id"] = sim_name;
01572                         value["columns"][0]["column"] = "sim_name";
01573                         value["columns"][0]["value"] = sim_name;
01574                         list->addElement(value);
01575                         num_results++;
01576                 }
01577         }
01578         
01579         list->selectByValue(selected_value);
01580 
01581         if (found_null_sim)
01582         {
01583                 mCompletingRegionName = "";
01584         }
01585 
01586         if (match_found)
01587         {
01588                 mExactMatch = TRUE;
01589                 childSetFocus("search_results");
01590                 onCommitSearchResult(NULL, this);
01591         }
01592         else if (!mExactMatch && num_results > 0)
01593         {
01594                 list->selectFirstItem(); // select first item by default
01595                 childSetFocus("search_results");
01596                 onCommitSearchResult(NULL, this);
01597         }
01598         else
01599         {
01600                 list->addCommentText("None found.");
01601                 list->operateOnAll(LLCtrlListInterface::OP_DESELECT);
01602         }
01603 }
01604 
01605 // static
01606 void LLFloaterWorldMap::onCommitLocation(LLUICtrl* ctrl, void* userdata)
01607 {
01608         LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
01609         LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
01610         if ( LLTracker::TRACKING_LOCATION == tracking_status)
01611         {
01612                 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
01613                 F64 local_x = self->childGetValue("spin x");
01614                 F64 local_y = self->childGetValue("spin y");
01615                 F64 local_z = self->childGetValue("spin z");
01616                 pos_global.mdV[VX] += -fmod(pos_global.mdV[VX], 256.0) + local_x;
01617                 pos_global.mdV[VY] += -fmod(pos_global.mdV[VY], 256.0) + local_y;
01618                 pos_global.mdV[VZ] = local_z;
01619                 self->trackLocation(pos_global);
01620         }
01621 }
01622 
01623 // static
01624 void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata)
01625 {
01626         LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata;
01627 
01628         LLCtrlListInterface *list = self->childGetListInterface("search_results");
01629         if (!list) return;
01630 
01631         LLSD selected_value = list->getSelectedValue();
01632         LLString sim_name = selected_value.asString();
01633         if (sim_name.empty())
01634         {
01635                 return;
01636         }
01637         LLString::toLower(sim_name);
01638 
01639         std::map<U64, LLSimInfo*>::const_iterator it;
01640         for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
01641         {
01642                 LLSimInfo* info = (*it).second;
01643                 LLString info_sim_name = info->mName;
01644                 LLString::toLower(info_sim_name);
01645 
01646                 if (sim_name == info_sim_name)
01647                 {
01648                         LLVector3d pos_global = from_region_handle( info->mHandle );
01649                         F64 local_x = self->childGetValue("spin x");
01650                         F64 local_y = self->childGetValue("spin y");
01651                         F64 local_z = self->childGetValue("spin z");
01652                         pos_global.mdV[VX] += local_x;
01653                         pos_global.mdV[VY] += local_y;
01654                         pos_global.mdV[VZ] = local_z;
01655 
01656                         self->childSetValue("location", sim_name);
01657                         self->trackLocation(pos_global);
01658                         self->setDefaultBtn("Teleport");
01659                         break;
01660                 }
01661         }
01662 
01663         onShowTargetBtn(self);
01664 }

Generated on Fri May 16 08:33:35 2008 for SecondLife by  doxygen 1.5.5