PageRenderTime 1690ms CodeModel.GetById 164ms app.highlight 1169ms RepoModel.GetById 121ms app.codeStats 1ms

/indra/newview/lltoolpie.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1890 lines | 1462 code | 254 blank | 174 comment | 332 complexity | c63fa80013735e49cdd879fedf6fb607 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file lltoolpie.cpp
   3 * @brief LLToolPie class implementation
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "lltoolpie.h"
  30
  31#include "indra_constants.h"
  32#include "llclickaction.h"
  33#include "llparcel.h"
  34
  35#include "llagent.h"
  36#include "llagentcamera.h"
  37#include "llavatarnamecache.h"
  38#include "llfocusmgr.h"
  39#include "llfirstuse.h"
  40#include "llfloaterland.h"
  41#include "llfloaterreg.h"
  42#include "llfloaterscriptdebug.h"
  43#include "lltooltip.h"
  44#include "llhudeffecttrail.h"
  45#include "llhudmanager.h"
  46#include "llkeyboard.h"
  47#include "llmediaentry.h"
  48#include "llmenugl.h"
  49#include "llmutelist.h"
  50#include "llresmgr.h"  // getMonetaryString
  51#include "llselectmgr.h"
  52#include "lltoolfocus.h"
  53#include "lltoolgrab.h"
  54#include "lltoolmgr.h"
  55#include "lltoolselect.h"
  56#include "lltrans.h"
  57#include "llviewercamera.h"
  58#include "llviewerparcelmedia.h"
  59#include "llviewercontrol.h"
  60#include "llviewermenu.h"
  61#include "llviewerobjectlist.h"
  62#include "llviewerobject.h"
  63#include "llviewerparcelmgr.h"
  64#include "llviewerwindow.h"
  65#include "llviewermedia.h"
  66#include "llvoavatarself.h"
  67#include "llviewermediafocus.h"
  68#include "llworld.h"
  69#include "llui.h"
  70#include "llweb.h"
  71#include "pipeline.h"	// setHighlightObject
  72
  73extern BOOL gDebugClicks;
  74
  75static void handle_click_action_play();
  76static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp);
  77static ECursorType cursor_from_parcel_media(U8 click_action);
  78
  79LLToolPie::LLToolPie()
  80:	LLTool(std::string("Pie")),
  81	mMouseButtonDown( false ),
  82	mMouseOutsideSlop( false ),
  83	mMouseSteerX(-1),
  84	mMouseSteerY(-1),
  85	mBlockClickToWalk(false),
  86	mClickAction(0),
  87	mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
  88	mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") )
  89{
  90}
  91
  92BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
  93{
  94	BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
  95	
  96	// This override DISABLES the keyboard focus reset that LLTool::handleAnyMouseClick adds.
  97	// LLToolPie will do the right thing in its pick callback.
  98	
  99	return result;
 100}
 101
 102BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 103{
 104	mMouseOutsideSlop = FALSE;
 105	mMouseDownX = x;
 106	mMouseDownY = y;
 107
 108	//left mouse down always picks transparent
 109	mPick = gViewerWindow->pickImmediate(x, y, TRUE);
 110	mPick.mKeyMask = mask;
 111
 112	mMouseButtonDown = true;
 113	
 114	handleLeftClickPick();
 115
 116	return TRUE;
 117}
 118
 119// Spawn context menus on right mouse down so you can drag over and select
 120// an item.
 121BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
 122{
 123	// don't pick transparent so users can't "pay" transparent objects
 124	mPick = gViewerWindow->pickImmediate(x, y, FALSE);
 125	mPick.mKeyMask = mask;
 126
 127	// claim not handled so UI focus stays same
 128	
 129	handleRightClickPick();
 130	
 131	return FALSE;
 132}
 133
 134BOOL LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask)
 135{
 136	LLToolMgr::getInstance()->clearTransientTool();
 137	return LLTool::handleRightMouseUp(x, y, mask);
 138}
 139
 140BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks)
 141{
 142	return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks);
 143}
 144
 145// True if you selected an object.
 146BOOL LLToolPie::handleLeftClickPick()
 147{
 148	S32 x = mPick.mMousePt.mX;
 149	S32 y = mPick.mMousePt.mY;
 150	MASK mask = mPick.mKeyMask;
 151	if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL)
 152	{
 153		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel();
 154		if (parcel)
 155		{
 156			LLViewerParcelMgr::getInstance()->selectCollisionParcel();
 157			if (parcel->getParcelFlag(PF_USE_PASS_LIST) 
 158				&& !LLViewerParcelMgr::getInstance()->isCollisionBanned())
 159			{
 160				// if selling passes, just buy one
 161				void* deselect_when_done = (void*)TRUE;
 162				LLPanelLandGeneral::onClickBuyPass(deselect_when_done);
 163			}
 164			else
 165			{
 166				// not selling passes, get info
 167				LLFloaterReg::showInstance("about_land");
 168			}
 169		}
 170
 171		gFocusMgr.setKeyboardFocus(NULL);
 172		return LLTool::handleMouseDown(x, y, mask);
 173	}
 174
 175	// didn't click in any UI object, so must have clicked in the world
 176	LLViewerObject *object = mPick.getObject();
 177	LLViewerObject *parent = NULL;
 178
 179	if (mPick.mPickType != LLPickInfo::PICK_LAND)
 180	{
 181		LLViewerParcelMgr::getInstance()->deselectLand();
 182	}
 183	
 184	if (object)
 185	{
 186		parent = object->getRootEdit();
 187	}
 188
 189	if (handleMediaClick(mPick))
 190	{
 191		return TRUE;
 192	}
 193
 194	// If it's a left-click, and we have a special action, do it.
 195	if (useClickAction(mask, object, parent))
 196	{
 197		mClickAction = 0;
 198		if (object && object->getClickAction()) 
 199		{
 200			mClickAction = object->getClickAction();
 201		}
 202		else if (parent && parent->getClickAction()) 
 203		{
 204			mClickAction = parent->getClickAction();
 205		}
 206
 207		switch(mClickAction)
 208		{
 209		case CLICK_ACTION_TOUCH:
 210			// touch behavior down below...
 211			break;
 212		case CLICK_ACTION_SIT:
 213			{
 214				if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // agent not already sitting
 215				{
 216					handle_object_sit_or_stand();
 217					// put focus in world when sitting on an object
 218					gFocusMgr.setKeyboardFocus(NULL);
 219					return TRUE;
 220				} // else nothing (fall through to touch)
 221			}
 222		case CLICK_ACTION_PAY:
 223			if ( mClickActionPayEnabled )
 224			{
 225				if ((object && object->flagTakesMoney())
 226					|| (parent && parent->flagTakesMoney()))
 227				{
 228					// pay event goes to object actually clicked on
 229					mClickActionObject = object;
 230					mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
 231					if (LLSelectMgr::getInstance()->selectGetAllValid())
 232					{
 233						// call this right away, since we have all the info we need to continue the action
 234						selectionPropertiesReceived();
 235					}
 236					return TRUE;
 237				}
 238			}
 239			break;
 240		case CLICK_ACTION_BUY:
 241			if ( mClickActionBuyEnabled )
 242			{
 243				mClickActionObject = parent;
 244				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
 245				if (LLSelectMgr::getInstance()->selectGetAllValid())
 246				{
 247					// call this right away, since we have all the info we need to continue the action
 248					selectionPropertiesReceived();
 249				}
 250				return TRUE;
 251			}
 252			break;
 253		case CLICK_ACTION_OPEN:
 254			if (parent && parent->allowOpen())
 255			{
 256				mClickActionObject = parent;
 257				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
 258				if (LLSelectMgr::getInstance()->selectGetAllValid())
 259				{
 260					// call this right away, since we have all the info we need to continue the action
 261					selectionPropertiesReceived();
 262				}
 263			}
 264			return TRUE;	
 265		case CLICK_ACTION_PLAY:
 266			handle_click_action_play();
 267			return TRUE;
 268		case CLICK_ACTION_OPEN_MEDIA:
 269			// mClickActionObject = object;
 270			handle_click_action_open_media(object);
 271			return TRUE;
 272		case CLICK_ACTION_ZOOM:
 273			{	
 274				const F32 PADDING_FACTOR = 2.f;
 275				LLViewerObject* object = gObjectList.findObject(mPick.mObjectID);
 276				
 277				if (object)
 278				{
 279					gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
 280					
 281					LLBBox bbox = object->getBoundingBoxAgent() ;
 282					F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
 283					F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
 284				
 285					LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent();
 286					obj_to_cam.normVec();
 287					
 288					LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
 289					gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), 
 290													  object_center_global, 
 291													  mPick.mObjectID );
 292				}
 293			}
 294			return TRUE;			
 295		default:
 296			// nothing
 297			break;
 298		}
 299	}
 300
 301	// put focus back "in world"
 302	if (gFocusMgr.getKeyboardFocus())
 303	{
 304		// don't click to walk on attempt to give focus to world
 305		mBlockClickToWalk = true;
 306		gFocusMgr.setKeyboardFocus(NULL);
 307	}
 308
 309	BOOL touchable = (object && object->flagHandleTouch()) 
 310					 || (parent && parent->flagHandleTouch());
 311
 312	// Switch to grab tool if physical or triggerable
 313	if (object && 
 314		!object->isAvatar() && 
 315		((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) 
 316		)
 317	{
 318		gGrabTransientTool = this;
 319		mMouseButtonDown = false;
 320		LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
 321		return LLToolGrab::getInstance()->handleObjectHit( mPick );
 322	}
 323	
 324	LLHUDIcon* last_hit_hud_icon = mPick.mHUDIcon;
 325	if (!object && last_hit_hud_icon && last_hit_hud_icon->getSourceObject())
 326	{
 327		LLFloaterScriptDebug::show(last_hit_hud_icon->getSourceObject()->getID());
 328	}
 329
 330	// If left-click never selects or spawns a menu
 331	// Eat the event.
 332	if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
 333	{
 334		// mouse already released
 335		if (!mMouseButtonDown)
 336		{
 337			return true;
 338		}
 339
 340		while( object && object->isAttachment() && !object->flagHandleTouch())
 341		{
 342			// don't pick avatar through hud attachment
 343			if (object->isHUDAttachment())
 344			{
 345				break;
 346			}
 347			object = (LLViewerObject*)object->getParent();
 348		}
 349		if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
 350		{
 351			// we left clicked on avatar, switch to focus mode
 352			mMouseButtonDown = false;
 353			LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
 354			gViewerWindow->hideCursor();
 355			LLToolCamera::getInstance()->setMouseCapture(TRUE);
 356			LLToolCamera::getInstance()->pickCallback(mPick);
 357			gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
 358
 359			return TRUE;
 360		}
 361	//////////
 362	//	// Could be first left-click on nothing
 363	//	LLFirstUse::useLeftClickNoHit();
 364	/////////
 365		
 366		// Eat the event
 367		return LLTool::handleMouseDown(x, y, mask);
 368	}
 369
 370	if (gAgent.leftButtonGrabbed())
 371	{
 372		// if the left button is grabbed, don't put up the pie menu
 373		return LLTool::handleMouseDown(x, y, mask);
 374	}
 375
 376	// Can't ignore children here.
 377	LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
 378
 379	// Spawn pie menu
 380	LLTool::handleRightMouseDown(x, y, mask);
 381	return TRUE;
 382}
 383
 384BOOL LLToolPie::useClickAction(MASK mask, 
 385							   LLViewerObject* object, 
 386							   LLViewerObject* parent)
 387{
 388	return	mask == MASK_NONE
 389			&& object
 390			&& !object->isAttachment() 
 391			&& LLPrimitive::isPrimitive(object->getPCode())
 392			&& (object->getClickAction() 
 393				|| parent->getClickAction());
 394
 395}
 396
 397U8 final_click_action(LLViewerObject* obj)
 398{
 399	if (!obj) return CLICK_ACTION_NONE;
 400	if (obj->isAttachment()) return CLICK_ACTION_NONE;
 401
 402	U8 click_action = CLICK_ACTION_TOUCH;
 403	LLViewerObject* parent = obj->getRootEdit();
 404	if (obj->getClickAction()
 405	    || (parent && parent->getClickAction()))
 406	{
 407		if (obj->getClickAction())
 408		{
 409			click_action = obj->getClickAction();
 410		}
 411		else if (parent && parent->getClickAction())
 412		{
 413			click_action = parent->getClickAction();
 414		}
 415	}
 416	return click_action;
 417}
 418
 419ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
 420{
 421	LLViewerObject* parent = NULL;
 422	if (object)
 423	{
 424		parent = object->getRootEdit();
 425	}
 426	U8 click_action = final_click_action(object);
 427	ECursorType cursor = UI_CURSOR_ARROW;
 428	switch(click_action)
 429	{
 430	case CLICK_ACTION_SIT:
 431		{
 432			if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
 433			{
 434				cursor = UI_CURSOR_TOOLSIT;
 435			}
 436		}
 437		break;
 438	case CLICK_ACTION_BUY:
 439		if ( mClickActionBuyEnabled )
 440		{
 441			cursor = UI_CURSOR_TOOLBUY;
 442		}
 443		break;
 444	case CLICK_ACTION_OPEN:
 445		// Open always opens the parent.
 446		if (parent && parent->allowOpen())
 447		{
 448			cursor = UI_CURSOR_TOOLOPEN;
 449		}
 450		break;
 451	case CLICK_ACTION_PAY:	
 452		if ( mClickActionPayEnabled )
 453		{
 454			if ((object && object->flagTakesMoney())
 455				|| (parent && parent->flagTakesMoney()))
 456			{
 457				cursor = UI_CURSOR_TOOLBUY;
 458			}
 459		}
 460		break;
 461	case CLICK_ACTION_ZOOM:
 462			cursor = UI_CURSOR_TOOLZOOMIN;
 463			break;			
 464	case CLICK_ACTION_PLAY:
 465	case CLICK_ACTION_OPEN_MEDIA: 
 466		cursor = cursor_from_parcel_media(click_action);
 467		break;
 468	default:
 469		break;
 470	}
 471	return cursor;
 472}
 473
 474void LLToolPie::resetSelection()
 475{
 476	mLeftClickSelection = NULL;
 477	mClickActionObject = NULL;
 478	mClickAction = 0;
 479}
 480
 481void LLToolPie::walkToClickedLocation()
 482{
 483	if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
 484	mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
 485	mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
 486	mAutoPilotDestination->setPixelSize(5);
 487	mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
 488	mAutoPilotDestination->setDuration(3.f);
 489
 490	handle_go_to();
 491}
 492
 493// When we get object properties after left-clicking on an object
 494// with left-click = buy, if it's the same object, do the buy.
 495
 496// static
 497void LLToolPie::selectionPropertiesReceived()
 498{
 499	// Make sure all data has been received.
 500	// This function will be called repeatedly as the data comes in.
 501	if (!LLSelectMgr::getInstance()->selectGetAllValid())
 502	{
 503		return;
 504	}
 505
 506	LLObjectSelection* selection = LLToolPie::getInstance()->getLeftClickSelection();
 507	if (selection)
 508	{
 509		LLViewerObject* selected_object = selection->getPrimaryObject();
 510		// since we don't currently have a way to lock a selection, it could have changed
 511		// after we initially clicked on the object
 512		if (selected_object == LLToolPie::getInstance()->getClickActionObject())
 513		{
 514			U8 click_action = LLToolPie::getInstance()->getClickAction();
 515			switch (click_action)
 516			{
 517			case CLICK_ACTION_BUY:
 518				if ( LLToolPie::getInstance()->mClickActionBuyEnabled )
 519				{
 520					handle_buy();
 521				}
 522				break;
 523			case CLICK_ACTION_PAY:
 524				if ( LLToolPie::getInstance()->mClickActionPayEnabled )
 525				{
 526					handle_give_money_dialog();
 527				}
 528				break;
 529			case CLICK_ACTION_OPEN:
 530				LLFloaterReg::showInstance("openobject");
 531				break;
 532			default:
 533				break;
 534			}
 535		}
 536	}
 537	LLToolPie::getInstance()->resetSelection();
 538}
 539
 540BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 541{
 542	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE);
 543	LLViewerObject *parent = NULL;
 544	LLViewerObject *object = mHoverPick.getObject();
 545	if (object)
 546	{
 547		parent = object->getRootEdit();
 548	}
 549
 550	// Show screen-space highlight glow effect
 551	bool show_highlight = false;
 552
 553	if (handleMediaHover(mHoverPick))
 554	{
 555		// *NOTE: If you think the hover glow conflicts with the media outline, you
 556		// could disable it here.
 557		show_highlight = true;
 558		// cursor set by media object
 559		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 560	}
 561	else if (!mMouseOutsideSlop 
 562		&& mMouseButtonDown 
 563		&& gSavedSettings.getBOOL("ClickToWalk"))
 564	{
 565		S32 delta_x = x - mMouseDownX;
 566		S32 delta_y = y - mMouseDownY;
 567		S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold");
 568		if (delta_x * delta_x + delta_y * delta_y > threshold * threshold)
 569		{
 570			startCameraSteering();
 571			steerCameraWithMouse(x, y);
 572			gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
 573		}
 574		else
 575		{
 576			gViewerWindow->setCursor(UI_CURSOR_ARROW);
 577		}
 578	}
 579	else if (inCameraSteerMode())
 580	{
 581		steerCameraWithMouse(x, y);
 582		gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
 583	}
 584	else
 585	{
 586		// perform a separate pick that detects transparent objects since they respond to 1-click actions
 587		LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE);
 588
 589		LLViewerObject* click_action_object = click_action_pick.getObject();
 590
 591		if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit()))
 592		{
 593			show_highlight = true;
 594			ECursorType cursor = cursorFromObject(click_action_object);
 595			gViewerWindow->setCursor(cursor);
 596			lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 597		}
 598		
 599		else if ((object && !object->isAvatar() && object->usePhysics()) 
 600				 || (parent && !parent->isAvatar() && parent->usePhysics()))
 601		{
 602			show_highlight = true;
 603			gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
 604			lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 605		}
 606		else if ( (object && object->flagHandleTouch()) 
 607				  || (parent && parent->flagHandleTouch()))
 608		{
 609			show_highlight = true;
 610			gViewerWindow->setCursor(UI_CURSOR_HAND);
 611			lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 612		}
 613		else
 614		{
 615			gViewerWindow->setCursor(UI_CURSOR_ARROW);
 616			lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 617		}
 618	}
 619
 620	if(!object)
 621	{
 622		LLViewerMediaFocus::getInstance()->clearHover();
 623	}
 624
 625	static LLCachedControl<bool> enable_highlight(
 626		gSavedSettings, "RenderHoverGlowEnable", false);
 627	LLDrawable* drawable = NULL;
 628	if (enable_highlight && show_highlight && object)
 629	{
 630		drawable = object->mDrawable;
 631	}
 632	gPipeline.setHighlightObject(drawable);
 633
 634	return TRUE;
 635}
 636
 637BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 638{
 639	LLViewerObject* obj = mPick.getObject();
 640	U8 click_action = final_click_action(obj);
 641
 642	// let media have first pass at click
 643	if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
 644	{
 645		mBlockClickToWalk = true;
 646	}
 647	stopCameraSteering();
 648	mMouseButtonDown = false;
 649
 650	if (click_action == CLICK_ACTION_NONE				// not doing 1-click action
 651		&& gSavedSettings.getBOOL("ClickToWalk")		// click to walk enabled
 652		&& !gAgent.getFlying()							// don't auto-navigate while flying until that works
 653		&& gAgentAvatarp
 654		&& !gAgentAvatarp->isSitting()
 655		&& !mBlockClickToWalk							// another behavior hasn't cancelled click to walk
 656		&& !mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
 657		&& (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
 658			|| mPick.mObjectID.notNull()))				// or on an object
 659	{
 660		// handle special cases of steering picks
 661		LLViewerObject* avatar_object = mPick.getObject();
 662
 663		// get pointer to avatar
 664		while (avatar_object && !avatar_object->isAvatar())
 665		{
 666			avatar_object = (LLViewerObject*)avatar_object->getParent();
 667		}
 668
 669		if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
 670		{
 671			const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
 672			// pretend we picked some point a bit in front of avatar
 673			mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
 674		}
 675		gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
 676		walkToClickedLocation();
 677		LLFirstUse::notMoving(false);
 678
 679		return TRUE;
 680	}
 681	gViewerWindow->setCursor(UI_CURSOR_ARROW);
 682	if (hasMouseCapture())
 683	{
 684		setMouseCapture(FALSE);
 685	}
 686
 687	LLToolMgr::getInstance()->clearTransientTool();
 688	gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
 689
 690	mBlockClickToWalk = false;
 691	return LLTool::handleMouseUp(x, y, mask);
 692}
 693
 694void LLToolPie::stopClickToWalk()
 695{
 696	mPick.mPosGlobal = gAgent.getPositionGlobal();
 697	handle_go_to();
 698	if(mAutoPilotDestination) 
 699	{ 
 700		mAutoPilotDestination->markDead(); 
 701	}
 702}
 703
 704BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 705{
 706	if (gDebugClicks)
 707	{
 708		llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl;
 709	}
 710
 711	if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
 712	{
 713		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
 714			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
 715		{
 716			walkToClickedLocation();
 717			return TRUE;
 718		}
 719	}
 720	else if (gSavedSettings.getBOOL("DoubleClickTeleport"))
 721	{
 722		LLViewerObject* objp = mPick.getObject();
 723		LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
 724
 725		bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
 726		bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND;
 727		bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero();
 728		bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
 729		bool has_click_action = final_click_action(objp);
 730
 731		if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
 732		{
 733			LLVector3d pos = mPick.mPosGlobal;
 734			pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
 735			gAgent.teleportViaLocationLookAt(pos);
 736			return TRUE;
 737		}
 738	}
 739
 740	return FALSE;
 741}
 742
 743static bool needs_tooltip(LLSelectNode* nodep)
 744{
 745	if (!nodep) 
 746		return false;
 747
 748	LLViewerObject* object = nodep->getObject();
 749	LLViewerObject *parent = (LLViewerObject *)object->getParent();
 750	if (object->flagHandleTouch()
 751		|| (parent && parent->flagHandleTouch())
 752		|| object->flagTakesMoney()
 753		|| (parent && parent->flagTakesMoney())
 754		|| object->flagAllowInventoryAdd()
 755		)
 756	{
 757		return true;
 758	}
 759
 760	U8 click_action = final_click_action(object);
 761	if (click_action != 0)
 762	{
 763		return true;
 764	}
 765
 766	if (nodep->mValid)
 767	{
 768		bool anyone_copy = anyone_copy_selection(nodep);
 769		bool for_sale = for_sale_selection(nodep);
 770		if (anyone_copy || for_sale)
 771		{
 772			return true;
 773		}
 774	}
 775	return false;
 776}
 777
 778
 779BOOL LLToolPie::handleTooltipLand(std::string line, std::string tooltip_msg)
 780{
 781	LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal );
 782	// 
 783	//  Do not show hover for land unless prefs are set to allow it.
 784	// 
 785	
 786	if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return TRUE; 
 787	
 788	// Didn't hit an object, but since we have a land point we
 789	// must be hovering over land.
 790	
 791	LLParcel* hover_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
 792	LLUUID owner;
 793	S32 width = 0;
 794	S32 height = 0;
 795	
 796	if ( hover_parcel )
 797	{
 798		owner = hover_parcel->getOwnerID();
 799		width = S32(LLViewerParcelMgr::getInstance()->getHoverParcelWidth());
 800		height = S32(LLViewerParcelMgr::getInstance()->getHoverParcelHeight());
 801	}
 802	
 803	// Line: "Land"
 804	line.clear();
 805	line.append(LLTrans::getString("TooltipLand"));
 806	if (hover_parcel)
 807	{
 808		line.append(hover_parcel->getName());
 809	}
 810	tooltip_msg.append(line);
 811	tooltip_msg.push_back('\n');
 812	
 813	// Line: "Owner: James Linden"
 814	line.clear();
 815	line.append(LLTrans::getString("TooltipOwner") + " ");
 816	
 817	if ( hover_parcel )
 818	{
 819		std::string name;
 820		if (LLUUID::null == owner)
 821		{
 822			line.append(LLTrans::getString("TooltipPublic"));
 823		}
 824		else if (hover_parcel->getIsGroupOwned())
 825		{
 826			if (gCacheName->getGroupName(owner, name))
 827			{
 828				line.append(name);
 829				line.append(LLTrans::getString("TooltipIsGroup"));
 830			}
 831			else
 832			{
 833				line.append(LLTrans::getString("RetrievingData"));
 834			}
 835		}
 836		else if(gCacheName->getFullName(owner, name))
 837		{
 838			line.append(name);
 839		}
 840		else
 841		{
 842			line.append(LLTrans::getString("RetrievingData"));
 843		}
 844	}
 845	else
 846	{
 847		line.append(LLTrans::getString("RetrievingData"));
 848	}
 849	tooltip_msg.append(line);
 850	tooltip_msg.push_back('\n');
 851	
 852	// Line: "no fly, not safe, no build"
 853	
 854	// Don't display properties for your land.  This is just
 855	// confusing, because you can do anything on your own land.
 856	if ( hover_parcel && owner != gAgent.getID() )
 857	{
 858		S32 words = 0;
 859		
 860		line.clear();
 861		// JC - Keep this in the same order as the checkboxes
 862		// on the land info panel
 863		if ( !hover_parcel->getAllowModify() )
 864		{
 865			if ( hover_parcel->getAllowGroupModify() )
 866			{
 867				line.append(LLTrans::getString("TooltipFlagGroupBuild"));
 868			}
 869			else
 870			{
 871				line.append(LLTrans::getString("TooltipFlagNoBuild"));
 872			}
 873			words++;
 874		}
 875		
 876		if ( !hover_parcel->getAllowTerraform() )
 877		{
 878			if (words) line.append(", ");
 879			line.append(LLTrans::getString("TooltipFlagNoEdit"));
 880			words++;
 881		}
 882		
 883		if ( hover_parcel->getAllowDamage() )
 884		{
 885			if (words) line.append(", ");
 886			line.append(LLTrans::getString("TooltipFlagNotSafe"));
 887			words++;
 888		}
 889		
 890		// Maybe we should reflect the estate's block fly bit here as well?  DK 12/1/04
 891		if ( !hover_parcel->getAllowFly() )
 892		{
 893			if (words) line.append(", ");
 894			line.append(LLTrans::getString("TooltipFlagNoFly"));
 895			words++;
 896		}
 897		
 898		if ( !hover_parcel->getAllowOtherScripts() )
 899		{
 900			if (words) line.append(", ");
 901			if ( hover_parcel->getAllowGroupScripts() )
 902			{
 903				line.append(LLTrans::getString("TooltipFlagGroupScripts"));
 904			}
 905			else
 906			{
 907				line.append(LLTrans::getString("TooltipFlagNoScripts"));
 908			}
 909			
 910			words++;
 911		}
 912		
 913		if (words) 
 914		{
 915			tooltip_msg.append(line);
 916			tooltip_msg.push_back('\n');
 917		}
 918	}
 919	
 920	if (hover_parcel && hover_parcel->getParcelFlag(PF_FOR_SALE))
 921	{
 922		LLStringUtil::format_map_t args;
 923		S32 price = hover_parcel->getSalePrice();
 924		args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
 925		line = LLTrans::getString("TooltipForSaleL$", args);
 926		tooltip_msg.append(line);
 927		tooltip_msg.push_back('\n');
 928	}
 929	
 930	// trim last newlines
 931	if (!tooltip_msg.empty())
 932	{
 933		tooltip_msg.erase(tooltip_msg.size() - 1);
 934		LLToolTipMgr::instance().show(tooltip_msg);
 935	}
 936	
 937	return TRUE;
 938}
 939
 940BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg)
 941{
 942	if ( hover_object->isHUDAttachment() )
 943	{
 944		// no hover tips for HUD elements, since they can obscure
 945		// what the HUD is displaying
 946		return TRUE;
 947	}
 948	
 949	if ( hover_object->isAttachment() )
 950	{
 951		// get root of attachment then parent, which is avatar
 952		LLViewerObject* root_edit = hover_object->getRootEdit();
 953		if (!root_edit)
 954		{
 955			// Strange parenting issue, don't show any text
 956			return TRUE;
 957		}
 958		hover_object = (LLViewerObject*)root_edit->getParent();
 959		if (!hover_object)
 960		{
 961			// another strange parenting issue, bail out
 962			return TRUE;
 963		}
 964	}
 965	
 966	line.clear();
 967	if (hover_object->isAvatar())
 968	{
 969		// only show tooltip if same inspector not already open
 970		LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
 971		if (!existing_inspector 
 972			|| !existing_inspector->getVisible()
 973			|| existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID())
 974		{
 975			// IDEVO: try to get display name + username
 976			std::string final_name;
 977			std::string full_name;
 978			if (!gCacheName->getFullName(hover_object->getID(), full_name))
 979			{
 980			LLNameValue* firstname = hover_object->getNVPair("FirstName");
 981			LLNameValue* lastname =  hover_object->getNVPair("LastName");
 982			if (firstname && lastname)
 983			{
 984					full_name = LLCacheName::buildFullName(
 985						firstname->getString(), lastname->getString());
 986				}
 987				else
 988				{
 989					full_name = LLTrans::getString("TooltipPerson");
 990				}
 991			}
 992
 993			LLAvatarName av_name;
 994			if (LLAvatarNameCache::useDisplayNames() && 
 995				LLAvatarNameCache::get(hover_object->getID(), &av_name))
 996			{
 997				final_name = av_name.getCompleteName();
 998			}
 999			else
1000			{
1001				final_name = full_name;
1002			}
1003
1004			// *HACK: We may select this object, so pretend it was clicked
1005			mPick = mHoverPick;
1006			LLInspector::Params p;
1007			p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
1008			p.message(final_name);
1009			p.image.name("Inspector_I");
1010			p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
1011			p.visible_time_near(6.f);
1012			p.visible_time_far(3.f);
1013			p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay"));
1014			p.wrap(false);
1015			
1016			LLToolTipMgr::instance().show(p);
1017		}
1018	}
1019	else
1020	{
1021		//
1022		//  We have hit a regular object (not an avatar or attachment)
1023		// 
1024		
1025		//
1026		//  Default prefs will suppress display unless the object is interactive
1027		//
1028		bool show_all_object_tips =
1029		(bool)gSavedSettings.getBOOL("ShowAllObjectHoverTip");			
1030		LLSelectNode *nodep = LLSelectMgr::getInstance()->getHoverNode();
1031		
1032		// only show tooltip if same inspector not already open
1033		LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_object");
1034		if (nodep &&
1035			(!existing_inspector 
1036			 || !existing_inspector->getVisible()
1037			 || existing_inspector->getKey()["object_id"].asUUID() != hover_object->getID()))
1038		{
1039
1040			// Add price to tooltip for items on sale
1041			bool for_sale = for_sale_selection(nodep);
1042			if(for_sale)
1043			{
1044				LLStringUtil::format_map_t args;
1045				S32 price = nodep->mSaleInfo.getSalePrice();
1046				args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
1047				tooltip_msg.append(LLTrans::getString("TooltipPrice", args) );
1048			}
1049
1050			if (nodep->mName.empty())
1051			{
1052				tooltip_msg.append(LLTrans::getString("TooltipNoName"));
1053			}
1054			else
1055			{
1056				tooltip_msg.append( nodep->mName );
1057			}
1058			
1059			bool has_media = false;
1060			bool is_time_based_media = false;
1061			bool is_web_based_media = false;
1062			bool is_media_playing = false;
1063			bool is_media_displaying = false;
1064			
1065			// Does this face have media?
1066			const LLTextureEntry* tep = hover_object->getTE(mHoverPick.mObjectFace);
1067			
1068			if(tep)
1069			{
1070				has_media = tep->hasMedia();
1071				const LLMediaEntry* mep = has_media ? tep->getMediaData() : NULL;
1072				if (mep)
1073				{
1074					viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
1075					LLPluginClassMedia* media_plugin = NULL;
1076					
1077					if (media_impl.notNull() && (media_impl->hasMedia()))
1078					{
1079						is_media_displaying = true;
1080						//LLStringUtil::format_map_t args;
1081						
1082						media_plugin = media_impl->getMediaPlugin();
1083						if(media_plugin)
1084						{	
1085							if(media_plugin->pluginSupportsMediaTime())
1086							{
1087								is_time_based_media = true;
1088								is_web_based_media = false;
1089								//args["[CurrentURL]"] =  media_impl->getMediaURL();
1090								is_media_playing = media_impl->isMediaPlaying();
1091							}
1092							else
1093							{
1094								is_time_based_media = false;
1095								is_web_based_media = true;
1096								//args["[CurrentURL]"] =  media_plugin->getLocation();
1097							}
1098							//tooltip_msg.append(LLTrans::getString("CurrentURL", args));
1099						}
1100					}
1101				}
1102			}
1103			
1104
1105			// Avoid showing tip over media that's displaying unless it's for sale
1106			// also check the primary node since sometimes it can have an action even though
1107			// the root node doesn't
1108			
1109			bool needs_tip = (!is_media_displaying || 
1110				              for_sale) &&
1111				(has_media || 
1112				 needs_tooltip(nodep) || 
1113				 needs_tooltip(LLSelectMgr::getInstance()->getPrimaryHoverNode()));
1114			
1115			if (show_all_object_tips || needs_tip)
1116			{
1117				// We may select this object, so pretend it was clicked
1118				mPick = mHoverPick;
1119				LLInspector::Params p;
1120				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
1121				p.message(tooltip_msg);
1122				p.image.name("Inspector_I");
1123				p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
1124				p.time_based_media(is_time_based_media);
1125				p.web_based_media(is_web_based_media);
1126				p.media_playing(is_media_playing);
1127				p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
1128				p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
1129				p.visible_time_near(6.f);
1130				p.visible_time_far(3.f);
1131				p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
1132				p.wrap(false);
1133				
1134				LLToolTipMgr::instance().show(p);
1135			}
1136		}
1137	}
1138	
1139	return TRUE;
1140}
1141
1142BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask)
1143{
1144	if (!LLUI::sSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE;
1145	if (!mHoverPick.isValid()) return TRUE;
1146
1147	LLViewerObject* hover_object = mHoverPick.getObject();
1148	
1149	// update hover object and hover parcel
1150	LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace);
1151	
1152	
1153	std::string tooltip_msg;
1154	std::string line;
1155
1156	if ( hover_object )
1157	{
1158		handleTooltipObject(hover_object, line, tooltip_msg  );
1159	}
1160	else if (mHoverPick.mPickType == LLPickInfo::PICK_LAND)
1161	{
1162		handleTooltipLand(line, tooltip_msg);
1163	}
1164
1165	return TRUE;
1166}
1167
1168static void show_inspector(const char* inspector, const char* param, const LLUUID& source_id)
1169{
1170	LLSD params;
1171	params[param] = source_id;
1172	if (LLToolTipMgr::instance().toolTipVisible())
1173	{
1174		LLRect rect = LLToolTipMgr::instance().getToolTipRect();
1175		params["pos"]["x"] = rect.mLeft;
1176		params["pos"]["y"] = rect.mTop;
1177	}
1178
1179	LLFloaterReg::showInstance(inspector, params);
1180}
1181
1182
1183static void show_inspector(const char* inspector,  LLSD& params)
1184{
1185	if (LLToolTipMgr::instance().toolTipVisible())
1186	{
1187		LLRect rect = LLToolTipMgr::instance().getToolTipRect();
1188		params["pos"]["x"] = rect.mLeft;
1189		params["pos"]["y"] = rect.mTop;
1190	}
1191	
1192	LLFloaterReg::showInstance(inspector, params);
1193}
1194
1195
1196// static
1197void LLToolPie::showAvatarInspector(const LLUUID& avatar_id)
1198{
1199	show_inspector("inspect_avatar", "avatar_id", avatar_id);
1200}
1201
1202// static
1203void LLToolPie::showObjectInspector(const LLUUID& object_id)
1204{
1205	show_inspector("inspect_object", "object_id", object_id);
1206}
1207
1208
1209// static
1210void LLToolPie::showObjectInspector(const LLUUID& object_id, const S32& object_face)
1211{
1212	LLSD params;
1213	params["object_id"] = object_id;
1214	params["object_face"] = object_face;
1215	show_inspector("inspect_object", params);
1216}
1217
1218// static
1219void LLToolPie::playCurrentMedia(const LLPickInfo& info)
1220{
1221	//FIXME: how do we handle object in different parcel than us?
1222	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1223	if (!parcel) return;
1224	
1225	LLPointer<LLViewerObject> objectp = info.getObject();
1226	
1227	// Early out cases.  Must clear media hover. 
1228	// did not hit an object or did not hit a valid face
1229	if ( objectp.isNull() ||
1230		info.mObjectFace < 0 || 
1231		info.mObjectFace >= objectp->getNumTEs() )
1232	{
1233		return;
1234	}
1235	
1236	// Does this face have media?
1237	const LLTextureEntry* tep = objectp->getTE(info.mObjectFace);
1238	if (!tep)
1239		return;
1240	
1241	const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
1242	if(!mep)
1243		return;
1244	
1245	//TODO: Can you Use it? 
1246
1247	LLPluginClassMedia* media_plugin = NULL;
1248	
1249	viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
1250		
1251	if(media_impl.notNull() && media_impl->hasMedia())
1252	{
1253		media_plugin = media_impl->getMediaPlugin();
1254		if (media_plugin && media_plugin->pluginSupportsMediaTime())
1255		{
1256			if(media_impl->isMediaPlaying())
1257			{
1258				media_impl->pause();
1259			}
1260			else 
1261			{
1262				media_impl->play();
1263			}
1264		}
1265	}
1266
1267
1268}
1269
1270// static
1271void LLToolPie::VisitHomePage(const LLPickInfo& info)
1272{
1273	//FIXME: how do we handle object in different parcel than us?
1274	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1275	if (!parcel) return;
1276	
1277	LLPointer<LLViewerObject> objectp = info.getObject();
1278	
1279	// Early out cases.  Must clear media hover. 
1280	// did not hit an object or did not hit a valid face
1281	if ( objectp.isNull() ||
1282		info.mObjectFace < 0 || 
1283		info.mObjectFace >= objectp->getNumTEs() )
1284	{
1285		return;
1286	}
1287	
1288	// Does this face have media?
1289	const LLTextureEntry* tep = objectp->getTE(info.mObjectFace);
1290	if (!tep)
1291		return;
1292	
1293	const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
1294	if(!mep)
1295		return;
1296	
1297	//TODO: Can you Use it? 
1298	
1299	LLPluginClassMedia* media_plugin = NULL;
1300	
1301	viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
1302	
1303	if(media_impl.notNull() && media_impl->hasMedia())
1304	{
1305		media_plugin = media_impl->getMediaPlugin();
1306		
1307		if (media_plugin && !(media_plugin->pluginSupportsMediaTime()))
1308		{
1309			media_impl->navigateHome();
1310		}
1311	}
1312}
1313
1314void LLToolPie::handleSelect()
1315{
1316	// tool is reselected when app gets focus, etc.
1317	mBlockClickToWalk = true;	
1318}
1319
1320void LLToolPie::handleDeselect()
1321{
1322	if(	hasMouseCapture() )
1323	{
1324		setMouseCapture( FALSE );  // Calls onMouseCaptureLost() indirectly
1325	}
1326	// remove temporary selection for pie menu
1327	LLSelectMgr::getInstance()->setHoverObject(NULL);
1328	LLSelectMgr::getInstance()->validateSelection();
1329}
1330
1331LLTool* LLToolPie::getOverrideTool(MASK mask)
1332{
1333	if (gSavedSettings.getBOOL("EnableGrab"))
1334	{
1335		if (mask == MASK_CONTROL)
1336		{
1337			return LLToolGrab::getInstance();
1338		}
1339		else if (mask == (MASK_CONTROL | MASK_SHIFT))
1340		{
1341			return LLToolGrab::getInstance();
1342		}
1343	}
1344	return LLTool::getOverrideTool(mask);
1345}
1346
1347void LLToolPie::stopEditing()
1348{
1349	if(	hasMouseCapture() )
1350	{
1351		setMouseCapture( FALSE );  // Calls onMouseCaptureLost() indirectly
1352	}
1353}
1354
1355void LLToolPie::onMouseCaptureLost()
1356{
1357	stopCameraSteering();
1358	mMouseButtonDown = false;
1359	handleMediaMouseUp();
1360}
1361
1362void LLToolPie::stopCameraSteering()
1363{
1364	mMouseOutsideSlop = false;
1365}
1366
1367bool LLToolPie::inCameraSteerMode()
1368{
1369	return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
1370}
1371
1372// true if x,y outside small box around start_x,start_y
1373BOOL LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
1374{
1375	S32 dx = x - start_x;
1376	S32 dy = y - start_y;
1377
1378	return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
1379}
1380
1381
1382void LLToolPie::render()
1383{
1384	return;
1385}
1386
1387static void handle_click_action_play()
1388{
1389	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1390	if (!parcel) return;
1391
1392	LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus();
1393	switch(status)
1394	{
1395		case LLViewerMediaImpl::MEDIA_PLAYING:
1396			LLViewerParcelMedia::pause();
1397			break;
1398
1399		case LLViewerMediaImpl::MEDIA_PAUSED:
1400			LLViewerParcelMedia::start();
1401			break;
1402
1403		default:
1404			LLViewerParcelMedia::play(parcel);
1405			break;
1406	}
1407}
1408
1409bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
1410{
1411	//FIXME: how do we handle object in different parcel than us?
1412	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1413	LLPointer<LLViewerObject> objectp = pick.getObject();
1414
1415
1416	if (!parcel ||
1417		objectp.isNull() ||
1418		pick.mObjectFace < 0 || 
1419		pick.mObjectFace >= objectp->getNumTEs()) 
1420	{
1421		LLViewerMediaFocus::getInstance()->clearFocus();
1422
1423		return false;
1424	}
1425
1426	// Does this face have media?
1427	const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
1428	if(!tep)
1429		return false;
1430
1431	LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
1432	if(!mep)
1433		return false;
1434	
1435	viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
1436
1437	if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
1438	{
1439		if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
1440		{
1441			// It's okay to give this a null impl
1442			LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
1443		}
1444		else
1445		{
1446			// Make sure keyboard focus is set to the media focus object.
1447			gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
1448			LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
1449			
1450			media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE));
1451			mMediaMouseCaptureID = mep->getMediaID();
1452			setMouseCapture(TRUE);  // This object will send a mouse-up to the media when it loses capture.
1453		}
1454
1455		return true;
1456	}
1457
1458	LLViewerMediaFocus::getInstance()->clearFocus();
1459
1460	return false;
1461}
1462
1463bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
1464{
1465	//FIXME: how do we handle object in different parcel than us?
1466	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1467	if (!parcel) return false;
1468
1469	LLPointer<LLViewerObject> objectp = pick.getObject();
1470
1471	// Early out cases.  Must clear media hover. 
1472	// did not hit an object or did not hit a valid face
1473	if ( objectp.isNull() ||
1474		pick.mObjectFace < 0 || 
1475		pick.mObjectFace >= objectp->getNumTEs() )
1476	{
1477		LLViewerMediaFocus::getInstance()->clearHover();
1478		return false;
1479	}
1480
1481	// Does this face have media?
1482	const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
1483	if(!tep)
1484		return false;
1485	
1486	const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
1487	if (mep
1488		&& gSavedSettings.getBOOL("MediaOnAPrimUI"))
1489	{		
1490		viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
1491		
1492		if(media_impl.notNull())
1493		{
1494			// Update media hover object
1495			if (!LLViewerMediaFocus::getInstance()->isHoveringOverFace(objectp, pick.mObjectFace))
1496			{
1497				LLViewerMediaFocus::getInstance()->setHoverFace(objectp, pick.mObjectFace, media_impl, pick.mNormal);
1498			}
1499			
1500			// If this is the focused media face, send mouse move events.
1501			if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
1502			{
1503				media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(TRUE));
1504				gViewerWindow->setCursor(media_impl->getLastSetCursor());
1505			}
1506			else
1507			{
1508				// This is not the focused face -- set the default cursor.
1509				gViewerWindow->setCursor(UI_CURSOR_ARROW);
1510			}
1511
1512			return true;
1513		}
1514	}
1515	
1516	// In all other cases, clear media hover.
1517	LLViewerMediaFocus::getInstance()->clearHover();
1518
1519	return false;
1520}
1521
1522bool LLToolPie::handleMediaMouseUp()
1523{
1524	bool result = false;
1525	if(mMediaMouseCaptureID.notNull())
1526	{
1527		// Face media needs to know the mouse went up.
1528		viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mMediaMouseCaptureID);
1529		if(media_impl)
1530		{
1531			// This will send a mouseUp event to the plugin using the last known mouse coordinate (from a mouseDown or mouseMove), which is what we want.
1532			media_impl->onMouseCaptureLost();
1533		}
1534		
1535		mMediaMouseCaptureID.setNull();	
1536
1537		result = true;		
1538	}	
1539	
1540	return result;
1541}
1542
1543static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp)
1544{
1545	//FIXME: how do we handle object in different parcel than us?
1546	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1547	if (!parcel) return;
1548
1549	// did we hit an object?
1550	if (objectp.isNull()) return;
1551
1552	// did we hit a valid face on the object?
1553	S32 face = LLToolPie::getInstance()->getPick().mObjectFace;
1554	if( face < 0 || face >= objectp->getNumTEs() ) return;
1555		
1556	// is media playing on this face?
1557	if (LLViewerMedia::getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL)
1558	{
1559		handle_click_action_play();
1560		return;
1561	}
1562
1563	std::string media_url = std::string ( parcel->getMediaURL () );
1564	std::string media_type = std::string ( parcel->getMediaType() );
1565	LLStringUtil::trim(media_url);
1566
1567	LLWeb::loadURL(media_url);
1568}
1569
1570static ECursorType cursor_from_parcel_media(U8 click_action)
1571{
1572	// HACK: This is directly referencing an impl name.  BAD!
1573	// This can be removed when we have a truly generic media browser that only 
1574	// builds an impl based on the type of url it is passed.
1575	
1576	//FIXME: how do we handle object in different parcel than us?
1577	ECursorType open_cursor = UI_CURSOR_ARROW;
1578	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
1579	if (!parcel) return open_cursor;
1580
1581	std::string media_url = std::string ( parcel->getMediaURL () );
1582	std::string media_type = std::string ( parcel->getMediaType() );
1583	LLStringUtil::trim(media_url);
1584
1585	open_cursor = UI_CURSOR_TOOLMEDIAOPEN;
1586
1587	LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus();
1588	switch(status)
1589	{
1590		case LLViewerMediaImpl::MEDIA_PLAYING:
1591			return click_action == CLICK_ACTION_PLAY ? UI_CURSOR_TOOLPAUSE : open_cursor;
1592		default:
1593			return UI_CURSOR_TOOLPLAY;
1594	}
1595}
1596
1597
1598// True if we handled the event.
1599BOOL LLToolPie::handleRightClickPick()
1600{
1601	S32 x = mPick.mMousePt.mX;
1602	S32 y = mPick.mMousePt.mY;
1603	MASK mask = mPick.mKeyMask;
1604
1605	if (mPick.mPickType != LLPickInfo::PICK_LAND)
1606	{
1607		LLViewerParcelMgr::getInstance()->deselectLand();
1608	}
1609
1610	// didn't click in any UI object, so must have clicked in the world
1611	LLViewerObject *object = mPick.getObject();
1612	LLViewerObject *parent = NULL;
1613	if(object)
1614		parent = object->getRootEdit();
1615	
1616	// Can't ignore children here.
1617	LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
1618
1619	// Spawn pie menu
1620	if (mPick.mPickType == LLPickInfo::PICK_LAND)
1621	{
1622		LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal );
1623		gMenuHolder->setParcelSelection(selection);
1624		gMenuLand->show(x, y);
1625
1626		showVisualContextMenuEffect();
1627
1628	}
1629	else if (mPick.mObjectID == gAgent.getID() )
1630	{
1631		if(!gMenuAvatarSelf) 
1632		{
1633			//either at very early startup stage or at late quitting stage,
1634			//this event is ignored.
1635			return TRUE ;
1636		}
1637
1638		gMenuAvatarSelf->show(x, y);
1639	}
1640	else if (object)
1641	{
1642		gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
1643
1644		bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner());
1645		if (object->isAvatar() 
1646			|| is_other_attachment)
1647		{
1648			// Find the attachment's avatar
1649			while( object && object->isAttachment())
1650			{
1651				object = (LLViewerObject*)object->getParent();
1652				llassert(object);
1653			}
1654
1655			if (!object)
1656			{
1657				return TRUE; // unexpected, but escape
1658			}
1659
1660			// Object is an avatar, so check for mute by id.
1661			LLVOAvatar* avatar = (LLVOAvatar*)object;
1662			std::string name = avatar->getFullname();
1663			std::string mute_msg;
1664			if (LLMuteList::getInstance()->isMuted(avatar->getID(), avatar->getFullname()))
1665			{
1666				mute_msg = LLTrans::getString("UnmuteAvatar");
1667			}
1668			else
1669			{
1670				mute_msg = LLTrans::getString("MuteAvatar");
1671			}
1672
1673			if (is_other_attachment)
1674			{
1675				gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
1676				gMenuAttachmentOther->show(x, y);
1677			}
1678			else
1679			{
1680				gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
1681				gMenuAvatarOther->show(x, y);
1682			}
1683		}
1684		else if (object->isAttachment())
1685		{
1686			gMenuAttachmentSelf->show(x, y);
1687		}
1688		else
1689		{
1690			// BUG: What about chatting child objects?
1691			std::string name;
1692			LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
1693			if (node)
1694			{
1695				name = node->mName;
1696			}
1697			std::string mute_msg;
1698			if (LLMuteList::getInstance()->isMuted(object->getID(), name))
1699			{
1700				mute_msg = LLTrans::getString("UnmuteObject");
1701			}
1702			else
1703			{
1704				mute_msg = LLTrans::getString("MuteObject2");
1705			}
1706			
1707			gMenuHolder->getChild<LLUICtrl>("Object Mute")->setValue(mute_msg);
1708			gMenuObject->show(x, y);
1709
1710			showVisualContextMenuEffect();
1711		}
1712	}
1713
1714	LLTool::handleRightMouseDown(x, y, mask);
1715	// We handled the event.
1716	return TRUE;
1717}
1718
1719void LLToolPie::showVisualContextMenuEffect()
1720{
1721	// VEFFECT: ShowPie
1722	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
1723	effectp->setPositionGlobal(mPick.mPosGlobal);
1724	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1725	effectp->setDuration(0.25f);
1726}
1727
1728typedef enum e_near_far
1729{
1730	NEAR_INTERSECTION,
1731	FAR_INTERSECTION
1732} ENearFar;
1733
1734bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, e_near_far near_far, LLVector3& intersection_pt)
1735{
1736	// do ray/sphere intersection by solving quadratic equation
1737	LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center;
1738	F32 B = 2.f * ray_dir * sphere_to_ray_start_vec;
1739	F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
1740
1741	F32 discriminant = B*B - 4.f*C;
1742	if (discriminant >= 0.f)
1743	{	// intersection detected, now find closest one
1744		F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
1745
1746		if (t0 > 0.f && near_far == NEAR_INTERSECTION)
1747		{
1748			intersection_pt = ray_pt + ray_dir * t0;
1749		}
1750		else
1751		{
1752			F32 t1 = (-B + sqrtf(discriminant)) / 2.f;
1753			intersection_pt = ray_pt + ray_dir * t1;
1754		}
1755		return true;
1756	}
1757	else
1758	{	// no intersection
1759		return false;
1760	}
1761}
1762
1763void LLToolPie::startCameraSteering()
1764{
1765	LLFirstUse::notMoving(false);
1766	mMouseOutsideSlop = true;
1767	mBlockClickToWalk = true;
1768
1769	if (gAgentCamera.getFocusOnAvatar())
1770	{
1771		mSteerPick = mPick;
1772
1773		// handle special cases of steering picks
1774		LLViewerObject* avatar_object = mSteerPick.getObject();
1775
1776		// get pointer to avatar
1777		while (avatar_object && !avatar_object->isAvatar())
1778		{
1779			avatar_object = (LLViewerObject*)avatar_object->getParent();
1780		}
1781
1782		// if clicking on own avatar...
1783		if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
1784		{
1785			// ...project pick point a few meters in front of avatar
1786			mSteerPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * 3.0;
1787		}
1788
1789		if (!mSteerPick.isValid())
1790		{
1791			mSteerPick.mPosGlobal = gAgent.getPosGlobalFromAgent(
1792				LLViewerCamera::instance().getOrigin() + gViewerWindow->mouseDirectionGlobal(mSteerPick.mMousePt.mX, mSteerPick.mMousePt.mY) * 100.f);
1793		}
1794
1795		setMouseCapture(TRUE);
1796		
1797		mMouseSteerX = mMouseDownX;
1798		mMouseSteerY = mMouseDownY;
1799		const LLVector3 camera_to_rotation_center	= gAgent.getFrameAgent().getOrigin() - LLViewerCamera::instance().getOrigin();
1800		const LLVector3 rotation_center_to_pick		= gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal) - gAgent.getFrameAgent().getOrigin();
1801
1802		mClockwise = camera_to_rotation_center * rotation_center_to_pick < 0.f;
1803		if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); }
1804		mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
1805		mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal);
1806		mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190));
1807		mMouseSteerGrabPoint->setPixelSize(5);
1808		mMouseSteerGrabPoint->setDuration(2.f);
1809	}
1810}
1811
1812void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
1813{
1814	const LLViewerCamera& camera = LLViewerCamera::instance();
1815	const LLCoordFrame& rotation_frame = gAgent.getFrameAgent();
1816	const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal);
1817	const LLVector3 pick_rotation_center = rotation_frame.getOrigin() + parallel_component(pick_pos - rotation_frame.getOrigin(), rotation_frame.getUpAxis());
1818	const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f;
1819	const F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(pick_rotation_center, camera.getOrigin());;
1820	const F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, pick_rotation_center), min_rotation_radius, F32_MAX);
1821	const LLVector3 camera_to_rotation_center = pick_rotation_center - camera.getOrigin();
1822	const LLVector3 adjusted_camera_pos = LLViewerCamera::instance().getOrigin() + projected_vec(camera_to_rotation_center, rotation_

Large files files are truncated, but you can click here to view the full file