Basically to avoid calling LLTrans::getString 250 times per second, and seeing INFO: log_sStringTemplates_accesses: LLTrans::getString/findString called 19000 in total. INFO: log_sStringTemplates_accesses: LLTrans::getString/findString called 20000 in total. etc, every 40 seconds in the log.
910 lines
23 KiB
C++
910 lines
23 KiB
C++
/**
|
|
* @file llhoverview.cpp
|
|
* @brief LLHoverView class implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2001-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
// self include
|
|
#include "llhoverview.h"
|
|
|
|
// Library includes
|
|
#include "llfontgl.h"
|
|
#include "message.h"
|
|
#include "llgl.h"
|
|
#include "llrender.h"
|
|
#include "llfontgl.h"
|
|
#include "llparcel.h"
|
|
#include "lldbstrings.h"
|
|
#include "llclickaction.h"
|
|
|
|
// Viewer includes
|
|
#include "llagent.h"
|
|
#include "llagentcamera.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llcachename.h"
|
|
#include "llviewercontrol.h"
|
|
#include "lldrawable.h"
|
|
#include "llpermissions.h"
|
|
#include "llresmgr.h"
|
|
#include "llselectmgr.h"
|
|
#include "lltrans.h"
|
|
#include "lltoolmgr.h"
|
|
#include "lltoolpie.h"
|
|
#include "lltoolselectland.h"
|
|
#include "llui.h"
|
|
#include "llviewercamera.h"
|
|
#include "llviewerobject.h"
|
|
#include "llviewerobjectlist.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llglheaders.h"
|
|
#include "llviewertexturelist.h"
|
|
//#include "lltoolobjpicker.h"
|
|
#include "llhudmanager.h" // HACK for creating flex obj's
|
|
#include "llviewermenu.h"
|
|
#include "llviewermedia.h"
|
|
#include "llmediaentry.h"
|
|
|
|
#include "llhudmanager.h" // For testing effects
|
|
#include "llhudeffect.h"
|
|
|
|
#include "hippogridmanager.h"
|
|
|
|
// [RLVa:KB]
|
|
#include "rlvhandler.h"
|
|
// [/RLVa:KB]
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
const char* DEFAULT_DESC = "(No Description)";
|
|
const F32 DELAY_BEFORE_SHOW_TIP = 0.35f;
|
|
const F32 DELAY_BEFORE_REFRESH_TIP = 0.50f;
|
|
|
|
//
|
|
// Local globals
|
|
//
|
|
|
|
LLHoverView *gHoverView = NULL;
|
|
|
|
//
|
|
// Static member functions
|
|
//
|
|
BOOL LLHoverView::sShowHoverTips = TRUE;
|
|
|
|
//
|
|
// Member functions
|
|
//
|
|
|
|
LLHoverView::LLHoverView(const std::string& name, const LLRect& rect)
|
|
: LLView(name, rect, FALSE)
|
|
{
|
|
mDoneHoverPick = FALSE;
|
|
mStartHoverPickTimer = FALSE;
|
|
mHoverActive = FALSE;
|
|
mUseHover = TRUE;
|
|
mTyping = FALSE;
|
|
mHoverOffset.clearVec();
|
|
//<singu>
|
|
mLastTextHoverObject = NULL;
|
|
//</singu>
|
|
}
|
|
|
|
LLHoverView::~LLHoverView()
|
|
{
|
|
}
|
|
|
|
void LLHoverView::updateHover(LLTool* current_tool)
|
|
{
|
|
BOOL picking_tool = ( current_tool == LLToolPie::getInstance()
|
|
|| current_tool == LLToolSelectLand::getInstance() );
|
|
|
|
mUseHover = !gAgentCamera.cameraMouselook()
|
|
&& picking_tool
|
|
&& !mTyping;
|
|
if (mUseHover)
|
|
{
|
|
if ((gViewerWindow->getMouseVelocityStat()->getPrev(0) < 0.01f)
|
|
&& (LLViewerCamera::getInstance()->getAngularVelocityStat()->getPrev(0) < 0.01f)
|
|
&& (LLViewerCamera::getInstance()->getVelocityStat()->getPrev(0) < 0.01f))
|
|
{
|
|
if (!mStartHoverPickTimer)
|
|
{
|
|
mStartHoverTimer.reset();
|
|
mStartHoverPickTimer = TRUE;
|
|
// Clear the existing text so that we do not briefly show the wrong data.
|
|
mText.clear();
|
|
//<singu>
|
|
mLastTextHoverObject = NULL;
|
|
//</singu>
|
|
}
|
|
|
|
if (mDoneHoverPick)
|
|
{
|
|
// Just update the hover data
|
|
updateText();
|
|
}
|
|
else if (mStartHoverTimer.getElapsedTimeF32() > DELAY_BEFORE_SHOW_TIP)
|
|
{
|
|
gViewerWindow->pickAsync(gViewerWindow->getCurrentMouseX(),
|
|
gViewerWindow->getCurrentMouseY(), 0, pickCallback );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cancelHover();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void LLHoverView::pickCallback(const LLPickInfo& pick_info)
|
|
{
|
|
gHoverView->mLastPickInfo = pick_info;
|
|
LLViewerObject* hit_obj = pick_info.getObject();
|
|
|
|
if (hit_obj)
|
|
{
|
|
gHoverView->setHoverActive(TRUE);
|
|
LLSelectMgr::getInstance()->setHoverObject(hit_obj, pick_info.mObjectFace);
|
|
gHoverView->mLastHoverObject = hit_obj;
|
|
gHoverView->mHoverOffset = pick_info.mObjectOffset;
|
|
}
|
|
else
|
|
{
|
|
gHoverView->mLastHoverObject = NULL;
|
|
}
|
|
|
|
// We didn't hit an object, but we did hit land.
|
|
if (!hit_obj && pick_info.mPosGlobal != LLVector3d::zero)
|
|
{
|
|
gHoverView->setHoverActive(TRUE);
|
|
gHoverView->mHoverLandGlobal = pick_info.mPosGlobal;
|
|
LLViewerParcelMgr::getInstance()->setHoverParcel( gHoverView->mHoverLandGlobal );
|
|
}
|
|
else
|
|
{
|
|
gHoverView->mHoverLandGlobal = LLVector3d::zero;
|
|
}
|
|
|
|
gHoverView->mDoneHoverPick = TRUE;
|
|
}
|
|
|
|
void LLHoverView::setTyping(BOOL b)
|
|
{
|
|
mTyping = b;
|
|
}
|
|
|
|
|
|
void LLHoverView::cancelHover()
|
|
{
|
|
mStartHoverTimer.reset();
|
|
mDoneHoverPick = FALSE;
|
|
mStartHoverPickTimer = FALSE;
|
|
|
|
LLSelectMgr::getInstance()->setHoverObject(NULL);
|
|
// Can't do this, some code relies on hover object still being
|
|
// set after the hover is cancelled! Dammit. JC
|
|
// mLastHoverObject = NULL;
|
|
|
|
setHoverActive(FALSE);
|
|
}
|
|
|
|
void LLHoverView::resetLastHoverObject()
|
|
{
|
|
mLastHoverObject = NULL;
|
|
}
|
|
|
|
void LLHoverView::updateText()
|
|
{
|
|
LLViewerObject* hit_object = getLastHoverObject();
|
|
std::string line;
|
|
|
|
//<singu>
|
|
if (hit_object == mLastTextHoverObject &&
|
|
!(mLastTextHoverObjectTimer.getStarted() && mLastTextHoverObjectTimer.hasExpired()))
|
|
{
|
|
// mText is already up to date.
|
|
return;
|
|
}
|
|
mLastTextHoverObject = hit_object;
|
|
mLastTextHoverObjectTimer.stop();
|
|
bool retrieving_data = false;
|
|
//</singu>
|
|
|
|
mText.clear();
|
|
if ( hit_object )
|
|
{
|
|
if ( hit_object->isHUDAttachment() )
|
|
{
|
|
// no hover tips for HUD elements, since they can obscure
|
|
// what the HUD is displaying
|
|
return;
|
|
}
|
|
|
|
if ( hit_object->isAttachment() )
|
|
{
|
|
// get root of attachment then parent, which is avatar
|
|
LLViewerObject* root_edit = hit_object->getRootEdit();
|
|
if (!root_edit)
|
|
{
|
|
// Strange parenting issue, don't show any text
|
|
return;
|
|
}
|
|
hit_object = (LLViewerObject*)root_edit->getParent();
|
|
if (!hit_object)
|
|
{
|
|
// another strange parenting issue, bail out
|
|
return;
|
|
}
|
|
}
|
|
|
|
line.clear();
|
|
if (hit_object->isAvatar())
|
|
{
|
|
LLNameValue* title = hit_object->getNVPair("Title");
|
|
LLNameValue* firstname = hit_object->getNVPair("FirstName");
|
|
LLNameValue* lastname = hit_object->getNVPair("LastName");
|
|
if (firstname && lastname)
|
|
{
|
|
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
|
|
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
|
{
|
|
line = RlvStrings::getAnonym(line.append(firstname->getString()).append(1, ' ').append(lastname->getString()));
|
|
}
|
|
else
|
|
{
|
|
// [/RLVa:KB]
|
|
std::string complete_name;
|
|
if (!LLAvatarNameCache::getPNSName(hit_object->getID(), complete_name))
|
|
complete_name = firstname->getString() + std::string(" ") + lastname->getString();
|
|
|
|
if (title)
|
|
{
|
|
line.append(title->getString());
|
|
line.append(1, ' ');
|
|
}
|
|
line += complete_name;
|
|
|
|
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
|
|
}
|
|
// [/RLVa:KB]
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("TooltipPerson"));
|
|
}
|
|
mText.push_back(line);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We have hit a regular object (not an avatar or attachment)
|
|
//
|
|
|
|
//
|
|
// Default prefs will suppress display unless the object is interactive
|
|
//
|
|
BOOL suppressObjectHoverDisplay = !gSavedSettings.getBOOL("ShowAllObjectHoverTip");
|
|
|
|
LLSelectNode *nodep = LLSelectMgr::getInstance()->getHoverNode();
|
|
if (nodep)
|
|
{
|
|
line.clear();
|
|
|
|
bool for_copy = nodep->mValid && nodep->mPermissions->getMaskEveryone() & PERM_COPY && hit_object && hit_object->permCopy();
|
|
bool for_sale = nodep->mValid && for_sale_selection(nodep);
|
|
|
|
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 = hit_object ? hit_object->getTE(mLastPickInfo.mObjectFace) : NULL;
|
|
|
|
if(tep)
|
|
{
|
|
has_media = tep->hasMedia();
|
|
const LLMediaEntry* mep = has_media ? tep->getMediaData() : NULL;
|
|
if (mep)
|
|
{
|
|
viewer_media_t media_impl = LLViewerMedia::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
|
|
|
|
if(!suppressObjectHoverDisplay || !is_media_displaying || for_sale)
|
|
{
|
|
if (nodep->mName.empty())
|
|
{
|
|
line.append(LLTrans::getString("TooltipNoName"));
|
|
}
|
|
else
|
|
{
|
|
line.append( nodep->mName );
|
|
}
|
|
|
|
mText.push_back(line);
|
|
|
|
if (!nodep->mDescription.empty()
|
|
&& nodep->mDescription != DEFAULT_DESC)
|
|
{
|
|
mText.push_back( nodep->mDescription );
|
|
}
|
|
|
|
// Line: "Owner: James Linden"
|
|
line.clear();
|
|
line.append(LLTrans::getString("TooltipOwner") + " ");
|
|
|
|
if (nodep->mValid)
|
|
{
|
|
LLUUID owner;
|
|
std::string name;
|
|
if (!nodep->mPermissions->isGroupOwned())
|
|
{
|
|
owner = nodep->mPermissions->getOwner();
|
|
if (LLUUID::null == owner)
|
|
{
|
|
line.append(LLTrans::getString("TooltipPublic"));
|
|
}
|
|
else if(LLAvatarNameCache::getPNSName(owner, name))
|
|
{
|
|
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
|
|
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
|
{
|
|
name = RlvStrings::getAnonym(name);
|
|
}
|
|
// [/RLVa:KB]
|
|
|
|
line.append(name);
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("RetrievingData"));
|
|
retrieving_data = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string name;
|
|
owner = nodep->mPermissions->getGroup();
|
|
if (gCacheName->getGroupName(owner, name))
|
|
{
|
|
line.append(name);
|
|
line.append(LLTrans::getString("TooltipIsGroup"));
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("RetrievingData"));
|
|
retrieving_data = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("RetrievingData"));
|
|
retrieving_data = true;
|
|
}
|
|
mText.push_back(line);
|
|
|
|
// Build a line describing any special properties of this object.
|
|
LLViewerObject *object = hit_object;
|
|
LLViewerObject *parent = (LLViewerObject *)object->getParent();
|
|
|
|
if (object &&
|
|
(object->flagUsePhysics() ||
|
|
object->flagScripted() ||
|
|
object->flagHandleTouch() || (parent && parent->flagHandleTouch()) ||
|
|
object->flagTakesMoney() || (parent && parent->flagTakesMoney()) ||
|
|
object->flagAllowInventoryAdd() ||
|
|
object->flagTemporary() ||
|
|
object->flagPhantom()) )
|
|
{
|
|
line.clear();
|
|
if (object->flagScripted())
|
|
{
|
|
|
|
line.append(LLTrans::getString("TooltipFlagScript") + " ");
|
|
}
|
|
|
|
if (object->flagUsePhysics())
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagPhysics") + " ");
|
|
}
|
|
|
|
if (object->flagHandleTouch() || (parent && parent->flagHandleTouch()) )
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagTouch") + " ");
|
|
suppressObjectHoverDisplay = FALSE; // Show tip
|
|
}
|
|
|
|
if (object->flagTakesMoney() || (parent && parent->flagTakesMoney()) )
|
|
{
|
|
line.append(gHippoGridManager->getConnectedGrid()->getCurrencySymbol() + " ");
|
|
suppressObjectHoverDisplay = FALSE; // Show tip
|
|
}
|
|
|
|
if (object->flagAllowInventoryAdd())
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagDropInventory") + " ");
|
|
suppressObjectHoverDisplay = FALSE; // Show tip
|
|
}
|
|
|
|
if (object->flagPhantom())
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagPhantom") + " ");
|
|
}
|
|
|
|
if (object->flagTemporary())
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagTemporary") + " ");
|
|
}
|
|
|
|
if (object->flagUsePhysics() ||
|
|
object->flagHandleTouch() ||
|
|
(parent && parent->flagHandleTouch()) )
|
|
{
|
|
line.append(LLTrans::getString("TooltipFlagRightClickMenu") + " ");
|
|
}
|
|
mText.push_back(line);
|
|
}
|
|
|
|
// Free to copy / For Sale: L$
|
|
line.clear();
|
|
if (nodep->mValid)
|
|
{
|
|
if (for_copy)
|
|
{
|
|
line.append(LLTrans::getString("TooltipFreeToCopy"));
|
|
suppressObjectHoverDisplay = FALSE; // Show tip
|
|
}
|
|
else if (for_sale)
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["[AMOUNT]"] = llformat("%d", nodep->mSaleInfo.getSalePrice());
|
|
line.append(LLTrans::getString("TooltipForSaleL$", args));
|
|
suppressObjectHoverDisplay = FALSE; // Show tip
|
|
}
|
|
else
|
|
{
|
|
// Nothing if not for sale
|
|
// line.append("Not for sale");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["[MESSAGE]"] = LLTrans::getString("RetrievingData");
|
|
retrieving_data = true;
|
|
line.append(LLTrans::getString("TooltipForSaleMsg", args));
|
|
}
|
|
mText.push_back(line);
|
|
line.clear();
|
|
S32 prim_count = LLSelectMgr::getInstance()->getHoverObjects()->getObjectCount();
|
|
line.append(llformat("Prims: %d", prim_count));
|
|
mText.push_back(line);
|
|
|
|
line.clear();
|
|
line.append("Position: ");
|
|
|
|
LLViewerRegion *region = gAgent.getRegion();
|
|
LLVector3 position = region->getPosRegionFromGlobal(hit_object->getPositionGlobal());//regionp->getOriginAgent();
|
|
LLVector3 mypos = region->getPosRegionFromGlobal(gAgent.getPositionGlobal());
|
|
|
|
|
|
LLVector3 delta = position - mypos;
|
|
F32 distance = (F32)delta.magVec();
|
|
|
|
line.append(llformat("<%.02f,%.02f,%.02f>",position.mV[0],position.mV[1],position.mV[2]));
|
|
mText.push_back(line);
|
|
line.clear();
|
|
line.append(llformat("Distance: %.02fm",distance));
|
|
mText.push_back(line);
|
|
}
|
|
else
|
|
{
|
|
suppressObjectHoverDisplay = TRUE;
|
|
}
|
|
// If the hover tip shouldn't be shown, delete all the object text
|
|
if (suppressObjectHoverDisplay)
|
|
{
|
|
mText.clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( mHoverLandGlobal != LLVector3d::zero )
|
|
{
|
|
//
|
|
// Do not show hover for land unless prefs are set to allow it.
|
|
//
|
|
|
|
if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return;
|
|
|
|
// 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)
|
|
{
|
|
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Added: RLVa-0.2.0b
|
|
line.append( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
|
|
? hover_parcel->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL) );
|
|
// [/RLVa:KB]
|
|
//line.append(hover_parcel->getName());
|
|
}
|
|
mText.push_back(line);
|
|
|
|
// 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"));
|
|
retrieving_data = true;
|
|
}
|
|
}
|
|
else if(gCacheName->getFullName(owner, name))
|
|
{
|
|
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b
|
|
line.append( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? name : RlvStrings::getAnonym(name));
|
|
// [/RLVa:KB]
|
|
//line.append(name);
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("RetrievingData"));
|
|
retrieving_data = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
line.append(LLTrans::getString("RetrievingData"));
|
|
retrieving_data = true;
|
|
}
|
|
mText.push_back(line);
|
|
|
|
// 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)
|
|
{
|
|
mText.push_back(line);
|
|
}
|
|
}
|
|
|
|
if (hover_parcel && hover_parcel->getParcelFlag(PF_FOR_SALE))
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["[AMOUNT]"] = llformat("%d", hover_parcel->getSalePrice());
|
|
line = LLTrans::getString("TooltipForSaleL$", args);
|
|
mText.push_back(line);
|
|
}
|
|
}
|
|
|
|
//<singu>
|
|
if (retrieving_data)
|
|
{
|
|
// Keep doing this twice per second, until all data was retrieved.
|
|
mLastTextHoverObjectTimer.start(DELAY_BEFORE_REFRESH_TIP);
|
|
}
|
|
//</singu>
|
|
}
|
|
|
|
void LLHoverView::draw()
|
|
{
|
|
if ( !isHovering() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// To toggle off hover tips, you have to just suppress the draw.
|
|
// The picking is still needed to do cursor changes over physical
|
|
// and scripted objects. JC
|
|
// if (!sShowHoverTips)
|
|
// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l
|
|
#ifdef RLV_EXTENSION_CMD_INTERACT
|
|
if ( (!sShowHoverTips) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) )
|
|
#else
|
|
if (!sShowHoverTips)
|
|
#endif // RLV_EXTENSION_CMD_INTERACT
|
|
// [/RLVa:KB]
|
|
{
|
|
return;
|
|
}
|
|
|
|
const F32 MAX_HOVER_DISPLAY_SECS = 5.f;
|
|
if (mHoverTimer.getElapsedTimeF32() > MAX_HOVER_DISPLAY_SECS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const F32 MAX_ALPHA = 0.9f;
|
|
//const F32 STEADY_ALPHA = 0.3f;
|
|
F32 alpha;
|
|
if (mHoverActive)
|
|
{
|
|
alpha = 1.f;
|
|
|
|
if (isHoveringObject())
|
|
{
|
|
// look at object
|
|
LLViewerObject *hover_object = getLastHoverObject();
|
|
if (hover_object->isAvatar())
|
|
{
|
|
gAgentCamera.setLookAt(LOOKAT_TARGET_HOVER, getLastHoverObject(), LLVector3::zero);
|
|
}
|
|
else
|
|
{
|
|
gAgentCamera.setLookAt(LOOKAT_TARGET_HOVER, getLastHoverObject(), mHoverOffset);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alpha = llmax(0.f, MAX_ALPHA - mHoverTimer.getElapsedTimeF32()*2.f);
|
|
}
|
|
|
|
// Bail out if no text to display
|
|
if (mText.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't draw if no alpha
|
|
if (alpha <= 0.f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLUIImagePtr box_imagep = LLUI::getUIImage("rounded_square.tga");
|
|
LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
|
|
|
|
const LLFontGL* fontp = LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF_SMALL);
|
|
|
|
// Render text.
|
|
LLColor4 text_color = gColors.getColor("ToolTipTextColor");
|
|
// LLColor4 border_color = gColors.getColor("ToolTipBorderColor");
|
|
LLColor4 bg_color = gColors.getColor("ToolTipBgColor");
|
|
LLColor4 shadow_color = gColors.getColor("ColorDropShadow");
|
|
|
|
// Could decrease the alpha here. JC
|
|
//text_color.mV[VALPHA] = alpha;
|
|
//border_color.mV[VALPHA] = alpha;
|
|
//bg_color.mV[VALPHA] = alpha;
|
|
|
|
S32 max_width = 0;
|
|
S32 num_lines = mText.size();
|
|
for (text_list_t::iterator iter = mText.begin(); iter != mText.end(); ++iter)
|
|
{
|
|
max_width = llmax(max_width, (S32)fontp->getWidth(*iter));
|
|
}
|
|
|
|
S32 left = mHoverPos.mX + 10;
|
|
S32 top = mHoverPos.mY - 16;
|
|
S32 right = mHoverPos.mX + max_width + 30;
|
|
S32 bottom = mHoverPos.mY - 24 - llfloor(num_lines*fontp->getLineHeight());
|
|
|
|
// Push down if there's a one-click icon
|
|
if (mHoverActive
|
|
&& isHoveringObject()
|
|
&& mLastHoverObject->getClickAction() != CLICK_ACTION_NONE)
|
|
{
|
|
const S32 CLICK_OFFSET = 10;
|
|
top -= CLICK_OFFSET;
|
|
bottom -= CLICK_OFFSET;
|
|
}
|
|
|
|
// Make sure the rect is completely visible
|
|
LLRect old_rect = getRect();
|
|
setRect( LLRect(left, top, right, bottom ) );
|
|
translateIntoRect( gViewerWindow->getVirtualWindowRect(), FALSE );
|
|
left = getRect().mLeft;
|
|
top = getRect().mTop;
|
|
right = getRect().mRight;
|
|
bottom = getRect().mBottom;
|
|
setRect(old_rect);
|
|
|
|
LLGLSUIDefault gls_ui;
|
|
|
|
shadow_color.mV[VALPHA] = 0.7f * alpha;
|
|
S32 shadow_offset = gSavedSettings.getS32("DropShadowTooltip");
|
|
shadow_imagep->draw(LLRect(left + shadow_offset, top - shadow_offset, right + shadow_offset, bottom - shadow_offset), shadow_color);
|
|
|
|
bg_color.mV[VALPHA] = alpha;
|
|
box_imagep->draw(LLRect(left, top, right, bottom), bg_color);
|
|
|
|
S32 cur_offset = top - 4;
|
|
for (text_list_t::iterator iter = mText.begin(); iter != mText.end(); ++iter)
|
|
{
|
|
fontp->renderUTF8(*iter, 0, left + 10, cur_offset, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
cur_offset -= llfloor(fontp->getLineHeight());
|
|
}
|
|
}
|
|
|
|
void LLHoverView::setHoverActive(const BOOL active)
|
|
{
|
|
if (active != mHoverActive)
|
|
{
|
|
mHoverTimer.reset();
|
|
}
|
|
|
|
mHoverActive = active;
|
|
|
|
if (active)
|
|
{
|
|
mHoverPos = gViewerWindow->getCurrentMouse();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL LLHoverView::isHoveringLand() const
|
|
{
|
|
return !mHoverLandGlobal.isExactlyZero();
|
|
}
|
|
|
|
|
|
BOOL LLHoverView::isHoveringObject() const
|
|
{
|
|
return !mLastHoverObject.isNull() && !mLastHoverObject->isDead();
|
|
}
|
|
|
|
|
|
LLViewerObject* LLHoverView::getLastHoverObject() const
|
|
{
|
|
if (!mLastHoverObject.isNull() && !mLastHoverObject->isDead())
|
|
{
|
|
return mLastHoverObject;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// EOF
|