lltoolpie.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "lltoolpie.h"
00035 
00036 #include "indra_constants.h"
00037 #include "llclickaction.h"
00038 #include "llparcel.h"
00039 
00040 #include "llagent.h"
00041 #include "llviewercontrol.h"
00042 #include "llfirstuse.h"
00043 #include "llfloateravatarinfo.h"
00044 #include "llfloaterland.h"
00045 #include "llfloaterscriptdebug.h"
00046 #include "llhoverview.h"
00047 #include "llhudeffecttrail.h"
00048 #include "llhudmanager.h"
00049 #include "llmenugl.h"
00050 #include "llmutelist.h"
00051 #include "llselectmgr.h"
00052 #include "lltoolfocus.h"
00053 #include "lltoolgrab.h"
00054 #include "lltoolmgr.h"
00055 #include "lltoolselect.h"
00056 #include "llviewercamera.h"
00057 #include "llviewermenu.h"
00058 #include "llviewerobject.h"
00059 #include "llviewerobjectlist.h"
00060 #include "llviewerparcelmgr.h"
00061 #include "llviewerwindow.h"
00062 #include "llvoavatar.h"
00063 #include "llworld.h"
00064 #include "llui.h"
00065 
00066 LLToolPie *gToolPie = NULL;
00067 
00068 LLPointer<LLViewerObject> LLToolPie::sClickActionObject;
00069 LLHandle<LLObjectSelection> LLToolPie::sLeftClickSelection = NULL;
00070 U8 LLToolPie::sClickAction = 0;
00071 
00072 extern void handle_buy(void*);
00073 
00074 extern BOOL gDebugClicks;
00075 
00076 LLToolPie::LLToolPie()
00077 :       LLTool("Select"),
00078         mPieMouseButtonDown( FALSE ),
00079         mGrabMouseButtonDown( FALSE ),
00080         mHitLand( FALSE ),
00081         mHitObjectID(),
00082         mMouseOutsideSlop( FALSE )
00083 { }
00084 
00085 
00086 BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
00087 {
00088         //left mouse down always picks transparent
00089         gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, leftMouseCallback, 
00090                                                                                           TRUE, TRUE);
00091         mGrabMouseButtonDown = TRUE;
00092         return TRUE;
00093 }
00094 
00095 // static
00096 void LLToolPie::leftMouseCallback(S32 x, S32 y, MASK mask)
00097 {
00098         gToolPie->pickAndShowMenu(x, y, mask, FALSE);
00099 }
00100 
00101 BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
00102 {
00103         // Pick faces in case they select "Copy Texture" and need that info.
00104         gPickFaces = TRUE;
00105         // don't pick transparent so users can't "pay" transparent objects
00106         gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, rightMouseCallback,
00107                                                                                           FALSE, TRUE);
00108         mPieMouseButtonDown = TRUE; 
00109         // don't steal focus from UI
00110         return FALSE;
00111 }
00112 
00113 // static
00114 void LLToolPie::rightMouseCallback(S32 x, S32 y, MASK mask)
00115 {
00116         gToolPie->pickAndShowMenu(x, y, mask, TRUE);
00117 }
00118 
00119 // True if you selected an object.
00120 BOOL LLToolPie::pickAndShowMenu(S32 x, S32 y, MASK mask, BOOL always_show)
00121 {
00122         if (!always_show && gLastHitParcelWall)
00123         {
00124                 LLParcel* parcel = gParcelMgr->getCollisionParcel();
00125                 if (parcel)
00126                 {
00127                         gParcelMgr->selectCollisionParcel();
00128                         if (parcel->getParcelFlag(PF_USE_PASS_LIST) 
00129                                 && !gParcelMgr->isCollisionBanned())
00130                         {
00131                                 // if selling passes, just buy one
00132                                 void* deselect_when_done = (void*)TRUE;
00133                                 LLPanelLandGeneral::onClickBuyPass(deselect_when_done);
00134                         }
00135                         else
00136                         {
00137                                 // not selling passes, get info
00138                                 LLFloaterLand::show();
00139                         }
00140                 }
00141 
00142                 return LLTool::handleMouseDown(x, y, mask);
00143         }
00144 
00145         // didn't click in any UI object, so must have clicked in the world
00146         LLViewerObject *object = gViewerWindow->lastObjectHit();
00147         LLViewerObject *parent = NULL;
00148 
00149         mHitLand = !object && !gLastHitPosGlobal.isExactlyZero();
00150         if (!mHitLand)
00151         {
00152                 gParcelMgr->deselectLand();
00153         }
00154         
00155         if (object)
00156         {
00157                 mHitObjectID = object->mID;
00158 
00159                 parent = object->getRootEdit();
00160         }
00161         else
00162         {
00163                 mHitObjectID.setNull();
00164         }
00165 
00166         BOOL touchable = (object && object->flagHandleTouch()) 
00167                                          || (parent && parent->flagHandleTouch());
00168 
00169         // If it's a left-click, and we have a special action, do it.
00170         if (useClickAction(always_show, mask, object, parent))
00171         {
00172                 sClickAction = 0;
00173                 if (object && object->getClickAction()) 
00174                 {
00175                         sClickAction = object->getClickAction();
00176                 }
00177                 else if (parent && parent->getClickAction()) 
00178                 {
00179                         sClickAction = parent->getClickAction();
00180                 }
00181 
00182                 switch(sClickAction)
00183                 {
00184                 case CLICK_ACTION_TOUCH:
00185                 default:
00186                         // nothing
00187                         break;
00188                 case CLICK_ACTION_SIT:
00189                         handle_sit_or_stand();
00190                         return TRUE;
00191                 case CLICK_ACTION_PAY:
00192                         if (object && object->flagTakesMoney()
00193                                 || parent && parent->flagTakesMoney())
00194                         {
00195                                 // pay event goes to object actually clicked on
00196                                 sClickActionObject = object;
00197                                 sLeftClickSelection = LLToolSelect::handleObjectSelection(object, MASK_NONE, FALSE, TRUE);
00198                                 return TRUE;
00199                         }
00200                         break;
00201                 case CLICK_ACTION_BUY:
00202                         sClickActionObject = parent;
00203                         sLeftClickSelection = LLToolSelect::handleObjectSelection(parent, MASK_NONE, FALSE, TRUE);
00204                         return TRUE;
00205                 case CLICK_ACTION_OPEN:
00206                         if (parent && parent->allowOpen())
00207                         {
00208                                 sClickActionObject = parent;
00209                                 sLeftClickSelection = LLToolSelect::handleObjectSelection(parent, MASK_NONE, FALSE, TRUE);
00210                         }
00211                         return TRUE;
00212                 }
00213         }
00214 
00215         // Switch to grab tool if physical or triggerable
00216         if (object && 
00217                 !object->isAvatar() && 
00218                 ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) && 
00219                 !always_show)
00220         {
00221                 gGrabTransientTool = this;
00222                 gToolMgr->getCurrentToolset()->selectTool( gToolGrab );
00223                 return gToolGrab->handleObjectHit( object, x, y, mask);
00224         }
00225         
00226         if (!object && gLastHitHUDIcon && gLastHitHUDIcon->getSourceObject())
00227         {
00228                 LLFloaterScriptDebug::show(gLastHitHUDIcon->getSourceObject()->getID());
00229         }
00230 
00231         // If left-click never selects or spawns a menu
00232         // Eat the event.
00233         if (!gSavedSettings.getBOOL("LeftClickShowMenu")
00234                 && !always_show)
00235         {
00236                 // mouse already released
00237                 if (!mGrabMouseButtonDown)
00238                 {
00239                         return TRUE;
00240                 }
00241 
00242                 while( object && object->isAttachment() && !object->flagHandleTouch())
00243                 {
00244                         // don't pick avatar through hud attachment
00245                         if (object->isHUDAttachment())
00246                         {
00247                                 break;
00248                         }
00249                         object = (LLViewerObject*)object->getParent();
00250                 }
00251                 if (object && object == gAgent.getAvatarObject())
00252                 {
00253                         // we left clicked on avatar, switch to focus mode
00254                         gToolMgr->setTransientTool(gToolCamera);
00255                         gViewerWindow->hideCursor();
00256                         gToolCamera->setMouseCapture(TRUE);
00257                         gToolCamera->pickCallback(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY(), mask);
00258                         gAgent.setFocusOnAvatar(TRUE, TRUE);
00259 
00260                         return TRUE;
00261                 }
00262                 // Could be first left-click on nothing
00263                 LLFirstUse::useLeftClickNoHit();
00264 
00265                 // Eat the event
00266                 return LLTool::handleMouseDown(x, y, mask);
00267         }
00268 
00269         if (!always_show && gAgent.leftButtonGrabbed())
00270         {
00271                 // if the left button is grabbed, don't put up the pie menu
00272                 return LLTool::handleMouseDown(x, y, mask);
00273         }
00274 
00275         // Can't ignore children here.
00276         LLToolSelect::handleObjectSelection(object, mask, FALSE, TRUE);
00277 
00278         // Spawn pie menu
00279         if (mHitLand)
00280         {
00281                 LLParcelSelectionHandle selection = gParcelMgr->selectParcelAt( gLastHitPosGlobal );
00282                 gMenuHolder->setParcelSelection(selection);
00283                 gPieLand->show(x, y, mPieMouseButtonDown);
00284 
00285                 // VEFFECT: ShowPie
00286                 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
00287                 effectp->setPositionGlobal(gLastHitPosGlobal);
00288                 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
00289                 effectp->setDuration(0.25f);
00290         }
00291         else if (mHitObjectID == gAgent.getID() )
00292         {
00293                 gPieSelf->show(x, y, mPieMouseButtonDown);
00294         }
00295         else if (object)
00296         {
00297                 gMenuHolder->setObjectSelection(gSelectMgr->getSelection());
00298 
00299                 if (object->isAvatar() 
00300                         || (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner()))
00301                 {
00302                         // Find the attachment's avatar
00303                         while( object && object->isAttachment())
00304                         {
00305                                 object = (LLViewerObject*)object->getParent();
00306                         }
00307 
00308                         // Object is an avatar, so check for mute by id.
00309                         LLVOAvatar* avatar = (LLVOAvatar*)object;
00310                         LLString name = avatar->getFullname();
00311                         if (gMuteListp->isMuted(avatar->getID(), name))
00312                         {
00313                                 gMenuHolder->childSetText("Avatar Mute", LLString("Unmute")); // *TODO:Translate
00314                                 //gMutePieMenu->setLabel("Unmute");
00315                         }
00316                         else
00317                         {
00318                                 gMenuHolder->childSetText("Avatar Mute", LLString("Mute")); // *TODO:Translate
00319                                 //gMutePieMenu->setLabel("Mute");
00320                         }
00321 
00322                         gPieAvatar->show(x, y, mPieMouseButtonDown);
00323                 }
00324                 else if (object->isAttachment())
00325                 {
00326                         gPieAttachment->show(x, y, mPieMouseButtonDown);
00327                 }
00328                 else
00329                 {
00330                         // BUG: What about chatting child objects?
00331                         LLString name;
00332                         LLSelectNode* node = gSelectMgr->getSelection()->getFirstRootNode();
00333                         if (node)
00334                         {
00335                                 name = node->mName;
00336                         }
00337                         if (gMuteListp->isMuted(object->getID(), name))
00338                         {
00339                                 gMenuHolder->childSetText("Object Mute", LLString("Unmute")); // *TODO:Translate
00340                                 //gMuteObjectPieMenu->setLabel("Unmute");
00341                         }
00342                         else
00343                         {
00344                                 gMenuHolder->childSetText("Object Mute", LLString("Mute")); // *TODO:Translate
00345                                 //gMuteObjectPieMenu->setLabel("Mute");
00346                         }
00347                         
00348                         gPieObject->show(x, y, mPieMouseButtonDown);
00349 
00350                         // VEFFECT: ShowPie object
00351                         // Don't show when you click on someone else, it freaks them
00352                         // out.
00353                         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
00354                         effectp->setPositionGlobal(gLastHitPosGlobal);
00355                         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
00356                         effectp->setDuration(0.25f);
00357                 }
00358         }
00359 
00360         if (always_show)
00361         {
00362                 // ignore return value
00363                 LLTool::handleRightMouseDown(x, y, mask);
00364         }
00365         else
00366         {
00367                 // ignore return value
00368                 LLTool::handleMouseDown(x, y, mask);
00369         }
00370 
00371         // We handled the event.
00372         return TRUE;
00373 }
00374 
00375 BOOL LLToolPie::useClickAction(BOOL always_show, 
00376                                                            MASK mask, 
00377                                                            LLViewerObject* object, 
00378                                                            LLViewerObject* parent)
00379 {
00380         return  !always_show
00381                         && mask == MASK_NONE
00382                         && object
00383                         && !object->isAttachment() 
00384                         && LLPrimitive::isPrimitive(object->getPCode())
00385                         && (object->getClickAction() 
00386                                 || parent->getClickAction());
00387 
00388 }
00389 
00390 U8 final_click_action(LLViewerObject* obj)
00391 {
00392         if (!obj) return CLICK_ACTION_NONE;
00393         if (obj->isAttachment()) return CLICK_ACTION_NONE;
00394 
00395         U8 click_action = CLICK_ACTION_TOUCH;
00396         LLViewerObject* parent = obj->getRootEdit();
00397         if (obj->getClickAction()
00398             || (parent && parent->getClickAction()))
00399         {
00400                 if (obj->getClickAction())
00401                 {
00402                         click_action = obj->getClickAction();
00403                 }
00404                 else if (parent && parent->getClickAction())
00405                 {
00406                         click_action = parent->getClickAction();
00407                 }
00408         }
00409         return click_action;
00410 }
00411 
00412 // When we get object properties after left-clicking on an object
00413 // with left-click = buy, if it's the same object, do the buy.
00414 // static
00415 void LLToolPie::selectionPropertiesReceived()
00416 {
00417         // Make sure all data has been received.
00418         // This function will be called repeatedly as the data comes in.
00419         if (!gSelectMgr->selectGetAllValid())
00420         {
00421                 return;
00422         }
00423 
00424         if (!sLeftClickSelection->isEmpty())
00425         {
00426                 LLViewerObject* selected_object = sLeftClickSelection->getPrimaryObject();
00427                 // since we don't currently have a way to lock a selection, it could have changed
00428                 // after we initially clicked on the object
00429                 if (selected_object == sClickActionObject)
00430                 {
00431                         switch (sClickAction)
00432                         {
00433                         case CLICK_ACTION_BUY:
00434                                 handle_buy(NULL);
00435                                 break;
00436                         case CLICK_ACTION_PAY:
00437                                 handle_give_money_dialog();
00438                                 break;
00439                         case CLICK_ACTION_OPEN:
00440                                 handle_object_open();
00441                                 break;
00442                         default:
00443                                 break;
00444                         }
00445                 }
00446         }
00447         sLeftClickSelection = NULL;
00448         sClickActionObject = NULL;
00449         sClickAction = 0;
00450 }
00451 
00452 BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
00453 {
00454                 /*
00455         // If auto-rotate occurs, tag mouse-outside-slop to make sure the drag
00456         // gets started.
00457         const S32 ROTATE_H_MARGIN = (S32) (0.1f * gViewerWindow->getWindowWidth() );
00458         const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD;
00459         const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
00460         // ...normal modes can only yaw
00461         if (x < ROTATE_H_MARGIN)
00462         {
00463                 gAgent.yaw(rotate_angle);
00464                 mMouseOutsideSlop = TRUE;
00465         }
00466         else if (x > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN)
00467         {
00468                 gAgent.yaw(-rotate_angle);
00469                 mMouseOutsideSlop = TRUE;
00470         }
00471         */
00472         
00473         LLViewerObject *object = NULL;
00474         LLViewerObject *parent = NULL;
00475         if (gHoverView)
00476         {
00477                 object = gHoverView->getLastHoverObject();
00478         }
00479 
00480         if (object)
00481         {
00482                 parent = object->getRootEdit();
00483         }
00484 
00485         if (object && useClickAction(FALSE, mask, object, parent))
00486         {
00487                 U8 click_action = final_click_action(object);
00488                 ECursorType cursor = UI_CURSOR_ARROW;
00489                 switch(click_action)
00490                 {
00491                 default: break;
00492                 case CLICK_ACTION_SIT:  cursor = UI_CURSOR_TOOLSIT; break;
00493                 case CLICK_ACTION_BUY:  cursor = UI_CURSOR_TOOLBUY; break;
00494                 case CLICK_ACTION_OPEN:
00495                         // Open always opens the parent.
00496                         if (parent && parent->allowOpen())
00497                         {
00498                                 cursor = UI_CURSOR_TOOLOPEN;
00499                         }
00500                         break;
00501                 case CLICK_ACTION_PAY:  
00502                         if ((object && object->flagTakesMoney())
00503                                 || (parent && parent->flagTakesMoney()))
00504                         {
00505                                 cursor = UI_CURSOR_TOOLPAY;
00506                         }
00507                         break;
00508                 }
00509                 gViewerWindow->getWindow()->setCursor(cursor);
00510                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
00511         }
00512         else if ((object && !object->isAvatar() && object->usePhysics()) 
00513                          || (parent && !parent->isAvatar() && parent->usePhysics()))
00514         {
00515                 gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLGRAB);
00516                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
00517         }
00518         else if ( (object && object->flagHandleTouch()) 
00519                           || (parent && parent->flagHandleTouch()))
00520         {
00521                 gViewerWindow->getWindow()->setCursor(UI_CURSOR_HAND);
00522                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
00523         }
00524         else
00525         {
00526                 gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
00527                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
00528         }
00529 
00530         return TRUE;
00531 }
00532 
00533 BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
00534 {
00535         LLViewerObject* obj = gViewerWindow->lastObjectHit();
00536         U8 click_action = final_click_action(obj);
00537         if (click_action != CLICK_ACTION_NONE)
00538         {
00539                 switch(click_action)
00540                 {
00541                 case CLICK_ACTION_BUY:
00542                 case CLICK_ACTION_PAY:
00543                 case CLICK_ACTION_OPEN:
00544                         // Because these actions open UI dialogs, we won't change
00545                         // the cursor again until the next hover and GL pick over
00546                         // the world.  Keep the cursor an arrow, assuming that 
00547                         // after the user moves off the UI, they won't be on the
00548                         // same object anymore.
00549                         gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
00550                         // Make sure the hover-picked object is ignored.
00551                         gHoverView->resetLastHoverObject();
00552                         break;
00553                 default:
00554                         break;
00555                 }
00556         }
00557         mGrabMouseButtonDown = FALSE;
00558         gToolMgr->clearTransientTool();
00559         gAgent.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
00560         return LLTool::handleMouseUp(x, y, mask);
00561 }
00562 
00563 BOOL LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask)
00564 {
00565         mPieMouseButtonDown = FALSE; 
00566         gToolMgr->clearTransientTool();
00567         return LLTool::handleRightMouseUp(x, y, mask);
00568 }
00569 
00570 
00571 BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
00572 {
00573         if (gDebugClicks)
00574         {
00575                 llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl;
00576         }
00577 
00578         if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
00579         {
00580                 if (gLastHitLand
00581                         && !gLastHitPosGlobal.isExactlyZero())
00582                 {
00583                         handle_go_to();
00584                         return TRUE;
00585                 }
00586                 else if (gLastHitObjectID.notNull()
00587                                  && !gLastHitPosGlobal.isExactlyZero())
00588                 {
00589                         // Hit an object
00590                         // HACK: Call the last hit position the point we hit on the object
00591                         gLastHitPosGlobal += gLastHitObjectOffset;
00592                         handle_go_to();
00593                         return TRUE;
00594                 }
00595         }
00596 
00597         return FALSE;
00598 
00599         /* JC - don't do go-there, because then double-clicking on physical
00600         objects gets you into trouble.
00601 
00602         // If double-click on object or land, go there.
00603         LLViewerObject *object = gViewerWindow->lastObjectHit();
00604         if (object)
00605         {
00606                 if (object->isAvatar())
00607                 {
00608                         LLFloaterAvatarInfo::showFromAvatar(object->getID());
00609                 }
00610                 else
00611                 {
00612                         handle_go_to(NULL);
00613                 }
00614         }
00615         else if (!gLastHitPosGlobal.isExactlyZero())
00616         {
00617                 handle_go_to(NULL);
00618         }
00619 
00620         return TRUE;
00621         */
00622 }
00623 
00624 
00625 void LLToolPie::handleDeselect()
00626 {
00627         if(     hasMouseCapture() )
00628         {
00629                 setMouseCapture( FALSE );  // Calls onMouseCaptureLost() indirectly
00630         }
00631         // remove temporary selection for pie menu
00632         gSelectMgr->validateSelection();
00633 }
00634 
00635 LLTool* LLToolPie::getOverrideTool(MASK mask)
00636 {
00637         if (mask == MASK_CONTROL)
00638         {
00639                 return gToolGrab;
00640         }
00641         else if (mask == (MASK_CONTROL | MASK_SHIFT))
00642         {
00643                 return gToolGrab;
00644         }
00645 
00646         return LLTool::getOverrideTool(mask);
00647 }
00648 
00649 void LLToolPie::stopEditing()
00650 {
00651         if(     hasMouseCapture() )
00652         {
00653                 setMouseCapture( FALSE );  // Calls onMouseCaptureLost() indirectly
00654         }
00655 }
00656 
00657 void LLToolPie::onMouseCaptureLost()
00658 {
00659         mMouseOutsideSlop = FALSE;
00660 }
00661 
00662 
00663 // true if x,y outside small box around start_x,start_y
00664 BOOL LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
00665 {
00666         S32 dx = x - start_x;
00667         S32 dy = y - start_y;
00668 
00669         return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
00670 }
00671 
00672 
00673 void LLToolPie::render()
00674 {
00675         return;
00676 }
00677 
00678 

Generated on Thu Jul 1 06:09:22 2010 for Second Life Viewer by  doxygen 1.4.7