diff options
| author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
|---|---|---|
| committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
| commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
| tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/lltoolpie.cpp | |
| parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
| parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) | |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/lltoolpie.cpp')
| -rw-r--r-- | indra/newview/lltoolpie.cpp | 4071 |
1 files changed, 2036 insertions, 2035 deletions
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 884b619208..7fbdadbf12 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -1,2035 +1,2036 @@ -/** - * @file lltoolpie.cpp - * @brief LLToolPie class implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lltoolpie.h" - -#include "indra_constants.h" -#include "llclickaction.h" -#include "llparcel.h" - -#include "llagent.h" -#include "llagentcamera.h" -#include "llavatarnamecache.h" -#include "llfocusmgr.h" -#include "llfirstuse.h" -#include "llfloaterland.h" -#include "llfloaterreg.h" -#include "llfloaterscriptdebug.h" -#include "lltooltip.h" -#include "llhudeffecttrail.h" -#include "llhudicon.h" -#include "llhudmanager.h" -#include "llkeyboard.h" -#include "llmediaentry.h" -#include "llmenugl.h" -#include "llmutelist.h" -#include "llresmgr.h" // getMonetaryString -#include "llselectmgr.h" -#include "lltoolfocus.h" -#include "lltoolgrab.h" -#include "lltoolmgr.h" -#include "lltoolselect.h" -#include "lltrans.h" -#include "llviewercamera.h" -#include "llviewerparcelmedia.h" -#include "llviewercontrol.h" -#include "llviewermenu.h" -#include "llviewerobjectlist.h" -#include "llviewerobject.h" -#include "llviewerparcelmgr.h" -#include "llviewerwindow.h" -#include "llviewerinput.h" -#include "llviewermedia.h" -#include "llvoavatarself.h" -#include "llviewermediafocus.h" -#include "llworld.h" -#include "llui.h" -#include "llweb.h" -#include "pipeline.h" // setHighlightObject -#include "lluiusage.h" - -extern bool gDebugClicks; - -static void handle_click_action_play(); -static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp); -static ECursorType cursor_from_parcel_media(U8 click_action); - -LLToolPie::LLToolPie() -: LLTool(std::string("Pie")), - mMouseButtonDown( false ), - mMouseOutsideSlop( false ), - mMouseSteerX(-1), - mMouseSteerY(-1), - mClickAction(0), - mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), - mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ), - mDoubleClickTimer() -{ -} - -bool LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down) -{ - bool result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); - - // This override DISABLES the keyboard focus reset that LLTool::handleAnyMouseClick adds. - // LLToolPie will do the right thing in its pick callback. - - return result; -} - -bool LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mDoubleClickTimer.getStarted()) - { - mDoubleClickTimer.stop(); - } - - mMouseOutsideSlop = false; - mMouseDownX = x; - mMouseDownY = y; - LLTimer pick_timer; - bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - LLPickInfo transparent_pick = gViewerWindow->pickImmediate(x, y, true /*includes transparent*/, pick_rigged, false, true, false); - LLPickInfo visible_pick = gViewerWindow->pickImmediate(x, y, false, pick_rigged); - LLViewerObject *transp_object = transparent_pick.getObject(); - LLViewerObject *visible_object = visible_pick.getObject(); - - // Current set of priorities - // 1. Transparent attachment pick - // 2. Transparent actionable pick - // 3. Visible attachment pick (e.x we click on attachment under invisible floor) - // 4. Visible actionable pick - // 5. Transparent pick (e.x. movement on transparent object/floor, our default pick) - // left mouse down always picks transparent (but see handleMouseUp). - // Also see LLToolPie::handleHover() - priorities are a bit different there. - // Todo: we need a more consistent set of rules to work with - if (transp_object == visible_object || !visible_object || - !transp_object) // avoid potential for null dereference below, don't make assumptions about behavior of pickImmediate - { - mPick = transparent_pick; - } - else - { - // Select between two non-null picks - LLViewerObject *transp_parent = transp_object->getRootEdit(); - LLViewerObject *visible_parent = visible_object->getRootEdit(); - if (transp_object->isAttachment()) - { - // 1. Transparent attachment - mPick = transparent_pick; - } - else if (transp_object->getClickAction() != CLICK_ACTION_DISABLED - && (useClickAction(mask, transp_object, transp_parent) || transp_object->flagHandleTouch() || (transp_parent && transp_parent->flagHandleTouch()))) - { - // 2. Transparent actionable pick - mPick = transparent_pick; - } - else if (visible_object->isAttachment()) - { - // 3. Visible attachment pick - mPick = visible_pick; - } - else if (visible_object->getClickAction() != CLICK_ACTION_DISABLED - && (useClickAction(mask, visible_object, visible_parent) || visible_object->flagHandleTouch() || (visible_parent && visible_parent->flagHandleTouch()))) - { - // 4. Visible actionable pick - mPick = visible_pick; - } - else - { - // 5. Default: transparent - mPick = transparent_pick; - } - } - LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL; - - mPick.mKeyMask = mask; - - mMouseButtonDown = true; - - // If nothing clickable is picked, needs to return - // false for click-to-walk or click-to-teleport to work. - return handleLeftClickPick(); -} - -// Spawn context menus on right mouse down so you can drag over and select -// an item. -bool LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - bool pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes"); - - // don't pick transparent so users can't "pay" transparent objects - mPick = gViewerWindow->pickImmediate(x, y, - /*bool pick_transparent*/ false, - /*bool pick_rigged*/ true, - /*bool pick_particle*/ true, - /*bool pick_unselectable*/ true, - pick_reflection_probe); - mPick.mKeyMask = mask; - - // claim not handled so UI focus stays same - if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - handleRightClickPick(); - } - return false; -} - -bool LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask) -{ - LLToolMgr::getInstance()->clearTransientTool(); - return LLTool::handleRightMouseUp(x, y, mask); -} - -bool LLToolPie::handleScrollWheelAny(S32 x, S32 y, S32 clicks_x, S32 clicks_y) -{ - bool res = false; - // mHoverPick should have updated on its own and we should have a face - // in LLViewerMediaFocus in case of media, so just reuse mHoverPick - if (mHoverPick.mUVCoords.mV[VX] >= 0.f && mHoverPick.mUVCoords.mV[VY] >= 0.f) - { - res = LLViewerMediaFocus::getInstance()->handleScrollWheel(mHoverPick.mUVCoords, clicks_x, clicks_y); - } - else - { - // this won't provide correct coordinates in case of object selection - res = LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks_x, clicks_y); - } - return res; -} - -bool LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - return handleScrollWheelAny(x, y, 0, clicks); -} - -bool LLToolPie::handleScrollHWheel(S32 x, S32 y, S32 clicks) -{ - return handleScrollWheelAny(x, y, clicks, 0); -} - -// True if you selected an object. -bool LLToolPie::handleLeftClickPick() -{ - S32 x = mPick.mMousePt.mX; - S32 y = mPick.mMousePt.mY; - MASK mask = mPick.mKeyMask; - if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL) - { - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel(); - if (parcel) - { - LLViewerParcelMgr::getInstance()->selectCollisionParcel(); - if (parcel->getParcelFlag(PF_USE_PASS_LIST) - && !LLViewerParcelMgr::getInstance()->isCollisionBanned()) - { - // if selling passes, just buy one - void* deselect_when_done = (void*)true; - LLPanelLandGeneral::onClickBuyPass(deselect_when_done); - } - else - { - // not selling passes, get info - LLFloaterReg::showInstance("about_land"); - } - } - - gFocusMgr.setKeyboardFocus(NULL); - return LLTool::handleMouseDown(x, y, mask); - } - - // didn't click in any UI object, so must have clicked in the world - LLViewerObject *object = mPick.getObject(); - LLViewerObject *parent = NULL; - - if (mPick.mPickType != LLPickInfo::PICK_LAND) - { - LLViewerParcelMgr::getInstance()->deselectLand(); - } - - if (object) - { - parent = object->getRootEdit(); - } - - if (handleMediaClick(mPick)) - { - return true; - } - - // If it's a left-click, and we have a special action, do it. - if (useClickAction(mask, object, parent)) - { - mClickAction = 0; - if (object && object->getClickAction()) - { - mClickAction = object->getClickAction(); - } - else if (parent && parent->getClickAction()) - { - mClickAction = parent->getClickAction(); - } - - switch(mClickAction) - { - case CLICK_ACTION_TOUCH: - // touch behavior down below... - break; - case CLICK_ACTION_SIT: - { - if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // agent not already sitting - { - handle_object_sit_or_stand(); - // put focus in world when sitting on an object - gFocusMgr.setKeyboardFocus(NULL); - return true; - } // else nothing (fall through to touch) - } - case CLICK_ACTION_PAY: - if ( mClickActionPayEnabled ) - { - if ((object && object->flagTakesMoney()) - || (parent && parent->flagTakesMoney())) - { - // pay event goes to object actually clicked on - mClickActionObject = object; - mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true); - if (LLSelectMgr::getInstance()->selectGetAllValid()) - { - // call this right away, since we have all the info we need to continue the action - selectionPropertiesReceived(); - } - return true; - } - } - break; - case CLICK_ACTION_BUY: - if ( mClickActionBuyEnabled ) - { - mClickActionObject = parent; - mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true, true); - if (LLSelectMgr::getInstance()->selectGetAllValid()) - { - // call this right away, since we have all the info we need to continue the action - selectionPropertiesReceived(); - } - return true; - } - break; - case CLICK_ACTION_OPEN: - if (parent && parent->allowOpen()) - { - mClickActionObject = parent; - mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true, true); - if (LLSelectMgr::getInstance()->selectGetAllValid()) - { - // call this right away, since we have all the info we need to continue the action - selectionPropertiesReceived(); - } - } - return true; - case CLICK_ACTION_PLAY: - handle_click_action_play(); - return true; - case CLICK_ACTION_OPEN_MEDIA: - // mClickActionObject = object; - handle_click_action_open_media(object); - return true; - case CLICK_ACTION_ZOOM: - { - const F32 PADDING_FACTOR = 2.f; - LLViewerObject* object = gObjectList.findObject(mPick.mObjectID); - - if (object) - { - gAgentCamera.setFocusOnAvatar(false, ANIMATE); - - LLBBox bbox = object->getBoundingBoxAgent() ; - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); - obj_to_cam.normVec(); - - LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); - gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), - object_center_global, - mPick.mObjectID ); - } - } - return true; - case CLICK_ACTION_DISABLED: - return true; - default: - // nothing - break; - } - } - - // put focus back "in world" - if (gFocusMgr.getKeyboardFocus()) - { - gFocusMgr.setKeyboardFocus(NULL); - } - - bool touchable = object - && (object->getClickAction() != CLICK_ACTION_DISABLED) - && (object->flagHandleTouch() || (parent && parent->flagHandleTouch())); - - // Switch to grab tool if physical or triggerable - if (object && - !object->isAvatar() && - ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) - ) - { - gGrabTransientTool = this; - mMouseButtonDown = false; - LLToolGrab::getInstance()->setClickedInMouselook(gAgentCamera.cameraMouselook()); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() ); - return LLToolGrab::getInstance()->handleObjectHit( mPick ); - } - - LLHUDIcon* last_hit_hud_icon = mPick.mHUDIcon; - if (!object && last_hit_hud_icon && last_hit_hud_icon->getSourceObject()) - { - LLFloaterScriptDebug::show(last_hit_hud_icon->getSourceObject()->getID()); - } - - // If left-click never selects or spawns a menu - // Eat the event. - - // mouse already released - if (!mMouseButtonDown) - { - return true; - } - - while (object && object->isAttachment() && !object->flagHandleTouch()) - { - // don't pick avatar through hud attachment - if (object->isHUDAttachment()) - { - break; - } - object = (LLViewerObject*)object->getParent(); - } - if (object && object == gAgentAvatarp) - { - // we left clicked on avatar, switch to focus mode - mMouseButtonDown = false; - LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance()); - gViewerWindow->hideCursor(); - LLToolCamera::getInstance()->setMouseCapture(true); - LLToolCamera::getInstance()->setClickPickPending(); - LLToolCamera::getInstance()->pickCallback(mPick); - gAgentCamera.setFocusOnAvatar(true, true); - - return true; - } - ////////// - // // Could be first left-click on nothing - // LLFirstUse::useLeftClickNoHit(); - ///////// - - return LLTool::handleMouseDown(x, y, mask); -} - -bool LLToolPie::useClickAction(MASK mask, - LLViewerObject* object, - LLViewerObject* parent) -{ - return mask == MASK_NONE - && object - && !object->isAttachment() - && LLPrimitive::isPrimitive(object->getPCode()) - // useClickAction does not handle Touch (0) or Disabled action - && ((object->getClickAction() && object->getClickAction() != CLICK_ACTION_DISABLED) - || (parent && parent->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED)); - -} - -U8 final_click_action(LLViewerObject* obj) -{ - if (!obj) return CLICK_ACTION_NONE; - if (obj->isAttachment()) return CLICK_ACTION_NONE; - - U8 click_action = CLICK_ACTION_TOUCH; - LLViewerObject* parent = obj->getRootEdit(); - U8 object_action = obj->getClickAction(); - U8 parent_action = parent ? parent->getClickAction() : CLICK_ACTION_TOUCH; - if (parent_action == CLICK_ACTION_DISABLED || object_action) - { - // CLICK_ACTION_DISABLED ("None" in UI) is intended for child action to - // override parent's action when assigned to parent or to child - click_action = object_action; - } - else if (parent_action) - { - click_action = parent_action; - } - return click_action; -} - -ECursorType LLToolPie::cursorFromObject(LLViewerObject* object) -{ - LLViewerObject* parent = NULL; - if (object) - { - parent = object->getRootEdit(); - } - U8 click_action = final_click_action(object); - ECursorType cursor = UI_CURSOR_ARROW; - switch(click_action) - { - case CLICK_ACTION_SIT: - { - if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting? - { - cursor = UI_CURSOR_TOOLSIT; - } - } - break; - case CLICK_ACTION_BUY: - if ( mClickActionBuyEnabled ) - { - LLSelectNode* node = LLSelectMgr::getInstance()->getHoverNode(); - if (!node || node->mSaleInfo.isForSale()) - { - cursor = UI_CURSOR_TOOLBUY; - } - } - break; - case CLICK_ACTION_OPEN: - // Open always opens the parent. - if (parent && parent->allowOpen()) - { - cursor = UI_CURSOR_TOOLOPEN; - } - break; - case CLICK_ACTION_PAY: - if ( mClickActionPayEnabled ) - { - if ((object && object->flagTakesMoney()) - || (parent && parent->flagTakesMoney())) - { - cursor = UI_CURSOR_TOOLBUY; - } - } - break; - case CLICK_ACTION_ZOOM: - cursor = UI_CURSOR_TOOLZOOMIN; - break; - case CLICK_ACTION_PLAY: - case CLICK_ACTION_OPEN_MEDIA: - cursor = cursor_from_parcel_media(click_action); - break; - case CLICK_ACTION_DISABLED: - break; - default: - break; - } - return cursor; -} - -void LLToolPie::resetSelection() -{ - mLeftClickSelection = NULL; - mClickActionObject = NULL; - mClickAction = 0; -} - -bool LLToolPie::walkToClickedLocation() -{ - if (gAgent.getFlying() // don't auto-navigate while flying until that works - || !gAgentAvatarp - || gAgentAvatarp->isSitting()) - { - return false; - } - - LLUIUsage::instance().logCommand("Agent.WalkToClickedLocation"); - - LLPickInfo saved_pick = mPick; - if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY, - false /* ignore transparent */, - false /* ignore rigged */, - false /* ignore particles */); - } - else - { - // We do not handle hover in mouselook as we do in other modes, so - // use croshair's position to do a pick - mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2, - gViewerWindow->getWorldViewRectScaled().getHeight() / 2, - false /* ignore transparent */, - false /* ignore rigged */, - false /* ignore particles */); - } - - if (mPick.mPickType == LLPickInfo::PICK_OBJECT) - { - if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) - { - mPick = saved_pick; - return false; - } - } - - LLViewerObject* avatar_object = mPick.getObject(); - - // get pointer to avatar - while (avatar_object && !avatar_object->isAvatar()) - { - avatar_object = (LLViewerObject*)avatar_object->getParent(); - } - - if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf()) - { - const F64 SELF_CLICK_WALK_DISTANCE = 3.0; - // pretend we picked some point a bit in front of avatar - mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; - } - - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { - gAgentCamera.setFocusOnAvatar(true, true); - - if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); } - mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, false); - mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); - mAutoPilotDestination->setPixelSize(5); - mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); - mAutoPilotDestination->setDuration(3.f); - - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, false); - LLFirstUse::notMoving(false); - showVisualContextMenuEffect(); - return true; - } - else - { - LL_DEBUGS() << "walk target was " - << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero") - << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land") - << ", pick object was " << mPick.mObjectID - << LL_ENDL; - mPick = saved_pick; - return false; - } -} - -bool LLToolPie::teleportToClickedLocation() -{ - if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) - { - // We do not handle hover in mouselook as we do in other modes, so - // use croshair's position to do a pick - bool pick_rigged = false; - mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2, - gViewerWindow->getWorldViewRectScaled().getHeight() / 2, - false, - pick_rigged); - } - LLViewerObject* objp = mHoverPick.getObject(); - LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; - - if (objp && (objp->getAvatar() == gAgentAvatarp || objp == gAgentAvatarp)) // ex: nametag - { - // Don't teleport to self, teleporting to other avatars is fine - return false; - } - - bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); - bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND; - bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero(); - bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); - U8 click_action = final_click_action(objp); // default action: 0 - touch - bool has_click_action = (click_action || has_touch_handler) && click_action != CLICK_ACTION_DISABLED; - - if (pos_non_zero && (is_land || (is_in_world && !has_click_action))) - { - LLVector3d pos = mHoverPick.mPosGlobal; - pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); - gAgent.teleportViaLocationLookAt(pos); - mPick = mHoverPick; - showVisualContextMenuEffect(); - return true; - } - return false; -} - -// When we get object properties after left-clicking on an object -// with left-click = buy, if it's the same object, do the buy. - -// static -void LLToolPie::selectionPropertiesReceived() -{ - // Make sure all data has been received. - // This function will be called repeatedly as the data comes in. - if (!LLSelectMgr::getInstance()->selectGetAllValid()) - { - return; - } - - LLObjectSelection* selection = LLToolPie::getInstance()->getLeftClickSelection(); - if (selection) - { - LLViewerObject* selected_object = selection->getPrimaryObject(); - // since we don't currently have a way to lock a selection, it could have changed - // after we initially clicked on the object - if (selected_object == LLToolPie::getInstance()->getClickActionObject()) - { - U8 click_action = LLToolPie::getInstance()->getClickAction(); - switch (click_action) - { - case CLICK_ACTION_BUY: - if ( LLToolPie::getInstance()->mClickActionBuyEnabled ) - { - handle_buy(); - } - break; - case CLICK_ACTION_PAY: - if ( LLToolPie::getInstance()->mClickActionPayEnabled ) - { - handle_give_money_dialog(); - } - break; - case CLICK_ACTION_OPEN: - LLFloaterReg::showInstance("openobject"); - break; - case CLICK_ACTION_DISABLED: - break; - default: - break; - } - } - } - LLToolPie::getInstance()->resetSelection(); -} - -bool LLToolPie::handleHover(S32 x, S32 y, MASK mask) -{ - bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - mHoverPick = gViewerWindow->pickImmediate(x, y, false, pick_rigged); - LLViewerObject *parent = NULL; - LLViewerObject *object = mHoverPick.getObject(); - LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace); - if (object) - { - parent = object->getRootEdit(); - } - - if (!handleMediaHover(mHoverPick) - && !mMouseOutsideSlop - && mMouseButtonDown - // disable camera steering if click on land is not used for moving - && gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON)) - { - S32 delta_x = x - mMouseDownX; - S32 delta_y = y - mMouseDownY; - S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold"); - if (delta_x * delta_x + delta_y * delta_y > threshold * threshold) - { - startCameraSteering(); - steerCameraWithMouse(x, y); - gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_ARROW); - } - } - else if (inCameraSteerMode()) - { - steerCameraWithMouse(x, y); - gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); - } - else - { - // perform a separate pick that detects transparent objects since they respond to 1-click actions - LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, false, pick_rigged); - - LLViewerObject* click_action_object = click_action_pick.getObject(); - - if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit())) - { - ECursorType cursor = cursorFromObject(click_action_object); - gViewerWindow->setCursor(cursor); - LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; - } - - else if ((object && !object->isAvatar() && object->flagUsePhysics()) - || (parent && !parent->isAvatar() && parent->flagUsePhysics())) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); - LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; - } - else if ((!object || object->getClickAction() != CLICK_ACTION_DISABLED) - && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) - && (!object || !object->isAvatar())) - { - gViewerWindow->setCursor(UI_CURSOR_HAND); - LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; - } - else - { - gViewerWindow->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; - } - } - - if(!object) - { - LLViewerMediaFocus::getInstance()->clearHover(); - } - - return true; -} - -bool LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) -{ - if (!mDoubleClickTimer.getStarted()) - { - mDoubleClickTimer.start(); - } - else - { - mDoubleClickTimer.reset(); - } - LLViewerObject* obj = mPick.getObject(); - - stopCameraSteering(); - mMouseButtonDown = false; - - gViewerWindow->setCursor(UI_CURSOR_ARROW); - if (hasMouseCapture()) - { - setMouseCapture(false); - } - - LLToolMgr::getInstance()->clearTransientTool(); - gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on - - return LLTool::handleMouseUp(x, y, mask); -} - -void LLToolPie::stopClickToWalk() -{ - mPick.mPosGlobal = gAgent.getPositionGlobal(); - handle_go_to(); - if(mAutoPilotDestination) - { - mAutoPilotDestination->markDead(); - } -} - -bool LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - if (gDebugClicks) - { - LL_INFOS() << "LLToolPie handleDoubleClick (becoming mouseDown)" << LL_ENDL; - } - - if (handleMediaDblClick(mPick)) - { - return true; - } - - if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)) - { - mDoubleClickTimer.stop(); - return false; - } - mDoubleClickTimer.stop(); - - return false; -} - -static bool needs_tooltip(LLSelectNode* nodep) -{ - if (!nodep || !nodep->mValid) - return false; - return true; -} - - -bool LLToolPie::handleTooltipLand(std::string line, std::string tooltip_msg) -{ - // Do not show hover for land unless prefs are set to allow it. - if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return true; - - LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal ); - - // Didn't hit an object, but since we have a land point we - // must be hovering over land. - - LLParcel* hover_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel(); - LLUUID owner; - - if ( hover_parcel ) - { - owner = hover_parcel->getOwnerID(); - } - - // Line: "Land" - line.clear(); - line.append(LLTrans::getString("TooltipLand")); - if (hover_parcel) - { - line.append(hover_parcel->getName()); - } - tooltip_msg.append(line); - tooltip_msg.push_back('\n'); - - // Line: "Owner: James Linden" - line.clear(); - line.append(LLTrans::getString("TooltipOwner") + " "); - - if ( hover_parcel ) - { - std::string name; - if (LLUUID::null == owner) - { - line.append(LLTrans::getString("TooltipPublic")); - } - else if (hover_parcel->getIsGroupOwned()) - { - if (gCacheName->getGroupName(owner, name)) - { - line.append(name); - line.append(LLTrans::getString("TooltipIsGroup")); - } - else - { - line.append(LLTrans::getString("RetrievingData")); - } - } - else - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(owner, &av_name)) - { - name = av_name.getUserName(); - line.append(name); - } - else - { - line.append(LLTrans::getString("RetrievingData")); - } - } - } - else - { - line.append(LLTrans::getString("RetrievingData")); - } - tooltip_msg.append(line); - tooltip_msg.push_back('\n'); - - // Line: "no fly, not safe, no build" - - // Don't display properties for your land. This is just - // confusing, because you can do anything on your own land. - if ( hover_parcel && owner != gAgent.getID() ) - { - S32 words = 0; - - line.clear(); - // JC - Keep this in the same order as the checkboxes - // on the land info panel - if ( !hover_parcel->getAllowModify() ) - { - if ( hover_parcel->getAllowGroupModify() ) - { - line.append(LLTrans::getString("TooltipFlagGroupBuild")); - } - else - { - line.append(LLTrans::getString("TooltipFlagNoBuild")); - } - words++; - } - - if ( !hover_parcel->getAllowTerraform() ) - { - if (words) line.append(", "); - line.append(LLTrans::getString("TooltipFlagNoEdit")); - words++; - } - - if ( hover_parcel->getAllowDamage() ) - { - if (words) line.append(", "); - line.append(LLTrans::getString("TooltipFlagNotSafe")); - words++; - } - - // Maybe we should reflect the estate's block fly bit here as well? DK 12/1/04 - if ( !hover_parcel->getAllowFly() ) - { - if (words) line.append(", "); - line.append(LLTrans::getString("TooltipFlagNoFly")); - words++; - } - - if ( !hover_parcel->getAllowOtherScripts() ) - { - if (words) line.append(", "); - if ( hover_parcel->getAllowGroupScripts() ) - { - line.append(LLTrans::getString("TooltipFlagGroupScripts")); - } - else - { - line.append(LLTrans::getString("TooltipFlagNoScripts")); - } - - words++; - } - - if (words) - { - tooltip_msg.append(line); - tooltip_msg.push_back('\n'); - } - } - - if (hover_parcel && hover_parcel->getParcelFlag(PF_FOR_SALE)) - { - LLStringUtil::format_map_t args; - S32 price = hover_parcel->getSalePrice(); - args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price); - line = LLTrans::getString("TooltipForSaleL$", args); - tooltip_msg.append(line); - tooltip_msg.push_back('\n'); - } - - // trim last newlines - if (!tooltip_msg.empty()) - { - tooltip_msg.erase(tooltip_msg.size() - 1); - LLToolTipMgr::instance().show(tooltip_msg); - } - - return true; -} - -bool LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg) -{ - if ( hover_object->isHUDAttachment() ) - { - // no hover tips for HUD elements, since they can obscure - // what the HUD is displaying - return true; - } - - if ( hover_object->isAttachment() ) - { - // get root of attachment then parent, which is avatar - LLViewerObject* root_edit = hover_object->getRootEdit(); - if (!root_edit) - { - // Strange parenting issue, don't show any text - return true; - } - hover_object = (LLViewerObject*)root_edit->getParent(); - if (!hover_object) - { - // another strange parenting issue, bail out - return true; - } - } - - line.clear(); - if (hover_object->isAvatar()) - { - // only show tooltip if same inspector not already open - LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar"); - if (!existing_inspector - || !existing_inspector->getVisible() - || existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID()) - { - // Try to get display name + username - std::string final_name; - LLAvatarName av_name; - if (LLAvatarNameCache::get(hover_object->getID(), &av_name)) - { - final_name = av_name.getCompleteName(); - } - else - { - final_name = LLTrans::getString("TooltipPerson");; - } - - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(final_name); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); - } - } - else - { - // - // We have hit a regular object (not an avatar or attachment) - // - - // - // Default prefs will suppress display unless the object is interactive - // - bool show_all_object_tips = - (bool)gSavedSettings.getBOOL("ShowAllObjectHoverTip"); - LLSelectNode *nodep = LLSelectMgr::getInstance()->getHoverNode(); - - // only show tooltip if same inspector not already open - LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_object"); - if (nodep && - (!existing_inspector - || !existing_inspector->getVisible() - || existing_inspector->getKey()["object_id"].asUUID() != hover_object->getID())) - { - - // Add price to tooltip for items on sale - bool for_sale = for_sale_selection(nodep); - if(for_sale) - { - LLStringUtil::format_map_t args; - S32 price = nodep->mSaleInfo.getSalePrice(); - args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price); - tooltip_msg.append(LLTrans::getString("TooltipPrice", args) ); - } - - if (nodep->mName.empty()) - { - tooltip_msg.append(LLTrans::getString("TooltipNoName")); - } - else - { - tooltip_msg.append( nodep->mName ); - } - - bool has_media = false; - bool is_time_based_media = false; - bool is_web_based_media = false; - bool is_media_playing = false; - bool is_media_displaying = false; - - // Does this face have media? - const LLTextureEntry* tep = hover_object->getTE(mHoverPick.mObjectFace); - - if(tep) - { - has_media = tep->hasMedia(); - const LLMediaEntry* mep = has_media ? tep->getMediaData() : NULL; - if (mep) - { - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - LLPluginClassMedia* media_plugin = NULL; - - if (media_impl.notNull() && (media_impl->hasMedia())) - { - is_media_displaying = true; - //LLStringUtil::format_map_t args; - - media_plugin = media_impl->getMediaPlugin(); - if(media_plugin) - { - if(media_plugin->pluginSupportsMediaTime()) - { - is_time_based_media = true; - is_web_based_media = false; - //args["[CurrentURL]"] = media_impl->getMediaURL(); - is_media_playing = media_impl->isMediaPlaying(); - } - else - { - is_time_based_media = false; - is_web_based_media = true; - //args["[CurrentURL]"] = media_plugin->getLocation(); - } - //tooltip_msg.append(LLTrans::getString("CurrentURL", args)); - } - } - } - } - - - // Avoid showing tip over media that's displaying unless it's for sale - // also check the primary node since sometimes it can have an action even though - // the root node doesn't - - bool needs_tip = (!is_media_displaying || - for_sale) && - (has_media || - needs_tooltip(nodep) || - needs_tooltip(LLSelectMgr::getInstance()->getPrimaryHoverNode())); - - if (show_all_object_tips || needs_tip) - { - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(tooltip_msg); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace)); - p.time_based_media(is_time_based_media); - p.web_based_media(is_web_based_media); - p.media_playing(is_media_playing); - p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick)); - p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick)); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); - } - } - } - - return true; -} - -bool LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) -{ - static LLCachedControl<bool> show_hover_tips(*LLUI::getInstance()->mSettingGroups["config"], "ShowHoverTips", true); - if (!show_hover_tips) return true; - if (!mHoverPick.isValid()) return true; - - LLViewerObject* hover_object = mHoverPick.getObject(); - - // update hover object and hover parcel - LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace); - - - std::string tooltip_msg; - std::string line; - - if ( hover_object ) - { - handleTooltipObject(hover_object, line, tooltip_msg ); - } - else if (mHoverPick.mPickType == LLPickInfo::PICK_LAND) - { - handleTooltipLand(line, tooltip_msg); - } - - return true; -} - -static void show_inspector(const char* inspector, const char* param, const LLUUID& source_id) -{ - LLSD params; - params[param] = source_id; - if (LLToolTipMgr::instance().toolTipVisible()) - { - LLRect rect = LLToolTipMgr::instance().getToolTipRect(); - params["pos"]["x"] = rect.mLeft; - params["pos"]["y"] = rect.mTop; - } - - LLFloaterReg::showInstance(inspector, params); -} - - -static void show_inspector(const char* inspector, LLSD& params) -{ - if (LLToolTipMgr::instance().toolTipVisible()) - { - LLRect rect = LLToolTipMgr::instance().getToolTipRect(); - params["pos"]["x"] = rect.mLeft; - params["pos"]["y"] = rect.mTop; - } - - LLFloaterReg::showInstance(inspector, params); -} - - -// static -void LLToolPie::showAvatarInspector(const LLUUID& avatar_id) -{ - show_inspector("inspect_avatar", "avatar_id", avatar_id); -} - -// static -void LLToolPie::showObjectInspector(const LLUUID& object_id) -{ - show_inspector("inspect_object", "object_id", object_id); -} - - -// static -void LLToolPie::showObjectInspector(const LLUUID& object_id, const S32& object_face) -{ - LLSD params; - params["object_id"] = object_id; - params["object_face"] = object_face; - show_inspector("inspect_object", params); -} - -// static -void LLToolPie::playCurrentMedia(const LLPickInfo& info) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return; - - LLPointer<LLViewerObject> objectp = info.getObject(); - - // Early out cases. Must clear media hover. - // did not hit an object or did not hit a valid face - if ( objectp.isNull() || - info.mObjectFace < 0 || - info.mObjectFace >= objectp->getNumTEs() ) - { - return; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(info.mObjectFace); - if (!tep) - return; - - const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; - if(!mep) - return; - - //TODO: Can you Use it? - - LLPluginClassMedia* media_plugin = NULL; - - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - - if(media_impl.notNull() && media_impl->hasMedia()) - { - media_plugin = media_impl->getMediaPlugin(); - if (media_plugin && media_plugin->pluginSupportsMediaTime()) - { - if(media_impl->isMediaPlaying()) - { - media_impl->pause(); - } - else - { - media_impl->play(); - } - } - } - - -} - -// static -void LLToolPie::VisitHomePage(const LLPickInfo& info) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return; - - LLPointer<LLViewerObject> objectp = info.getObject(); - - // Early out cases. Must clear media hover. - // did not hit an object or did not hit a valid face - if ( objectp.isNull() || - info.mObjectFace < 0 || - info.mObjectFace >= objectp->getNumTEs() ) - { - return; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(info.mObjectFace); - if (!tep) - return; - - const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; - if(!mep) - return; - - //TODO: Can you Use it? - - LLPluginClassMedia* media_plugin = NULL; - - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - - if(media_impl.notNull() && media_impl->hasMedia()) - { - media_plugin = media_impl->getMediaPlugin(); - - if (media_plugin && !(media_plugin->pluginSupportsMediaTime())) - { - media_impl->navigateHome(); - } - } -} - -void LLToolPie::handleSelect() -{ - // tool is reselected when app gets focus, etc. -} - -void LLToolPie::handleDeselect() -{ - if( hasMouseCapture() ) - { - setMouseCapture( false ); // Calls onMouseCaptureLost() indirectly - } - // remove temporary selection for pie menu - LLSelectMgr::getInstance()->setHoverObject(NULL); - - // Menu may be still up during transfer to different tool. - // toolfocus and toolgrab should retain menu, they will clear it if needed - MASK override_mask = gKeyboard ? gKeyboard->currentMask(true) : 0; - if (gMenuHolder && (!gMenuHolder->getVisible() || (override_mask & (MASK_ALT | MASK_CONTROL)) == 0)) - { - // in most cases menu is useless without correct selection, so either keep both or discard both - gMenuHolder->hideMenus(); - LLSelectMgr::getInstance()->validateSelection(); - } -} - -LLTool* LLToolPie::getOverrideTool(MASK mask) -{ - if (gSavedSettings.getBOOL("EnableGrab")) - { - if (mask == DEFAULT_GRAB_MASK) - { - return LLToolGrab::getInstance(); - } - else if (mask == (MASK_CONTROL | MASK_SHIFT)) - { - return LLToolGrab::getInstance(); - } - } - return LLTool::getOverrideTool(mask); -} - -void LLToolPie::stopEditing() -{ - if( hasMouseCapture() ) - { - setMouseCapture( false ); // Calls onMouseCaptureLost() indirectly - } -} - -void LLToolPie::onMouseCaptureLost() -{ - stopCameraSteering(); - mMouseButtonDown = false; - handleMediaMouseUp(); -} - -void LLToolPie::stopCameraSteering() -{ - mMouseOutsideSlop = false; -} - -bool LLToolPie::inCameraSteerMode() -{ - return mMouseButtonDown && mMouseOutsideSlop; -} - -// true if x,y outside small box around start_x,start_y -bool LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y) -{ - S32 dx = x - start_x; - S32 dy = y - start_y; - - return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy); -} - - -void LLToolPie::render() -{ - return; -} - -static void handle_click_action_play() -{ - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return; - - LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus(); - switch(status) - { - case LLViewerMediaImpl::MEDIA_PLAYING: - LLViewerParcelMedia::getInstance()->pause(); - break; - - case LLViewerMediaImpl::MEDIA_PAUSED: - LLViewerParcelMedia::getInstance()->start(); - break; - - default: - LLViewerParcelMedia::getInstance()->play(parcel); - break; - } -} - -bool LLToolPie::handleMediaClick(const LLPickInfo& pick) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - LLPointer<LLViewerObject> objectp = pick.getObject(); - - - if (!parcel || - objectp.isNull() || - pick.mObjectFace < 0 || - pick.mObjectFace >= objectp->getNumTEs()) - { - LLViewerMediaFocus::getInstance()->clearFocus(); - - return false; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - if (!tep) - return false; - - LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; - if (!mep) - return false; - - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - - if (gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull()) - { - // It's okay to give this a null impl - LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); - } - else - { - // Make sure keyboard focus is set to the media focus object. - gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); - LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl(); - - media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(true)); - mMediaMouseCaptureID = mep->getMediaID(); - setMouseCapture(true); // This object will send a mouse-up to the media when it loses capture. - } - - return true; - } - - LLViewerMediaFocus::getInstance()->clearFocus(); - - return false; -} - -bool LLToolPie::handleMediaDblClick(const LLPickInfo& pick) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - LLPointer<LLViewerObject> objectp = pick.getObject(); - - - if (!parcel || - objectp.isNull() || - pick.mObjectFace < 0 || - pick.mObjectFace >= objectp->getNumTEs()) - { - LLViewerMediaFocus::getInstance()->clearFocus(); - - return false; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - if (!tep) - return false; - - LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; - if (!mep) - return false; - - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - - if (gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull()) - { - // It's okay to give this a null impl - LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); - } - else - { - // Make sure keyboard focus is set to the media focus object. - gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); - LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl(); - - media_impl->mouseDoubleClick(pick.mUVCoords, gKeyboard->currentMask(true)); - mMediaMouseCaptureID = mep->getMediaID(); - setMouseCapture(true); // This object will send a mouse-up to the media when it loses capture. - } - - return true; - } - - LLViewerMediaFocus::getInstance()->clearFocus(); - - return false; -} - -bool LLToolPie::handleMediaHover(const LLPickInfo& pick) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return false; - - LLPointer<LLViewerObject> objectp = pick.getObject(); - - // Early out cases. Must clear media hover. - // did not hit an object or did not hit a valid face - if ( objectp.isNull() || - pick.mObjectFace < 0 || - pick.mObjectFace >= objectp->getNumTEs() ) - { - LLViewerMediaFocus::getInstance()->clearHover(); - return false; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - if(!tep) - return false; - - const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; - if (mep - && gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); - - if(media_impl.notNull()) - { - // Update media hover object - if (!LLViewerMediaFocus::getInstance()->isHoveringOverFace(objectp, pick.mObjectFace)) - { - LLViewerMediaFocus::getInstance()->setHoverFace(objectp, pick.mObjectFace, media_impl, pick.mNormal); - } - - // If this is the focused media face, send mouse move events. - if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace)) - { - media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(true)); - gViewerWindow->setCursor(media_impl->getLastSetCursor()); - } - else - { - // This is not the focused face -- set the default cursor. - gViewerWindow->setCursor(UI_CURSOR_ARROW); - } - - return true; - } - } - - // In all other cases, clear media hover. - LLViewerMediaFocus::getInstance()->clearHover(); - - return false; -} - -bool LLToolPie::handleMediaMouseUp() -{ - bool result = false; - if(mMediaMouseCaptureID.notNull()) - { - // Face media needs to know the mouse went up. - viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaMouseCaptureID); - if(media_impl) - { - // 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. - media_impl->onMouseCaptureLost(); - } - - mMediaMouseCaptureID.setNull(); - - result = true; - } - - return result; -} - -static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) -{ - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return; - - // did we hit an object? - if (objectp.isNull()) return; - - // did we hit a valid face on the object? - S32 face = LLToolPie::getInstance()->getPick().mObjectFace; - if( face < 0 || face >= objectp->getNumTEs() ) return; - - // is media playing on this face? - if (LLViewerMedia::getInstance()->getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL) - { - handle_click_action_play(); - return; - } - - std::string media_url = std::string ( parcel->getMediaURL () ); - std::string media_type = std::string ( parcel->getMediaType() ); - LLStringUtil::trim(media_url); - - LLWeb::loadURL(media_url); -} - -static ECursorType cursor_from_parcel_media(U8 click_action) -{ - // HACK: This is directly referencing an impl name. BAD! - // This can be removed when we have a truly generic media browser that only - // builds an impl based on the type of url it is passed. - - //FIXME: how do we handle object in different parcel than us? - ECursorType open_cursor = UI_CURSOR_ARROW; - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) return open_cursor; - - std::string media_url = std::string ( parcel->getMediaURL () ); - std::string media_type = std::string ( parcel->getMediaType() ); - LLStringUtil::trim(media_url); - - open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - - LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus(); - switch(status) - { - case LLViewerMediaImpl::MEDIA_PLAYING: - return click_action == CLICK_ACTION_PLAY ? UI_CURSOR_TOOLPAUSE : open_cursor; - default: - return UI_CURSOR_TOOLPLAY; - } -} - - -// True if we handled the event. -bool LLToolPie::handleRightClickPick() -{ - S32 x = mPick.mMousePt.mX; - S32 y = mPick.mMousePt.mY; - MASK mask = mPick.mKeyMask; - - if (mPick.mPickType != LLPickInfo::PICK_LAND) - { - LLViewerParcelMgr::getInstance()->deselectLand(); - } - - // didn't click in any UI object, so must have clicked in the world - LLViewerObject *object = mPick.getObject(); - - // Can't ignore children here. - LLToolSelect::handleObjectSelection(mPick, false, true); - - // Spawn pie menu - if (mPick.mPickType == LLPickInfo::PICK_LAND) - { - LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal ); - gMenuHolder->setParcelSelection(selection); - gMenuLand->show(x, y); - - showVisualContextMenuEffect(); - - } - else if (mPick.mObjectID == gAgent.getID() ) - { - if(!gMenuAvatarSelf) - { - //either at very early startup stage or at late quitting stage, - //this event is ignored. - return true ; - } - - gMenuAvatarSelf->show(x, y); - } - else if (object) - { - gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - - bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner()); - if (object->isAvatar() || is_other_attachment) - { - // Find the attachment's avatar - while( object && object->isAttachment()) - { - object = (LLViewerObject*)object->getParent(); - llassert(object); - } - - if (!object) - { - return true; // unexpected, but escape - } - - // Object is an avatar, so check for mute by id. - LLVOAvatar* avatar = (LLVOAvatar*)object; - std::string name = avatar->getFullname(); - std::string mute_msg; - if (LLMuteList::getInstance()->isMuted(avatar->getID(), avatar->getFullname())) - { - mute_msg = LLTrans::getString("UnmuteAvatar"); - } - else - { - mute_msg = LLTrans::getString("MuteAvatar"); - } - - if (is_other_attachment) - { - gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAttachmentOther->show(x, y); - } - else - { - gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAvatarOther->show(x, y); - } - } - else if (object->isAttachment()) - { - gMenuAttachmentSelf->show(x, y); - } - else - { - // BUG: What about chatting child objects? - std::string name; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - - gMenuObject->show(x, y); - - showVisualContextMenuEffect(); - } - } - else if (mPick.mParticleOwnerID.notNull()) - { - if (gMenuMuteParticle && mPick.mParticleOwnerID != gAgent.getID()) - { - gMenuMuteParticle->show(x,y); - } - } - - // non UI object - put focus back "in world" - if (gFocusMgr.getKeyboardFocus()) - { - gFocusMgr.setKeyboardFocus(NULL); - } - - LLTool::handleRightMouseDown(x, y, mask); - // We handled the event. - return true; -} - -void LLToolPie::showVisualContextMenuEffect() -{ - // VEFFECT: ShowPie - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, true); - effectp->setPositionGlobal(mPick.mPosGlobal); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - effectp->setDuration(0.25f); -} - -typedef enum e_near_far -{ - NEAR_INTERSECTION, - FAR_INTERSECTION -} ENearFar; - -bool 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) -{ - // do ray/sphere intersection by solving quadratic equation - LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center; - F32 B = 2.f * ray_dir * sphere_to_ray_start_vec; - F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius); - - F32 discriminant = B*B - 4.f*C; - if (discriminant >= 0.f) - { // intersection detected, now find closest one - F32 t0 = (-B - sqrtf(discriminant)) / 2.f; - - if (t0 > 0.f && near_far == NEAR_INTERSECTION) - { - intersection_pt = ray_pt + ray_dir * t0; - } - else - { - F32 t1 = (-B + sqrtf(discriminant)) / 2.f; - intersection_pt = ray_pt + ray_dir * t1; - } - return true; - } - else - { // no intersection - return false; - } -} - -void LLToolPie::startCameraSteering() -{ - LLFirstUse::notMoving(false); - mMouseOutsideSlop = true; - - if (gAgentCamera.getFocusOnAvatar()) - { - mSteerPick = mPick; - - // handle special cases of steering picks - LLViewerObject* avatar_object = mSteerPick.getObject(); - - // get pointer to avatar - while (avatar_object && !avatar_object->isAvatar()) - { - avatar_object = (LLViewerObject*)avatar_object->getParent(); - } - - // if clicking on own avatar... - if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf()) - { - // ...project pick point a few meters in front of avatar - mSteerPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * 3.0; - } - - if (!mSteerPick.isValid()) - { - mSteerPick.mPosGlobal = gAgent.getPosGlobalFromAgent( - LLViewerCamera::instance().getOrigin() + gViewerWindow->mouseDirectionGlobal(mSteerPick.mMousePt.mX, mSteerPick.mMousePt.mY) * 100.f); - } - - setMouseCapture(true); - - mMouseSteerX = mMouseDownX; - mMouseSteerY = mMouseDownY; - const LLVector3 camera_to_rotation_center = gAgent.getFrameAgent().getOrigin() - LLViewerCamera::instance().getOrigin(); - const LLVector3 rotation_center_to_pick = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal) - gAgent.getFrameAgent().getOrigin(); - - mClockwise = camera_to_rotation_center * rotation_center_to_pick < 0.f; - if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); } - mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, false); - mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal); - mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190)); - mMouseSteerGrabPoint->setPixelSize(5); - mMouseSteerGrabPoint->setDuration(2.f); - } -} - -void LLToolPie::steerCameraWithMouse(S32 x, S32 y) -{ - const LLViewerCamera& camera = LLViewerCamera::instance(); - const LLCoordFrame& rotation_frame = gAgent.getFrameAgent(); - const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal); - const LLVector3 pick_rotation_center = rotation_frame.getOrigin() + parallel_component(pick_pos - rotation_frame.getOrigin(), rotation_frame.getUpAxis()); - const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f; - const F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(pick_rotation_center, camera.getOrigin());; - const F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, pick_rotation_center), min_rotation_radius, F32_MAX); - const LLVector3 camera_to_rotation_center = pick_rotation_center - camera.getOrigin(); - const LLVector3 adjusted_camera_pos = LLViewerCamera::instance().getOrigin() + projected_vec(camera_to_rotation_center, rotation_frame.getUpAxis()); - const F32 camera_distance_from_rotation_center = dist_vec(adjusted_camera_pos, pick_rotation_center); - - LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_frame.getUpAxis()); - mouse_ray.normalize(); - - LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_frame.getUpAxis()); - old_mouse_ray.normalize(); - - F32 yaw_angle; - F32 old_yaw_angle; - LLVector3 mouse_on_sphere; - LLVector3 old_mouse_on_sphere; - - if (intersect_ray_with_sphere( - adjusted_camera_pos, - mouse_ray, - pick_rotation_center, - pick_distance_from_rotation_center, - FAR_INTERSECTION, - mouse_on_sphere)) - { - LLVector3 mouse_sphere_offset = mouse_on_sphere - pick_rotation_center; - yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis()); - } - else - { - yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center); - if (mouse_ray * rotation_frame.getLeftAxis() < 0.f) - { - yaw_angle *= -1.f; - } - } - - if (intersect_ray_with_sphere( - adjusted_camera_pos, - old_mouse_ray, - pick_rotation_center, - pick_distance_from_rotation_center, - FAR_INTERSECTION, - old_mouse_on_sphere)) - { - LLVector3 mouse_sphere_offset = old_mouse_on_sphere - pick_rotation_center; - old_yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis()); - } - else - { - old_yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center); - - if (mouse_ray * rotation_frame.getLeftAxis() < 0.f) - { - old_yaw_angle *= -1.f; - } - } - - const F32 delta_angle = yaw_angle - old_yaw_angle; - - if (mClockwise) - { - gAgent.yaw(delta_angle); - } - else - { - gAgent.yaw(-delta_angle); - } - - mMouseSteerX = x; - mMouseSteerY = y; -} +/**
+ * @file lltoolpie.cpp
+ * @brief LLToolPie class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltoolpie.h"
+
+#include "indra_constants.h"
+#include "llclickaction.h"
+#include "llparcel.h"
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llavatarnamecache.h"
+#include "llfocusmgr.h"
+#include "llfirstuse.h"
+#include "llfloaterland.h"
+#include "llfloaterreg.h"
+#include "llfloaterscriptdebug.h"
+#include "lltooltip.h"
+#include "llhudeffecttrail.h"
+#include "llhudicon.h"
+#include "llhudmanager.h"
+#include "llkeyboard.h"
+#include "llmediaentry.h"
+#include "llmenugl.h"
+#include "llmutelist.h"
+#include "llresmgr.h" // getMonetaryString
+#include "llselectmgr.h"
+#include "lltoolfocus.h"
+#include "lltoolgrab.h"
+#include "lltoolmgr.h"
+#include "lltoolselect.h"
+#include "lltrans.h"
+#include "llviewercamera.h"
+#include "llviewerparcelmedia.h"
+#include "llviewercontrol.h"
+#include "llviewermenu.h"
+#include "llviewerobjectlist.h"
+#include "llviewerobject.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerwindow.h"
+#include "llviewerinput.h"
+#include "llviewermedia.h"
+#include "llvoavatarself.h"
+#include "llviewermediafocus.h"
+#include "llworld.h"
+#include "llui.h"
+#include "llweb.h"
+#include "pipeline.h" // setHighlightObject
+#include "lluiusage.h"
+
+extern bool gDebugClicks;
+
+static void handle_click_action_play();
+static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp);
+static ECursorType cursor_from_parcel_media(U8 click_action);
+
+LLToolPie::LLToolPie()
+: LLTool(std::string("Pie")),
+ mMouseButtonDown( false ),
+ mMouseOutsideSlop( false ),
+ mMouseSteerX(-1),
+ mMouseSteerY(-1),
+ mClickAction(0),
+ mClickActionBuyEnabled( true ),
+ mClickActionPayEnabled( true ),
+ mDoubleClickTimer()
+{
+}
+
+bool LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down)
+{
+ bool result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
+
+ // This override DISABLES the keyboard focus reset that LLTool::handleAnyMouseClick adds.
+ // LLToolPie will do the right thing in its pick callback.
+
+ return result;
+}
+
+bool LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (mDoubleClickTimer.getStarted())
+ {
+ mDoubleClickTimer.stop();
+ }
+
+ mMouseOutsideSlop = false;
+ mMouseDownX = x;
+ mMouseDownY = y;
+ LLTimer pick_timer;
+ bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ LLPickInfo transparent_pick = gViewerWindow->pickImmediate(x, y, true /*includes transparent*/, pick_rigged, false, true, false);
+ LLPickInfo visible_pick = gViewerWindow->pickImmediate(x, y, false, pick_rigged);
+ LLViewerObject *transp_object = transparent_pick.getObject();
+ LLViewerObject *visible_object = visible_pick.getObject();
+
+ // Current set of priorities
+ // 1. Transparent attachment pick
+ // 2. Transparent actionable pick
+ // 3. Visible attachment pick (e.x we click on attachment under invisible floor)
+ // 4. Visible actionable pick
+ // 5. Transparent pick (e.x. movement on transparent object/floor, our default pick)
+ // left mouse down always picks transparent (but see handleMouseUp).
+ // Also see LLToolPie::handleHover() - priorities are a bit different there.
+ // Todo: we need a more consistent set of rules to work with
+ if (transp_object == visible_object || !visible_object ||
+ !transp_object) // avoid potential for null dereference below, don't make assumptions about behavior of pickImmediate
+ {
+ mPick = transparent_pick;
+ }
+ else
+ {
+ // Select between two non-null picks
+ LLViewerObject *transp_parent = transp_object->getRootEdit();
+ LLViewerObject *visible_parent = visible_object->getRootEdit();
+ if (transp_object->isAttachment())
+ {
+ // 1. Transparent attachment
+ mPick = transparent_pick;
+ }
+ else if (transp_object->getClickAction() != CLICK_ACTION_DISABLED
+ && (useClickAction(mask, transp_object, transp_parent) || transp_object->flagHandleTouch() || (transp_parent && transp_parent->flagHandleTouch())))
+ {
+ // 2. Transparent actionable pick
+ mPick = transparent_pick;
+ }
+ else if (visible_object->isAttachment())
+ {
+ // 3. Visible attachment pick
+ mPick = visible_pick;
+ }
+ else if (visible_object->getClickAction() != CLICK_ACTION_DISABLED
+ && (useClickAction(mask, visible_object, visible_parent) || visible_object->flagHandleTouch() || (visible_parent && visible_parent->flagHandleTouch())))
+ {
+ // 4. Visible actionable pick
+ mPick = visible_pick;
+ }
+ else
+ {
+ // 5. Default: transparent
+ mPick = transparent_pick;
+ }
+ }
+ LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;
+
+ mPick.mKeyMask = mask;
+
+ mMouseButtonDown = true;
+
+ // If nothing clickable is picked, needs to return
+ // false for click-to-walk or click-to-teleport to work.
+ return handleLeftClickPick();
+}
+
+// Spawn context menus on right mouse down so you can drag over and select
+// an item.
+bool LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ bool pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes");
+
+ // don't pick transparent so users can't "pay" transparent objects
+ mPick = gViewerWindow->pickImmediate(x, y,
+ /*bool pick_transparent*/ false,
+ /*bool pick_rigged*/ true,
+ /*bool pick_particle*/ true,
+ /*bool pick_unselectable*/ true,
+ pick_reflection_probe);
+ mPick.mKeyMask = mask;
+
+ // claim not handled so UI focus stays same
+ if(gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+ {
+ handleRightClickPick();
+ }
+ return false;
+}
+
+bool LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+ LLToolMgr::getInstance()->clearTransientTool();
+ return LLTool::handleRightMouseUp(x, y, mask);
+}
+
+bool LLToolPie::handleScrollWheelAny(S32 x, S32 y, S32 clicks_x, S32 clicks_y)
+{
+ bool res = false;
+ // mHoverPick should have updated on its own and we should have a face
+ // in LLViewerMediaFocus in case of media, so just reuse mHoverPick
+ if (mHoverPick.mUVCoords.mV[VX] >= 0.f && mHoverPick.mUVCoords.mV[VY] >= 0.f)
+ {
+ res = LLViewerMediaFocus::getInstance()->handleScrollWheel(mHoverPick.mUVCoords, clicks_x, clicks_y);
+ }
+ else
+ {
+ // this won't provide correct coordinates in case of object selection
+ res = LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks_x, clicks_y);
+ }
+ return res;
+}
+
+bool LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ return handleScrollWheelAny(x, y, 0, clicks);
+}
+
+bool LLToolPie::handleScrollHWheel(S32 x, S32 y, S32 clicks)
+{
+ return handleScrollWheelAny(x, y, clicks, 0);
+}
+
+// True if you selected an object.
+bool LLToolPie::handleLeftClickPick()
+{
+ S32 x = mPick.mMousePt.mX;
+ S32 y = mPick.mMousePt.mY;
+ MASK mask = mPick.mKeyMask;
+ if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL)
+ {
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel();
+ if (parcel)
+ {
+ LLViewerParcelMgr::getInstance()->selectCollisionParcel();
+ if (parcel->getParcelFlag(PF_USE_PASS_LIST)
+ && !LLViewerParcelMgr::getInstance()->isCollisionBanned())
+ {
+ // if selling passes, just buy one
+ void* deselect_when_done = (void*)true;
+ LLPanelLandGeneral::onClickBuyPass(deselect_when_done);
+ }
+ else
+ {
+ // not selling passes, get info
+ LLFloaterReg::showInstance("about_land");
+ }
+ }
+
+ gFocusMgr.setKeyboardFocus(NULL);
+ return LLTool::handleMouseDown(x, y, mask);
+ }
+
+ // didn't click in any UI object, so must have clicked in the world
+ LLViewerObject *object = mPick.getObject();
+ LLViewerObject *parent = NULL;
+
+ if (mPick.mPickType != LLPickInfo::PICK_LAND)
+ {
+ LLViewerParcelMgr::getInstance()->deselectLand();
+ }
+
+ if (object)
+ {
+ parent = object->getRootEdit();
+ }
+
+ if (handleMediaClick(mPick))
+ {
+ return true;
+ }
+
+ // If it's a left-click, and we have a special action, do it.
+ if (useClickAction(mask, object, parent))
+ {
+ mClickAction = 0;
+ if (object && object->getClickAction())
+ {
+ mClickAction = object->getClickAction();
+ }
+ else if (parent && parent->getClickAction())
+ {
+ mClickAction = parent->getClickAction();
+ }
+
+ switch(mClickAction)
+ {
+ case CLICK_ACTION_TOUCH:
+ // touch behavior down below...
+ break;
+ case CLICK_ACTION_SIT:
+ {
+ if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // agent not already sitting
+ {
+ handle_object_sit_or_stand();
+ // put focus in world when sitting on an object
+ gFocusMgr.setKeyboardFocus(NULL);
+ return true;
+ } // else nothing (fall through to touch)
+ }
+ case CLICK_ACTION_PAY:
+ if ( mClickActionPayEnabled )
+ {
+ if ((object && object->flagTakesMoney())
+ || (parent && parent->flagTakesMoney()))
+ {
+ // pay event goes to object actually clicked on
+ mClickActionObject = object;
+ mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true);
+ if (LLSelectMgr::getInstance()->selectGetAllValid())
+ {
+ // call this right away, since we have all the info we need to continue the action
+ selectionPropertiesReceived();
+ }
+ return true;
+ }
+ }
+ break;
+ case CLICK_ACTION_BUY:
+ if ( mClickActionBuyEnabled )
+ {
+ mClickActionObject = parent;
+ mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true, true);
+ if (LLSelectMgr::getInstance()->selectGetAllValid())
+ {
+ // call this right away, since we have all the info we need to continue the action
+ selectionPropertiesReceived();
+ }
+ return true;
+ }
+ break;
+ case CLICK_ACTION_OPEN:
+ if (parent && parent->allowOpen())
+ {
+ mClickActionObject = parent;
+ mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, false, true, true);
+ if (LLSelectMgr::getInstance()->selectGetAllValid())
+ {
+ // call this right away, since we have all the info we need to continue the action
+ selectionPropertiesReceived();
+ }
+ }
+ return true;
+ case CLICK_ACTION_PLAY:
+ handle_click_action_play();
+ return true;
+ case CLICK_ACTION_OPEN_MEDIA:
+ // mClickActionObject = object;
+ handle_click_action_open_media(object);
+ return true;
+ case CLICK_ACTION_ZOOM:
+ {
+ const F32 PADDING_FACTOR = 2.f;
+ LLViewerObject* object = gObjectList.findObject(mPick.mObjectID);
+
+ if (object)
+ {
+ gAgentCamera.setFocusOnAvatar(false, ANIMATE);
+
+ LLBBox bbox = object->getBoundingBoxAgent() ;
+ F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
+ F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
+
+ LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent();
+ obj_to_cam.normVec();
+
+ LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
+ gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance),
+ object_center_global,
+ mPick.mObjectID );
+ }
+ }
+ return true;
+ case CLICK_ACTION_DISABLED:
+ return true;
+ default:
+ // nothing
+ break;
+ }
+ }
+
+ // put focus back "in world"
+ if (gFocusMgr.getKeyboardFocus())
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
+ bool touchable = object
+ && (object->getClickAction() != CLICK_ACTION_DISABLED)
+ && (object->flagHandleTouch() || (parent && parent->flagHandleTouch()));
+
+ // Switch to grab tool if physical or triggerable
+ if (object &&
+ !object->isAvatar() &&
+ ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable)
+ )
+ {
+ gGrabTransientTool = this;
+ mMouseButtonDown = false;
+ LLToolGrab::getInstance()->setClickedInMouselook(gAgentCamera.cameraMouselook());
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
+ return LLToolGrab::getInstance()->handleObjectHit( mPick );
+ }
+
+ LLHUDIcon* last_hit_hud_icon = mPick.mHUDIcon;
+ if (!object && last_hit_hud_icon && last_hit_hud_icon->getSourceObject())
+ {
+ LLFloaterScriptDebug::show(last_hit_hud_icon->getSourceObject()->getID());
+ }
+
+ // If left-click never selects or spawns a menu
+ // Eat the event.
+
+ // mouse already released
+ if (!mMouseButtonDown)
+ {
+ return true;
+ }
+
+ while (object && object->isAttachment() && !object->flagHandleTouch())
+ {
+ // don't pick avatar through hud attachment
+ if (object->isHUDAttachment())
+ {
+ break;
+ }
+ object = (LLViewerObject*)object->getParent();
+ }
+ if (object && object == gAgentAvatarp)
+ {
+ // we left clicked on avatar, switch to focus mode
+ mMouseButtonDown = false;
+ LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
+ gViewerWindow->hideCursor();
+ LLToolCamera::getInstance()->setMouseCapture(true);
+ LLToolCamera::getInstance()->setClickPickPending();
+ LLToolCamera::getInstance()->pickCallback(mPick);
+ gAgentCamera.setFocusOnAvatar(true, true);
+
+ return true;
+ }
+ //////////
+ // // Could be first left-click on nothing
+ // LLFirstUse::useLeftClickNoHit();
+ /////////
+
+ return LLTool::handleMouseDown(x, y, mask);
+}
+
+bool LLToolPie::useClickAction(MASK mask,
+ LLViewerObject* object,
+ LLViewerObject* parent)
+{
+ return mask == MASK_NONE
+ && object
+ && !object->isAttachment()
+ && LLPrimitive::isPrimitive(object->getPCode())
+ // useClickAction does not handle Touch (0) or Disabled action
+ && ((object->getClickAction() && object->getClickAction() != CLICK_ACTION_DISABLED)
+ || (parent && parent->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED));
+
+}
+
+U8 final_click_action(LLViewerObject* obj)
+{
+ if (!obj) return CLICK_ACTION_NONE;
+ if (obj->isAttachment()) return CLICK_ACTION_NONE;
+
+ U8 click_action = CLICK_ACTION_TOUCH;
+ LLViewerObject* parent = obj->getRootEdit();
+ U8 object_action = obj->getClickAction();
+ U8 parent_action = parent ? parent->getClickAction() : CLICK_ACTION_TOUCH;
+ if (parent_action == CLICK_ACTION_DISABLED || object_action)
+ {
+ // CLICK_ACTION_DISABLED ("None" in UI) is intended for child action to
+ // override parent's action when assigned to parent or to child
+ click_action = object_action;
+ }
+ else if (parent_action)
+ {
+ click_action = parent_action;
+ }
+ return click_action;
+}
+
+ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
+{
+ LLViewerObject* parent = NULL;
+ if (object)
+ {
+ parent = object->getRootEdit();
+ }
+ U8 click_action = final_click_action(object);
+ ECursorType cursor = UI_CURSOR_ARROW;
+ switch(click_action)
+ {
+ case CLICK_ACTION_SIT:
+ {
+ if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
+ {
+ cursor = UI_CURSOR_TOOLSIT;
+ }
+ }
+ break;
+ case CLICK_ACTION_BUY:
+ if ( mClickActionBuyEnabled )
+ {
+ LLSelectNode* node = LLSelectMgr::getInstance()->getHoverNode();
+ if (!node || node->mSaleInfo.isForSale())
+ {
+ cursor = UI_CURSOR_TOOLBUY;
+ }
+ }
+ break;
+ case CLICK_ACTION_OPEN:
+ // Open always opens the parent.
+ if (parent && parent->allowOpen())
+ {
+ cursor = UI_CURSOR_TOOLOPEN;
+ }
+ break;
+ case CLICK_ACTION_PAY:
+ if ( mClickActionPayEnabled )
+ {
+ if ((object && object->flagTakesMoney())
+ || (parent && parent->flagTakesMoney()))
+ {
+ cursor = UI_CURSOR_TOOLBUY;
+ }
+ }
+ break;
+ case CLICK_ACTION_ZOOM:
+ cursor = UI_CURSOR_TOOLZOOMIN;
+ break;
+ case CLICK_ACTION_PLAY:
+ case CLICK_ACTION_OPEN_MEDIA:
+ cursor = cursor_from_parcel_media(click_action);
+ break;
+ case CLICK_ACTION_DISABLED:
+ break;
+ default:
+ break;
+ }
+ return cursor;
+}
+
+void LLToolPie::resetSelection()
+{
+ mLeftClickSelection = NULL;
+ mClickActionObject = NULL;
+ mClickAction = 0;
+}
+
+bool LLToolPie::walkToClickedLocation()
+{
+ if (gAgent.getFlying() // don't auto-navigate while flying until that works
+ || !gAgentAvatarp
+ || gAgentAvatarp->isSitting())
+ {
+ return false;
+ }
+
+ LLUIUsage::instance().logCommand("Agent.WalkToClickedLocation");
+
+ LLPickInfo saved_pick = mPick;
+ if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+ {
+ mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
+ false /* ignore transparent */,
+ false /* ignore rigged */,
+ false /* ignore particles */);
+ }
+ else
+ {
+ // We do not handle hover in mouselook as we do in other modes, so
+ // use croshair's position to do a pick
+ mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+ gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+ false /* ignore transparent */,
+ false /* ignore rigged */,
+ false /* ignore particles */);
+ }
+
+ if (mPick.mPickType == LLPickInfo::PICK_OBJECT)
+ {
+ if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
+ {
+ mPick = saved_pick;
+ return false;
+ }
+ }
+
+ LLViewerObject* avatar_object = mPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
+ {
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+ // pretend we picked some point a bit in front of avatar
+ mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
+ }
+
+ if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+ (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
+ {
+ gAgentCamera.setFocusOnAvatar(true, true);
+
+ if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+ mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, false);
+ mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+ mAutoPilotDestination->setPixelSize(5);
+ mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
+ mAutoPilotDestination->setDuration(3.f);
+
+ LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+ gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, false);
+ LLFirstUse::notMoving(false);
+ showVisualContextMenuEffect();
+ return true;
+ }
+ else
+ {
+ LL_DEBUGS() << "walk target was "
+ << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
+ << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
+ << ", pick object was " << mPick.mObjectID
+ << LL_ENDL;
+ mPick = saved_pick;
+ return false;
+ }
+}
+
+bool LLToolPie::teleportToClickedLocation()
+{
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ // We do not handle hover in mouselook as we do in other modes, so
+ // use croshair's position to do a pick
+ bool pick_rigged = false;
+ mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+ gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+ false,
+ pick_rigged);
+ }
+ LLViewerObject* objp = mHoverPick.getObject();
+ LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
+
+ if (objp && (objp->getAvatar() == gAgentAvatarp || objp == gAgentAvatarp)) // ex: nametag
+ {
+ // Don't teleport to self, teleporting to other avatars is fine
+ return false;
+ }
+
+ bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
+ bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND;
+ bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero();
+ bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
+ U8 click_action = final_click_action(objp); // default action: 0 - touch
+ bool has_click_action = (click_action || has_touch_handler) && click_action != CLICK_ACTION_DISABLED;
+
+ if (pos_non_zero && (is_land || (is_in_world && !has_click_action)))
+ {
+ LLVector3d pos = mHoverPick.mPosGlobal;
+ pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
+ gAgent.teleportViaLocationLookAt(pos);
+ mPick = mHoverPick;
+ showVisualContextMenuEffect();
+ return true;
+ }
+ return false;
+}
+
+// When we get object properties after left-clicking on an object
+// with left-click = buy, if it's the same object, do the buy.
+
+// static
+void LLToolPie::selectionPropertiesReceived()
+{
+ // Make sure all data has been received.
+ // This function will be called repeatedly as the data comes in.
+ if (!LLSelectMgr::getInstance()->selectGetAllValid())
+ {
+ return;
+ }
+
+ LLObjectSelection* selection = LLToolPie::getInstance()->getLeftClickSelection();
+ if (selection)
+ {
+ LLViewerObject* selected_object = selection->getPrimaryObject();
+ // since we don't currently have a way to lock a selection, it could have changed
+ // after we initially clicked on the object
+ if (selected_object == LLToolPie::getInstance()->getClickActionObject())
+ {
+ U8 click_action = LLToolPie::getInstance()->getClickAction();
+ switch (click_action)
+ {
+ case CLICK_ACTION_BUY:
+ if ( LLToolPie::getInstance()->mClickActionBuyEnabled )
+ {
+ handle_buy();
+ }
+ break;
+ case CLICK_ACTION_PAY:
+ if ( LLToolPie::getInstance()->mClickActionPayEnabled )
+ {
+ handle_give_money_dialog();
+ }
+ break;
+ case CLICK_ACTION_OPEN:
+ LLFloaterReg::showInstance("openobject");
+ break;
+ case CLICK_ACTION_DISABLED:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ LLToolPie::getInstance()->resetSelection();
+}
+
+bool LLToolPie::handleHover(S32 x, S32 y, MASK mask)
+{
+ bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ mHoverPick = gViewerWindow->pickImmediate(x, y, false, pick_rigged);
+ LLViewerObject *parent = NULL;
+ LLViewerObject *object = mHoverPick.getObject();
+ LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace);
+ if (object)
+ {
+ parent = object->getRootEdit();
+ }
+
+ if (!handleMediaHover(mHoverPick)
+ && !mMouseOutsideSlop
+ && mMouseButtonDown
+ // disable camera steering if click on land is not used for moving
+ && gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON))
+ {
+ S32 delta_x = x - mMouseDownX;
+ S32 delta_y = y - mMouseDownY;
+ if (delta_x * delta_x + delta_y * delta_y > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD)
+ {
+ startCameraSteering();
+ steerCameraWithMouse(x, y);
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ }
+ }
+ else if (inCameraSteerMode())
+ {
+ steerCameraWithMouse(x, y);
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ }
+ else
+ {
+ // perform a separate pick that detects transparent objects since they respond to 1-click actions
+ LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, false, pick_rigged);
+
+ LLViewerObject* click_action_object = click_action_pick.getObject();
+
+ if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit()))
+ {
+ ECursorType cursor = cursorFromObject(click_action_object);
+ gViewerWindow->setCursor(cursor);
+ LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
+ }
+
+ else if ((object && !object->isAvatar() && object->flagUsePhysics())
+ || (parent && !parent->isAvatar() && parent->flagUsePhysics()))
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
+ }
+ else if ((!object || object->getClickAction() != CLICK_ACTION_DISABLED)
+ && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch()))
+ && (!object || !object->isAvatar()))
+ {
+ gViewerWindow->setCursor(UI_CURSOR_HAND);
+ LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
+ }
+ }
+
+ if(!object)
+ {
+ LLViewerMediaFocus::getInstance()->clearHover();
+ }
+
+ return true;
+}
+
+bool LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ if (!mDoubleClickTimer.getStarted())
+ {
+ mDoubleClickTimer.start();
+ }
+ else
+ {
+ mDoubleClickTimer.reset();
+ }
+ LLViewerObject* obj = mPick.getObject();
+
+ stopCameraSteering();
+ mMouseButtonDown = false;
+
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ if (hasMouseCapture())
+ {
+ setMouseCapture(false);
+ }
+
+ LLToolMgr::getInstance()->clearTransientTool();
+ gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
+
+ return LLTool::handleMouseUp(x, y, mask);
+}
+
+void LLToolPie::stopClickToWalk()
+{
+ mPick.mPosGlobal = gAgent.getPositionGlobal();
+ handle_go_to();
+ if(mAutoPilotDestination)
+ {
+ mAutoPilotDestination->markDead();
+ }
+}
+
+bool LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ if (gDebugClicks)
+ {
+ LL_INFOS() << "LLToolPie handleDoubleClick (becoming mouseDown)" << LL_ENDL;
+ }
+
+ if (handleMediaDblClick(mPick))
+ {
+ return true;
+ }
+
+ if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
+ {
+ mDoubleClickTimer.stop();
+ return false;
+ }
+ mDoubleClickTimer.stop();
+
+ return false;
+}
+
+static bool needs_tooltip(LLSelectNode* nodep)
+{
+ if (!nodep || !nodep->mValid)
+ return false;
+ return true;
+}
+
+
+bool LLToolPie::handleTooltipLand(std::string line, std::string tooltip_msg)
+{
+ // Do not show hover for land unless prefs are set to allow it.
+ if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return true;
+
+ LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal );
+
+ // Didn't hit an object, but since we have a land point we
+ // must be hovering over land.
+
+ LLParcel* hover_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
+ LLUUID owner;
+
+ if ( hover_parcel )
+ {
+ owner = hover_parcel->getOwnerID();
+ }
+
+ // Line: "Land"
+ line.clear();
+ line.append(LLTrans::getString("TooltipLand"));
+ if (hover_parcel)
+ {
+ line.append(hover_parcel->getName());
+ }
+ tooltip_msg.append(line);
+ tooltip_msg.push_back('\n');
+
+ // Line: "Owner: James Linden"
+ line.clear();
+ line.append(LLTrans::getString("TooltipOwner") + " ");
+
+ if ( hover_parcel )
+ {
+ std::string name;
+ if (LLUUID::null == owner)
+ {
+ line.append(LLTrans::getString("TooltipPublic"));
+ }
+ else if (hover_parcel->getIsGroupOwned())
+ {
+ if (gCacheName->getGroupName(owner, name))
+ {
+ line.append(name);
+ line.append(LLTrans::getString("TooltipIsGroup"));
+ }
+ else
+ {
+ line.append(LLTrans::getString("RetrievingData"));
+ }
+ }
+ else
+ {
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(owner, &av_name))
+ {
+ name = av_name.getUserName();
+ line.append(name);
+ }
+ else
+ {
+ line.append(LLTrans::getString("RetrievingData"));
+ }
+ }
+ }
+ else
+ {
+ line.append(LLTrans::getString("RetrievingData"));
+ }
+ tooltip_msg.append(line);
+ tooltip_msg.push_back('\n');
+
+ // Line: "no fly, not safe, no build"
+
+ // Don't display properties for your land. This is just
+ // confusing, because you can do anything on your own land.
+ if ( hover_parcel && owner != gAgent.getID() )
+ {
+ S32 words = 0;
+
+ line.clear();
+ // JC - Keep this in the same order as the checkboxes
+ // on the land info panel
+ if ( !hover_parcel->getAllowModify() )
+ {
+ if ( hover_parcel->getAllowGroupModify() )
+ {
+ line.append(LLTrans::getString("TooltipFlagGroupBuild"));
+ }
+ else
+ {
+ line.append(LLTrans::getString("TooltipFlagNoBuild"));
+ }
+ words++;
+ }
+
+ if ( !hover_parcel->getAllowTerraform() )
+ {
+ if (words) line.append(", ");
+ line.append(LLTrans::getString("TooltipFlagNoEdit"));
+ words++;
+ }
+
+ if ( hover_parcel->getAllowDamage() )
+ {
+ if (words) line.append(", ");
+ line.append(LLTrans::getString("TooltipFlagNotSafe"));
+ words++;
+ }
+
+ // Maybe we should reflect the estate's block fly bit here as well? DK 12/1/04
+ if ( !hover_parcel->getAllowFly() )
+ {
+ if (words) line.append(", ");
+ line.append(LLTrans::getString("TooltipFlagNoFly"));
+ words++;
+ }
+
+ if ( !hover_parcel->getAllowOtherScripts() )
+ {
+ if (words) line.append(", ");
+ if ( hover_parcel->getAllowGroupScripts() )
+ {
+ line.append(LLTrans::getString("TooltipFlagGroupScripts"));
+ }
+ else
+ {
+ line.append(LLTrans::getString("TooltipFlagNoScripts"));
+ }
+
+ words++;
+ }
+
+ if (words)
+ {
+ tooltip_msg.append(line);
+ tooltip_msg.push_back('\n');
+ }
+ }
+
+ if (hover_parcel && hover_parcel->getParcelFlag(PF_FOR_SALE))
+ {
+ LLStringUtil::format_map_t args;
+ S32 price = hover_parcel->getSalePrice();
+ args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
+ line = LLTrans::getString("TooltipForSaleL$", args);
+ tooltip_msg.append(line);
+ tooltip_msg.push_back('\n');
+ }
+
+ // trim last newlines
+ if (!tooltip_msg.empty())
+ {
+ tooltip_msg.erase(tooltip_msg.size() - 1);
+ LLToolTipMgr::instance().show(tooltip_msg);
+ }
+
+ return true;
+}
+
+bool LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg)
+{
+ if ( hover_object->isHUDAttachment() )
+ {
+ // no hover tips for HUD elements, since they can obscure
+ // what the HUD is displaying
+ return true;
+ }
+
+ if ( hover_object->isAttachment() )
+ {
+ // get root of attachment then parent, which is avatar
+ LLViewerObject* root_edit = hover_object->getRootEdit();
+ if (!root_edit)
+ {
+ // Strange parenting issue, don't show any text
+ return true;
+ }
+ hover_object = (LLViewerObject*)root_edit->getParent();
+ if (!hover_object)
+ {
+ // another strange parenting issue, bail out
+ return true;
+ }
+ }
+
+ line.clear();
+ if (hover_object->isAvatar())
+ {
+ // only show tooltip if same inspector not already open
+ LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
+ if (!existing_inspector
+ || !existing_inspector->getVisible()
+ || existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID())
+ {
+ // Try to get display name + username
+ std::string final_name;
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(hover_object->getID(), &av_name))
+ {
+ final_name = av_name.getCompleteName();
+ }
+ else
+ {
+ final_name = LLTrans::getString("TooltipPerson");;
+ }
+
+ const F32 INSPECTOR_TOOLTIP_DELAY = 0.35f;
+
+ LLInspector::Params p;
+ p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+ p.message(final_name);
+ p.image.name("Inspector_I");
+ p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
+ p.visible_time_near(6.f);
+ p.visible_time_far(3.f);
+ p.delay_time(INSPECTOR_TOOLTIP_DELAY);
+ p.wrap(false);
+
+ LLToolTipMgr::instance().show(p);
+ }
+ }
+ else
+ {
+ //
+ // We have hit a regular object (not an avatar or attachment)
+ //
+
+ //
+ // Default prefs will suppress display unless the object is interactive
+ //
+ bool show_all_object_tips =
+ (bool)gSavedSettings.getBOOL("ShowAllObjectHoverTip");
+ LLSelectNode *nodep = LLSelectMgr::getInstance()->getHoverNode();
+
+ // only show tooltip if same inspector not already open
+ LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_object");
+ if (nodep &&
+ (!existing_inspector
+ || !existing_inspector->getVisible()
+ || existing_inspector->getKey()["object_id"].asUUID() != hover_object->getID()))
+ {
+
+ // Add price to tooltip for items on sale
+ bool for_sale = for_sale_selection(nodep);
+ if(for_sale)
+ {
+ LLStringUtil::format_map_t args;
+ S32 price = nodep->mSaleInfo.getSalePrice();
+ args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
+ tooltip_msg.append(LLTrans::getString("TooltipPrice", args) );
+ }
+
+ if (nodep->mName.empty())
+ {
+ tooltip_msg.append(LLTrans::getString("TooltipNoName"));
+ }
+ else
+ {
+ tooltip_msg.append( nodep->mName );
+ }
+
+ bool has_media = false;
+ bool is_time_based_media = false;
+ bool is_web_based_media = false;
+ bool is_media_playing = false;
+ bool is_media_displaying = false;
+
+ // Does this face have media?
+ const LLTextureEntry* tep = hover_object->getTE(mHoverPick.mObjectFace);
+
+ if(tep)
+ {
+ has_media = tep->hasMedia();
+ const LLMediaEntry* mep = has_media ? tep->getMediaData() : NULL;
+ if (mep)
+ {
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+ LLPluginClassMedia* media_plugin = NULL;
+
+ if (media_impl.notNull() && (media_impl->hasMedia()))
+ {
+ is_media_displaying = true;
+ //LLStringUtil::format_map_t args;
+
+ media_plugin = media_impl->getMediaPlugin();
+ if(media_plugin)
+ {
+ if(media_plugin->pluginSupportsMediaTime())
+ {
+ is_time_based_media = true;
+ is_web_based_media = false;
+ //args["[CurrentURL]"] = media_impl->getMediaURL();
+ is_media_playing = media_impl->isMediaPlaying();
+ }
+ else
+ {
+ is_time_based_media = false;
+ is_web_based_media = true;
+ //args["[CurrentURL]"] = media_plugin->getLocation();
+ }
+ //tooltip_msg.append(LLTrans::getString("CurrentURL", args));
+ }
+ }
+ }
+ }
+
+
+ // Avoid showing tip over media that's displaying unless it's for sale
+ // also check the primary node since sometimes it can have an action even though
+ // the root node doesn't
+
+ bool needs_tip = (!is_media_displaying ||
+ for_sale) &&
+ (has_media ||
+ needs_tooltip(nodep) ||
+ needs_tooltip(LLSelectMgr::getInstance()->getPrimaryHoverNode()));
+
+ if (show_all_object_tips || needs_tip)
+ {
+ LLInspector::Params p;
+ p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+ p.message(tooltip_msg);
+ p.image.name("Inspector_I");
+ p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
+ p.time_based_media(is_time_based_media);
+ p.web_based_media(is_web_based_media);
+ p.media_playing(is_media_playing);
+ p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
+ p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
+ p.visible_time_near(6.f);
+ p.visible_time_far(3.f);
+ p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
+ p.wrap(false);
+
+ LLToolTipMgr::instance().show(p);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask)
+{
+ static LLCachedControl<bool> show_hover_tips(*LLUI::getInstance()->mSettingGroups["config"], "ShowHoverTips", true);
+ if (!show_hover_tips) return true;
+ if (!mHoverPick.isValid()) return true;
+
+ LLViewerObject* hover_object = mHoverPick.getObject();
+
+ // update hover object and hover parcel
+ LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace);
+
+
+ std::string tooltip_msg;
+ std::string line;
+
+ if ( hover_object )
+ {
+ handleTooltipObject(hover_object, line, tooltip_msg );
+ }
+ else if (mHoverPick.mPickType == LLPickInfo::PICK_LAND)
+ {
+ handleTooltipLand(line, tooltip_msg);
+ }
+
+ return true;
+}
+
+static void show_inspector(const char* inspector, const char* param, const LLUUID& source_id)
+{
+ LLSD params;
+ params[param] = source_id;
+ if (LLToolTipMgr::instance().toolTipVisible())
+ {
+ LLRect rect = LLToolTipMgr::instance().getToolTipRect();
+ params["pos"]["x"] = rect.mLeft;
+ params["pos"]["y"] = rect.mTop;
+ }
+
+ LLFloaterReg::showInstance(inspector, params);
+}
+
+
+static void show_inspector(const char* inspector, LLSD& params)
+{
+ if (LLToolTipMgr::instance().toolTipVisible())
+ {
+ LLRect rect = LLToolTipMgr::instance().getToolTipRect();
+ params["pos"]["x"] = rect.mLeft;
+ params["pos"]["y"] = rect.mTop;
+ }
+
+ LLFloaterReg::showInstance(inspector, params);
+}
+
+
+// static
+void LLToolPie::showAvatarInspector(const LLUUID& avatar_id)
+{
+ show_inspector("inspect_avatar", "avatar_id", avatar_id);
+}
+
+// static
+void LLToolPie::showObjectInspector(const LLUUID& object_id)
+{
+ show_inspector("inspect_object", "object_id", object_id);
+}
+
+
+// static
+void LLToolPie::showObjectInspector(const LLUUID& object_id, const S32& object_face)
+{
+ LLSD params;
+ params["object_id"] = object_id;
+ params["object_face"] = object_face;
+ show_inspector("inspect_object", params);
+}
+
+// static
+void LLToolPie::playCurrentMedia(const LLPickInfo& info)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return;
+
+ LLPointer<LLViewerObject> objectp = info.getObject();
+
+ // Early out cases. Must clear media hover.
+ // did not hit an object or did not hit a valid face
+ if ( objectp.isNull() ||
+ info.mObjectFace < 0 ||
+ info.mObjectFace >= objectp->getNumTEs() )
+ {
+ return;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = objectp->getTE(info.mObjectFace);
+ if (!tep)
+ return;
+
+ const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
+ if(!mep)
+ return;
+
+ //TODO: Can you Use it?
+
+ LLPluginClassMedia* media_plugin = NULL;
+
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+
+ if(media_impl.notNull() && media_impl->hasMedia())
+ {
+ media_plugin = media_impl->getMediaPlugin();
+ if (media_plugin && media_plugin->pluginSupportsMediaTime())
+ {
+ if(media_impl->isMediaPlaying())
+ {
+ media_impl->pause();
+ }
+ else
+ {
+ media_impl->play();
+ }
+ }
+ }
+
+
+}
+
+// static
+void LLToolPie::VisitHomePage(const LLPickInfo& info)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return;
+
+ LLPointer<LLViewerObject> objectp = info.getObject();
+
+ // Early out cases. Must clear media hover.
+ // did not hit an object or did not hit a valid face
+ if ( objectp.isNull() ||
+ info.mObjectFace < 0 ||
+ info.mObjectFace >= objectp->getNumTEs() )
+ {
+ return;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = objectp->getTE(info.mObjectFace);
+ if (!tep)
+ return;
+
+ const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
+ if(!mep)
+ return;
+
+ //TODO: Can you Use it?
+
+ LLPluginClassMedia* media_plugin = NULL;
+
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+
+ if(media_impl.notNull() && media_impl->hasMedia())
+ {
+ media_plugin = media_impl->getMediaPlugin();
+
+ if (media_plugin && !(media_plugin->pluginSupportsMediaTime()))
+ {
+ media_impl->navigateHome();
+ }
+ }
+}
+
+void LLToolPie::handleSelect()
+{
+ // tool is reselected when app gets focus, etc.
+}
+
+void LLToolPie::handleDeselect()
+{
+ if( hasMouseCapture() )
+ {
+ setMouseCapture( false ); // Calls onMouseCaptureLost() indirectly
+ }
+ // remove temporary selection for pie menu
+ LLSelectMgr::getInstance()->setHoverObject(NULL);
+
+ // Menu may be still up during transfer to different tool.
+ // toolfocus and toolgrab should retain menu, they will clear it if needed
+ MASK override_mask = gKeyboard ? gKeyboard->currentMask(true) : 0;
+ if (gMenuHolder && (!gMenuHolder->getVisible() || (override_mask & (MASK_ALT | MASK_CONTROL)) == 0))
+ {
+ // in most cases menu is useless without correct selection, so either keep both or discard both
+ gMenuHolder->hideMenus();
+ LLSelectMgr::getInstance()->validateSelection();
+ }
+}
+
+LLTool* LLToolPie::getOverrideTool(MASK mask)
+{
+ if (gSavedSettings.getBOOL("EnableGrab"))
+ {
+ if (mask == DEFAULT_GRAB_MASK)
+ {
+ return LLToolGrab::getInstance();
+ }
+ else if (mask == (MASK_CONTROL | MASK_SHIFT))
+ {
+ return LLToolGrab::getInstance();
+ }
+ }
+ return LLTool::getOverrideTool(mask);
+}
+
+void LLToolPie::stopEditing()
+{
+ if( hasMouseCapture() )
+ {
+ setMouseCapture( false ); // Calls onMouseCaptureLost() indirectly
+ }
+}
+
+void LLToolPie::onMouseCaptureLost()
+{
+ stopCameraSteering();
+ mMouseButtonDown = false;
+ handleMediaMouseUp();
+}
+
+void LLToolPie::stopCameraSteering()
+{
+ mMouseOutsideSlop = false;
+}
+
+bool LLToolPie::inCameraSteerMode()
+{
+ return mMouseButtonDown && mMouseOutsideSlop;
+}
+
+// true if x,y outside small box around start_x,start_y
+bool LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
+{
+ S32 dx = x - start_x;
+ S32 dy = y - start_y;
+
+ return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
+}
+
+
+void LLToolPie::render()
+{
+ return;
+}
+
+static void handle_click_action_play()
+{
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return;
+
+ LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus();
+ switch(status)
+ {
+ case LLViewerMediaImpl::MEDIA_PLAYING:
+ LLViewerParcelMedia::getInstance()->pause();
+ break;
+
+ case LLViewerMediaImpl::MEDIA_PAUSED:
+ LLViewerParcelMedia::getInstance()->start();
+ break;
+
+ default:
+ LLViewerParcelMedia::getInstance()->play(parcel);
+ break;
+ }
+}
+
+bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ LLPointer<LLViewerObject> objectp = pick.getObject();
+
+
+ if (!parcel ||
+ objectp.isNull() ||
+ pick.mObjectFace < 0 ||
+ pick.mObjectFace >= objectp->getNumTEs())
+ {
+ LLViewerMediaFocus::getInstance()->clearFocus();
+
+ return false;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
+ if (!tep)
+ return false;
+
+ LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
+ if (!mep)
+ return false;
+
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+
+ if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
+ {
+ if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
+ {
+ // It's okay to give this a null impl
+ LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
+ }
+ else
+ {
+ // Make sure keyboard focus is set to the media focus object.
+ gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+ LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
+
+ media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(true));
+ mMediaMouseCaptureID = mep->getMediaID();
+ setMouseCapture(true); // This object will send a mouse-up to the media when it loses capture.
+ }
+
+ return true;
+ }
+
+ LLViewerMediaFocus::getInstance()->clearFocus();
+
+ return false;
+}
+
+bool LLToolPie::handleMediaDblClick(const LLPickInfo& pick)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ LLPointer<LLViewerObject> objectp = pick.getObject();
+
+
+ if (!parcel ||
+ objectp.isNull() ||
+ pick.mObjectFace < 0 ||
+ pick.mObjectFace >= objectp->getNumTEs())
+ {
+ LLViewerMediaFocus::getInstance()->clearFocus();
+
+ return false;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
+ if (!tep)
+ return false;
+
+ LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
+ if (!mep)
+ return false;
+
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+
+ if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
+ {
+ if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
+ {
+ // It's okay to give this a null impl
+ LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
+ }
+ else
+ {
+ // Make sure keyboard focus is set to the media focus object.
+ gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+ LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
+
+ media_impl->mouseDoubleClick(pick.mUVCoords, gKeyboard->currentMask(true));
+ mMediaMouseCaptureID = mep->getMediaID();
+ setMouseCapture(true); // This object will send a mouse-up to the media when it loses capture.
+ }
+
+ return true;
+ }
+
+ LLViewerMediaFocus::getInstance()->clearFocus();
+
+ return false;
+}
+
+bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return false;
+
+ LLPointer<LLViewerObject> objectp = pick.getObject();
+
+ // Early out cases. Must clear media hover.
+ // did not hit an object or did not hit a valid face
+ if ( objectp.isNull() ||
+ pick.mObjectFace < 0 ||
+ pick.mObjectFace >= objectp->getNumTEs() )
+ {
+ LLViewerMediaFocus::getInstance()->clearHover();
+ return false;
+ }
+
+ // Does this face have media?
+ const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
+ if(!tep)
+ return false;
+
+ const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
+ if (mep
+ && gSavedSettings.getBOOL("MediaOnAPrimUI"))
+ {
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+
+ if(media_impl.notNull())
+ {
+ // Update media hover object
+ if (!LLViewerMediaFocus::getInstance()->isHoveringOverFace(objectp, pick.mObjectFace))
+ {
+ LLViewerMediaFocus::getInstance()->setHoverFace(objectp, pick.mObjectFace, media_impl, pick.mNormal);
+ }
+
+ // If this is the focused media face, send mouse move events.
+ if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
+ {
+ media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(true));
+ gViewerWindow->setCursor(media_impl->getLastSetCursor());
+ }
+ else
+ {
+ // This is not the focused face -- set the default cursor.
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ }
+
+ return true;
+ }
+ }
+
+ // In all other cases, clear media hover.
+ LLViewerMediaFocus::getInstance()->clearHover();
+
+ return false;
+}
+
+bool LLToolPie::handleMediaMouseUp()
+{
+ bool result = false;
+ if(mMediaMouseCaptureID.notNull())
+ {
+ // Face media needs to know the mouse went up.
+ viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mMediaMouseCaptureID);
+ if(media_impl)
+ {
+ // 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.
+ media_impl->onMouseCaptureLost();
+ }
+
+ mMediaMouseCaptureID.setNull();
+
+ result = true;
+ }
+
+ return result;
+}
+
+static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp)
+{
+ //FIXME: how do we handle object in different parcel than us?
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return;
+
+ // did we hit an object?
+ if (objectp.isNull()) return;
+
+ // did we hit a valid face on the object?
+ S32 face = LLToolPie::getInstance()->getPick().mObjectFace;
+ if( face < 0 || face >= objectp->getNumTEs() ) return;
+
+ // is media playing on this face?
+ if (LLViewerMedia::getInstance()->getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL)
+ {
+ handle_click_action_play();
+ return;
+ }
+
+ std::string media_url = std::string ( parcel->getMediaURL () );
+ std::string media_type = std::string ( parcel->getMediaType() );
+ LLStringUtil::trim(media_url);
+
+ LLWeb::loadURL(media_url);
+}
+
+static ECursorType cursor_from_parcel_media(U8 click_action)
+{
+ // HACK: This is directly referencing an impl name. BAD!
+ // This can be removed when we have a truly generic media browser that only
+ // builds an impl based on the type of url it is passed.
+
+ //FIXME: how do we handle object in different parcel than us?
+ ECursorType open_cursor = UI_CURSOR_ARROW;
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return open_cursor;
+
+ std::string media_url = std::string ( parcel->getMediaURL () );
+ std::string media_type = std::string ( parcel->getMediaType() );
+ LLStringUtil::trim(media_url);
+
+ open_cursor = UI_CURSOR_TOOLMEDIAOPEN;
+
+ LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getInstance()->getStatus();
+ switch(status)
+ {
+ case LLViewerMediaImpl::MEDIA_PLAYING:
+ return click_action == CLICK_ACTION_PLAY ? UI_CURSOR_TOOLPAUSE : open_cursor;
+ default:
+ return UI_CURSOR_TOOLPLAY;
+ }
+}
+
+
+// True if we handled the event.
+bool LLToolPie::handleRightClickPick()
+{
+ S32 x = mPick.mMousePt.mX;
+ S32 y = mPick.mMousePt.mY;
+ MASK mask = mPick.mKeyMask;
+
+ if (mPick.mPickType != LLPickInfo::PICK_LAND)
+ {
+ LLViewerParcelMgr::getInstance()->deselectLand();
+ }
+
+ // didn't click in any UI object, so must have clicked in the world
+ LLViewerObject *object = mPick.getObject();
+
+ // Can't ignore children here.
+ LLToolSelect::handleObjectSelection(mPick, false, true);
+
+ // Spawn pie menu
+ if (mPick.mPickType == LLPickInfo::PICK_LAND)
+ {
+ LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal );
+ gMenuHolder->setParcelSelection(selection);
+ gMenuLand->show(x, y);
+
+ showVisualContextMenuEffect();
+
+ }
+ else if (mPick.mObjectID == gAgent.getID() )
+ {
+ if(!gMenuAvatarSelf)
+ {
+ //either at very early startup stage or at late quitting stage,
+ //this event is ignored.
+ return true ;
+ }
+
+ gMenuAvatarSelf->show(x, y);
+ }
+ else if (object)
+ {
+ gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+
+ bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner());
+ if (object->isAvatar() || is_other_attachment)
+ {
+ // Find the attachment's avatar
+ while( object && object->isAttachment())
+ {
+ object = (LLViewerObject*)object->getParent();
+ llassert(object);
+ }
+
+ if (!object)
+ {
+ return true; // unexpected, but escape
+ }
+
+ // Object is an avatar, so check for mute by id.
+ LLVOAvatar* avatar = (LLVOAvatar*)object;
+ std::string name = avatar->getFullname();
+ std::string mute_msg;
+ if (LLMuteList::getInstance()->isMuted(avatar->getID(), avatar->getFullname()))
+ {
+ mute_msg = LLTrans::getString("UnmuteAvatar");
+ }
+ else
+ {
+ mute_msg = LLTrans::getString("MuteAvatar");
+ }
+
+ if (is_other_attachment)
+ {
+ gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+ gMenuAttachmentOther->show(x, y);
+ }
+ else
+ {
+ gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+ gMenuAvatarOther->show(x, y);
+ }
+ }
+ else if (object->isAttachment())
+ {
+ gMenuAttachmentSelf->show(x, y);
+ }
+ else
+ {
+ // BUG: What about chatting child objects?
+ std::string name;
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node)
+ {
+ name = node->mName;
+ }
+
+ gMenuObject->show(x, y);
+
+ showVisualContextMenuEffect();
+ }
+ }
+ else if (mPick.mParticleOwnerID.notNull())
+ {
+ if (gMenuMuteParticle && mPick.mParticleOwnerID != gAgent.getID())
+ {
+ gMenuMuteParticle->show(x,y);
+ }
+ }
+
+ // non UI object - put focus back "in world"
+ if (gFocusMgr.getKeyboardFocus())
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
+ LLTool::handleRightMouseDown(x, y, mask);
+ // We handled the event.
+ return true;
+}
+
+void LLToolPie::showVisualContextMenuEffect()
+{
+ // VEFFECT: ShowPie
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, true);
+ effectp->setPositionGlobal(mPick.mPosGlobal);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ effectp->setDuration(0.25f);
+}
+
+typedef enum e_near_far
+{
+ NEAR_INTERSECTION,
+ FAR_INTERSECTION
+} ENearFar;
+
+bool 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)
+{
+ // do ray/sphere intersection by solving quadratic equation
+ LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center;
+ F32 B = 2.f * ray_dir * sphere_to_ray_start_vec;
+ F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
+
+ F32 discriminant = B*B - 4.f*C;
+ if (discriminant >= 0.f)
+ { // intersection detected, now find closest one
+ F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
+
+ if (t0 > 0.f && near_far == NEAR_INTERSECTION)
+ {
+ intersection_pt = ray_pt + ray_dir * t0;
+ }
+ else
+ {
+ F32 t1 = (-B + sqrtf(discriminant)) / 2.f;
+ intersection_pt = ray_pt + ray_dir * t1;
+ }
+ return true;
+ }
+ else
+ { // no intersection
+ return false;
+ }
+}
+
+void LLToolPie::startCameraSteering()
+{
+ LLFirstUse::notMoving(false);
+ mMouseOutsideSlop = true;
+
+ if (gAgentCamera.getFocusOnAvatar())
+ {
+ mSteerPick = mPick;
+
+ // handle special cases of steering picks
+ LLViewerObject* avatar_object = mSteerPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
+ {
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ // if clicking on own avatar...
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ // ...project pick point a few meters in front of avatar
+ mSteerPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * 3.0;
+ }
+
+ if (!mSteerPick.isValid())
+ {
+ mSteerPick.mPosGlobal = gAgent.getPosGlobalFromAgent(
+ LLViewerCamera::instance().getOrigin() + gViewerWindow->mouseDirectionGlobal(mSteerPick.mMousePt.mX, mSteerPick.mMousePt.mY) * 100.f);
+ }
+
+ setMouseCapture(true);
+
+ mMouseSteerX = mMouseDownX;
+ mMouseSteerY = mMouseDownY;
+ const LLVector3 camera_to_rotation_center = gAgent.getFrameAgent().getOrigin() - LLViewerCamera::instance().getOrigin();
+ const LLVector3 rotation_center_to_pick = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal) - gAgent.getFrameAgent().getOrigin();
+
+ mClockwise = camera_to_rotation_center * rotation_center_to_pick < 0.f;
+ if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); }
+ mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, false);
+ mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal);
+ mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190));
+ mMouseSteerGrabPoint->setPixelSize(5);
+ mMouseSteerGrabPoint->setDuration(2.f);
+ }
+}
+
+void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
+{
+ const LLViewerCamera& camera = LLViewerCamera::instance();
+ const LLCoordFrame& rotation_frame = gAgent.getFrameAgent();
+ const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal);
+ const LLVector3 pick_rotation_center = rotation_frame.getOrigin() + parallel_component(pick_pos - rotation_frame.getOrigin(), rotation_frame.getUpAxis());
+ const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f;
+ const F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(pick_rotation_center, camera.getOrigin());;
+ const F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, pick_rotation_center), min_rotation_radius, F32_MAX);
+ const LLVector3 camera_to_rotation_center = pick_rotation_center - camera.getOrigin();
+ const LLVector3 adjusted_camera_pos = LLViewerCamera::instance().getOrigin() + projected_vec(camera_to_rotation_center, rotation_frame.getUpAxis());
+ const F32 camera_distance_from_rotation_center = dist_vec(adjusted_camera_pos, pick_rotation_center);
+
+ LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_frame.getUpAxis());
+ mouse_ray.normalize();
+
+ LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_frame.getUpAxis());
+ old_mouse_ray.normalize();
+
+ F32 yaw_angle;
+ F32 old_yaw_angle;
+ LLVector3 mouse_on_sphere;
+ LLVector3 old_mouse_on_sphere;
+
+ if (intersect_ray_with_sphere(
+ adjusted_camera_pos,
+ mouse_ray,
+ pick_rotation_center,
+ pick_distance_from_rotation_center,
+ FAR_INTERSECTION,
+ mouse_on_sphere))
+ {
+ LLVector3 mouse_sphere_offset = mouse_on_sphere - pick_rotation_center;
+ yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis());
+ }
+ else
+ {
+ yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center);
+ if (mouse_ray * rotation_frame.getLeftAxis() < 0.f)
+ {
+ yaw_angle *= -1.f;
+ }
+ }
+
+ if (intersect_ray_with_sphere(
+ adjusted_camera_pos,
+ old_mouse_ray,
+ pick_rotation_center,
+ pick_distance_from_rotation_center,
+ FAR_INTERSECTION,
+ old_mouse_on_sphere))
+ {
+ LLVector3 mouse_sphere_offset = old_mouse_on_sphere - pick_rotation_center;
+ old_yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis());
+ }
+ else
+ {
+ old_yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center);
+
+ if (mouse_ray * rotation_frame.getLeftAxis() < 0.f)
+ {
+ old_yaw_angle *= -1.f;
+ }
+ }
+
+ const F32 delta_angle = yaw_angle - old_yaw_angle;
+
+ if (mClockwise)
+ {
+ gAgent.yaw(delta_angle);
+ }
+ else
+ {
+ gAgent.yaw(-delta_angle);
+ }
+
+ mMouseSteerX = x;
+ mMouseSteerY = y;
+}
|
