summaryrefslogtreecommitdiff
path: root/indra/newview/lltoolgrab.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/lltoolgrab.cpp
Print done when done.
Diffstat (limited to 'indra/newview/lltoolgrab.cpp')
-rw-r--r--indra/newview/lltoolgrab.cpp875
1 files changed, 875 insertions, 0 deletions
diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
new file mode 100644
index 0000000000..898322d5ca
--- /dev/null
+++ b/indra/newview/lltoolgrab.cpp
@@ -0,0 +1,875 @@
+/**
+ * @file lltoolgrab.cpp
+ * @brief LLToolGrab class implementation
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltoolgrab.h"
+
+// library headers
+#include "indra_constants.h" // for agent control flags
+#include "llviewercontrol.h"
+#include "llquaternion.h"
+#include "llbox.h"
+#include "message.h"
+#include "llview.h"
+#include "llfontgl.h"
+#include "llui.h"
+
+// newview headers
+#include "llagent.h"
+//#include "llfloateravatarinfo.h"
+#include "lldrawable.h"
+#include "llfloatertools.h"
+#include "llhudeffect.h"
+#include "llhudmanager.h"
+#include "llregionposition.h"
+#include "llselectmgr.h"
+#include "llstatusbar.h"
+#include "lltoolmgr.h"
+#include "lltoolpie.h"
+#include "llviewercamera.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewerwindow.h"
+#include "llvoavatar.h"
+#include "llworld.h"
+#include "viewer.h"
+
+const S32 SLOP_DIST_SQ = 4;
+
+// Override modifier key behavior with these buttons
+BOOL gGrabBtnVertical = FALSE;
+BOOL gGrabBtnSpin = FALSE;
+LLTool* gGrabTransientTool = NULL;
+LLToolGrab *gToolGrab = NULL;
+extern BOOL gDebugClicks;
+
+//
+// Methods
+//
+LLToolGrab::LLToolGrab( LLToolComposite* composite )
+: LLTool( "Grab", composite ),
+ mMode( GRAB_INACTIVE ),
+ mVerticalDragging( FALSE ),
+ mHitLand(FALSE),
+ mHitObjectID(),
+ mGrabObject( NULL ),
+ mMouseDownX( -1 ),
+ mMouseDownY( -1 ),
+ mHasMoved( FALSE ),
+ mSpinGrabbing( FALSE ),
+ mSpinRotation(),
+ mHideBuildHighlight(FALSE)
+{ }
+
+LLToolGrab::~LLToolGrab()
+{ }
+
+
+// virtual
+void LLToolGrab::handleSelect()
+{
+ gFloaterTools->setStatusText("Drag to move objects, Ctrl to lift, Ctrl-Shift to spin");
+ gGrabBtnVertical = FALSE;
+ gGrabBtnSpin = FALSE;
+}
+
+void LLToolGrab::handleDeselect()
+{
+ if( hasMouseCapture() )
+ {
+ setMouseCapture( FALSE );
+ }
+
+ gFloaterTools->setStatusText("");
+}
+
+BOOL LLToolGrab::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ if (gDebugClicks)
+ {
+ llinfos << "LLToolGrab handleDoubleClick (becoming mouseDown)" << llendl;
+ }
+
+ return FALSE;
+}
+
+BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (gDebugClicks)
+ {
+ llinfos << "LLToolGrab handleMouseDown" << llendl;
+ }
+
+ mHitLand = FALSE;
+
+ // call the base class to propogate info to sim
+ LLTool::handleMouseDown(x, y, mask);
+
+ if (!gAgent.leftButtonGrabbed())
+ {
+ // can grab transparent objects (how touch event propagates, scripters rely on this)
+ gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, TRUE);
+ }
+ return TRUE;
+}
+
+void LLToolGrab::pickCallback(S32 x, S32 y, MASK mask)
+{
+ LLViewerObject *objectp = gObjectList.findObject( gLastHitObjectID );
+
+ BOOL extend_select = (mask & MASK_SHIFT);
+
+ if (!extend_select && !gSelectMgr->isEmpty())
+ {
+ gSelectMgr->deselectAll();
+ gToolGrab->mDeselectedThisClick = TRUE;
+ }
+ else
+ {
+ gToolGrab->mDeselectedThisClick = FALSE;
+ }
+
+ // if not over object, do nothing
+ if (!objectp)
+ {
+ gToolGrab->setMouseCapture(TRUE);
+ gToolGrab->mMode = GRAB_NOOBJECT;
+ gToolGrab->mHitObjectID.setNull();
+ }
+ else
+ {
+ gToolGrab->handleObjectHit(objectp, x, y, mask);
+ }
+}
+
+BOOL LLToolGrab::handleObjectHit(LLViewerObject *objectp, S32 x, S32 y, MASK mask)
+{
+ mMouseDownX = x;
+ mMouseDownY = y;
+ mMouseMask = mask;
+
+ if (gDebugClicks)
+ {
+ llinfos << "LLToolGrab handleObjectHit " << mMouseDownX << "," << mMouseDownY << llendl;
+ }
+
+ if (objectp->isAvatar())
+ {
+ if (gGrabTransientTool)
+ {
+ gBasicToolset->selectTool( gGrabTransientTool );
+ gGrabTransientTool = NULL;
+ }
+ return TRUE;
+ }
+
+ setMouseCapture( TRUE );
+
+ mHitObjectID = objectp->getID();
+
+ // Grabs always start from the root
+ // objectp = (LLViewerObject *)objectp->getRoot();
+
+ LLViewerObject* parent = objectp->getRootEdit();
+ BOOL script_touch = (objectp && objectp->flagHandleTouch()) || (parent && parent->flagHandleTouch());
+
+ // Clicks on scripted or physical objects are temporary grabs, so
+ // not "Build mode"
+ mHideBuildHighlight = script_touch || objectp->usePhysics();
+
+ if (!objectp->usePhysics())
+ {
+ // In mouselook, we shouldn't be able to grab non-physical,
+ // non-touchable objects. If it has a touch handler, we
+ // do grab it (so llDetectedGrab works), but movement is
+ // blocked on the server side. JC
+ if (gAgent.cameraMouselook() && !script_touch)
+ {
+ mMode = GRAB_LOCKED;
+ }
+ else
+ {
+ mMode = GRAB_NONPHYSICAL;
+ }
+ gViewerWindow->hideCursor();
+ gViewerWindow->moveCursorToCenter();
+ // Don't bail out here, go on and grab so buttons can get
+ // their "touched" event.
+ }
+ else if( !objectp->permMove() )
+ {
+ // if mouse is over a physical object without move permission, show feedback if user tries to move it.
+ mMode = GRAB_LOCKED;
+
+ // Don't bail out here, go on and grab so buttons can get
+ // their "touched" event.
+ }
+ else
+ {
+ // if mouse is over a physical object with move permission,
+ // select it and enter "grab" mode (hiding cursor, etc.)
+
+ mMode = GRAB_ACTIVE_CENTER;
+
+ gViewerWindow->hideCursor();
+ gViewerWindow->moveCursorToCenter();
+ }
+
+ // Always send "touched" message
+
+ mAccumDeltaX = 0;
+ mAccumDeltaY = 0;
+ mHasMoved = FALSE;
+ mOutsideSlop = FALSE;
+
+ mGrabObject = objectp;
+
+ mGrabOffset.clearVec();
+
+ mVerticalDragging = (mask == MASK_VERTICAL) || gGrabBtnVertical;
+
+ startGrab(x, y);
+
+ if ((mask == MASK_SPIN) || gGrabBtnSpin)
+ {
+ startSpin();
+ }
+
+ gSelectMgr->updateSelectionCenter(); // update selection beam
+
+ // update point at
+ LLViewerObject *edit_object = gObjectList.findObject(mHitObjectID);
+ if (edit_object)
+ {
+ LLVector3 local_edit_point = gAgent.getPosAgentFromGlobal(gLastHitNonFloraPosGlobal);
+ local_edit_point -= edit_object->getPositionAgent();
+ local_edit_point = local_edit_point * ~edit_object->getRenderRotation();
+ gAgent.setPointAt(POINTAT_TARGET_GRAB, edit_object, local_edit_point );
+ gAgent.setLookAt(LOOKAT_TARGET_SELECT, edit_object, local_edit_point );
+ }
+
+ // on transient grabs (clicks on world objects), kill the grab immediately
+ if (!gViewerWindow->getLeftMouseDown()
+ && gGrabTransientTool
+ && (mMode == GRAB_NONPHYSICAL || mMode == GRAB_LOCKED))
+ {
+ gBasicToolset->selectTool( gGrabTransientTool );
+ gGrabTransientTool = NULL;
+ }
+
+ return TRUE;
+}
+
+
+void LLToolGrab::startSpin()
+{
+ mSpinGrabbing = TRUE;
+
+ // Was saveSelectedObjectTransform()
+ LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
+ mSpinRotation = root->getRotation();
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ObjectSpinStart);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
+ msg->sendMessage( mGrabObject->getRegion()->getHost() );
+}
+
+
+void LLToolGrab::stopSpin()
+{
+ mSpinGrabbing = FALSE;
+
+ LLMessageSystem *msg = gMessageSystem;
+ switch(mMode)
+ {
+ case GRAB_ACTIVE_CENTER:
+ case GRAB_NONPHYSICAL:
+ case GRAB_LOCKED:
+ msg->newMessageFast(_PREHASH_ObjectSpinStop);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
+ msg->sendMessage( mGrabObject->getRegion()->getHost() );
+ break;
+
+ case GRAB_NOOBJECT:
+ case GRAB_INACTIVE:
+ default:
+ // do nothing
+ break;
+ }
+}
+
+
+void LLToolGrab::startGrab(S32 x, S32 y)
+{
+ // Compute grab_offset in the OBJECT's root's coordinate frame
+ // (sometimes root == object)
+ LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
+
+ // drag from center
+ LLVector3d grab_start_global = root->getPositionGlobal();
+
+ // Where the grab starts, relative to the center of the root object of the set.
+ // JC - This code looks wonky, but I believe it does the right thing.
+ // Otherwise, when you grab a linked object set, it "pops" on the start
+ // of the drag.
+ LLVector3d grab_offsetd = root->getPositionGlobal() - mGrabObject->getPositionGlobal();
+
+ LLVector3 grab_offset;
+ grab_offset.setVec(grab_offsetd);
+
+ LLQuaternion rotation = root->getRotation();
+ rotation.conjQuat();
+ grab_offset = grab_offset * rotation;
+
+ // This planar drag starts at the grab point
+ mDragStartPointGlobal = grab_start_global;
+ mDragStartFromCamera = grab_start_global - gAgent.getCameraPositionGlobal();
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ObjectGrab);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
+ msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset );
+ msg->sendMessage( mGrabObject->getRegion()->getHost());
+
+ mGrabOffsetFromCenterInitial = grab_offset;
+ mGrabHiddenOffsetFromCamera = mDragStartFromCamera;
+
+ mGrabTimer.reset();
+}
+
+
+BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
+{
+ mLastMouseX = x;
+ mLastMouseY = y;
+
+ if (!gViewerWindow->getLeftMouseDown())
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ setMouseCapture(FALSE);
+ return TRUE;
+ }
+
+ // Do the right hover based on mode
+ switch( mMode )
+ {
+ case GRAB_ACTIVE_CENTER:
+ case GRAB_NONPHYSICAL:
+ handleHoverActive( x, y, mask ); // cursor hidden
+ break;
+
+ case GRAB_INACTIVE:
+ handleHoverInactive( x, y, mask ); // cursor set here
+ break;
+
+ case GRAB_NOOBJECT:
+ case GRAB_LOCKED:
+ handleHoverFailed( x, y, mask );
+ break;
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+// Dragging.
+void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask)
+{
+ llassert( hasMouseCapture() );
+ llassert( mGrabObject );
+ if (mGrabObject->isDead())
+ {
+ // Bail out of drag because object has been killed
+ setMouseCapture(FALSE);
+ return;
+ }
+
+ //--------------------------------------------------
+ // Toggle spinning
+ //--------------------------------------------------
+ if (mSpinGrabbing && !(mask == MASK_SPIN) && !gGrabBtnSpin)
+ {
+ // user released ALT key, stop spinning
+ stopSpin();
+ }
+ else if (!mSpinGrabbing && (mask == MASK_SPIN) )
+ {
+ // user pressed ALT key, start spinning
+ startSpin();
+ }
+
+ //--------------------------------------------------
+ // Toggle vertical dragging
+ //--------------------------------------------------
+ if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical)
+ {
+ // ...switch to horizontal dragging
+ mVerticalDragging = FALSE;
+
+ mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
+ mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
+ }
+ else if (!mVerticalDragging && (mask == MASK_VERTICAL) )
+ {
+ // ...switch to vertical dragging
+ mVerticalDragging = TRUE;
+
+ mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
+ mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
+ }
+
+ const F32 RADIANS_PER_PIXEL_X = 0.01f;
+ const F32 RADIANS_PER_PIXEL_Y = 0.01f;
+
+ const F32 SENSITIVITY_X = 0.0075f;
+ const F32 SENSITIVITY_Y = 0.0075f;
+
+ S32 dx = x - (gViewerWindow->getWindowWidth() / 2);
+ S32 dy = y - (gViewerWindow->getWindowHeight() / 2);
+
+ if (dx != 0 || dy != 0)
+ {
+ mAccumDeltaX += dx;
+ mAccumDeltaY += dy;
+ S32 dist_sq = mAccumDeltaX * mAccumDeltaX + mAccumDeltaY * mAccumDeltaY;
+ if (dist_sq > SLOP_DIST_SQ)
+ {
+ mOutsideSlop = TRUE;
+ }
+
+ // mouse has moved outside center
+ mHasMoved = TRUE;
+
+ if (mSpinGrabbing)
+ {
+ //------------------------------------------------------
+ // Handle spinning
+ //------------------------------------------------------
+
+ // x motion maps to rotation around vertical axis
+ LLVector3 up(0.f, 0.f, 1.f);
+ LLQuaternion rotation_around_vertical( dx*RADIANS_PER_PIXEL_X, up );
+
+ // y motion maps to rotation around left axis
+ const LLVector3 &agent_left = gCamera->getLeftAxis();
+ LLQuaternion rotation_around_left( dy*RADIANS_PER_PIXEL_Y, agent_left );
+
+ // compose with current rotation
+ mSpinRotation = mSpinRotation * rotation_around_vertical;
+ mSpinRotation = mSpinRotation * rotation_around_left;
+
+ // TODO: Throttle these
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ObjectSpinUpdate);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
+ msg->addQuatFast(_PREHASH_Rotation, mSpinRotation );
+ msg->sendMessage( mGrabObject->getRegion()->getHost() );
+ }
+ else
+ {
+ //------------------------------------------------------
+ // Handle grabbing
+ //------------------------------------------------------
+
+ LLVector3d x_part;
+ x_part.setVec(gCamera->getLeftAxis());
+ x_part.mdV[VZ] = 0.0;
+ x_part.normVec();
+
+ LLVector3d y_part;
+ if( mVerticalDragging )
+ {
+ y_part.setVec(gCamera->getUpAxis());
+ // y_part.setVec(0.f, 0.f, 1.f);
+ }
+ else
+ {
+ // drag toward camera
+ y_part = x_part % LLVector3d::z_axis;
+ y_part.mdV[VZ] = 0.0;
+ y_part.normVec();
+ }
+
+ mGrabHiddenOffsetFromCamera = mGrabHiddenOffsetFromCamera
+ + (x_part * (-dx * SENSITIVITY_X))
+ + (y_part * ( dy * SENSITIVITY_Y));
+
+
+ // Send the message to the viewer.
+ F32 dt = mGrabTimer.getElapsedTimeAndResetF32();
+ U32 dt_milliseconds = (U32) (1000.f * dt);
+
+ // need to return offset from mGrabStartPoint
+ LLVector3d grab_point_global;
+
+ grab_point_global = gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
+
+ /* Snap to grid disabled for grab tool - very confusing
+ // Handle snapping to grid, but only when the tool is formally selected.
+ BOOL snap_on = gSavedSettings.getBOOL("SnapEnabled");
+ if (snap_on && !gGrabTransientTool)
+ {
+ F64 snap_size = gSavedSettings.getF32("GridResolution");
+ U8 snap_dimensions = (mVerticalDragging ? 3 : 2);
+
+ for (U8 i = 0; i < snap_dimensions; i++)
+ {
+ grab_point_global.mdV[i] += snap_size / 2;
+ grab_point_global.mdV[i] -= fmod(grab_point_global.mdV[i], snap_size);
+ }
+ }
+ */
+
+ // Don't let object centers go underground.
+ F32 land_height = gWorldPointer->resolveLandHeightGlobal(grab_point_global);
+
+ if (grab_point_global.mdV[VZ] < land_height)
+ {
+ grab_point_global.mdV[VZ] = land_height;
+ }
+
+ // For safety, cap heights where objects can be dragged
+ if (grab_point_global.mdV[VZ] > MAX_OBJECT_Z)
+ {
+ grab_point_global.mdV[VZ] = MAX_OBJECT_Z;
+ }
+
+ grab_point_global = gWorldp->clipToVisibleRegions(mDragStartPointGlobal, grab_point_global);
+ // propagate constrained grab point back to grab offset
+ mGrabHiddenOffsetFromCamera = grab_point_global - gAgent.getCameraPositionGlobal();
+
+ // Handle auto-rotation at screen edge.
+ LLVector3 grab_pos_agent = gAgent.getPosAgentFromGlobal( grab_point_global );
+
+ LLCoordGL grab_center_gl( gViewerWindow->getWindowWidth() / 2, gViewerWindow->getWindowHeight() / 2);
+ gCamera->projectPosAgentToScreen(grab_pos_agent, grab_center_gl);
+
+ const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20;
+ const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD;
+ const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
+ // ...build mode moves camera about focus point
+ if (grab_center_gl.mX < ROTATE_H_MARGIN)
+ {
+ if (gAgent.getFocusOnAvatar())
+ {
+ gAgent.yaw(rotate_angle);
+ }
+ else
+ {
+ gAgent.cameraOrbitAround(rotate_angle);
+ }
+ }
+ else if (grab_center_gl.mX > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN)
+ {
+ if (gAgent.getFocusOnAvatar())
+ {
+ gAgent.yaw(-rotate_angle);
+ }
+ else
+ {
+ gAgent.cameraOrbitAround(-rotate_angle);
+ }
+ }
+
+ // Don't move above top of screen or below bottom
+ if ((grab_center_gl.mY < gViewerWindow->getWindowHeight() - 6)
+ && (grab_center_gl.mY > 24))
+ {
+ // Transmit update to simulator
+ LLVector3 grab_pos_region = mGrabObject->getRegion()->getPosRegionFromGlobal( grab_point_global );
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ObjectGrabUpdate);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
+ msg->addVector3Fast(_PREHASH_GrabOffsetInitial, mGrabOffsetFromCenterInitial );
+ msg->addVector3Fast(_PREHASH_GrabPosition, grab_pos_region );
+ msg->addU32Fast(_PREHASH_TimeSinceLast, dt_milliseconds );
+ msg->sendMessage( mGrabObject->getRegion()->getHost() );
+ }
+ }
+
+ gViewerWindow->moveCursorToCenter();
+
+ gSelectMgr->updateSelectionCenter();
+
+ }
+
+ // once we've initiated a drag, lock the camera down
+ if (mHasMoved)
+ {
+ if (!gAgent.cameraMouselook() &&
+ !mGrabObject->isHUDAttachment() &&
+ mGrabObject->getRoot() == gAgent.getAvatarObject()->getRoot())
+ {
+ // force focus to point in space where we were looking previously
+ gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
+ gAgent.setFocusOnAvatar(FALSE, ANIMATE);
+ }
+ else
+ {
+ gAgent.clearFocusObject();
+ }
+ }
+
+ // HACK to avoid assert: error checking system makes sure that the cursor is set during every handleHover. This is actually a no-op since the cursor is hidden.
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (active) [cursor hidden]" << llendl;
+}
+
+
+// Not dragging. Just showing affordances
+void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask)
+{
+ const F32 ROTATE_ANGLE_PER_SECOND = 40.f * DEG_TO_RAD;
+ const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
+
+ // Look for cursor against the edge of the screen
+ // Only works in fullscreen
+ if (gSavedSettings.getBOOL("FullScreen"))
+ {
+ if (gAgent.cameraThirdPerson() )
+ {
+ if (x == 0)
+ {
+ gAgent.yaw(rotate_angle);
+ //gAgent.setControlFlags(AGENT_CONTROL_YAW_POS);
+ }
+ else if (x == (gViewerWindow->getWindowWidth() - 1) )
+ {
+ gAgent.yaw(-rotate_angle);
+ //gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG);
+ }
+ }
+ }
+
+ // JC - TODO - change cursor based on gGrabBtnVertical, gGrabBtnSpin
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (inactive-not over editable object)" << llendl;
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+}
+
+// User is trying to do something that's not allowed.
+void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask)
+{
+ if( GRAB_NOOBJECT == mMode )
+ {
+ gViewerWindow->setCursor(UI_CURSOR_NO);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (not on object)" << llendl;
+ }
+ else
+ {
+ S32 dist_sq = (x-mMouseDownX) * (x-mMouseDownX) + (y-mMouseDownY) * (y-mMouseDownY);
+ if( mOutsideSlop || dist_sq > SLOP_DIST_SQ )
+ {
+ mOutsideSlop = TRUE;
+
+ switch( mMode )
+ {
+ case GRAB_LOCKED:
+ gViewerWindow->setCursor(UI_CURSOR_GRABLOCKED);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, no move permission)" << llendl;
+ break;
+
+// Non physical now handled by handleHoverActive - CRO
+// case GRAB_NONPHYSICAL:
+// gViewerWindow->setCursor(UI_CURSOR_ARROW);
+// lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, nonphysical)" << llendl;
+// break;
+ default:
+ llassert(0);
+ }
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed but within slop)" << llendl;
+ }
+ }
+}
+
+
+
+
+BOOL LLToolGrab::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ // call the base class to propogate info to sim
+ LLTool::handleMouseUp(x, y, mask);
+
+ if( hasMouseCapture() )
+ {
+ setMouseCapture( FALSE );
+ }
+ mMode = GRAB_INACTIVE;
+
+ // HACK: Make some grabs temporary
+ if (gGrabTransientTool)
+ {
+ gBasicToolset->selectTool( gGrabTransientTool );
+ gGrabTransientTool = NULL;
+ }
+
+ //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
+
+ return TRUE;
+}
+
+void LLToolGrab::stopEditing()
+{
+ if( hasMouseCapture() )
+ {
+ setMouseCapture( FALSE );
+ }
+}
+
+void LLToolGrab::onMouseCaptureLost()
+{
+ // First, fix cursor placement
+ if( !gAgent.cameraMouselook()
+ && (GRAB_ACTIVE_CENTER == mMode || GRAB_NONPHYSICAL == mMode))
+ {
+ llassert( mGrabObject );
+
+ if (mGrabObject->isHUDAttachment())
+ {
+ // ...move cursor "naturally", as if it had moved when hidden
+ S32 x = mMouseDownX + mAccumDeltaX;
+ S32 y = mMouseDownY + mAccumDeltaY;
+ LLUI::setCursorPositionScreen(x, y);
+ }
+ else if (mHasMoved)
+ {
+ // ...move cursor back to the center of the object
+ LLVector3 grab_point_agent = mGrabObject->getRenderPosition();
+
+ LLCoordGL gl_point;
+ gCamera->projectPosAgentToScreen(grab_point_agent, gl_point);
+
+ LLUI::setCursorPositionScreen(gl_point.mX, gl_point.mY);
+ }
+ else
+ {
+ // ...move cursor back to click position
+ LLUI::setCursorPositionScreen(mMouseDownX, mMouseDownY);
+ }
+
+ gViewerWindow->showCursor();
+ }
+
+ stopGrab();
+ stopSpin();
+ mMode = GRAB_INACTIVE;
+
+ mHideBuildHighlight = FALSE;
+
+ mGrabObject = NULL;
+
+ gSelectMgr->updateSelectionCenter();
+ gAgent.setPointAt(POINTAT_TARGET_CLEAR);
+ gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
+
+ dialog_refresh_all();
+}
+
+
+void LLToolGrab::stopGrab()
+{
+ // Next, send messages to simulator
+ LLMessageSystem *msg = gMessageSystem;
+ switch(mMode)
+ {
+ case GRAB_ACTIVE_CENTER:
+ case GRAB_NONPHYSICAL:
+ case GRAB_LOCKED:
+ msg->newMessageFast(_PREHASH_ObjectDeGrab);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
+ msg->sendMessage(mGrabObject->getRegion()->getHost());
+
+ mVerticalDragging = FALSE;
+ mGrabOffset.clearVec();
+ break;
+
+ case GRAB_NOOBJECT:
+ case GRAB_INACTIVE:
+ default:
+ // do nothing
+ break;
+ }
+
+ mHideBuildHighlight = FALSE;
+}
+
+
+void LLToolGrab::draw()
+{ }
+
+void LLToolGrab::render()
+{ }
+
+BOOL LLToolGrab::isEditing()
+{
+ // Can't just compare to null directly due to "smart" pointer.
+ LLViewerObject *obj = mGrabObject;
+ return (obj != NULL);
+}
+
+LLViewerObject* LLToolGrab::getEditingObject()
+{
+ return mGrabObject;
+}
+
+
+LLVector3d LLToolGrab::getEditingPointGlobal()
+{
+ return getGrabPointGlobal();
+}
+
+LLVector3d LLToolGrab::getGrabPointGlobal()
+{
+ switch(mMode)
+ {
+ case GRAB_ACTIVE_CENTER:
+ case GRAB_NONPHYSICAL:
+ case GRAB_LOCKED:
+ return gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
+
+ case GRAB_NOOBJECT:
+ case GRAB_INACTIVE:
+ default:
+ return gAgent.getPositionGlobal();
+ }
+}