aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltoolgrab.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/lltoolgrab.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/lltoolgrab.cpp')
-rw-r--r--linden/indra/newview/lltoolgrab.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/linden/indra/newview/lltoolgrab.cpp b/linden/indra/newview/lltoolgrab.cpp
new file mode 100644
index 0000000..90dbd48
--- /dev/null
+++ b/linden/indra/newview/lltoolgrab.cpp
@@ -0,0 +1,894 @@
1/**
2 * @file lltoolgrab.cpp
3 * @brief LLToolGrab class implementation
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "lltoolgrab.h"
31
32// library headers
33#include "indra_constants.h" // for agent control flags
34#include "llviewercontrol.h"
35#include "llquaternion.h"
36#include "llbox.h"
37#include "message.h"
38#include "llview.h"
39#include "llfontgl.h"
40#include "llui.h"
41
42// newview headers
43#include "llagent.h"
44//#include "llfloateravatarinfo.h"
45#include "lldrawable.h"
46#include "llfloatertools.h"
47#include "llhudeffect.h"
48#include "llhudmanager.h"
49#include "llregionposition.h"
50#include "llselectmgr.h"
51#include "llstatusbar.h"
52#include "lltoolmgr.h"
53#include "lltoolpie.h"
54#include "llviewercamera.h"
55#include "llviewerobject.h"
56#include "llviewerobjectlist.h"
57#include "llviewerregion.h"
58#include "llviewerwindow.h"
59#include "llvoavatar.h"
60#include "llworld.h"
61#include "viewer.h"
62
63const S32 SLOP_DIST_SQ = 4;
64
65// Override modifier key behavior with these buttons
66BOOL gGrabBtnVertical = FALSE;
67BOOL gGrabBtnSpin = FALSE;
68LLTool* gGrabTransientTool = NULL;
69LLToolGrab *gToolGrab = NULL;
70extern BOOL gDebugClicks;
71
72//
73// Methods
74//
75LLToolGrab::LLToolGrab( LLToolComposite* composite )
76: LLTool( "Grab", composite ),
77 mMode( GRAB_INACTIVE ),
78 mVerticalDragging( FALSE ),
79 mHitLand(FALSE),
80 mHitObjectID(),
81 mGrabObject( NULL ),
82 mMouseDownX( -1 ),
83 mMouseDownY( -1 ),
84 mHasMoved( FALSE ),
85 mSpinGrabbing( FALSE ),
86 mSpinRotation(),
87 mHideBuildHighlight(FALSE)
88{ }
89
90LLToolGrab::~LLToolGrab()
91{ }
92
93
94// virtual
95void LLToolGrab::handleSelect()
96{
97 gFloaterTools->setStatusText("Drag to move objects, Ctrl to lift, Ctrl-Shift to spin");
98 gGrabBtnVertical = FALSE;
99 gGrabBtnSpin = FALSE;
100}
101
102void LLToolGrab::handleDeselect()
103{
104 if( hasMouseCapture() )
105 {
106 setMouseCapture( FALSE );
107 }
108
109 gFloaterTools->setStatusText("");
110}
111
112BOOL LLToolGrab::handleDoubleClick(S32 x, S32 y, MASK mask)
113{
114 if (gDebugClicks)
115 {
116 llinfos << "LLToolGrab handleDoubleClick (becoming mouseDown)" << llendl;
117 }
118
119 return FALSE;
120}
121
122BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask)
123{
124 if (gDebugClicks)
125 {
126 llinfos << "LLToolGrab handleMouseDown" << llendl;
127 }
128
129 mHitLand = FALSE;
130
131 // call the base class to propogate info to sim
132 LLTool::handleMouseDown(x, y, mask);
133
134 if (!gAgent.leftButtonGrabbed())
135 {
136 // can grab transparent objects (how touch event propagates, scripters rely on this)
137 gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, TRUE);
138 }
139 return TRUE;
140}
141
142void LLToolGrab::pickCallback(S32 x, S32 y, MASK mask)
143{
144 LLViewerObject *objectp = gObjectList.findObject( gLastHitObjectID );
145
146 BOOL extend_select = (mask & MASK_SHIFT);
147
148 if (!extend_select && !gSelectMgr->isEmpty())
149 {
150 gSelectMgr->deselectAll();
151 gToolGrab->mDeselectedThisClick = TRUE;
152 }
153 else
154 {
155 gToolGrab->mDeselectedThisClick = FALSE;
156 }
157
158 // if not over object, do nothing
159 if (!objectp)
160 {
161 gToolGrab->setMouseCapture(TRUE);
162 gToolGrab->mMode = GRAB_NOOBJECT;
163 gToolGrab->mHitObjectID.setNull();
164 }
165 else
166 {
167 gToolGrab->handleObjectHit(objectp, x, y, mask);
168 }
169}
170
171BOOL LLToolGrab::handleObjectHit(LLViewerObject *objectp, S32 x, S32 y, MASK mask)
172{
173 mMouseDownX = x;
174 mMouseDownY = y;
175 mMouseMask = mask;
176
177 if (gDebugClicks)
178 {
179 llinfos << "LLToolGrab handleObjectHit " << mMouseDownX << "," << mMouseDownY << llendl;
180 }
181
182 if (objectp->isAvatar())
183 {
184 if (gGrabTransientTool)
185 {
186 gBasicToolset->selectTool( gGrabTransientTool );
187 gGrabTransientTool = NULL;
188 }
189 return TRUE;
190 }
191
192 setMouseCapture( TRUE );
193
194 mHitObjectID = objectp->getID();
195
196 // Grabs always start from the root
197 // objectp = (LLViewerObject *)objectp->getRoot();
198
199 LLViewerObject* parent = objectp->getRootEdit();
200 BOOL script_touch = (objectp && objectp->flagHandleTouch()) || (parent && parent->flagHandleTouch());
201
202 // Clicks on scripted or physical objects are temporary grabs, so
203 // not "Build mode"
204 mHideBuildHighlight = script_touch || objectp->usePhysics();
205
206 if (!objectp->usePhysics())
207 {
208 // In mouselook, we shouldn't be able to grab non-physical,
209 // non-touchable objects. If it has a touch handler, we
210 // do grab it (so llDetectedGrab works), but movement is
211 // blocked on the server side. JC
212 if (gAgent.cameraMouselook() && !script_touch)
213 {
214 mMode = GRAB_LOCKED;
215 }
216 else
217 {
218 mMode = GRAB_NONPHYSICAL;
219 }
220 gViewerWindow->hideCursor();
221 gViewerWindow->moveCursorToCenter();
222 // Don't bail out here, go on and grab so buttons can get
223 // their "touched" event.
224 }
225 else if( !objectp->permMove() )
226 {
227 // if mouse is over a physical object without move permission, show feedback if user tries to move it.
228 mMode = GRAB_LOCKED;
229
230 // Don't bail out here, go on and grab so buttons can get
231 // their "touched" event.
232 }
233 else
234 {
235 // if mouse is over a physical object with move permission,
236 // select it and enter "grab" mode (hiding cursor, etc.)
237
238 mMode = GRAB_ACTIVE_CENTER;
239
240 gViewerWindow->hideCursor();
241 gViewerWindow->moveCursorToCenter();
242 }
243
244 // Always send "touched" message
245
246 mAccumDeltaX = 0;
247 mAccumDeltaY = 0;
248 mHasMoved = FALSE;
249 mOutsideSlop = FALSE;
250
251 mGrabObject = objectp;
252
253 mGrabOffset.clearVec();
254
255 mVerticalDragging = (mask == MASK_VERTICAL) || gGrabBtnVertical;
256
257 startGrab(x, y);
258
259 if ((mask == MASK_SPIN) || gGrabBtnSpin)
260 {
261 startSpin();
262 }
263
264 gSelectMgr->updateSelectionCenter(); // update selection beam
265
266 // update point at
267 LLViewerObject *edit_object = gObjectList.findObject(mHitObjectID);
268 if (edit_object)
269 {
270 LLVector3 local_edit_point = gAgent.getPosAgentFromGlobal(gLastHitNonFloraPosGlobal);
271 local_edit_point -= edit_object->getPositionAgent();
272 local_edit_point = local_edit_point * ~edit_object->getRenderRotation();
273 gAgent.setPointAt(POINTAT_TARGET_GRAB, edit_object, local_edit_point );
274 gAgent.setLookAt(LOOKAT_TARGET_SELECT, edit_object, local_edit_point );
275 }
276
277 // on transient grabs (clicks on world objects), kill the grab immediately
278 if (!gViewerWindow->getLeftMouseDown()
279 && gGrabTransientTool
280 && (mMode == GRAB_NONPHYSICAL || mMode == GRAB_LOCKED))
281 {
282 gBasicToolset->selectTool( gGrabTransientTool );
283 gGrabTransientTool = NULL;
284 }
285
286 return TRUE;
287}
288
289
290void LLToolGrab::startSpin()
291{
292 mSpinGrabbing = TRUE;
293
294 // Was saveSelectedObjectTransform()
295 LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
296 mSpinRotation = root->getRotation();
297
298 LLMessageSystem *msg = gMessageSystem;
299 msg->newMessageFast(_PREHASH_ObjectSpinStart);
300 msg->nextBlockFast(_PREHASH_AgentData);
301 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
302 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
303 msg->nextBlockFast(_PREHASH_ObjectData);
304 msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
305 msg->sendMessage( mGrabObject->getRegion()->getHost() );
306}
307
308
309void LLToolGrab::stopSpin()
310{
311 mSpinGrabbing = FALSE;
312
313 LLMessageSystem *msg = gMessageSystem;
314 switch(mMode)
315 {
316 case GRAB_ACTIVE_CENTER:
317 case GRAB_NONPHYSICAL:
318 case GRAB_LOCKED:
319 msg->newMessageFast(_PREHASH_ObjectSpinStop);
320 msg->nextBlockFast(_PREHASH_AgentData);
321 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
322 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
323 msg->nextBlockFast(_PREHASH_ObjectData);
324 msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
325 msg->sendMessage( mGrabObject->getRegion()->getHost() );
326 break;
327
328 case GRAB_NOOBJECT:
329 case GRAB_INACTIVE:
330 default:
331 // do nothing
332 break;
333 }
334}
335
336
337void LLToolGrab::startGrab(S32 x, S32 y)
338{
339 // Compute grab_offset in the OBJECT's root's coordinate frame
340 // (sometimes root == object)
341 LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
342
343 // drag from center
344 LLVector3d grab_start_global = root->getPositionGlobal();
345
346 // Where the grab starts, relative to the center of the root object of the set.
347 // JC - This code looks wonky, but I believe it does the right thing.
348 // Otherwise, when you grab a linked object set, it "pops" on the start
349 // of the drag.
350 LLVector3d grab_offsetd = root->getPositionGlobal() - mGrabObject->getPositionGlobal();
351
352 LLVector3 grab_offset;
353 grab_offset.setVec(grab_offsetd);
354
355 LLQuaternion rotation = root->getRotation();
356 rotation.conjQuat();
357 grab_offset = grab_offset * rotation;
358
359 // This planar drag starts at the grab point
360 mDragStartPointGlobal = grab_start_global;
361 mDragStartFromCamera = grab_start_global - gAgent.getCameraPositionGlobal();
362
363 LLMessageSystem *msg = gMessageSystem;
364 msg->newMessageFast(_PREHASH_ObjectGrab);
365 msg->nextBlockFast(_PREHASH_AgentData);
366 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
367 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
368 msg->nextBlockFast(_PREHASH_ObjectData);
369 msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
370 msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset );
371 msg->sendMessage( mGrabObject->getRegion()->getHost());
372
373 mGrabOffsetFromCenterInitial = grab_offset;
374 mGrabHiddenOffsetFromCamera = mDragStartFromCamera;
375
376 mGrabTimer.reset();
377}
378
379
380BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
381{
382 mLastMouseX = x;
383 mLastMouseY = y;
384
385 if (!gViewerWindow->getLeftMouseDown())
386 {
387 gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
388 setMouseCapture(FALSE);
389 return TRUE;
390 }
391
392 // Do the right hover based on mode
393 switch( mMode )
394 {
395 case GRAB_ACTIVE_CENTER:
396 case GRAB_NONPHYSICAL:
397 handleHoverActive( x, y, mask ); // cursor hidden
398 break;
399
400 case GRAB_INACTIVE:
401 handleHoverInactive( x, y, mask ); // cursor set here
402 break;
403
404 case GRAB_NOOBJECT:
405 case GRAB_LOCKED:
406 handleHoverFailed( x, y, mask );
407 break;
408
409 }
410
411 return TRUE;
412}
413
414
415
416
417// Dragging.
418void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask)
419{
420 llassert( hasMouseCapture() );
421 llassert( mGrabObject );
422 if (mGrabObject->isDead())
423 {
424 // Bail out of drag because object has been killed
425 setMouseCapture(FALSE);
426 return;
427 }
428
429 //--------------------------------------------------
430 // Toggle spinning
431 //--------------------------------------------------
432 if (mSpinGrabbing && !(mask == MASK_SPIN) && !gGrabBtnSpin)
433 {
434 // user released ALT key, stop spinning
435 stopSpin();
436 }
437 else if (!mSpinGrabbing && (mask == MASK_SPIN) )
438 {
439 // user pressed ALT key, start spinning
440 startSpin();
441 }
442
443 //--------------------------------------------------
444 // Toggle vertical dragging
445 //--------------------------------------------------
446 if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical)
447 {
448 // ...switch to horizontal dragging
449 mVerticalDragging = FALSE;
450
451 mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
452 mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
453 }
454 else if (!mVerticalDragging && (mask == MASK_VERTICAL) )
455 {
456 // ...switch to vertical dragging
457 mVerticalDragging = TRUE;
458
459 mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
460 mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
461 }
462
463 const F32 RADIANS_PER_PIXEL_X = 0.01f;
464 const F32 RADIANS_PER_PIXEL_Y = 0.01f;
465
466 const F32 SENSITIVITY_X = 0.0075f;
467 const F32 SENSITIVITY_Y = 0.0075f;
468
469 S32 dx = x - (gViewerWindow->getWindowWidth() / 2);
470 S32 dy = y - (gViewerWindow->getWindowHeight() / 2);
471
472 if (dx != 0 || dy != 0)
473 {
474 mAccumDeltaX += dx;
475 mAccumDeltaY += dy;
476 S32 dist_sq = mAccumDeltaX * mAccumDeltaX + mAccumDeltaY * mAccumDeltaY;
477 if (dist_sq > SLOP_DIST_SQ)
478 {
479 mOutsideSlop = TRUE;
480 }
481
482 // mouse has moved outside center
483 mHasMoved = TRUE;
484
485 if (mSpinGrabbing)
486 {
487 //------------------------------------------------------
488 // Handle spinning
489 //------------------------------------------------------
490
491 // x motion maps to rotation around vertical axis
492 LLVector3 up(0.f, 0.f, 1.f);
493 LLQuaternion rotation_around_vertical( dx*RADIANS_PER_PIXEL_X, up );
494
495 // y motion maps to rotation around left axis
496 const LLVector3 &agent_left = gCamera->getLeftAxis();
497 LLQuaternion rotation_around_left( dy*RADIANS_PER_PIXEL_Y, agent_left );
498
499 // compose with current rotation
500 mSpinRotation = mSpinRotation * rotation_around_vertical;
501 mSpinRotation = mSpinRotation * rotation_around_left;
502
503 // TODO: Throttle these
504 LLMessageSystem *msg = gMessageSystem;
505 msg->newMessageFast(_PREHASH_ObjectSpinUpdate);
506 msg->nextBlockFast(_PREHASH_AgentData);
507 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
508 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
509 msg->nextBlockFast(_PREHASH_ObjectData);
510 msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
511 msg->addQuatFast(_PREHASH_Rotation, mSpinRotation );
512 msg->sendMessage( mGrabObject->getRegion()->getHost() );
513 }
514 else
515 {
516 //------------------------------------------------------
517 // Handle grabbing
518 //------------------------------------------------------
519
520 LLVector3d x_part;
521 x_part.setVec(gCamera->getLeftAxis());
522 x_part.mdV[VZ] = 0.0;
523 x_part.normVec();
524
525 LLVector3d y_part;
526 if( mVerticalDragging )
527 {
528 y_part.setVec(gCamera->getUpAxis());
529 // y_part.setVec(0.f, 0.f, 1.f);
530 }
531 else
532 {
533 // drag toward camera
534 y_part = x_part % LLVector3d::z_axis;
535 y_part.mdV[VZ] = 0.0;
536 y_part.normVec();
537 }
538
539 mGrabHiddenOffsetFromCamera = mGrabHiddenOffsetFromCamera
540 + (x_part * (-dx * SENSITIVITY_X))
541 + (y_part * ( dy * SENSITIVITY_Y));
542
543
544 // Send the message to the viewer.
545 F32 dt = mGrabTimer.getElapsedTimeAndResetF32();
546 U32 dt_milliseconds = (U32) (1000.f * dt);
547
548 // need to return offset from mGrabStartPoint
549 LLVector3d grab_point_global;
550
551 grab_point_global = gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
552
553 /* Snap to grid disabled for grab tool - very confusing
554 // Handle snapping to grid, but only when the tool is formally selected.
555 BOOL snap_on = gSavedSettings.getBOOL("SnapEnabled");
556 if (snap_on && !gGrabTransientTool)
557 {
558 F64 snap_size = gSavedSettings.getF32("GridResolution");
559 U8 snap_dimensions = (mVerticalDragging ? 3 : 2);
560
561 for (U8 i = 0; i < snap_dimensions; i++)
562 {
563 grab_point_global.mdV[i] += snap_size / 2;
564 grab_point_global.mdV[i] -= fmod(grab_point_global.mdV[i], snap_size);
565 }
566 }
567 */
568
569 // Don't let object centers go underground.
570 F32 land_height = gWorldPointer->resolveLandHeightGlobal(grab_point_global);
571
572 if (grab_point_global.mdV[VZ] < land_height)
573 {
574 grab_point_global.mdV[VZ] = land_height;
575 }
576
577 // For safety, cap heights where objects can be dragged
578 if (grab_point_global.mdV[VZ] > MAX_OBJECT_Z)
579 {
580 grab_point_global.mdV[VZ] = MAX_OBJECT_Z;
581 }
582
583 grab_point_global = gWorldp->clipToVisibleRegions(mDragStartPointGlobal, grab_point_global);
584 // propagate constrained grab point back to grab offset
585 mGrabHiddenOffsetFromCamera = grab_point_global - gAgent.getCameraPositionGlobal();
586
587 // Handle auto-rotation at screen edge.
588 LLVector3 grab_pos_agent = gAgent.getPosAgentFromGlobal( grab_point_global );
589
590 LLCoordGL grab_center_gl( gViewerWindow->getWindowWidth() / 2, gViewerWindow->getWindowHeight() / 2);
591 gCamera->projectPosAgentToScreen(grab_pos_agent, grab_center_gl);
592
593 const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20;
594 const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD;
595 const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
596 // ...build mode moves camera about focus point
597 if (grab_center_gl.mX < ROTATE_H_MARGIN)
598 {
599 if (gAgent.getFocusOnAvatar())
600 {
601 gAgent.yaw(rotate_angle);
602 }
603 else
604 {
605 gAgent.cameraOrbitAround(rotate_angle);
606 }
607 }
608 else if (grab_center_gl.mX > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN)
609 {
610 if (gAgent.getFocusOnAvatar())
611 {
612 gAgent.yaw(-rotate_angle);
613 }
614 else
615 {
616 gAgent.cameraOrbitAround(-rotate_angle);
617 }
618 }
619
620 // Don't move above top of screen or below bottom
621 if ((grab_center_gl.mY < gViewerWindow->getWindowHeight() - 6)
622 && (grab_center_gl.mY > 24))
623 {
624 // Transmit update to simulator
625 LLVector3 grab_pos_region = mGrabObject->getRegion()->getPosRegionFromGlobal( grab_point_global );
626
627 LLMessageSystem *msg = gMessageSystem;
628 msg->newMessageFast(_PREHASH_ObjectGrabUpdate);
629 msg->nextBlockFast(_PREHASH_AgentData);
630 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
631 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
632 msg->nextBlockFast(_PREHASH_ObjectData);
633 msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
634 msg->addVector3Fast(_PREHASH_GrabOffsetInitial, mGrabOffsetFromCenterInitial );
635 msg->addVector3Fast(_PREHASH_GrabPosition, grab_pos_region );
636 msg->addU32Fast(_PREHASH_TimeSinceLast, dt_milliseconds );
637 msg->sendMessage( mGrabObject->getRegion()->getHost() );
638 }
639 }
640
641 gViewerWindow->moveCursorToCenter();
642
643 gSelectMgr->updateSelectionCenter();
644
645 }
646
647 // once we've initiated a drag, lock the camera down
648 if (mHasMoved)
649 {
650 if (!gAgent.cameraMouselook() &&
651 !mGrabObject->isHUDAttachment() &&
652 mGrabObject->getRoot() == gAgent.getAvatarObject()->getRoot())
653 {
654 // force focus to point in space where we were looking previously
655 gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
656 gAgent.setFocusOnAvatar(FALSE, ANIMATE);
657 }
658 else
659 {
660 gAgent.clearFocusObject();
661 }
662 }
663
664 // 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.
665 gViewerWindow->setCursor(UI_CURSOR_ARROW);
666
667 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (active) [cursor hidden]" << llendl;
668}
669
670
671// Not dragging. Just showing affordances
672void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask)
673{
674 const F32 ROTATE_ANGLE_PER_SECOND = 40.f * DEG_TO_RAD;
675 const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
676
677 // Look for cursor against the edge of the screen
678 // Only works in fullscreen
679 if (gSavedSettings.getBOOL("FullScreen"))
680 {
681 if (gAgent.cameraThirdPerson() )
682 {
683 if (x == 0)
684 {
685 gAgent.yaw(rotate_angle);
686 //gAgent.setControlFlags(AGENT_CONTROL_YAW_POS);
687 }
688 else if (x == (gViewerWindow->getWindowWidth() - 1) )
689 {
690 gAgent.yaw(-rotate_angle);
691 //gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG);
692 }
693 }
694 }
695
696 // JC - TODO - change cursor based on gGrabBtnVertical, gGrabBtnSpin
697 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (inactive-not over editable object)" << llendl;
698 gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
699}
700
701// User is trying to do something that's not allowed.
702void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask)
703{
704 if( GRAB_NOOBJECT == mMode )
705 {
706 gViewerWindow->setCursor(UI_CURSOR_NO);
707 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (not on object)" << llendl;
708 }
709 else
710 {
711 S32 dist_sq = (x-mMouseDownX) * (x-mMouseDownX) + (y-mMouseDownY) * (y-mMouseDownY);
712 if( mOutsideSlop || dist_sq > SLOP_DIST_SQ )
713 {
714 mOutsideSlop = TRUE;
715
716 switch( mMode )
717 {
718 case GRAB_LOCKED:
719 gViewerWindow->setCursor(UI_CURSOR_GRABLOCKED);
720 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, no move permission)" << llendl;
721 break;
722
723// Non physical now handled by handleHoverActive - CRO
724// case GRAB_NONPHYSICAL:
725// gViewerWindow->setCursor(UI_CURSOR_ARROW);
726// lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, nonphysical)" << llendl;
727// break;
728 default:
729 llassert(0);
730 }
731 }
732 else
733 {
734 gViewerWindow->setCursor(UI_CURSOR_ARROW);
735 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed but within slop)" << llendl;
736 }
737 }
738}
739
740
741
742
743BOOL LLToolGrab::handleMouseUp(S32 x, S32 y, MASK mask)
744{
745 // call the base class to propogate info to sim
746 LLTool::handleMouseUp(x, y, mask);
747
748 if( hasMouseCapture() )
749 {
750 setMouseCapture( FALSE );
751 }
752 mMode = GRAB_INACTIVE;
753
754 // HACK: Make some grabs temporary
755 if (gGrabTransientTool)
756 {
757 gBasicToolset->selectTool( gGrabTransientTool );
758 gGrabTransientTool = NULL;
759 }
760
761 //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
762
763 return TRUE;
764}
765
766void LLToolGrab::stopEditing()
767{
768 if( hasMouseCapture() )
769 {
770 setMouseCapture( FALSE );
771 }
772}
773
774void LLToolGrab::onMouseCaptureLost()
775{
776 // First, fix cursor placement
777 if( !gAgent.cameraMouselook()
778 && (GRAB_ACTIVE_CENTER == mMode || GRAB_NONPHYSICAL == mMode))
779 {
780 llassert( mGrabObject );
781
782 if (mGrabObject->isHUDAttachment())
783 {
784 // ...move cursor "naturally", as if it had moved when hidden
785 S32 x = mMouseDownX + mAccumDeltaX;
786 S32 y = mMouseDownY + mAccumDeltaY;
787 LLUI::setCursorPositionScreen(x, y);
788 }
789 else if (mHasMoved)
790 {
791 // ...move cursor back to the center of the object
792 LLVector3 grab_point_agent = mGrabObject->getRenderPosition();
793
794 LLCoordGL gl_point;
795 gCamera->projectPosAgentToScreen(grab_point_agent, gl_point);
796
797 LLUI::setCursorPositionScreen(gl_point.mX, gl_point.mY);
798 }
799 else
800 {
801 // ...move cursor back to click position
802 LLUI::setCursorPositionScreen(mMouseDownX, mMouseDownY);
803 }
804
805 gViewerWindow->showCursor();
806 }
807
808 stopGrab();
809 stopSpin();
810 mMode = GRAB_INACTIVE;
811
812 mHideBuildHighlight = FALSE;
813
814 mGrabObject = NULL;
815
816 gSelectMgr->updateSelectionCenter();
817 gAgent.setPointAt(POINTAT_TARGET_CLEAR);
818 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
819
820 dialog_refresh_all();
821}
822
823
824void LLToolGrab::stopGrab()
825{
826 // Next, send messages to simulator
827 LLMessageSystem *msg = gMessageSystem;
828 switch(mMode)
829 {
830 case GRAB_ACTIVE_CENTER:
831 case GRAB_NONPHYSICAL:
832 case GRAB_LOCKED:
833 msg->newMessageFast(_PREHASH_ObjectDeGrab);
834 msg->nextBlockFast(_PREHASH_AgentData);
835 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
836 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
837 msg->nextBlockFast(_PREHASH_ObjectData);
838 msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
839 msg->sendMessage(mGrabObject->getRegion()->getHost());
840
841 mVerticalDragging = FALSE;
842 mGrabOffset.clearVec();
843 break;
844
845 case GRAB_NOOBJECT:
846 case GRAB_INACTIVE:
847 default:
848 // do nothing
849 break;
850 }
851
852 mHideBuildHighlight = FALSE;
853}
854
855
856void LLToolGrab::draw()
857{ }
858
859void LLToolGrab::render()
860{ }
861
862BOOL LLToolGrab::isEditing()
863{
864 // Can't just compare to null directly due to "smart" pointer.
865 LLViewerObject *obj = mGrabObject;
866 return (obj != NULL);
867}
868
869LLViewerObject* LLToolGrab::getEditingObject()
870{
871 return mGrabObject;
872}
873
874
875LLVector3d LLToolGrab::getEditingPointGlobal()
876{
877 return getGrabPointGlobal();
878}
879
880LLVector3d LLToolGrab::getGrabPointGlobal()
881{
882 switch(mMode)
883 {
884 case GRAB_ACTIVE_CENTER:
885 case GRAB_NONPHYSICAL:
886 case GRAB_LOCKED:
887 return gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
888
889 case GRAB_NOOBJECT:
890 case GRAB_INACTIVE:
891 default:
892 return gAgent.getPositionGlobal();
893 }
894}