aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra')
-rw-r--r--linden/indra/newview/CMakeLists.txt2
-rw-r--r--linden/indra/newview/app_settings/settings.xml131
-rw-r--r--linden/indra/newview/llagent.cpp110
-rw-r--r--linden/indra/newview/llagent.h7
-rw-r--r--linden/indra/newview/llfloateravatarlist.cpp1471
-rw-r--r--linden/indra/newview/llfloateravatarlist.h316
-rw-r--r--linden/indra/newview/llstartup.cpp6
-rw-r--r--linden/indra/newview/llviewermenu.cpp9
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/floater_radar.xml327
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml4
10 files changed, 2382 insertions, 1 deletions
diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt
index 9a4e2ed..df6d8b5 100644
--- a/linden/indra/newview/CMakeLists.txt
+++ b/linden/indra/newview/CMakeLists.txt
@@ -155,6 +155,7 @@ set(viewer_SOURCE_FILES
155 llfloaterassetbrowser.cpp 155 llfloaterassetbrowser.cpp
156 llfloaterauction.cpp 156 llfloaterauction.cpp
157 llfloateravatarinfo.cpp 157 llfloateravatarinfo.cpp
158 llfloateravatarlist.cpp
158 llfloateravatarpicker.cpp 159 llfloateravatarpicker.cpp
159 llfloateravatartextures.cpp 160 llfloateravatartextures.cpp
160 llfloaterbeacons.cpp 161 llfloaterbeacons.cpp
@@ -617,6 +618,7 @@ set(viewer_HEADER_FILES
617 llfloaterassetbrowser.h 618 llfloaterassetbrowser.h
618 llfloaterauction.h 619 llfloaterauction.h
619 llfloateravatarinfo.h 620 llfloateravatarinfo.h
621 llfloateravatarlist.h
620 llfloateravatarpicker.h 622 llfloateravatarpicker.h
621 llfloateravatartextures.h 623 llfloateravatartextures.h
622 llfloaterbeacons.h 624 llfloaterbeacons.h
diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml
index 3523c7f..c8ad381 100644
--- a/linden/indra/newview/app_settings/settings.xml
+++ b/linden/indra/newview/app_settings/settings.xml
@@ -2359,6 +2359,137 @@
2359 2359
2360 <!-- End: socks5 --> 2360 <!-- End: socks5 -->
2361 2361
2362 <!-- Begin: full radar (Advanced menu) -->
2363
2364 <key>ShowRadar</key>
2365 <map>
2366 <key>Comment</key>
2367 <string>Show the radar floater</string>
2368 <key>Persist</key>
2369 <integer>1</integer>
2370 <key>Type</key>
2371 <string>Boolean</string>
2372 <key>Value</key>
2373 <integer>0</integer>
2374 </map>
2375 <key>FloaterRadarRect</key>
2376 <map>
2377 <key>Comment</key>
2378 <string>Rectangle for Radar</string>
2379 <key>Persist</key>
2380 <integer>1</integer>
2381 <key>Type</key>
2382 <string>Rect</string>
2383 <key>Value</key>
2384 <array>
2385 <integer>0</integer>
2386 <integer>400</integer>
2387 <integer>200</integer>
2388 <integer>0</integer>
2389 </array>
2390 </map>
2391 <key>RadarKeepOpen</key>
2392 <map>
2393 <key>Comment</key>
2394 <string>Keeps radar updates running in background</string>
2395 <key>Persist</key>
2396 <integer>1</integer>
2397 <key>Type</key>
2398 <string>Boolean</string>
2399 <key>Value</key>
2400 <integer>0</integer>
2401 </map>
2402 <key>RadarUpdateRate</key>
2403 <map>
2404 <key>Comment</key>
2405 <string>Radar update rate (0 = high, 1 = medium, 2 = low)</string>
2406 <key>Persist</key>
2407 <integer>1</integer>
2408 <key>Type</key>
2409 <string>U32</string>
2410 <key>Value</key>
2411 <integer>1</integer>
2412 </map>
2413 <key>RadarAlertSim</key>
2414 <map>
2415 <key>Comment</key>
2416 <string>Whether the radar emits chat alerts for avatars entering/exiting sim</string>
2417 <key>Persist</key>
2418 <integer>1</integer>
2419 <key>Type</key>
2420 <string>Boolean</string>
2421 <key>Value</key>
2422 <integer>0</integer>
2423 </map>
2424 <key>RadarAlertDraw</key>
2425 <map>
2426 <key>Comment</key>
2427 <string>Whether the radar emits chat alerts for avatars entering/exiting draw distance</string>
2428 <key>Persist</key>
2429 <integer>1</integer>
2430 <key>Type</key>
2431 <string>Boolean</string>
2432 <key>Value</key>
2433 <integer>0</integer>
2434 </map>
2435 <key>RadarAlertShoutRange</key>
2436 <map>
2437 <key>Comment</key>
2438 <string>Whether the radar emits chat alerts for avatars entering/exiting shout range</string>
2439 <key>Persist</key>
2440 <integer>1</integer>
2441 <key>Type</key>
2442 <string>Boolean</string>
2443 <key>Value</key>
2444 <integer>0</integer>
2445 </map>
2446 <key>RadarAlertChatRange</key>
2447 <map>
2448 <key>Comment</key>
2449 <string>Whether the radar emits chat alerts for avatars entering/exiting chat range</string>
2450 <key>Persist</key>
2451 <integer>1</integer>
2452 <key>Type</key>
2453 <string>Boolean</string>
2454 <key>Value</key>
2455 <integer>1</integer>
2456 </map>
2457 <key>RadarChatAlerts</key>
2458 <map>
2459 <key>Comment</key>
2460 <string>Whether the radar emits chat alerts regarding the status of avatars it displays</string>
2461 <key>Persist</key>
2462 <integer>1</integer>
2463 <key>Type</key>
2464 <string>Boolean</string>
2465 <key>Value</key>
2466 <integer>0</integer>
2467 </map>
2468 <key>RadarChatKeys</key>
2469 <map>
2470 <key>Comment</key>
2471 <string>Enable private chat alerts for avatars entering the region</string>
2472 <key>Persist</key>
2473 <integer>1</integer>
2474 <key>Type</key>
2475 <string>Boolean</string>
2476 <key>Value</key>
2477 <integer>0</integer>
2478 </map>
2479 <key>RadarChatKeysChannel</key>
2480 <map>
2481 <key>Comment</key>
2482 <string>Private channel used to broadcast the key of incoming avatars</string>
2483 <key>Persist</key>
2484 <integer>1</integer>
2485 <key>Type</key>
2486 <string>S32</string>
2487 <key>Value</key>
2488 <integer>-8888888</integer>
2489 </map>
2490
2491 <!-- End: full radar (Advanced menu) -->
2492
2362 <!-- END IMPRUDENCE-SPECIFIC SETTINGS --> 2493 <!-- END IMPRUDENCE-SPECIFIC SETTINGS -->
2363 2494
2364 <key>AFKTimeout</key> 2495 <key>AFKTimeout</key>
diff --git a/linden/indra/newview/llagent.cpp b/linden/indra/newview/llagent.cpp
index 871c90d..88ec2ca 100644
--- a/linden/indra/newview/llagent.cpp
+++ b/linden/indra/newview/llagent.cpp
@@ -4772,6 +4772,116 @@ void LLAgent::lookAtLastChat()
4772 } 4772 }
4773} 4773}
4774 4774
4775void LLAgent::lookAtObject(LLUUID object_id, ECameraPosition camera_pos)
4776{
4777 // Block if camera is animating or not in normal third person camera mode
4778 if (mCameraAnimating || !cameraThirdPerson())
4779 {
4780 return;
4781 }
4782
4783 LLViewerObject *chatter = gObjectList.findObject(object_id);
4784 if (chatter)
4785 {
4786 LLVector3 delta_pos;
4787 if (chatter->isAvatar())
4788 {
4789 LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
4790 if (!mAvatarObject.isNull() && chatter_av->mHeadp)
4791 {
4792 delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
4793 }
4794 else
4795 {
4796 delta_pos = chatter->getPositionAgent() - getPositionAgent();
4797 }
4798 delta_pos.normVec();
4799
4800 setControlFlags(AGENT_CONTROL_STOP);
4801
4802 changeCameraToThirdPerson();
4803
4804 LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
4805 LLVector3 left = delta_pos % LLVector3::z_axis;
4806 left.normVec();
4807 LLVector3 up = left % delta_pos;
4808 up.normVec();
4809 new_camera_pos -= delta_pos * 0.4f;
4810 new_camera_pos += left * 0.3f;
4811 new_camera_pos += up * 0.2f;
4812
4813 F32 radius = chatter_av->getVObjRadius();
4814 LLVector3d view_dist(radius, radius, 0.0f);
4815
4816 if (chatter_av->mHeadp)
4817 {
4818 setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), object_id);
4819 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
4820
4821 switch(camera_pos)
4822 {
4823 case CAMERA_POSITION_SELF:
4824 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
4825 break;
4826 case CAMERA_POSITION_OBJECT:
4827 mCameraFocusOffsetTarget = view_dist;
4828 break;
4829 }
4830 }
4831 else
4832 {
4833 setFocusGlobal(chatter->getPositionGlobal(), object_id);
4834 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
4835
4836 switch(camera_pos)
4837 {
4838 case CAMERA_POSITION_SELF:
4839 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
4840 break;
4841 case CAMERA_POSITION_OBJECT:
4842 mCameraFocusOffsetTarget = view_dist;
4843 break;
4844 }
4845 }
4846 setFocusOnAvatar(FALSE, TRUE);
4847 }
4848 else
4849 {
4850 delta_pos = chatter->getRenderPosition() - getPositionAgent();
4851 delta_pos.normVec();
4852
4853 setControlFlags(AGENT_CONTROL_STOP);
4854
4855 changeCameraToThirdPerson();
4856
4857 LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
4858 LLVector3 left = delta_pos % LLVector3::z_axis;
4859 left.normVec();
4860 LLVector3 up = left % delta_pos;
4861 up.normVec();
4862 new_camera_pos -= delta_pos * 0.4f;
4863 new_camera_pos += left * 0.3f;
4864 new_camera_pos += up * 0.2f;
4865
4866 setFocusGlobal(chatter->getPositionGlobal(), object_id);
4867
4868 switch(camera_pos)
4869 {
4870 case CAMERA_POSITION_SELF:
4871 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
4872 break;
4873 case CAMERA_POSITION_OBJECT:
4874 F32 radius = chatter->getVObjRadius();
4875 LLVector3d view_dist(radius, radius, 0.0f);
4876 mCameraFocusOffsetTarget = view_dist;
4877 break;
4878 }
4879
4880 setFocusOnAvatar(FALSE, TRUE);
4881 }
4882 }
4883}
4884
4775const F32 SIT_POINT_EXTENTS = 0.2f; 4885const F32 SIT_POINT_EXTENTS = 0.2f;
4776 4886
4777void LLAgent::setStartPosition( U32 location_id ) 4887void LLAgent::setStartPosition( U32 location_id )
diff --git a/linden/indra/newview/llagent.h b/linden/indra/newview/llagent.h
index cea55fb..83490d3 100644
--- a/linden/indra/newview/llagent.h
+++ b/linden/indra/newview/llagent.h
@@ -82,6 +82,12 @@ typedef enum e_camera_modes
82 CAMERA_MODE_FOLLOW 82 CAMERA_MODE_FOLLOW
83} ECameraMode; 83} ECameraMode;
84 84
85typedef enum e_camera_position
86{
87 CAMERA_POSITION_SELF, /** Camera positioned at our position */
88 CAMERA_POSITION_OBJECT /** Camera positioned at observed object's position */
89} ECameraPosition;
90
85typedef enum e_anim_request 91typedef enum e_anim_request
86{ 92{
87 ANIM_REQUEST_START, 93 ANIM_REQUEST_START,
@@ -214,6 +220,7 @@ public:
214 220
215 void heardChat(const LLUUID& id); 221 void heardChat(const LLUUID& id);
216 void lookAtLastChat(); 222 void lookAtLastChat();
223 void lookAtObject(LLUUID avatar_id, ECameraPosition camera_pos);
217 F32 getTypingTime() { return mTypingTimer.getElapsedTimeF32(); } 224 F32 getTypingTime() { return mTypingTimer.getElapsedTimeF32(); }
218 225
219 void setAFK(); 226 void setAFK();
diff --git a/linden/indra/newview/llfloateravatarlist.cpp b/linden/indra/newview/llfloateravatarlist.cpp
new file mode 100644
index 0000000..59cd278
--- /dev/null
+++ b/linden/indra/newview/llfloateravatarlist.cpp
@@ -0,0 +1,1471 @@
1/**
2 * @file llfloateravatarlist.cpp
3 * @brief Avatar list/radar floater
4 *
5 * @author Dale Glass <dale@daleglass.net>, (C) 2007
6 */
7
8/**
9 * Rewritten by jcool410
10 * Removed usage of globals
11 * Removed TrustNET
12 * Added utilization of "minimap" data
13 * Heavily modified by Henri Beauchamp (the laggy spying tool becomes a true,
14 * low lag radar)
15 */
16
17#include "llviewerprecompiledheaders.h"
18
19#include "llavatarconstants.h"
20#include "llfloateravatarlist.h"
21
22#include "llcachename.h"
23#include "lluictrlfactory.h"
24#include "llviewerwindow.h"
25#include "llscrolllistctrl.h"
26#include "llradiogroup.h"
27#include "llviewercontrol.h"
28
29#include "llvoavatar.h"
30#include "llimview.h"
31#include "llfloateravatarinfo.h"
32#include "llregionflags.h"
33#include "llfloaterreporter.h"
34#include "llagent.h"
35#include "llviewerregion.h"
36#include "lltracker.h"
37#include "llviewerstats.h"
38#include "llerror.h"
39#include "llchat.h"
40#include "llfloaterchat.h"
41#include "llviewermessage.h"
42#include "llweb.h"
43#include "llviewerobjectlist.h"
44#include "llmutelist.h"
45#include "llcallbacklist.h"
46#include "llviewermenu.h"
47
48#include <time.h>
49#include <string.h>
50
51#include <map>
52
53
54#include "llworld.h"
55
56#include "llsdutil.h"
57
58/**
59 * @brief How long to keep people who are gone in the list and in memory.
60 */
61const F32 DEAD_KEEP_TIME = 10.0f;
62
63extern U32 gFrameCount;
64
65typedef enum e_radar_alert_type
66{
67 ALERT_TYPE_SIM = 0,
68 ALERT_TYPE_DRAW = 1,
69 ALERT_TYPE_SHOUTRANGE = 2,
70 ALERT_TYPE_CHATRANGE = 3
71} ERadarAlertType;
72
73void announce(std::string msg)
74{
75 //llinfos << "Radar broadcasting key: " << key.asString() << " - on channel " << gSavedSettings.getS32("RadarChatKeysChannel") << llendl;
76 gMessageSystem->newMessage("ScriptDialogReply");
77 gMessageSystem->nextBlock("AgentData");
78 gMessageSystem->addUUID("AgentID", gAgent.getID());
79 gMessageSystem->addUUID("SessionID", gAgent.getSessionID());
80 gMessageSystem->nextBlock("Data");
81 gMessageSystem->addUUID("ObjectID", gAgent.getID());
82 gMessageSystem->addS32("ChatChannel", gSavedSettings.getS32("RadarChatKeysChannel"));
83 gMessageSystem->addS32("ButtonIndex", 1);
84 gMessageSystem->addString("ButtonLabel", msg);
85 gAgent.sendReliableMessage();
86}
87
88void chat_avatar_status(std::string name, LLUUID key, ERadarAlertType type, bool entering)
89{
90 if (gSavedSettings.getBOOL("RadarChatAlerts"))
91 {
92 LLChat chat;
93 switch(type)
94 {
95 case ALERT_TYPE_SIM:
96 if (gSavedSettings.getBOOL("RadarAlertSim"))
97 {
98 chat.mText = name+" has "+(entering ? "entered" : "left")+" the sim.";
99 }
100 break;
101 case ALERT_TYPE_DRAW:
102 if (gSavedSettings.getBOOL("RadarAlertDraw"))
103 {
104 chat.mText = name+" has "+(entering ? "entered" : "left")+" draw distance.";
105 }
106 break;
107 case ALERT_TYPE_SHOUTRANGE:
108 if (gSavedSettings.getBOOL("RadarAlertShoutRange"))
109 {
110 chat.mText = name+" has "+(entering ? "entered" : "left")+" shout range.";
111 }
112 break;
113 case ALERT_TYPE_CHATRANGE:
114 if (gSavedSettings.getBOOL("RadarAlertChatRange"))
115 {
116 chat.mText = name+" has "+(entering ? "entered" : "left")+" chat range.";
117 }
118 break;
119 }
120 if (chat.mText != "")
121 {
122 chat.mSourceType = CHAT_SOURCE_SYSTEM;
123 LLFloaterChat::addChat(chat);
124 }
125 }
126 if (type == ALERT_TYPE_SIM && entering && gSavedSettings.getBOOL("RadarChatKeys"))
127 {
128 announce(key.asString());
129 }
130}
131
132LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string &name, const LLVector3d &position) :
133 mID(id), mName(name), mDisplayName(name), mPosition(position), mDrawPosition(), mMarked(FALSE),
134 mFocused(FALSE), mUpdateTimer(), mFrame(gFrameCount), mInSimFrame(U32_MAX), mInDrawFrame(U32_MAX),
135 mInChatFrame(U32_MAX), mInShoutFrame(U32_MAX)
136{
137}
138
139void LLAvatarListEntry::setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange)
140{
141 if (drawn)
142 {
143 mDrawPosition = position;
144 }
145 else if (mInDrawFrame == U32_MAX)
146 {
147 mDrawPosition.setZero();
148 }
149
150 mPosition = position;
151
152 mFrame = gFrameCount;
153 if (this_sim)
154 {
155 if (mInSimFrame == U32_MAX)
156 {
157 chat_avatar_status(mName, mID, ALERT_TYPE_SIM, true);
158 }
159 mInSimFrame = mFrame;
160 }
161 if (drawn)
162 {
163 if (mInDrawFrame == U32_MAX)
164 {
165 chat_avatar_status(mName, mID, ALERT_TYPE_DRAW, true);
166 }
167 mInDrawFrame = mFrame;
168 }
169 if (shoutrange)
170 {
171 if (mInShoutFrame == U32_MAX)
172 {
173 chat_avatar_status(mName, mID, ALERT_TYPE_SHOUTRANGE, true);
174 }
175 mInShoutFrame = mFrame;
176 }
177 if (chatrange)
178 {
179 if (mInChatFrame == U32_MAX)
180 {
181 chat_avatar_status(mName, mID, ALERT_TYPE_CHATRANGE, true);
182 }
183 mInChatFrame = mFrame;
184 }
185
186 mUpdateTimer.start();
187}
188
189bool LLAvatarListEntry::getAlive()
190{
191 U32 current = gFrameCount;
192 if (mInSimFrame != U32_MAX && (current - mInSimFrame) >= 2)
193 {
194 mInSimFrame = U32_MAX;
195 chat_avatar_status(mName, mID, ALERT_TYPE_SIM, false);
196 }
197 if (mInDrawFrame != U32_MAX && (current - mInDrawFrame) >= 2)
198 {
199 mInDrawFrame = U32_MAX;
200 chat_avatar_status(mName, mID, ALERT_TYPE_DRAW, false);
201 }
202 if (mInShoutFrame != U32_MAX && (current - mInShoutFrame) >= 2)
203 {
204 mInShoutFrame = U32_MAX;
205 chat_avatar_status(mName, mID, ALERT_TYPE_SHOUTRANGE, false);
206 }
207 if (mInChatFrame != U32_MAX && (current - mInChatFrame) >= 2)
208 {
209 mInChatFrame = U32_MAX;
210 chat_avatar_status(mName, mID, ALERT_TYPE_CHATRANGE, false);
211 }
212 return ((current - mFrame) <= 2);
213}
214
215F32 LLAvatarListEntry::getEntryAgeSeconds()
216{
217 return mUpdateTimer.getElapsedTimeF32();
218}
219
220BOOL LLAvatarListEntry::isDead()
221{
222 return getEntryAgeSeconds() > DEAD_KEEP_TIME;
223}
224
225LLFloaterAvatarList* LLFloaterAvatarList::sInstance = NULL;
226
227LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar"))
228{
229 llassert_always(sInstance == NULL);
230 sInstance = this;
231 mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3;
232}
233
234LLFloaterAvatarList::~LLFloaterAvatarList()
235{
236 gIdleCallbacks.deleteFunction(LLFloaterAvatarList::callbackIdle);
237 sInstance = NULL;
238}
239
240//static
241void LLFloaterAvatarList::toggle(void*)
242{
243#ifdef LL_RRINTERFACE_H //MK
244 if (gRRenabled && gAgent.mRRInterface.mContainsShownames)
245 {
246 if (sInstance && sInstance->getVisible())
247 {
248 sInstance->close(false);
249 }
250 }
251#endif //mk
252 if (sInstance)
253 {
254 if (sInstance->getVisible())
255 {
256 sInstance->close(false);
257 }
258 else
259 {
260 sInstance->open();
261 }
262 }
263 else
264 {
265 showInstance();
266 }
267}
268
269//static
270void LLFloaterAvatarList::showInstance()
271{
272#ifdef LL_RRINTERFACE_H //MK
273 if (gRRenabled && gAgent.mRRInterface.mContainsShownames)
274 {
275 return;
276 }
277#endif //mk
278 if (sInstance)
279 {
280 if (!sInstance->getVisible())
281 {
282 sInstance->open();
283 }
284 }
285 else
286 {
287 sInstance = new LLFloaterAvatarList();
288 LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_radar.xml");
289 }
290}
291
292void LLFloaterAvatarList::draw()
293{
294 LLFloater::draw();
295}
296
297void LLFloaterAvatarList::onOpen()
298{
299 gSavedSettings.setBOOL("ShowRadar", TRUE);
300 sInstance->setVisible(TRUE);
301}
302
303void LLFloaterAvatarList::onClose(bool app_quitting)
304{
305 sInstance->setVisible(FALSE);
306 if (!app_quitting)
307 {
308 gSavedSettings.setBOOL("ShowRadar", FALSE);
309 }
310 if (!gSavedSettings.getBOOL("RadarKeepOpen") || app_quitting)
311 {
312 destroy();
313 }
314}
315
316BOOL LLFloaterAvatarList::postBuild()
317{
318 // Default values
319 mTracking = FALSE;
320 mUpdate = TRUE;
321
322 // Hide them until some other way is found
323 // Users may not expect to find a Ban feature on the Eject button
324 childSetVisible("estate_ban_btn", false);
325
326 // Set callbacks
327 childSetAction("profile_btn", onClickProfile, this);
328 childSetAction("im_btn", onClickIM, this);
329 childSetAction("offer_btn", onClickTeleportOffer, this);
330 childSetAction("track_btn", onClickTrack, this);
331 childSetAction("mark_btn", onClickMark, this);
332 childSetAction("focus_btn", onClickFocus, this);
333 childSetAction("prev_in_list_btn", onClickPrevInList, this);
334 childSetAction("next_in_list_btn", onClickNextInList, this);
335 childSetAction("prev_marked_btn", onClickPrevMarked, this);
336 childSetAction("next_marked_btn", onClickNextMarked, this);
337
338 childSetAction("get_key_btn", onClickGetKey, this);
339
340 childSetAction("freeze_btn", onClickFreeze, this);
341 childSetAction("eject_btn", onClickEject, this);
342 childSetAction("mute_btn", onClickMute, this);
343 childSetAction("ar_btn", onClickAR, this);
344 childSetAction("teleport_btn", onClickTeleport, this);
345 childSetAction("estate_eject_btn", onClickEjectFromEstate, this);
346
347 childSetAction("send_keys_btn", onClickSendKeys, this);
348
349 getChild<LLRadioGroup>("update_rate")->setSelectedIndex(gSavedSettings.getU32("RadarUpdateRate"));
350 childSetCommitCallback("update_rate", onCommitUpdateRate, this);
351
352 // Get a pointer to the scroll list from the interface
353 mAvatarList = getChild<LLScrollListCtrl>("avatar_list");
354 mAvatarList->sortByColumn("distance", TRUE);
355 mAvatarList->setCommitOnSelectionChange(TRUE);
356 childSetCommitCallback("avatar_list", onSelectName, this);
357 refreshAvatarList();
358
359 gIdleCallbacks.addFunction(LLFloaterAvatarList::callbackIdle);
360
361 return TRUE;
362}
363
364void LLFloaterAvatarList::updateAvatarList()
365{
366 if (sInstance != this) return;
367
368#ifdef LL_RRINTERFACE_H //MK
369 if (gRRenabled && gAgent.mRRInterface.mContainsShownames)
370 {
371 close();
372 }
373#endif //mk
374
375 //llinfos << "radar refresh: updating map" << llendl;
376
377 // Check whether updates are enabled
378 LLCheckboxCtrl* check = getChild<LLCheckboxCtrl>("update_enabled_cb");
379 if (check && !check->getValue())
380 {
381 mUpdate = FALSE;
382 refreshTracker();
383 return;
384 }
385 else
386 {
387 mUpdate = TRUE;
388 }
389
390 LLVector3d mypos = gAgent.getPositionGlobal();
391
392 {
393 std::vector<LLUUID> avatar_ids;
394 std::vector<LLUUID> sorted_avatar_ids;
395 std::vector<LLVector3d> positions;
396
397 LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, F32_MAX);
398
399 sorted_avatar_ids = avatar_ids;
400 std::sort(sorted_avatar_ids.begin(), sorted_avatar_ids.end());
401
402 for (std::vector<LLCharacter*>::const_iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter)
403 {
404 LLUUID avid = (*iter)->getID();
405
406 if (!std::binary_search(sorted_avatar_ids.begin(), sorted_avatar_ids.end(), avid))
407 {
408 avatar_ids.push_back(avid);
409 }
410 }
411
412 size_t i;
413 size_t count = avatar_ids.size();
414
415 for (i = 0; i < count; ++i)
416 {
417 std::string name, first, last;
418 const LLUUID &avid = avatar_ids[i];
419
420 LLVector3d position;
421 LLViewerObject *obj = gObjectList.findObject(avid);
422
423 if (obj)
424 {
425 LLVOAvatar* avatarp = dynamic_cast<LLVOAvatar*>(obj);
426
427 if (avatarp == NULL)
428 {
429 continue;
430 }
431
432 // Skip if avatar is dead(what's that?)
433 // or if the avatar is ourselves.
434 if (avatarp->isDead() || avatarp->isSelf())
435 {
436 continue;
437 }
438
439 // Get avatar data
440 position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition());
441 name = avatarp->getFullname();
442
443 // Apparently, sometimes the name comes out empty, with a " " name. This is because
444 // getFullname concatenates first and last name with a " " in the middle.
445 // This code will avoid adding a nameless entry to the list until it acquires a name.
446
447 //duped for lower section
448 if (name.empty() || (name.compare(" ") == 0))// || (name.compare(gCacheName->getDefaultName()) == 0))
449 {
450 if (gCacheName->getName(avid, first, last))
451 {
452 name = first + " " + last;
453 }
454 else
455 {
456 continue;
457 }
458 }
459
460#ifdef LL_DISPLAY_NAMES
461 std::string display_name = name;
462 if (LLAvatarName::sOmitResidentAsLastName)
463 {
464 LLStringUtil::replaceString(display_name, " Resident", "");
465 }
466 if (LLAvatarNameCache::useDisplayNames())
467 {
468 LLAvatarName avatar_name;
469 if (LLAvatarNameCache::get(avid, &avatar_name))
470 {
471 if (LLAvatarNameCache::useDisplayNames() == 2)
472 {
473 display_name = avatar_name.mDisplayName;
474 }
475 else
476 {
477 display_name = avatar_name.getNames();
478 }
479 }
480 }
481#endif
482
483 if (avid.isNull())
484 {
485 //llinfos << "Key empty for avatar " << name << llendl;
486 continue;
487 }
488
489 if (mAvatars.count(avid) > 0)
490 {
491 // Avatar already in list, update position
492 F32 dist = (F32)(position - mypos).magVec();
493 mAvatars[avid].setPosition(position, (avatarp->getRegion() == gAgent.getRegion()), true, dist < 20.0, dist < 100.0);
494 }
495 else
496 {
497 // Avatar not there yet, add it
498 LLAvatarListEntry entry(avid, name, position);
499 mAvatars[avid] = entry;
500 }
501#ifdef LL_DISPLAY_NAMES
502 // update avatar display name.
503 mAvatars[avid].setDisplayName(display_name);
504#endif
505 }
506 else
507 {
508 if (i < positions.size())
509 {
510 position = positions[i];
511 }
512 else
513 {
514 continue;
515 }
516
517 if (gCacheName->getName(avid, first, last))
518 {
519 name = first + " " + last;
520 }
521 else
522 {
523 //name = gCacheName->getDefaultName();
524 continue; //prevent (Loading...)
525 }
526
527#ifdef LL_DISPLAY_NAMES
528 std::string display_name = name;
529 if (LLAvatarName::sOmitResidentAsLastName)
530 {
531 LLStringUtil::replaceString(display_name, " Resident", "");
532 }
533 if (LLAvatarNameCache::useDisplayNames())
534 {
535 LLAvatarName avatar_name;
536 if (LLAvatarNameCache::get(avid, &avatar_name))
537 {
538 if (LLAvatarNameCache::useDisplayNames() == 2)
539 {
540 display_name = avatar_name.mDisplayName;
541 }
542 else
543 {
544 display_name = avatar_name.getNames();
545 }
546 }
547 }
548#endif
549
550 if (mAvatars.count(avid) > 0)
551 {
552 // Avatar already in list, update position
553 F32 dist = (F32)(position - mypos).magVec();
554 mAvatars[avid].setPosition(position, gAgent.getRegion()->pointInRegionGlobal(position), false, dist < 20.0, dist < 100.0);
555 }
556 else
557 {
558 // Avatar not there yet, add it
559 LLAvatarListEntry entry(avid, name, position);
560 mAvatars[avid] = entry;
561 }
562#ifdef LL_DISPLAY_NAMES
563 // update avatar display name.
564 mAvatars[avid].setDisplayName(display_name);
565#endif
566 }
567 }
568 }
569
570// llinfos << "radar refresh: done" << llendl;
571
572 expireAvatarList();
573 refreshAvatarList();
574 refreshTracker();
575}
576
577void LLFloaterAvatarList::expireAvatarList()
578{
579// llinfos << "radar: expiring" << llendl;
580 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
581 std::queue<LLUUID> delete_queue;
582
583 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
584 {
585 LLAvatarListEntry *entry = &iter->second;
586
587 if (!entry->getAlive() && entry->isDead())
588 {
589 //llinfos << "radar: expiring avatar " << entry->getDisplayName() << llendl;
590 LLUUID av_id = entry->getID();
591 delete_queue.push(av_id);
592 if (av_id == mTrackedAvatar)
593 {
594 stopTracker();
595 }
596 }
597 }
598
599 while (!delete_queue.empty())
600 {
601 mAvatars.erase(delete_queue.front());
602 delete_queue.pop();
603 }
604}
605
606/**
607 * Redraws the avatar list
608 * Only does anything if the avatar list is visible.
609 * @author Dale Glass
610 */
611void LLFloaterAvatarList::refreshAvatarList()
612{
613 // Don't update list when interface is hidden
614 if (!sInstance->getVisible()) return;
615
616 // We rebuild the list fully each time it's refreshed
617 // The assumption is that it's faster to refill it and sort than
618 // to rebuild the whole list.
619 LLDynamicArray<LLUUID> selected = mAvatarList->getSelectedIDs();
620 S32 scrollpos = mAvatarList->getScrollPos();
621
622 mAvatarList->deleteAllItems();
623
624 LLVector3d mypos = gAgent.getPositionGlobal();
625 LLVector3d posagent;
626 posagent.setVec(gAgent.getPositionAgent());
627 LLVector3d simpos = mypos - posagent;
628
629 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
630 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
631 {
632 LLSD element;
633 LLUUID av_id;
634
635 LLAvatarListEntry *entry = &iter->second;
636
637 // Skip if avatar hasn't been around
638 if (entry->isDead())
639 {
640 continue;
641 }
642
643 av_id = entry->getID();
644
645 LLVector3d position = entry->getPosition();
646 BOOL UnknownAltitude = false;
647
648 LLVector3d delta = position - mypos;
649 F32 distance = (F32)delta.magVec();
650 if (position.mdV[VZ] == 0.0)
651 {
652 UnknownAltitude = true;
653 distance = 9000.0;
654 }
655 delta.mdV[2] = 0.0f;
656 F32 side_distance = (F32)delta.magVec();
657
658 // HACK: Workaround for an apparent bug:
659 // sometimes avatar entries get stuck, and are registered
660 // by the client as perpetually moving in the same direction.
661 // this makes sure they get removed from the visible list eventually
662
663 //jcool410 -- this fucks up seeing dueds thru minimap data > 1024m away, so, lets just say > 2048m to the side is bad
664 //aka 8 sims
665 if (side_distance > 2048.0f)
666 {
667 continue;
668 }
669
670 if (av_id.isNull())
671 {
672 //llwarns << "Avatar with null key somehow got into the list!" << llendl;
673 continue;
674 }
675
676 element["id"] = av_id;
677
678 element["columns"][LIST_MARK]["column"] = "marked";
679 element["columns"][LIST_MARK]["type"] = "text";
680 if (entry->isMarked())
681 {
682 element["columns"][LIST_MARK]["value"] = "X";
683 element["columns"][LIST_MARK]["color"] = LLColor4::blue.getValue();
684 element["columns"][LIST_MARK]["font-style"] = "BOLD";
685 }
686 else
687 {
688 element["columns"][LIST_MARK]["value"] = "";
689 }
690
691 element["columns"][LIST_AVATAR_NAME]["column"] = "avatar_name";
692 element["columns"][LIST_AVATAR_NAME]["type"] = "text";
693 element["columns"][LIST_AVATAR_NAME]["value"] = entry->getDisplayName().c_str();
694 if (entry->getEntryAgeSeconds() > 1.0f)
695 {
696 element["columns"][LIST_AVATAR_NAME]["font-style"] = "ITALIC";
697 }
698 else if (entry->isFocused())
699 {
700 element["columns"][LIST_AVATAR_NAME]["font-style"] = "BOLD";
701 }
702 if (LLMuteList::getInstance()->isMuted(av_id))
703 {
704 element["columns"][LIST_AVATAR_NAME]["color"] = LLColor4::red2.getValue();
705 }
706 else if (is_agent_friend(av_id))
707 {
708 element["columns"][LIST_AVATAR_NAME]["color"] = LLColor4::green3.getValue();
709 }
710
711 char temp[32];
712 LLColor4 color = LLColor4::black;
713 element["columns"][LIST_DISTANCE]["column"] = "distance";
714 element["columns"][LIST_DISTANCE]["type"] = "text";
715 if (UnknownAltitude)
716 {
717 strcpy(temp, "?");
718 if (entry->isDrawn())
719 {
720 color = LLColor4::green2;
721 }
722 }
723 else
724 {
725 if (distance < 100.0)
726 {
727 snprintf(temp, sizeof(temp), "%.1f", distance);
728 if (distance > 20.0f)
729 {
730 color = LLColor4::yellow1;
731 }
732 else
733 {
734 color = LLColor4::red;
735 }
736 }
737 else
738 {
739 if (entry->isDrawn())
740 {
741 color = LLColor4::green2;
742 }
743 snprintf(temp, sizeof(temp), "%d", (S32)distance);
744 }
745 }
746 element["columns"][LIST_DISTANCE]["value"] = temp;
747 element["columns"][LIST_DISTANCE]["color"] = color.getValue();
748
749 position = position - simpos;
750
751 S32 x = (S32)position.mdV[VX];
752 S32 y = (S32)position.mdV[VY];
753 if (x >= 0 && x <= 256 && y >= 0 && y <= 256)
754 {
755 snprintf(temp, sizeof(temp), "%d, %d", x, y);
756 }
757 else
758 {
759 temp[0] = '\0';
760 if (y < 0)
761 {
762 strcat(temp, "S");
763 }
764 else if (y > 256)
765 {
766 strcat(temp, "N");
767 }
768 if (x < 0)
769 {
770 strcat(temp, "W");
771 }
772 else if (x > 256)
773 {
774 strcat(temp, "E");
775 }
776 }
777 element["columns"][LIST_POSITION]["column"] = "position";
778 element["columns"][LIST_POSITION]["type"] = "text";
779 element["columns"][LIST_POSITION]["value"] = temp;
780
781 element["columns"][LIST_ALTITUDE]["column"] = "altitude";
782 element["columns"][LIST_ALTITUDE]["type"] = "text";
783 if (UnknownAltitude)
784 {
785 strcpy(temp, "?");
786 }
787 else
788 {
789 snprintf(temp, sizeof(temp), "%d", (S32)position.mdV[VZ]);
790 }
791 element["columns"][LIST_ALTITUDE]["value"] = temp;
792
793 // Add to list
794 mAvatarList->addElement(element, ADD_BOTTOM);
795 }
796
797 // finish
798 mAvatarList->sortItems();
799 mAvatarList->selectMultiple(selected);
800 mAvatarList->setScrollPos(scrollpos);
801
802// llinfos << "radar refresh: done" << llendl;
803
804}
805
806// static
807void LLFloaterAvatarList::onClickIM(void* userdata)
808{
809 //llinfos << "LLFloaterFriends::onClickIM()" << llendl;
810 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
811
812 LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs();
813 if (ids.size() > 0)
814 {
815 if (ids.size() == 1)
816 {
817 // Single avatar
818 LLUUID agent_id = ids[0];
819
820 char buffer[MAX_STRING];
821 snprintf(buffer, MAX_STRING, "%s", self->mAvatars[agent_id].getName().c_str());
822 gIMMgr->setFloaterOpen(TRUE);
823 gIMMgr->addSession(buffer, IM_NOTHING_SPECIAL, agent_id);
824 }
825 else
826 {
827 // Group IM
828 LLUUID session_id;
829 session_id.generate();
830 gIMMgr->setFloaterOpen(TRUE);
831 gIMMgr->addSession("Avatars Conference", IM_SESSION_CONFERENCE_START, ids[0], ids);
832 }
833 }
834}
835
836void LLFloaterAvatarList::onClickTeleportOffer(void *userdata)
837{
838 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
839
840 LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs();
841 if (ids.size() > 0)
842 {
843 handle_lure(ids);
844 }
845}
846
847void LLFloaterAvatarList::onClickTrack(void *userdata)
848{
849 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
850
851 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
852 if (!item) return;
853
854 LLUUID agent_id = item->getUUID();
855
856 if (self->mTracking && self->mTrackedAvatar == agent_id) {
857 self->stopTracker();
858 }
859 else
860 {
861 self->mTracking = TRUE;
862 self->mTrackedAvatar = agent_id;
863// trackAvatar only works for friends allowing you to see them on map...
864// LLTracker::trackAvatar(agent_id, self->mAvatars[agent_id].getDisplayName());
865 std::string name = self->mAvatars[agent_id].getDisplayName();
866 if (!self->mUpdate)
867 {
868 name += "\n(last known position)";
869 }
870 LLTracker::trackLocation(self->mAvatars[agent_id].getPosition(), name, "");
871 }
872}
873
874void LLFloaterAvatarList::stopTracker()
875{
876 LLTracker::stopTracking(NULL);
877 mTracking = FALSE;
878}
879
880void LLFloaterAvatarList::refreshTracker()
881{
882 if (!mTracking) return;
883
884 if (LLTracker::isTracking(NULL))
885 {
886 LLVector3d pos;
887 if (mUpdate)
888 {
889 pos = mAvatars[mTrackedAvatar].getPosition();
890 }
891 else
892 {
893 LLViewerObject *obj = gObjectList.findObject(mTrackedAvatar);
894 if (!obj)
895 {
896 stopTracker();
897 return;
898 }
899 LLVOAvatar* avatarp = dynamic_cast<LLVOAvatar*>(obj);
900 if (!avatarp)
901 {
902 stopTracker();
903 return;
904 }
905 pos = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition());
906 }
907 if (pos != LLTracker::getTrackedPositionGlobal())
908 {
909 std::string name = mAvatars[mTrackedAvatar].getDisplayName();
910 LLTracker::trackLocation(pos, name, "");
911 }
912 }
913 else
914 {
915 stopTracker();
916 }
917}
918
919LLAvatarListEntry * LLFloaterAvatarList::getAvatarEntry(LLUUID avatar)
920{
921 if (avatar.isNull())
922 {
923 return NULL;
924 }
925
926 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
927
928 iter = mAvatars.find(avatar);
929 if (iter == mAvatars.end())
930 {
931 return NULL;
932 }
933
934 return &iter->second;
935}
936
937//static
938void LLFloaterAvatarList::onClickMark(void *userdata)
939{
940 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
941 LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs();
942
943 for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
944 {
945 LLUUID avid = *itr;
946 LLAvatarListEntry *entry = self->getAvatarEntry(avid);
947 if (entry != NULL)
948 {
949 entry->toggleMark();
950 }
951 }
952}
953
954void LLFloaterAvatarList::onClickFocus(void *userdata)
955{
956 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
957
958 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
959 if (item)
960 {
961 self->mFocusedAvatar = item->getUUID();
962 self->focusOnCurrent();
963 }
964}
965
966void LLFloaterAvatarList::removeFocusFromAll()
967{
968 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
969
970 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
971 {
972 LLAvatarListEntry *entry = &iter->second;
973 entry->setFocus(FALSE);
974 }
975}
976
977void LLFloaterAvatarList::focusOnCurrent()
978{
979 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
980 LLAvatarListEntry *entry;
981
982 if (mAvatars.size() == 0)
983 {
984 return;
985 }
986
987 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
988 {
989 entry = &iter->second;
990
991 if (entry->isDead())
992 continue;
993
994 if (entry->getID() == mFocusedAvatar)
995 {
996 removeFocusFromAll();
997 entry->setFocus(TRUE);
998 gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
999 return;
1000 }
1001 }
1002}
1003
1004void LLFloaterAvatarList::focusOnPrev(BOOL marked_only)
1005{
1006 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
1007 LLAvatarListEntry *prev = NULL;
1008 LLAvatarListEntry *entry;
1009
1010 if (mAvatars.size() == 0)
1011 {
1012 return;
1013 }
1014
1015 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
1016 {
1017 entry = &iter->second;
1018
1019 if (entry->isDead())
1020 continue;
1021
1022 if (prev != NULL && entry->getID() == mFocusedAvatar)
1023 {
1024 break;
1025 }
1026
1027 if ((!marked_only && entry->isDrawn()) || entry->isMarked())
1028 {
1029 prev = entry;
1030 }
1031 }
1032
1033 if (prev != NULL)
1034 {
1035 removeFocusFromAll();
1036 prev->setFocus(TRUE);
1037 mFocusedAvatar = prev->getID();
1038 gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
1039 }
1040}
1041
1042void LLFloaterAvatarList::focusOnNext(BOOL marked_only)
1043{
1044 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
1045 BOOL found = FALSE;
1046 LLAvatarListEntry *next = NULL;
1047 LLAvatarListEntry *entry;
1048
1049 if (mAvatars.size() == 0)
1050 {
1051 return;
1052 }
1053
1054 for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
1055 {
1056 entry = &iter->second;
1057
1058 if (entry->isDead())
1059 continue;
1060
1061 if (next == NULL && ((!marked_only && entry->isDrawn()) || entry->isMarked()))
1062 {
1063 next = entry;
1064 }
1065
1066 if (found && ((!marked_only && entry->isDrawn()) || entry->isMarked()))
1067 {
1068 next = entry;
1069 break;
1070 }
1071
1072 if (entry->getID() == mFocusedAvatar)
1073 {
1074 found = TRUE;
1075 }
1076 }
1077
1078 if (next != NULL)
1079 {
1080 removeFocusFromAll();
1081 next->setFocus(TRUE);
1082 mFocusedAvatar = next->getID();
1083 gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
1084 }
1085}
1086
1087//static
1088void LLFloaterAvatarList::onClickPrevInList(void *userdata)
1089{
1090 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1091 self->focusOnPrev(FALSE);
1092}
1093
1094//static
1095void LLFloaterAvatarList::onClickNextInList(void *userdata)
1096{
1097 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1098 self->focusOnNext(FALSE);
1099}
1100
1101//static
1102void LLFloaterAvatarList::onClickPrevMarked(void *userdata)
1103{
1104 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1105 self->focusOnPrev(TRUE);
1106}
1107
1108//static
1109void LLFloaterAvatarList::onClickNextMarked(void *userdata)
1110{
1111 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1112 self->focusOnNext(TRUE);
1113}
1114
1115//static
1116void LLFloaterAvatarList::onClickGetKey(void *userdata)
1117{
1118 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1119 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
1120
1121 if (NULL == item) return;
1122
1123 LLUUID agent_id = item->getUUID();
1124
1125 char buffer[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
1126 agent_id.toString(buffer);
1127
1128 gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer));
1129}
1130
1131void LLFloaterAvatarList::onClickSendKeys(void *userdata)
1132{
1133 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1134 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
1135 LLAvatarListEntry *entry;
1136
1137 if (self->mAvatars.size() == 0)
1138 return;
1139
1140 for (iter = self->mAvatars.begin(); iter != self->mAvatars.end(); iter++)
1141 {
1142 entry = &iter->second;
1143
1144 if (!entry->isDead() && entry->isInSim())
1145 announce(entry->getID().asString());
1146 }
1147}
1148
1149static void send_freeze(const LLUUID& avatar_id, bool freeze)
1150{
1151 U32 flags = 0x0;
1152 if (!freeze)
1153 {
1154 // unfreeze
1155 flags |= 0x1;
1156 }
1157
1158 LLMessageSystem* msg = gMessageSystem;
1159 LLViewerObject* avatar = gObjectList.findObject(avatar_id);
1160
1161 if (avatar)
1162 {
1163 msg->newMessage("FreezeUser");
1164 msg->nextBlock("AgentData");
1165 msg->addUUID("AgentID", gAgent.getID());
1166 msg->addUUID("SessionID", gAgent.getSessionID());
1167 msg->nextBlock("Data");
1168 msg->addUUID("TargetID", avatar_id);
1169 msg->addU32("Flags", flags);
1170 msg->sendReliable( avatar->getRegion()->getHost());
1171 }
1172}
1173
1174static void send_eject(const LLUUID& avatar_id, bool ban)
1175{
1176 LLMessageSystem* msg = gMessageSystem;
1177 LLViewerObject* avatar = gObjectList.findObject(avatar_id);
1178
1179 if (avatar)
1180 {
1181 U32 flags = 0x0;
1182 if (ban)
1183 {
1184 // eject and add to ban list
1185 flags |= 0x1;
1186 }
1187
1188 msg->newMessage("EjectUser");
1189 msg->nextBlock("AgentData");
1190 msg->addUUID("AgentID", gAgent.getID());
1191 msg->addUUID("SessionID", gAgent.getSessionID());
1192 msg->nextBlock("Data");
1193 msg->addUUID("TargetID", avatar_id);
1194 msg->addU32("Flags", flags);
1195 msg->sendReliable( avatar->getRegion()->getHost());
1196 }
1197}
1198
1199static void send_estate_message(
1200 const char* request,
1201 const LLUUID &target)
1202{
1203
1204 LLMessageSystem* msg = gMessageSystem;
1205 LLUUID invoice;
1206
1207 // This seems to provide an ID so that the sim can say which request it's
1208 // replying to. I think this can be ignored for now.
1209 invoice.generate();
1210
1211 llinfos << "Sending estate request '" << request << "'" << llendl;
1212 msg->newMessage("EstateOwnerMessage");
1213 msg->nextBlockFast(_PREHASH_AgentData);
1214 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1215 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1216 msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
1217 msg->nextBlock("MethodData");
1218 msg->addString("Method", request);
1219 msg->addUUID("Invoice", invoice);
1220
1221 // Agent id
1222 msg->nextBlock("ParamList");
1223 msg->addString("Parameter", gAgent.getID().asString().c_str());
1224
1225 // Target
1226 msg->nextBlock("ParamList");
1227 msg->addString("Parameter", target.asString().c_str());
1228
1229 msg->sendReliable(gAgent.getRegion()->getHost());
1230}
1231
1232static void cmd_freeze(const LLUUID& avatar, const std::string &name) { send_freeze(avatar, true); }
1233static void cmd_unfreeze(const LLUUID& avatar, const std::string &name) { send_freeze(avatar, false); }
1234static void cmd_eject(const LLUUID& avatar, const std::string &name) { send_eject(avatar, false); }
1235static void cmd_ban(const LLUUID& avatar, const std::string &name) { send_eject(avatar, true); }
1236static void cmd_profile(const LLUUID& avatar, const std::string &name) { LLFloaterAvatarInfo::showFromDirectory(avatar); }
1237static void cmd_estate_eject(const LLUUID &avatar, const std::string &name){ send_estate_message("teleporthomeuser", avatar); }
1238
1239void LLFloaterAvatarList::doCommand(void (*func)(const LLUUID &avatar, const std::string &name))
1240{
1241 LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs();
1242
1243 for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
1244 {
1245 LLUUID avid = *itr;
1246 LLAvatarListEntry *entry = getAvatarEntry(avid);
1247 if (entry != NULL)
1248 {
1249 llinfos << "Executing command on " << entry->getDisplayName() << llendl;
1250 func(avid, entry->getName());
1251 }
1252 }
1253}
1254
1255std::string LLFloaterAvatarList::getSelectedNames(const std::string& separator)
1256{
1257 std::string ret = "";
1258
1259 LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs();
1260 for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
1261 {
1262 LLUUID avid = *itr;
1263 LLAvatarListEntry *entry = getAvatarEntry(avid);
1264 if (entry != NULL)
1265 {
1266 if (!ret.empty()) ret += separator;
1267 ret += entry->getName();
1268 }
1269 }
1270
1271 return ret;
1272}
1273
1274std::string LLFloaterAvatarList::getSelectedName()
1275{
1276 LLUUID id = getSelectedID();
1277 LLAvatarListEntry *entry = getAvatarEntry(id);
1278 if (entry)
1279 {
1280 return entry->getName();
1281 }
1282 return "";
1283}
1284
1285LLUUID LLFloaterAvatarList::getSelectedID()
1286{
1287 LLScrollListItem *item = mAvatarList->getFirstSelected();
1288 if (item) return item->getUUID();
1289 return LLUUID::null;
1290}
1291
1292//static
1293void LLFloaterAvatarList::callbackFreeze(const LLSD& notification, const LLSD& response)
1294{
1295 S32 option = LLNotification::getSelectedOption(notification, response);
1296
1297 LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance;
1298
1299 if (option == 0)
1300 {
1301 self->doCommand(cmd_freeze);
1302 }
1303 else if (option == 1)
1304 {
1305 self->doCommand(cmd_unfreeze);
1306 }
1307}
1308
1309//static
1310void LLFloaterAvatarList::callbackEject(const LLSD& notification, const LLSD& response)
1311{
1312 S32 option = LLNotification::getSelectedOption(notification, response);
1313
1314 LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance;
1315
1316 if (option == 0)
1317 {
1318 self->doCommand(cmd_eject);
1319 }
1320 else if (option == 1)
1321 {
1322 self->doCommand(cmd_ban);
1323 }
1324}
1325
1326//static
1327void LLFloaterAvatarList::callbackEjectFromEstate(const LLSD& notification, const LLSD& response)
1328{
1329 S32 option = LLNotification::getSelectedOption(notification, response);
1330
1331 LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance;
1332
1333 if (option == 0)
1334 {
1335 self->doCommand(cmd_estate_eject);
1336 }
1337}
1338
1339//static
1340void LLFloaterAvatarList::callbackIdle(void *userdata) {
1341 if (LLFloaterAvatarList::sInstance != NULL)
1342 {
1343 // Do not update at every frame: this would be insane !
1344 if (gFrameCount % LLFloaterAvatarList::sInstance->mUpdateRate == 0)
1345 {
1346 LLFloaterAvatarList::sInstance->updateAvatarList();
1347 }
1348 }
1349}
1350
1351void LLFloaterAvatarList::onClickFreeze(void *userdata)
1352{
1353 LLSD args;
1354 LLSD payload;
1355 args["AVATAR_NAME"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
1356 LLNotifications::instance().add("FreezeAvatarFullname", args, payload, callbackFreeze);
1357}
1358
1359//static
1360void LLFloaterAvatarList::onClickEject(void *userdata)
1361{
1362 LLSD args;
1363 LLSD payload;
1364 args["AVATAR_NAME"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
1365 LLNotifications::instance().add("EjectAvatarFullname", args, payload, callbackEject);
1366}
1367
1368//static
1369void LLFloaterAvatarList::onClickMute(void *userdata)
1370{
1371 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1372
1373 LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs();
1374 if (ids.size() > 0)
1375 {
1376 for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
1377 {
1378 LLUUID agent_id = *itr;
1379
1380 std::string agent_name;
1381 if (gCacheName->getFullName(agent_id, agent_name))
1382 {
1383 if (LLMuteList::getInstance()->isMuted(agent_id))
1384 {
1385 LLMute mute(agent_id, agent_name, LLMute::AGENT);
1386 LLMuteList::getInstance()->remove(mute);
1387 }
1388 else
1389 {
1390 LLMute mute(agent_id, agent_name, LLMute::AGENT);
1391 LLMuteList::getInstance()->add(mute);
1392 }
1393 }
1394 }
1395 }
1396}
1397
1398//static
1399void LLFloaterAvatarList::onClickEjectFromEstate(void *userdata)
1400{
1401 LLSD args;
1402 LLSD payload;
1403 args["EVIL_USER"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
1404 LLNotifications::instance().add("EstateKickUser", args, payload, callbackEjectFromEstate);
1405}
1406
1407//static
1408void LLFloaterAvatarList::onClickAR(void *userdata)
1409{
1410 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1411 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
1412 if (item)
1413 {
1414 LLUUID agent_id = item->getUUID();
1415 LLAvatarListEntry *entry = self->getAvatarEntry(agent_id);
1416 if (entry)
1417 {
1418 LLFloaterReporter::showFromObject(entry->getID());
1419 }
1420 }
1421}
1422
1423// static
1424void LLFloaterAvatarList::onClickProfile(void* userdata)
1425{
1426 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1427 self->doCommand(cmd_profile);
1428}
1429
1430//static
1431void LLFloaterAvatarList::onClickTeleport(void* userdata)
1432{
1433 LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
1434 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
1435 if (item)
1436 {
1437 LLUUID agent_id = item->getUUID();
1438 LLAvatarListEntry *entry = self->getAvatarEntry(agent_id);
1439 if (entry)
1440 {
1441// llinfos << "Trying to teleport to " << entry->getDisplayName() << " at " << entry->getPosition() << llendl;
1442 gAgent.teleportViaLocation(entry->getPosition());
1443 }
1444 }
1445}
1446
1447void LLFloaterAvatarList::onSelectName(LLUICtrl*, void* userdata)
1448{
1449 LLFloaterAvatarList* self = (LLFloaterAvatarList*)userdata;
1450
1451 LLScrollListItem *item = self->mAvatarList->getFirstSelected();
1452 if (item)
1453 {
1454 LLUUID agent_id = item->getUUID();
1455 LLAvatarListEntry *entry = self->getAvatarEntry(agent_id);
1456 if (entry)
1457 {
1458 BOOL enabled = entry->isDrawn();
1459 self->childSetEnabled("focus_btn", enabled);
1460 self->childSetEnabled("prev_in_list_btn", enabled);
1461 self->childSetEnabled("next_in_list_btn", enabled);
1462 }
1463 }
1464}
1465
1466void LLFloaterAvatarList::onCommitUpdateRate(LLUICtrl*, void* userdata)
1467{
1468 LLFloaterAvatarList* self = (LLFloaterAvatarList*)userdata;
1469
1470 self->mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3;
1471}
diff --git a/linden/indra/newview/llfloateravatarlist.h b/linden/indra/newview/llfloateravatarlist.h
new file mode 100644
index 0000000..75a95a7
--- /dev/null
+++ b/linden/indra/newview/llfloateravatarlist.h
@@ -0,0 +1,316 @@
1//
2// C++ Interface: llfloateravatarlist
3//
4// Description:
5//
6//
7// Original author: Dale Glass <dale@daleglass.net>, (C) 2007
8// Heavily modified by Henri Beauchamp 10/2009.
9//
10// Copyright: See COPYING file that comes with this distribution
11//
12//
13#include "llfloater.h"
14#include "llfloaterreporter.h"
15#include "lluuid.h"
16#include "lltimer.h"
17#include "llscrolllistctrl.h"
18
19#include <time.h>
20#include <map>
21#include <set>
22
23class LLFloaterAvatarList;
24
25/**
26 * @brief This class is used to hold data about avatars.
27 * We cache data about avatars to avoid repeating requests in this class.
28 * Instances are kept in a map<LLAvatarListEntry>. We keep track of the
29 * frame where the avatar was last seen.
30 */
31class LLAvatarListEntry {
32
33public:
34
35 /**
36 * @brief Initializes a list entry
37 * @param id Avatar's key
38 * @param name Avatar's name
39 * @param position Avatar's current position
40 */
41 LLAvatarListEntry(const LLUUID& id = LLUUID::null, const std::string &name = "", const LLVector3d &position = LLVector3d::zero);
42
43 /**
44 * Update world position.
45 * Affects age.
46 */
47 void setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange);
48
49 LLVector3d getPosition() { return mPosition; }
50
51 /**
52 * @brief Returns the age of this entry in frames
53 *
54 * This is only used for determining whether the avatar is still around.
55 * @see getEntryAgeSeconds
56 */
57 bool getAlive();
58
59 /**
60 * @brief Returns the age of this entry in seconds
61 */
62 F32 getEntryAgeSeconds();
63
64 /**
65 * @brief Returns the name of the avatar
66 */
67 std::string getName() { return mName; }
68
69 /**
70 * @brief Sets the display name of the avatar
71 */
72 void setDisplayName(std::string name) { mDisplayName = name; }
73
74 /**
75 * @brief Returns the display name of the avatar
76 */
77 std::string getDisplayName() { return mDisplayName; }
78
79 /**
80 * @brief Returns the ID of the avatar
81 */
82 LLUUID getID() { return mID; }
83
84 /**
85 * @brief Sets the 'focus' status on this entry (camera focused on this avatar)
86 */
87 void setFocus(BOOL value) { mFocused = value; }
88
89 BOOL isFocused() { return mFocused; }
90
91 BOOL isMarked() { return mMarked; }
92
93 BOOL isDrawn() { return (mInDrawFrame != U32_MAX); }
94
95 BOOL isInSim() { return (mInSimFrame != U32_MAX); }
96
97 /**
98 * @brief Returns whether the item is dead and shouldn't appear in the list
99 * @returns TRUE if dead
100 */
101 BOOL isDead();
102
103 void toggleMark() { mMarked = !mMarked; }
104
105private:
106 friend class LLFloaterAvatarList;
107
108 LLUUID mID;
109 std::string mName;
110 std::string mDisplayName;
111 LLVector3d mPosition;
112 LLVector3d mDrawPosition;
113 BOOL mMarked;
114 BOOL mFocused;
115
116 /**
117 * @brief Timer to keep track of whether avatars are still there
118 */
119 LLTimer mUpdateTimer;
120
121 /**
122 * @brief Last frame when this avatar was updated
123 */
124 U32 mFrame;
125 //last frame when this avatar was in sim
126 U32 mInSimFrame;
127 //last frame when this avatar was in draw
128 U32 mInDrawFrame;
129 //last frame when this avatar was in shout range
130 U32 mInShoutFrame;
131 //last frame when this avatar was in chat range
132 U32 mInChatFrame;
133};
134
135
136/**
137 * @brief Avatar List
138 * Implements an avatar scanner in the client.
139 *
140 * This is my first attempt to modify the SL source. This code is intended
141 * to have a dual purpose: doing the task, and providing an example of how
142 * to do it. For that reason, it's going to be commented as exhaustively
143 * as possible.
144 *
145 * Since I'm very new to C++ any suggestions on coding, style, etc are very
146 * welcome.
147 */
148class LLFloaterAvatarList : public LLFloater
149{
150 /**
151 * @brief Creates and initializes the LLFloaterAvatarList
152 * Here the interface is created, and callbacks are initialized.
153 */
154private:
155 LLFloaterAvatarList();
156public:
157 ~LLFloaterAvatarList();
158
159 /*virtual*/ void onClose(bool app_quitting);
160 /*virtual*/ void onOpen();
161 /*virtual*/ BOOL postBuild();
162 /*virtual*/ void draw();
163
164 /**
165 * @brief Toggles interface visibility
166 * There is only one instance of the avatar scanner at any time.
167 */
168 static void toggle(void*);
169
170 static void showInstance();
171
172 /**
173 * @brief Updates the internal avatar list with the currently present avatars.
174 */
175 void updateAvatarList();
176
177 /**
178 * @brief Refresh avatar list (display)
179 */
180 void refreshAvatarList();
181
182 /**
183 * @brief Returns the entry for an avatar, if preset
184 * @returns Pointer to avatar entry, NULL if not found.
185 */
186 LLAvatarListEntry* getAvatarEntry(LLUUID avatar);
187
188 /**
189 * @brief Returns a string with the selected names in the list
190 */
191 std::string getSelectedNames(const std::string& separator = ", ");
192 std::string getSelectedName();
193 LLUUID getSelectedID();
194
195private:
196 static LLFloaterAvatarList* sInstance;
197
198public:
199 static LLFloaterAvatarList* getInstance() { return sInstance; }
200private:
201 // when a line editor loses keyboard focus, it is committed.
202 // commit callbacks are named onCommitWidgetName by convention.
203 //void onCommitBaz(LLUICtrl* ctrl, void *userdata);
204
205 enum AVATARS_COLUMN_ORDER
206 {
207 LIST_MARK,
208 LIST_AVATAR_NAME,
209 LIST_DISTANCE,
210 LIST_POSITION,
211 LIST_ALTITUDE
212 };
213
214 typedef void (*avlist_command_t)(const LLUUID &avatar, const std::string &name);
215
216 /**
217 * @brief Removes focus status from all avatars in list
218 */
219 void removeFocusFromAll();
220
221 /**
222 * @brief Focus camera on current avatar
223 */
224 void focusOnCurrent();
225
226 /**
227 * @brief Focus camera on previous avatar
228 * @param marked_only Whether to choose only marked avatars
229 */
230 void focusOnPrev(BOOL marked_only);
231
232 /**
233 * @brief Focus camera on next avatar
234 * @param marked_only Whether to choose only marked avatars
235 */
236 void focusOnNext(BOOL marked_only);
237
238 /**
239 * @brief Handler for the "refresh" button click.
240 * I am unsure whether this is actually necessary at the time.
241 *
242 * LL: By convention, button callbacks are named onClickButtonLabel
243 * @param userdata Pointer to user data (LLFloaterAvatarList instance)
244 */
245
246 static void onClickProfile(void *userdata);
247 static void onClickIM(void *userdata);
248 static void onClickTeleportOffer(void *userdata);
249 static void onClickTrack(void *userdata);
250 static void onClickMark(void *userdata);
251 static void onClickFocus(void *userdata);
252
253 static void onClickPrevInList(void *userdata);
254 static void onClickNextInList(void *userdata);
255 static void onClickPrevMarked(void *userdata);
256 static void onClickNextMarked(void *userdata);
257 static void onClickGetKey(void *userdata);
258
259 static void onClickFreeze(void *userdata);
260 static void onClickEject(void *userdata);
261 static void onClickMute(void *userdata);
262 static void onClickAR(void *userdata);
263 static void onClickTeleport(void *userdata);
264 static void onClickEjectFromEstate(void *userdata);
265
266 static void callbackFreeze(const LLSD& notification, const LLSD& response);
267 static void callbackEject(const LLSD& notification, const LLSD& response);
268 static void callbackAR(void *userdata);
269 static void callbackEjectFromEstate(const LLSD& notification, const LLSD& response);
270
271 static void onSelectName(LLUICtrl*, void *userdata);
272
273 static void onCommitUpdateRate(LLUICtrl*, void *userdata);
274 static void onClickSendKeys(void *userdata);
275
276 static void callbackIdle(void *userdata);
277
278 void doCommand(avlist_command_t cmd);
279
280 /**
281 * @brief Cleanup avatar list, removing dead entries from it.
282 * This lets dead entries remain for some time. This makes it possible
283 * to keep people passing by in the list long enough that it's possible
284 * to do something to them.
285 */
286 void expireAvatarList();
287
288private:
289 /**
290 * @brief Pointer to the avatar scroll list
291 */
292 LLScrollListCtrl* mAvatarList;
293 std::map<LLUUID, LLAvatarListEntry> mAvatars;
294
295 /**
296 * @brief TRUE when Updating
297 */
298 BOOL mUpdate;
299
300 /**
301 * @brief Update rate (if min frames per update)
302 */
303 U32 mUpdateRate;
304
305 void stopTracker();
306 void refreshTracker();
307
308 // tracking data
309 BOOL mTracking; // Tracking ?
310 LLUUID mTrackedAvatar; // Who we are tracking
311
312 /**
313 * @brief Avatar the camera is focused on
314 */
315 LLUUID mFocusedAvatar;
316};
diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp
index 80ddfa4..88445c3 100644
--- a/linden/indra/newview/llstartup.cpp
+++ b/linden/indra/newview/llstartup.cpp
@@ -82,6 +82,7 @@
82 82
83#include "llagent.h" 83#include "llagent.h"
84#include "llagentpilot.h" 84#include "llagentpilot.h"
85#include "llfloateravatarlist.h"
85#include "llfloateravatarpicker.h" 86#include "llfloateravatarpicker.h"
86#include "llcallbacklist.h" 87#include "llcallbacklist.h"
87#include "llcallingcard.h" 88#include "llcallingcard.h"
@@ -2060,7 +2061,10 @@ bool idle_startup()
2060 { 2061 {
2061 LLFloaterMap::showInstance(); 2062 LLFloaterMap::showInstance();
2062 } 2063 }
2063 2064 if (gSavedSettings.getBOOL("ShowRadar"))
2065 {
2066 LLFloaterAvatarList::showInstance();
2067 }
2064 if (gSavedSettings.getBOOL("ShowCameraControls")) 2068 if (gSavedSettings.getBOOL("ShowCameraControls"))
2065 { 2069 {
2066 LLFloaterCamera::showInstance(); 2070 LLFloaterCamera::showInstance();
diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp
index b641ce9..e270dbb 100644
--- a/linden/indra/newview/llviewermenu.cpp
+++ b/linden/indra/newview/llviewermenu.cpp
@@ -89,6 +89,7 @@
89#include "llfloateractivespeakers.h" 89#include "llfloateractivespeakers.h"
90#include "llfloateranimpreview.h" 90#include "llfloateranimpreview.h"
91#include "llfloateravatarinfo.h" 91#include "llfloateravatarinfo.h"
92#include "llfloateravatarlist.h"
92#include "llfloateravatartextures.h" 93#include "llfloateravatartextures.h"
93#include "llfloaterbeacons.h" 94#include "llfloaterbeacons.h"
94#include "llfloaterbuildoptions.h" 95#include "llfloaterbuildoptions.h"
@@ -6147,6 +6148,10 @@ class LLShowFloater : public view_listener_t
6147 { 6148 {
6148 LLFloaterPerms::toggleInstance(LLSD()); 6149 LLFloaterPerms::toggleInstance(LLSD());
6149 } 6150 }
6151 else if (floater_name == "full radar")
6152 {
6153 LLFloaterAvatarList::toggle(NULL);
6154 }
6150 return true; 6155 return true;
6151 } 6156 }
6152}; 6157};
@@ -6221,6 +6226,10 @@ class LLFloaterVisible : public view_listener_t
6221 if (!instn) new_value = false; 6226 if (!instn) new_value = false;
6222 else new_value = instn->getVisible(); 6227 else new_value = instn->getVisible();
6223 } 6228 }
6229 else if (floater_name == "full radar")
6230 {
6231 new_value = (LLFloaterAvatarList::getInstance() != NULL);
6232 }
6224 gMenuHolder->findControl(control_name)->setValue(new_value); 6233 gMenuHolder->findControl(control_name)->setValue(new_value);
6225 return true; 6234 return true;
6226 } 6235 }
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_radar.xml b/linden/indra/newview/skins/default/xui/en-us/floater_radar.xml
new file mode 100644
index 0000000..7db7330
--- /dev/null
+++ b/linden/indra/newview/skins/default/xui/en-us/floater_radar.xml
@@ -0,0 +1,327 @@
1<?xml version="1.0" encoding="utf-8" standalone="yes"?>
2<floater name="radar" title="Radar"
3 can_resize="true" can_minimize="true" can_close="true" can_drag_on_left="false"
4 rect_control="FloaterRadarRect" min_width="300" min_height="300">
5
6 <scroll_list name="avatar_list"
7 left="10" right="-10" top="-20" bottom="140" can_resize="true"
8 column_padding="0" follows="left|top|bottom|right"
9 draw_heading="true" multi_select="true" search_column="1"
10 tool_tip="Hold shift or control while clicking to select multiple avatars">
11 <column name="marked" label="Mark" width="12" tool_tip="Marked avatars"/>
12 <column name="avatar_name" label="Name" dynamicwidth="true" tool_tip="Hold shift or control while clicking to select multiple avatars"/>
13 <column name="distance" label="Dist." width="48" tool_tip="Distance from your avatar (red=within chat range, yellow=within shout range, green=within draw distance)"/>
14 <column name="position" label="Pos." width="60" tool_tip="Position (X, Y) within this sim, or general direction (cardinal point) for outside sims"/>
15 <column name="altitude" label="Alt." width="48" tool_tip="Altitude"/>
16 </scroll_list>
17
18 <tab_container border="false" bottom_delta="-130" height="120" left="6" mouse_opaque="false"
19 name="actions_tab_container" tab_position="top" follows="left|right|bottom">
20 <panel border="true" bottom_delta="-130" follows="left|top|right|bottom" height="255"
21 label="Avatar" left="1" mouse_opaque="true"
22 name="actions_tab" width="398">
23 <!-- upper row -->
24 <button
25 name="profile_btn"
26 label="Profile"
27 tool_tip="Show picture, groups, and other information"
28 left="10"
29 bottom_delta="-180"
30 width="80"
31 height="20"
32 font="SansSerifSmall"
33 follows="bottom|left"
34 />
35 <button
36 name="track_btn"
37 label="(Un)Track"
38 tool_tip="Toggle tracking of this avatar's position"
39 left_delta="90"
40 bottom_delta="0"
41 width="80"
42 height="20"
43 font="SansSerifSmall"
44 follows="bottom|left"
45 />
46 <button
47 name="get_key_btn"
48 label="Get Key"
49 tool_tip="Copies avatar's key to the clipboard"
50 left_delta="90"
51 bottom_delta="0"
52 width="80"
53 height="20"
54 font="SansSerifSmall"
55 follows="bottom|left"
56 />
57 <!-- upper middle row -->
58 <button
59 name="im_btn"
60 label="IM"
61 tool_tip="Open Instant Message session"
62 left="10"
63 bottom_delta="-22"
64 width="80"
65 height="20"
66 font="SansSerifSmall"
67 follows="bottom|left"
68 />
69 <button
70 name="offer_btn"
71 label="Offer TP"
72 tool_tip="Offer Teleport"
73 left_delta="90"
74 bottom_delta="0"
75 width="80"
76 height="20"
77 font="SansSerifSmall"
78 follows="bottom|left"
79 />
80 <button
81 name="teleport_btn"
82 label="TP to"
83 tool_tip="Teleport to avatar's position"
84 left_delta="90"
85 bottom_delta="0"
86 width="80"
87 height="20"
88 font="SansSerifSmall"
89 follows="bottom|left"
90 />
91 <!-- lower middle row-->
92 <button
93 name="mark_btn"
94 label="(Un)Mark"
95 tool_tip="(Un)Mark this avatar in the list"
96 left="10"
97 bottom_delta="-22"
98 width="80"
99 height="20"
100 font="SansSerifSmall"
101 follows="bottom|left"
102 />
103 <button
104 name="prev_marked_btn"
105 label="Prev Marked"
106 tool_tip="Focus camera on previous marked avatar"
107 left_delta="90"
108 bottom_delta="0"
109 width="80"
110 height="20"
111 font="SansSerifSmall"
112 follows="bottom|left"
113 />
114 <button
115 name="next_marked_btn"
116 label="Next Marked"
117 tool_tip="Focus camera on next marked avatar"
118 left_delta="90"
119 bottom_delta="0"
120 width="80"
121 height="20"
122 font="SansSerifSmall"
123 follows="bottom|left"
124 />
125 <!-- lower row-->
126 <button
127 name="focus_btn"
128 label="Focus"
129 tool_tip="Focus camera on this avatar in the list"
130 left="10"
131 bottom_delta="-22"
132 width="80"
133 height="20"
134 font="SansSerifSmall"
135 follows="bottom|left"
136 />
137 <button
138 name="prev_in_list_btn"
139 label="Previous"
140 tool_tip="Focus camera on previous avatar in list"
141 left_delta="90"
142 bottom_delta="0"
143 width="80"
144 height="20"
145 font="SansSerifSmall"
146 follows="bottom|left"
147 />
148 <button
149 name="next_in_list_btn"
150 label="Next"
151 tool_tip="Focus camera on next avatar in list"
152 left_delta="90"
153 bottom_delta="0"
154 width="80"
155 height="20"
156 font="SansSerifSmall"
157 follows="bottom|left"
158 />
159
160 </panel>
161
162 <panel border="true" bottom_delta="-150" follows="left|top|right|bottom" height="255"
163 label="Alerts" left="1" mouse_opaque="true"
164 name="alerts_tab" width="398">
165 <check_box height="16" label="Display alerts in chat"
166 left="10" bottom_delta="-176" name="radar_alerts"
167 width="200" follows="bottom|left"
168 hidden="false" mouse_opaque="true" font="SansSerifSmall"
169 initial_value="true" enabled="true" radio_style="false"
170 control_name="RadarChatAlerts"
171 tool_tip="Announce alerts about incoming and outgoing avatars in chat" />
172
173 <check_box height="16" label="Avatars entering/exiting the sim"
174 left="20" bottom_delta="-18" name="alerts_sim"
175 width="200" follows="bottom|left"
176 hidden="false" mouse_opaque="true" font="SansSerifSmall"
177 initial_value="true" enabled="true" radio_style="false"
178 control_name="RadarAlertSim"
179 tool_tip="Report avatars entering or exiting the sim" />
180
181 <check_box height="16" label="Avatars within/beyond the draw distance"
182 left="20" bottom_delta="-18" name="alerts_draw"
183 width="200" follows="bottom|left"
184 hidden="false" mouse_opaque="true" font="SansSerifSmall"
185 initial_value="true" enabled="true" radio_style="false"
186 control_name="RadarAlertDraw"
187 tool_tip="Report avatars getting within or beyond the draw distance" />
188
189 <check_box height="16" label="Avatars within/beyond the shout range"
190 left="20" bottom_delta="-18" name="alerts_chat"
191 width="200" follows="bottom|left"
192 hidden="false" mouse_opaque="true" font="SansSerifSmall"
193 initial_value="true" enabled="true" radio_style="false"
194 control_name="RadarAlertShoutRange"
195 tool_tip="Report avatars getting within or beyond the shout range" />
196
197 <check_box height="16" label="Avatars within/beyond the chat range"
198 left="20" bottom_delta="-18" name="alerts_chat"
199 width="200" follows="bottom|left"
200 hidden="false" mouse_opaque="true" font="SansSerifSmall"
201 initial_value="true" enabled="true" radio_style="false"
202 control_name="RadarAlertChatRange"
203 tool_tip="Report avatars getting within or beyond the chat range" />
204 </panel>
205
206 <panel border="true" bottom_delta="-130" follows="left|top|right|bottom" height="255"
207 label="Moderation" left="1" mouse_opaque="true"
208 name="land_tab" width="398">
209
210 <!-- Upper row -->
211 <button
212 name="mute_btn"
213 label="(Un)Mute"
214 tool_tip="Mute or unmute this avatar (muted avatars' names are highlighted in red in the list)."
215 left="10"
216 bottom_delta="-200"
217 width="80"
218 height="20"
219 font="SansSerifSmall"
220 follows="bottom|left"
221 />
222 <button
223 name="freeze_btn"
224 label="Freeze"
225 tool_tip="Freeze the avatar, preventing it from moving"
226 left_delta="90"
227 bottom_delta="0"
228 width="80"
229 height="20"
230 font="SansSerifSmall"
231 follows="bottom|left"
232 />
233 <button
234 name="ar_btn"
235 label="AR"
236 tool_tip="Report abuse on this avatar"
237 left_delta="90"
238 bottom_delta="0"
239 width="80"
240 height="20"
241 font="SansSerifSmall"
242 follows="bottom|left"
243 />
244 <!-- Lower row -->
245 <button
246 name="eject_btn"
247 label="Eject"
248 tool_tip="Eject the avatar from the parcel"
249 left="10"
250 bottom_delta="-24"
251 width="80"
252 height="20"
253 font="SansSerifSmall"
254 follows="bottom|left"
255 />
256
257 <button
258 name="estate_eject_btn"
259 label="Eject from estate"
260 tool_tip="Eject this avatar from the estate"
261 left_delta="90"
262 bottom_delta="0"
263 width="170"
264 height="20"
265 font="SansSerifSmall"
266 follows="bottom|left"
267 />
268 </panel>
269
270 <panel border="true" bottom_delta="-150" follows="left|top|right|bottom" height="255"
271 label="Options" left="1" mouse_opaque="true"
272 name="options_tab" width="398">
273 <check_box height="16" label="Update"
274 left="10" bottom_delta="-180" name="update_enabled_cb"
275 width="200" follows="bottom|left"
276 hidden="false" mouse_opaque="true" font="SansSerifSmall"
277 initial_value="true" enabled="true" radio_style="false"
278 tool_tip="Set whether the avatar list should update" />
279 <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
280 bottom_delta="-24" drop_shadow_visible="true" enabled="true" font="SansSerifSmall" height="18" left="24"
281 mouse_opaque="false" name="rate" width="30">
282 Rate:
283 </text>
284 <radio_group draw_border="true" bottom_delta="2" left_delta="44" follows="bottom|left" width="196" height="20"
285 mouse_opaque="true" name="update_rate" control_name="RadarUpdateRate" enabled="true"
286 tool_tip="Rate of the radar updates (eats up more FPS when higher)">
287 <radio_item type="string" length="1" bottom_delta="0" height="16" left_delta="4" mouse_opaque="true"
288 name="high" width="20" follows="bottom|left">
289 High
290 </radio_item>
291 <radio_item type="string" length="1" bottom_delta="0" height="16" left_delta="30" mouse_opaque="true"
292 name="medium" width="25" follows="bottom|left">
293 Medium
294 </radio_item>
295 <radio_item type="string" length="1" bottom_delta="0" height="16" left_delta="35" mouse_opaque="true"
296 name="low" width="20" follows="bottom|left">
297 Low
298 </radio_item>
299 </radio_group>
300 <check_box height="16" label="Announce even when closed"
301 left="10" bottom_delta="-24" name="keep_open"
302 width="200" follows="bottom|left"
303 hidden="false" mouse_opaque="true" font="SansSerifSmall"
304 initial_value="true" enabled="true" radio_style="false"
305 control_name="RadarKeepOpen"
306 tool_tip="Hides floater instead of closing to still announce in chat" />
307 <check_box height="16" label="Announce keys to HUD"
308 left="10" bottom_delta="-20" name="radar_chat_keys"
309 width="200" follows="bottom|left"
310 hidden="false" mouse_opaque="true" font="SansSerifSmall"
311 initial_value="true" enabled="true" radio_style="false"
312 control_name="RadarChatKeys"
313 tool_tip="Set whether to send keys of avatars to LSL scripts" />
314 <button
315 name="send_keys_btn"
316 label="Announce now"
317 tool_tip="Send all keys to HUD now"
318 left_delta="150"
319 bottom_delta="-2"
320 width="100"
321 height="20"
322 font="SansSerifSmall"
323 follows="bottom|left"
324 />
325 </panel>
326 </tab_container>
327</floater> \ No newline at end of file
diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
index 5fbf337..b31122a 100644
--- a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
+++ b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml
@@ -1007,6 +1007,10 @@
1007 <on_click function="ShowFloater" userdata="animation list" /> 1007 <on_click function="ShowFloater" userdata="animation list" />
1008 <on_check function="FloaterVisible" userdata="animation list" /> 1008 <on_check function="FloaterVisible" userdata="animation list" />
1009 </menu_item_check> 1009 </menu_item_check>
1010 <menu_item_check label="Full Radar" name="Full Radar">
1011 <on_click function="ShowFloater" userdata="full radar" />
1012 <on_check function="FloaterVisible" userdata="full radar" />
1013 </menu_item_check>
1010 <menu_item_check label="Area Object Search" name="Area Object Search" 1014 <menu_item_check label="Area Object Search" name="Area Object Search"
1011 shortcut="alt|A"> 1015 shortcut="alt|A">
1012 <on_click function="ShowFloater" userdata="areasearch" /> 1016 <on_click function="ShowFloater" userdata="areasearch" />