1147 lines
44 KiB
C++
1147 lines
44 KiB
C++
/**
|
|
* @file llselectmgr.h
|
|
* @brief A manager for selected objects and TEs.
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifndef LL_LLSELECTMGR_H
|
|
#define LL_LLSELECTMGR_H
|
|
|
|
#include "llcharacter.h"
|
|
#include "lleditmenuhandler.h"
|
|
#include "llundo.h"
|
|
#include "lluuid.h"
|
|
#include "llpointer.h"
|
|
#include "llsafehandle.h"
|
|
#include "llsaleinfo.h"
|
|
#include "llcategory.h"
|
|
#include "v3dmath.h"
|
|
#include "llquaternion.h"
|
|
#include "llcoord.h"
|
|
#include "llframetimer.h"
|
|
#include "llbbox.h"
|
|
#include "llpermissions.h"
|
|
#include "llcontrol.h"
|
|
#include "llviewerobject.h" // LLObjectSelection::getSelectedTEValue template
|
|
#include "llmaterial.h"
|
|
|
|
#include <deque>
|
|
#include <boost/iterator/filter_iterator.hpp>
|
|
#include <boost/signals2.hpp>
|
|
#include <boost/make_shared.hpp> // boost::make_shared
|
|
|
|
class LLMessageSystem;
|
|
class LLViewerTexture;
|
|
class LLColor4;
|
|
class LLVector3;
|
|
class LLSelectNode;
|
|
|
|
const U8 UPD_NONE = 0x00;
|
|
const U8 UPD_POSITION = 0x01;
|
|
const U8 UPD_ROTATION = 0x02;
|
|
const U8 UPD_SCALE = 0x04;
|
|
const U8 UPD_LINKED_SETS = 0x08;
|
|
const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE
|
|
|
|
// <FS:Ansariel> Moved here to make them publically accessible
|
|
// For linked sets
|
|
const S32 MAX_CHILDREN_PER_TASK = 255;
|
|
const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 32;
|
|
// </FS:Ansariel>
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
enum EFSShowHideHighlight
|
|
{
|
|
FS_SHOW_HIDE_HIGHLIGHT_NORMAL = 0,
|
|
FS_SHOW_HIDE_HIGHLIGHT_SHOW = 1,
|
|
FS_SHOW_HIDE_HIGHLIGHT_HIDE = 2
|
|
};
|
|
// </FS:KC>
|
|
|
|
// This is used by the DeRezObject message to determine where to put
|
|
// derezed tasks.
|
|
enum EDeRezDestination
|
|
{
|
|
DRD_SAVE_INTO_AGENT_INVENTORY = 0,
|
|
DRD_ACQUIRE_TO_AGENT_INVENTORY = 1, // try to leave copy in world
|
|
DRD_SAVE_INTO_TASK_INVENTORY = 2,
|
|
DRD_ATTACHMENT = 3,
|
|
DRD_TAKE_INTO_AGENT_INVENTORY = 4, // delete from world
|
|
DRD_FORCE_TO_GOD_INVENTORY = 5, // force take copy
|
|
DRD_TRASH = 6,
|
|
DRD_ATTACHMENT_TO_INV = 7,
|
|
DRD_ATTACHMENT_EXISTS = 8,
|
|
DRD_RETURN_TO_OWNER = 9, // back to owner's inventory
|
|
DRD_RETURN_TO_LAST_OWNER = 10, // deeded object back to last owner's inventory
|
|
|
|
DRD_COUNT = 11
|
|
};
|
|
|
|
|
|
const S32 SELECT_ALL_TES = -1;
|
|
const S32 SELECT_MAX_TES = 32;
|
|
|
|
// Do something to all objects in the selection manager.
|
|
// The bool return value can be used to indicate if all
|
|
// objects are identical (gathering information) or if
|
|
// the operation was successful.
|
|
struct LLSelectedObjectFunctor
|
|
{
|
|
virtual ~LLSelectedObjectFunctor() {};
|
|
virtual bool apply(LLViewerObject* object) = 0;
|
|
};
|
|
|
|
// Do something to all select nodes in the selection manager.
|
|
// The bool return value can be used to indicate if all
|
|
// objects are identical (gathering information) or if
|
|
// the operation was successful.
|
|
struct LLSelectedNodeFunctor
|
|
{
|
|
virtual ~LLSelectedNodeFunctor() {};
|
|
virtual bool apply(LLSelectNode* node) = 0;
|
|
};
|
|
|
|
struct LLSelectedTEFunctor
|
|
{
|
|
virtual ~LLSelectedTEFunctor() {};
|
|
virtual bool apply(LLViewerObject* object, S32 face) = 0;
|
|
};
|
|
|
|
struct LLSelectedTEMaterialFunctor
|
|
{
|
|
virtual ~LLSelectedTEMaterialFunctor() {};
|
|
virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) = 0;
|
|
};
|
|
|
|
template <typename T> struct LLSelectedTEGetFunctor
|
|
{
|
|
virtual ~LLSelectedTEGetFunctor() {};
|
|
virtual T get(LLViewerObject* object, S32 te) = 0;
|
|
};
|
|
|
|
template <typename T> struct LLCheckIdenticalFunctor
|
|
{
|
|
static bool same(const T& a, const T& b, const T& tolerance);
|
|
};
|
|
|
|
typedef enum e_send_type
|
|
{
|
|
SEND_ONLY_ROOTS,
|
|
SEND_INDIVIDUALS,
|
|
SEND_ROOTS_FIRST, // useful for serial undos on linked sets
|
|
SEND_CHILDREN_FIRST // useful for serial transforms of linked sets
|
|
} ESendType;
|
|
|
|
typedef enum e_grid_mode
|
|
{
|
|
GRID_MODE_WORLD,
|
|
GRID_MODE_LOCAL,
|
|
GRID_MODE_REF_OBJECT
|
|
} EGridMode;
|
|
|
|
typedef enum e_action_type
|
|
{
|
|
SELECT_ACTION_TYPE_BEGIN,
|
|
SELECT_ACTION_TYPE_PICK,
|
|
SELECT_ACTION_TYPE_MOVE,
|
|
SELECT_ACTION_TYPE_ROTATE,
|
|
SELECT_ACTION_TYPE_SCALE,
|
|
NUM_ACTION_TYPES
|
|
}EActionType;
|
|
|
|
typedef enum e_selection_type
|
|
{
|
|
SELECT_TYPE_WORLD,
|
|
SELECT_TYPE_ATTACHMENT,
|
|
SELECT_TYPE_HUD
|
|
}ESelectType;
|
|
|
|
typedef std::vector<LLPointer<LLGLTFMaterial> > gltf_materials_vec_t;
|
|
|
|
const S32 TE_SELECT_MASK_ALL = 0xFFFFFFFF;
|
|
|
|
//<FS:Beq> Physics view in edit mode changes
|
|
void pushWireframe(LLDrawable* drawable);
|
|
//</FS:Beq>
|
|
// Contains information about a selected object, particularly which TEs are selected.
|
|
class LLSelectNode
|
|
{
|
|
public:
|
|
LLSelectNode(LLViewerObject* object, bool do_glow);
|
|
LLSelectNode(const LLSelectNode& nodep);
|
|
~LLSelectNode();
|
|
|
|
void selectAllTEs(bool b);
|
|
void selectTE(S32 te_index, bool selected);
|
|
void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected);
|
|
bool isTESelected(S32 te_index) const;
|
|
bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; }
|
|
S32 getLastSelectedTE() const;
|
|
S32 getLastOperatedTE() const { return mLastTESelected; }
|
|
S32 getTESelectMask() { return mTESelectMask; }
|
|
void renderOneSilhouette(const LLColor4 &color);
|
|
void setTransient(bool transient) { mTransient = transient; }
|
|
bool isTransient() const { return mTransient; }
|
|
LLViewerObject* getObject();
|
|
void setObject(LLViewerObject* object);
|
|
// *NOTE: invalidate stored textures and colors when # faces change
|
|
// Used by tools floater's color/texture pickers to restore changes
|
|
void saveColors();
|
|
void saveShinyColors();
|
|
void saveTextures(const uuid_vec_t& textures);
|
|
void saveTextureScaleRatios(LLRender::eTexIndex index_to_query);
|
|
|
|
// GLTF materials are applied to objects by ids,
|
|
// overrides get applied on top of materials resulting in
|
|
// final gltf material that users see.
|
|
// Ids get applied and restored by tools floater,
|
|
// overrides get applied in live material editor
|
|
void saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials);
|
|
|
|
bool allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const;
|
|
|
|
public:
|
|
bool mIndividualSelection; // For root objects and objects individually selected
|
|
|
|
bool mTransient;
|
|
bool mValid; // is extra information valid?
|
|
LLPermissions* mPermissions;
|
|
LLSaleInfo mSaleInfo;
|
|
LLAggregatePermissions mAggregatePerm;
|
|
LLAggregatePermissions mAggregateTexturePerm;
|
|
LLAggregatePermissions mAggregateTexturePermOwner;
|
|
std::string mName;
|
|
std::string mDescription;
|
|
LLCategory mCategory;
|
|
S16 mInventorySerial;
|
|
LLVector3 mSavedPositionLocal; // for interactively modifying object position
|
|
LLVector3 mLastPositionLocal;
|
|
LLVector3 mLastMoveLocal;
|
|
LLVector3d mSavedPositionGlobal; // for interactively modifying object position
|
|
LLVector3 mSavedScale; // for interactively modifying object scale
|
|
LLVector3 mLastScale;
|
|
LLQuaternion mSavedRotation; // for interactively modifying object rotation
|
|
LLQuaternion mLastRotation;
|
|
bool mDuplicated;
|
|
LLVector3d mDuplicatePos;
|
|
LLQuaternion mDuplicateRot;
|
|
LLUUID mItemID;
|
|
LLUUID mFolderID;
|
|
LLUUID mFromTaskID;
|
|
std::string mTouchName;
|
|
std::string mSitName;
|
|
U64 mCreationDate;
|
|
std::vector<LLColor4> mSavedColors;
|
|
std::vector<LLColor4> mSavedShinyColors;
|
|
uuid_vec_t mSavedTextures;
|
|
uuid_vec_t mSavedGLTFMaterialIds;
|
|
gltf_materials_vec_t mSavedGLTFOverrideMaterials;
|
|
std::vector<LLVector3> mTextureScaleRatios;
|
|
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
|
|
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
|
|
bool mSilhouetteExists; // need to generate silhouette?
|
|
S32 mSelectedGLTFNode = -1;
|
|
S32 mSelectedGLTFPrimitive = -1;
|
|
|
|
protected:
|
|
LLPointer<LLViewerObject> mObject;
|
|
S32 mTESelectMask;
|
|
S32 mLastTESelected;
|
|
|
|
// <FS:ND> For const access. Need to check for isDead yourself.
|
|
public:
|
|
LLViewerObject const* getObject() const { return mObject; }
|
|
// </FS:ND>
|
|
};
|
|
|
|
class LLObjectSelection : public LLRefCount
|
|
{
|
|
friend class LLSelectMgr;
|
|
friend class LLSafeHandle<LLObjectSelection>;
|
|
friend class LLSelectionCallbackData;
|
|
|
|
protected:
|
|
~LLObjectSelection();
|
|
|
|
public:
|
|
typedef std::list<LLSelectNode*> list_t;
|
|
|
|
// Iterators
|
|
struct is_non_null
|
|
{
|
|
bool operator()(LLSelectNode* node)
|
|
{
|
|
return (node->getObject() != NULL);
|
|
}
|
|
};
|
|
typedef boost::filter_iterator<is_non_null, list_t::iterator > iterator;
|
|
iterator begin() { return iterator(mList.begin(), mList.end()); }
|
|
iterator end() { return iterator(mList.end(), mList.end()); }
|
|
|
|
struct is_valid
|
|
{
|
|
bool operator()(LLSelectNode* node)
|
|
{
|
|
return (node->getObject() != NULL) && node->mValid;
|
|
}
|
|
};
|
|
typedef boost::filter_iterator<is_valid, list_t::iterator > valid_iterator;
|
|
valid_iterator valid_begin() { return valid_iterator(mList.begin(), mList.end()); }
|
|
valid_iterator valid_end() { return valid_iterator(mList.end(), mList.end()); }
|
|
|
|
struct is_root
|
|
{
|
|
bool operator()(LLSelectNode* node);
|
|
};
|
|
typedef boost::filter_iterator<is_root, list_t::iterator > root_iterator;
|
|
root_iterator root_begin() { return root_iterator(mList.begin(), mList.end()); }
|
|
root_iterator root_end() { return root_iterator(mList.end(), mList.end()); }
|
|
|
|
struct is_valid_root
|
|
{
|
|
bool operator()(LLSelectNode* node);
|
|
};
|
|
typedef boost::filter_iterator<is_valid_root, list_t::iterator > valid_root_iterator;
|
|
valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); }
|
|
valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); }
|
|
|
|
struct is_root_object
|
|
{
|
|
bool operator()(LLSelectNode* node);
|
|
};
|
|
typedef boost::filter_iterator<is_root_object, list_t::iterator > root_object_iterator;
|
|
root_object_iterator root_object_begin() { return root_object_iterator(mList.begin(), mList.end()); }
|
|
root_object_iterator root_object_end() { return root_object_iterator(mList.end(), mList.end()); }
|
|
|
|
public:
|
|
LLObjectSelection();
|
|
|
|
void updateEffects();
|
|
|
|
bool isEmpty() const;
|
|
|
|
LLSelectNode* getFirstNode(LLSelectedNodeFunctor* func = NULL);
|
|
LLSelectNode* getFirstRootNode(LLSelectedNodeFunctor* func = NULL, bool non_root_ok = false);
|
|
LLViewerObject* getFirstSelectedObject(LLSelectedNodeFunctor* func, bool get_parent = false);
|
|
LLViewerObject* getFirstObject();
|
|
LLViewerObject* getFirstRootObject(bool non_root_ok = false);
|
|
|
|
LLSelectNode* getFirstMoveableNode(bool get_root_first = false);
|
|
|
|
LLViewerObject* getFirstEditableObject(bool get_parent = false);
|
|
LLViewerObject* getFirstCopyableObject(bool get_parent = false);
|
|
LLViewerObject* getFirstDeleteableObject();
|
|
LLViewerObject* getFirstMoveableObject(bool get_parent = false);
|
|
LLViewerObject* getFirstUndoEnabledObject(bool get_parent = false);
|
|
|
|
/// Return the object that lead to this selection, possible a child
|
|
LLViewerObject* getPrimaryObject() { return mPrimaryObject; }
|
|
|
|
// iterate through texture entries
|
|
template <typename T> bool getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance = false, T tolerance = T());
|
|
template <typename T> bool isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value);
|
|
|
|
S32 getNumNodes();
|
|
LLSelectNode* findNode(LLViewerObject* objectp);
|
|
|
|
// count members
|
|
S32 getObjectCount();
|
|
F32 getSelectedObjectCost();
|
|
F32 getSelectedLinksetCost();
|
|
F32 getSelectedPhysicsCost();
|
|
F32 getSelectedLinksetPhysicsCost();
|
|
S32 getSelectedObjectRenderCost();
|
|
|
|
F32 getSelectedObjectStreamingCost(S32* total_bytes = NULL, S32* visible_bytes = NULL);
|
|
U32 getSelectedObjectTriangleCount(S32* vcount = NULL);
|
|
|
|
S32 getTECount();
|
|
S32 getRootObjectCount();
|
|
|
|
bool isMultipleTESelected();
|
|
bool contains(LLViewerObject* object);
|
|
bool contains(LLViewerObject* object, S32 te);
|
|
|
|
// returns true is any node is currenly worn as an attachment
|
|
bool isAttachment();
|
|
|
|
bool checkAnimatedObjectEstTris();
|
|
bool checkAnimatedObjectLinkable();
|
|
|
|
// Apply functors to various subsets of the selected objects
|
|
// If firstonly is false, returns the AND of all apply() calls.
|
|
// Else returns true immediately if any apply() call succeeds (i.e. OR with early exit)
|
|
bool applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly = false);
|
|
bool applyToObjects(LLSelectedObjectFunctor* func);
|
|
bool applyToTEs(LLSelectedTEFunctor* func, bool firstonly = false);
|
|
bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
|
|
bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
|
|
|
|
/*
|
|
* Used to apply (no-copy) textures to the selected object or
|
|
* selected face/faces of the object.
|
|
* This method moves (no-copy) texture to the object's inventory
|
|
* and doesn't make copy of the texture for each face.
|
|
* Then this only texture is used for all selected faces.
|
|
*/
|
|
void applyNoCopyTextureToTEs(LLViewerInventoryItem* item);
|
|
/*
|
|
* Multi-purpose function for applying PBR materials to the
|
|
* selected object or faces, any combination of copy/mod/transfer
|
|
* permission restrictions. This method moves the restricted
|
|
* material to the object's inventory and doesn't make a copy of the
|
|
* material for each face. Then this only material is used for
|
|
* all selected faces.
|
|
* Returns false if applying the material failed on one or more selected
|
|
* faces.
|
|
*/
|
|
bool applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item);
|
|
|
|
ESelectType getSelectType() const { return mSelectType; }
|
|
|
|
private:
|
|
void addNode(LLSelectNode *nodep);
|
|
void addNodeAtEnd(LLSelectNode *nodep);
|
|
void moveNodeToFront(LLSelectNode *nodep);
|
|
void removeNode(LLSelectNode *nodep);
|
|
void deleteAllNodes();
|
|
void cleanupNodes();
|
|
|
|
|
|
private:
|
|
list_t mList;
|
|
const LLObjectSelection &operator=(const LLObjectSelection &);
|
|
|
|
LLPointer<LLViewerObject> mPrimaryObject;
|
|
std::map<LLPointer<LLViewerObject>, LLSelectNode*> mSelectNodeMap;
|
|
ESelectType mSelectType;
|
|
|
|
// <FS:Zi> Fix for crash while selecting objects with derendered child prims
|
|
list_t mFailedNodesList;
|
|
bool checkNode(LLSelectNode* nodep);
|
|
// </FS:Zi>
|
|
};
|
|
|
|
typedef LLSafeHandle<LLObjectSelection> LLObjectSelectionHandle;
|
|
|
|
// Build time optimization, generate this once in .cpp file
|
|
#ifndef LLSELECTMGR_CPP
|
|
extern template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
|
|
#endif
|
|
|
|
// For use with getFirstTest()
|
|
struct LLSelectGetFirstTest;
|
|
|
|
// <FS:ND> To listened into received prop. messages
|
|
namespace nd
|
|
{
|
|
namespace selection
|
|
{
|
|
class PropertiesListener
|
|
{
|
|
public:
|
|
virtual void onProperties( LLSelectNode const * ) = 0;
|
|
};
|
|
|
|
class PropertiesServer
|
|
{
|
|
public:
|
|
PropertiesServer()
|
|
: mBatchMode( false )
|
|
{ }
|
|
|
|
void registerPropertyListener( nd::selection::PropertiesListener *aP) { mListener.insert( aP ); }
|
|
void removePropertyListener( nd::selection::PropertiesListener *aP) { mListener.erase( aP ); }
|
|
|
|
void enableBatchMode( ) { mBatchMode = true; }
|
|
void disableBatchMode( ) { mBatchMode = false; }
|
|
bool isBatchMode() const { return mBatchMode; }
|
|
|
|
protected:
|
|
void firePropertyReceived( LLSelectNode const *aNode )
|
|
{
|
|
for( std::set< nd::selection::PropertiesListener * >::iterator itr = mListener.begin(); itr != mListener.end(); ++itr )
|
|
(*itr)->onProperties( aNode );
|
|
}
|
|
|
|
private:
|
|
std::set< nd::selection::PropertiesListener * > mListener;
|
|
bool mBatchMode;
|
|
};
|
|
}
|
|
}
|
|
// </FS:ND>
|
|
|
|
// temporary storage, Ex: to attach objects after autopilot
|
|
class LLSelectionCallbackData
|
|
{
|
|
public:
|
|
LLSelectionCallbackData();
|
|
LLObjectSelectionHandle getSelection() { return mSelectedObjects; }
|
|
private:
|
|
LLObjectSelectionHandle mSelectedObjects;
|
|
};
|
|
|
|
class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>, public nd::selection::PropertiesServer
|
|
{
|
|
public:
|
|
static bool sRectSelectInclusive; // do we need to surround an object to pick it?
|
|
static bool sRenderHiddenSelections; // do we show selection silhouettes that are occluded?
|
|
static bool sRenderLightRadius; // do we show the radius of selected lights?
|
|
|
|
static F32 sHighlightThickness;
|
|
static F32 sHighlightUScale;
|
|
static F32 sHighlightVScale;
|
|
static F32 sHighlightAlpha;
|
|
static F32 sHighlightAlphaTest;
|
|
static F32 sHighlightUAnim;
|
|
static F32 sHighlightVAnim;
|
|
static LLColor4 sSilhouetteParentColor;
|
|
static LLColor4 sSilhouetteChildColor;
|
|
static LLColor4 sHighlightParentColor;
|
|
static LLColor4 sHighlightChildColor;
|
|
static LLColor4 sHighlightInspectColor;
|
|
static LLColor4 sContextSilhouetteColor;
|
|
|
|
LLCachedControl<bool> mHideSelectedObjects;
|
|
LLCachedControl<bool> mRenderHighlightSelections;
|
|
LLCachedControl<bool> mAllowSelectAvatar;
|
|
LLCachedControl<bool> mDebugSelectMgr;
|
|
|
|
public:
|
|
LLSelectMgr();
|
|
~LLSelectMgr();
|
|
|
|
static void cleanupGlobals();
|
|
|
|
// LLEditMenuHandler interface
|
|
virtual bool canUndo() const;
|
|
virtual void undo();
|
|
|
|
virtual bool canRedo() const;
|
|
virtual void redo();
|
|
|
|
virtual bool canDoDelete() const;
|
|
virtual void doDelete();
|
|
|
|
virtual void deselect();
|
|
virtual bool canDeselect() const;
|
|
|
|
virtual void duplicate();
|
|
virtual bool canDuplicate() const;
|
|
|
|
void clearSelections();
|
|
void update();
|
|
void updateEffects(); // Update HUD effects
|
|
|
|
// When we edit object's position/rotation/scale we set local
|
|
// overrides and ignore any updates (override received valeus).
|
|
// When we send data to server, we send local values and reset
|
|
// overrides
|
|
void resetObjectOverrides();
|
|
void resetObjectOverrides(LLObjectSelectionHandle selected_handle);
|
|
void overrideObjectUpdates();
|
|
|
|
void resetAvatarOverrides();
|
|
void overrideAvatarUpdates();
|
|
|
|
struct AvatarPositionOverride
|
|
{
|
|
AvatarPositionOverride();
|
|
AvatarPositionOverride(LLVector3 &vec, LLQuaternion &quat, LLViewerObject *obj) :
|
|
mLastPositionLocal(vec),
|
|
mLastRotation(quat),
|
|
mObject(obj)
|
|
{
|
|
}
|
|
LLVector3 mLastPositionLocal;
|
|
LLQuaternion mLastRotation;
|
|
LLPointer<LLViewerObject> mObject;
|
|
};
|
|
|
|
// Avatar overrides should persist even after selection
|
|
// was removed as long as edit floater is up
|
|
typedef std::map<LLUUID, AvatarPositionOverride> uuid_av_override_map_t;
|
|
uuid_av_override_map_t mAvatarOverridesMap;
|
|
public:
|
|
|
|
|
|
// Returns the previous value of mForceSelection
|
|
bool setForceSelection(bool force);
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Selection methods
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Add
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// This method is meant to select an object, and then select all
|
|
// of the ancestors and descendants. This should be the normal behavior.
|
|
//
|
|
// *NOTE: You must hold on to the object selection handle, otherwise
|
|
// the objects will be automatically deselected in 1 frame.
|
|
LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, bool add_to_end = false, bool ignore_select_owned = false);
|
|
|
|
// For when you want just a child object.
|
|
LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1);
|
|
|
|
// Same as above, but takes a list of objects. Used by rectangle select.
|
|
LLObjectSelectionHandle selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, bool send_to_sim = true);
|
|
|
|
// converts all objects currently highlighted to a selection, and returns it
|
|
LLObjectSelectionHandle selectHighlightedObjects();
|
|
|
|
LLObjectSelectionHandle setHoverObject(LLViewerObject *objectp, S32 face = -1);
|
|
LLSelectNode *getHoverNode();
|
|
LLSelectNode *getPrimaryHoverNode();
|
|
|
|
void highlightObjectOnly(LLViewerObject *objectp);
|
|
void highlightObjectAndFamily(LLViewerObject *objectp);
|
|
void highlightObjectAndFamily(const std::vector<LLViewerObject*>& list);
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Remove
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void deselectObjectOnly(LLViewerObject* object, bool send_to_sim = true);
|
|
void deselectObjectAndFamily(LLViewerObject* object, bool send_to_sim = true, bool include_entire_object = false);
|
|
|
|
// Send deselect messages to simulator, then clear the list
|
|
void deselectAll();
|
|
void deselectAllForStandingUp();
|
|
|
|
// deselect only if nothing else currently referencing the selection
|
|
void deselectUnused();
|
|
|
|
// Deselect if the selection center is too far away from the agent.
|
|
void deselectAllIfTooFar();
|
|
|
|
// Removes all highlighted objects from current selection
|
|
void deselectHighlightedObjects();
|
|
|
|
void unhighlightObjectOnly(LLViewerObject *objectp);
|
|
void unhighlightObjectAndFamily(LLViewerObject *objectp);
|
|
void unhighlightAll();
|
|
|
|
bool removeObjectFromSelections(const LLUUID &id);
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Selection editing
|
|
////////////////////////////////////////////////////////////////
|
|
bool linkObjects();
|
|
|
|
bool unlinkObjects();
|
|
|
|
void confirmUnlinkObjects(const LLSD& notification, const LLSD& response);
|
|
|
|
bool enableLinkObjects();
|
|
|
|
bool enableUnlinkObjects();
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Selection accessors
|
|
////////////////////////////////////////////////////////////////
|
|
LLObjectSelectionHandle getHoverObjects() { return mHoverObjects; }
|
|
LLObjectSelectionHandle getSelection() { return mSelectedObjects; }
|
|
// right now this just renders the selection with root/child colors instead of a single color
|
|
LLObjectSelectionHandle getEditSelection() { convertTransient(); return mSelectedObjects; }
|
|
LLObjectSelectionHandle getHighlightedObjects() { return mHighlightedObjects; }
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Grid manipulation
|
|
////////////////////////////////////////////////////////////////
|
|
void addGridObject(LLViewerObject* objectp);
|
|
void clearGridObjects();
|
|
void setGridMode(EGridMode mode);
|
|
EGridMode getGridMode() { return mGridMode; }
|
|
void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale, bool for_snap_guides = false);
|
|
|
|
bool getTEMode() const { return mTEMode; }
|
|
void setTEMode(bool b) { mTEMode = b; }
|
|
|
|
bool shouldShowSelection() const { return mShowSelection; }
|
|
|
|
LLBBox getBBoxOfSelection() const;
|
|
LLBBox getSavedBBoxOfSelection() const { return mSavedSelectionBBox; }
|
|
|
|
void dump();
|
|
void cleanup();
|
|
|
|
void updateSilhouettes();
|
|
void renderSilhouettes(bool for_hud);
|
|
void enableSilhouette(bool enable) { mRenderSilhouettes = enable; }
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
void setFSShowHideHighlight(EFSShowHideHighlight state) { mFSShowHideHighlight = state; }
|
|
// </FS:KC>
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Utility functions that operate on the current selection
|
|
////////////////////////////////////////////////////////////////
|
|
void saveSelectedObjectTransform(EActionType action_type);
|
|
void saveSelectedObjectColors();
|
|
void saveSelectedShinyColors();
|
|
void saveSelectedObjectTextures();
|
|
|
|
void selectionUpdatePhysics(bool use_physics);
|
|
void selectionUpdateTemporary(bool is_temporary);
|
|
void selectionUpdatePhantom(bool is_ghost);
|
|
void selectionDump();
|
|
|
|
bool selectionAllPCode(LLPCode code); // all objects have this PCode
|
|
bool selectionGetClickAction(U8 *out_action);
|
|
bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same
|
|
bool selectionGetGlow(F32 *glow);
|
|
|
|
void selectionSetPhysicsType(U8 type);
|
|
void selectionSetGravity(F32 gravity);
|
|
void selectionSetFriction(F32 friction);
|
|
void selectionSetDensity(F32 density);
|
|
void selectionSetRestitution(F32 restitution);
|
|
void selectionSetMaterial(U8 material);
|
|
bool selectionSetImage(const LLUUID& imageid, bool isPBR=true); // <FS:Beq/> inject PBR awareness.
|
|
bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only
|
|
void selectionSetColor(const LLColor4 &color);
|
|
void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
|
|
void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel
|
|
void selectionRevertColors();
|
|
void selectionRevertShinyColors();
|
|
bool selectionRevertTextures();
|
|
void selectionRevertGLTFMaterials();
|
|
void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id );
|
|
void selectionSetTexGen( U8 texgen );
|
|
void selectionSetShiny( U8 shiny, const LLUUID &image_id );
|
|
void selectionSetFullbright( U8 fullbright );
|
|
void selectionSetMedia( U8 media_type, const LLSD &media_data );
|
|
void selectionSetClickAction(U8 action);
|
|
void selectionSetIncludeInSearch(bool include_in_search);
|
|
void selectionSetGlow(const F32 glow);
|
|
void selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func, int specific_te = -1);
|
|
void selectionRemoveMaterial();
|
|
|
|
void selectionSetObjectPermissions(U8 perm_field, bool set, U32 perm_mask, bool override = false);
|
|
void selectionSetObjectName(const std::string& name);
|
|
void selectionSetObjectDescription(const std::string& desc);
|
|
void selectionSetObjectCategory(const LLCategory& category);
|
|
void selectionSetObjectSaleInfo(const LLSaleInfo& sale_info);
|
|
|
|
void selectionTexScaleAutofit(F32 repeats_per_meter);
|
|
void adjustTexturesByScale(bool send_to_sim, bool stretch);
|
|
|
|
bool selectionMove(const LLVector3& displ, F32 rx, F32 ry, F32 rz,
|
|
U32 update_type);
|
|
void sendSelectionMove();
|
|
|
|
void sendGodlikeRequest(const std::string& request, const std::string& parameter);
|
|
|
|
|
|
// will make sure all selected object meet current criteria, or deselect them otherwise
|
|
void validateSelection();
|
|
|
|
// returns true if it is possible to select this object
|
|
bool canSelectObject(LLViewerObject* object, bool ignore_select_owned = false);
|
|
|
|
// Returns true if the viewer has information on all selected objects
|
|
bool selectGetAllRootsValid();
|
|
bool selectGetAllValid();
|
|
bool selectGetAllValidAndObjectsFound();
|
|
|
|
// returns true if you can modify all selected objects.
|
|
bool selectGetRootsModify();
|
|
bool selectGetModify();
|
|
|
|
// returns true if all objects are in same region
|
|
bool selectGetSameRegion();
|
|
|
|
// returns true if is all objects are non-permanent-enforced
|
|
bool selectGetRootsNonPermanentEnforced();
|
|
bool selectGetNonPermanentEnforced();
|
|
|
|
// returns true if is all objects are permanent
|
|
bool selectGetRootsPermanent();
|
|
bool selectGetPermanent();
|
|
|
|
// returns true if is all objects are character
|
|
bool selectGetRootsCharacter();
|
|
bool selectGetCharacter();
|
|
|
|
// returns true if is all objects are not permanent
|
|
bool selectGetRootsNonPathfinding();
|
|
bool selectGetNonPathfinding();
|
|
|
|
// returns true if is all objects are not permanent
|
|
bool selectGetRootsNonPermanent();
|
|
bool selectGetNonPermanent();
|
|
|
|
// returns true if is all objects are not character
|
|
bool selectGetRootsNonCharacter();
|
|
bool selectGetNonCharacter();
|
|
|
|
bool selectGetEditableLinksets();
|
|
bool selectGetViewableCharacters();
|
|
|
|
// returns true if selected objects can be transferred.
|
|
bool selectGetRootsTransfer();
|
|
|
|
// returns true if selected objects can be copied.
|
|
bool selectGetRootsCopy();
|
|
|
|
bool selectGetCreator(LLUUID& id, std::string& name); // true if all have same creator, returns id
|
|
bool selectGetOwner(LLUUID& id, std::string& name); // true if all objects have same owner, returns id
|
|
bool selectGetLastOwner(LLUUID& id, std::string& name); // true if all objects have same owner, returns id
|
|
|
|
// returns true if all are the same. id is stuffed with
|
|
// the value found if available.
|
|
bool selectGetGroup(LLUUID& id);
|
|
bool selectGetPerm( U8 which_perm, U32* mask_on, U32* mask_off); // true if all have data, returns two masks, each indicating which bits are all on and all off
|
|
|
|
bool selectIsGroupOwned(); // true if all root objects have valid data and are group owned.
|
|
|
|
// returns true if all the nodes are valid. Accumulates
|
|
// permissions in the parameter.
|
|
bool selectGetPermissions(LLPermissions& perm);
|
|
|
|
// returns true if all the nodes are valid. Depends onto "edit linked" state
|
|
// Children in linksets are a bit special - they require not only move permission
|
|
// but also modify if "edit linked" is set, since you move them relative to parent
|
|
bool selectGetEditMoveLinksetPermissions(bool &move, bool &modify);
|
|
|
|
// Get a bunch of useful sale information for the object(s) selected.
|
|
// "_mixed" is true if not all objects have the same setting.
|
|
void selectGetAggregateSaleInfo(U32 &num_for_sale,
|
|
bool &is_for_sale_mixed,
|
|
bool &is_sale_price_mixed,
|
|
S32 &total_sale_price,
|
|
S32 &individual_sale_price);
|
|
|
|
// returns true if all nodes are valid.
|
|
bool selectGetCategory(LLCategory& category);
|
|
|
|
// returns true if all nodes are valid. method also stores an
|
|
// accumulated sale info.
|
|
bool selectGetSaleInfo(LLSaleInfo& sale_info);
|
|
|
|
// returns true if all nodes are valid. fills passed in object
|
|
// with the aggregate permissions of the selection.
|
|
bool selectGetAggregatePermissions(LLAggregatePermissions& ag_perm);
|
|
|
|
// returns true if all nodes are valid. fills passed in object
|
|
// with the aggregate permissions for texture inventory items of the selection.
|
|
bool selectGetAggregateTexturePermissions(LLAggregatePermissions& ag_perm);
|
|
|
|
LLPermissions* findObjectPermissions(const LLViewerObject* object);
|
|
|
|
bool isMovableAvatarSelected();
|
|
|
|
void selectDelete(); // Delete on simulator
|
|
void selectForceDelete(); // just delete, no into trash
|
|
void selectDuplicate(const LLVector3& offset, bool select_copy); // Duplicate on simulator
|
|
void repeatDuplicate();
|
|
void selectDuplicateOnRay(const LLVector3 &ray_start_region,
|
|
const LLVector3 &ray_end_region,
|
|
bool bypass_raycast,
|
|
bool ray_end_is_intersection,
|
|
const LLUUID &ray_target_id,
|
|
bool copy_centers,
|
|
bool copy_rotates,
|
|
bool select_copy);
|
|
|
|
void sendMultipleUpdate(U32 type); // Position, rotation, scale all in one
|
|
void sendOwner(const LLUUID& owner_id, const LLUUID& group_id, bool override = false);
|
|
void sendGroup(const LLUUID& group_id);
|
|
|
|
// Category ID is the UUID of the folder you want to contain the purchase.
|
|
// *NOTE: sale_info check doesn't work for multiple object buy,
|
|
// which UI does not currently support sale info is used for
|
|
// verification only, if it doesn't match region info then sale is
|
|
// canceled
|
|
void sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info);
|
|
void sendAttach(U8 attachment_point, bool replace);
|
|
void sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace);
|
|
void sendDetach();
|
|
void sendDropAttachment();
|
|
void sendLink();
|
|
void sendDelink();
|
|
//void sendHinge(U8 type);
|
|
//void sendDehinge();
|
|
void sendSelect();
|
|
|
|
void requestObjectPropertiesFamily(LLViewerObject* object); // asks sim for creator, permissions, resources, etc.
|
|
static void processObjectProperties(LLMessageSystem *mesgsys, void **user_data);
|
|
static void processObjectPropertiesFamily(LLMessageSystem *mesgsys, void **user_data);
|
|
static void processForceObjectSelect(LLMessageSystem* msg, void**);
|
|
|
|
void requestGodInfo();
|
|
|
|
LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; }
|
|
void updateSelectionCenter();
|
|
|
|
void pauseAssociatedAvatars();
|
|
|
|
void resetAgentHUDZoom();
|
|
void setAgentHUDZoom(F32 target_zoom, F32 current_zoom);
|
|
void getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const;
|
|
|
|
void updatePointAt();
|
|
|
|
// Internal list maintenance functions. TODO: Make these private!
|
|
void remove(std::vector<LLViewerObject*>& objects);
|
|
void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true);
|
|
void removeAll();
|
|
void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true, S32 gltf_node = -1, S32 gltf_primitive = -1);
|
|
void promoteSelectionToRoot();
|
|
void demoteSelectionToIndividuals();
|
|
|
|
private:
|
|
void convertTransient(); // converts temporarily selected objects to full-fledged selections
|
|
ESelectType getSelectTypeForObject(LLViewerObject* object);
|
|
void addAsFamily(std::vector<LLViewerObject*>& objects, bool add_to_end = false);
|
|
void generateSilhouette(LLSelectNode *nodep, const LLVector3& view_point);
|
|
void updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects);
|
|
// Send one message to each region containing an object on selection list.
|
|
void sendListToRegions( const std::string& message_name,
|
|
void (*pack_header)(void *user_data),
|
|
void (*pack_body)(LLSelectNode* node, void *user_data),
|
|
void (*log_func)(LLSelectNode* node, void *user_data),
|
|
void *user_data,
|
|
ESendType send_type);
|
|
void sendListToRegions( LLObjectSelectionHandle selected_handle,
|
|
const std::string& message_name,
|
|
void (*pack_header)(void *user_data),
|
|
void (*pack_body)(LLSelectNode* node, void *user_data),
|
|
void (*log_func)(LLSelectNode* node, void *user_data),
|
|
void *user_data,
|
|
ESendType send_type);
|
|
|
|
|
|
static void packAgentID( void *);
|
|
static void packAgentAndSessionID(void* user_data);
|
|
static void packAgentAndGroupID(void* user_data);
|
|
static void packAgentAndSessionAndGroupID(void* user_data);
|
|
static void packAgentIDAndSessionAndAttachment(void*);
|
|
static void packAgentGroupAndCatID(void*);
|
|
static void packDeleteHeader(void* userdata);
|
|
static void packDeRezHeader(void* user_data);
|
|
static void packObjectID( LLSelectNode* node, void *);
|
|
static void packObjectIDAsParam(LLSelectNode* node, void *);
|
|
static void packObjectIDAndRotation(LLSelectNode* node, void *);
|
|
static void packObjectLocalID(LLSelectNode* node, void *);
|
|
static void packObjectClickAction(LLSelectNode* node, void* data);
|
|
static void packObjectIncludeInSearch(LLSelectNode* node, void* data);
|
|
static void packObjectName(LLSelectNode* node, void* user_data);
|
|
static void packObjectDescription(LLSelectNode* node, void* user_data);
|
|
static void packObjectCategory(LLSelectNode* node, void* user_data);
|
|
static void packObjectSaleInfo(LLSelectNode* node, void* user_data);
|
|
static void packBuyObjectIDs(LLSelectNode* node, void* user_data);
|
|
static void packDuplicate( LLSelectNode* node, void *duplicate_data);
|
|
static void packDuplicateHeader(void*);
|
|
static void packDuplicateOnRayHead(void *user_data);
|
|
static void packPermissions(LLSelectNode* node, void *user_data);
|
|
static void packDeselect( LLSelectNode* node, void *user_data);
|
|
static void packMultipleUpdate(LLSelectNode* node, void *user_data);
|
|
static void packPhysics(LLSelectNode* node, void *user_data);
|
|
static void packShape(LLSelectNode* node, void *user_data);
|
|
static void packOwnerHead(void *user_data);
|
|
static void packHingeHead(void *user_data);
|
|
static void packPermissionsHead(void* user_data);
|
|
static void packGodlikeHead(void* user_data);
|
|
static void logNoOp(LLSelectNode* node, void *user_data);
|
|
static void logAttachmentRequest(LLSelectNode* node, void *user_data);
|
|
static void logDetachRequest(LLSelectNode* node, void *user_data);
|
|
static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle);
|
|
|
|
// Get the first ID that matches test and whether or not all ids are identical in selected objects.
|
|
void getFirst(LLSelectGetFirstTest* test);
|
|
|
|
public:
|
|
// Observer/callback support for when object selection changes or
|
|
// properties are received/updated
|
|
typedef boost::signals2::signal< void ()> update_signal_t;
|
|
update_signal_t mUpdateSignal;
|
|
|
|
private:
|
|
LLPointer<LLViewerTexture> mSilhouetteImagep;
|
|
LLObjectSelectionHandle mSelectedObjects;
|
|
LLObjectSelectionHandle mHoverObjects;
|
|
LLObjectSelectionHandle mHighlightedObjects;
|
|
std::set<LLPointer<LLViewerObject> > mRectSelectedObjects;
|
|
|
|
LLObjectSelection mGridObjects;
|
|
LLQuaternion mGridRotation;
|
|
LLVector3 mGridOrigin;
|
|
LLVector3 mGridScale;
|
|
EGridMode mGridMode;
|
|
|
|
bool mTEMode; // render te
|
|
LLRender::eTexIndex mTextureChannel; // diff, norm, or spec, depending on UI editing mode
|
|
LLVector3d mSelectionCenterGlobal;
|
|
LLBBox mSelectionBBox;
|
|
|
|
LLVector3d mLastSentSelectionCenterGlobal;
|
|
bool mShowSelection; // do we send the selection center name value and do we animate this selection?
|
|
LLVector3d mLastCameraPos; // camera position from last generation of selection silhouette
|
|
bool mRenderSilhouettes; // do we render the silhouette
|
|
LLBBox mSavedSelectionBBox;
|
|
|
|
LLFrameTimer mEffectsTimer;
|
|
bool mForceSelection;
|
|
|
|
std::vector<LLAnimPauseRequest> mPauseRequests;
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
EFSShowHideHighlight mFSShowHideHighlight;
|
|
// </FS:KC>
|
|
|
|
// <FS:Zi> Warning when trying to duplicate while in edit linked parts/select face mode
|
|
public:
|
|
// returns true if current selection does not contain individual selections
|
|
// (edit linked parts, select face)
|
|
bool selectGetNoIndividual();
|
|
// </FS:Zi>
|
|
};
|
|
|
|
// *DEPRECATED: For callbacks or observers, use
|
|
// LLSelectMgr::getInstance()->mUpdateSignal.connect( callback )
|
|
// Update subscribers to the selection list
|
|
void dialog_refresh_all();
|
|
|
|
// Templates
|
|
//-----------------------------------------------------------------------------
|
|
// getSelectedTEValue
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance, T tolerance)
|
|
{
|
|
bool have_first = false;
|
|
bool have_selected = false;
|
|
T selected_value = T();
|
|
|
|
// Now iterate through all TEs to test for sameness
|
|
bool identical = true;
|
|
for (iterator iter = begin(); iter != end(); iter++)
|
|
{
|
|
LLSelectNode* node = *iter;
|
|
LLViewerObject* object = node->getObject();
|
|
S32 selected_te = -1;
|
|
if (object == getPrimaryObject())
|
|
{
|
|
selected_te = node->getLastSelectedTE();
|
|
}
|
|
for (S32 te = 0; te < object->getNumTEs(); ++te)
|
|
{
|
|
if (!node->isTESelected(te))
|
|
{
|
|
continue;
|
|
}
|
|
T value = func->get(object, te);
|
|
if (!have_first)
|
|
{
|
|
have_first = true;
|
|
if (!have_selected)
|
|
{
|
|
selected_value = value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( value != selected_value )
|
|
{
|
|
if (!has_tolerance)
|
|
{
|
|
identical = false;
|
|
}
|
|
else if (!LLCheckIdenticalFunctor<T>::same(value, selected_value, tolerance))
|
|
{
|
|
identical = false;
|
|
}
|
|
}
|
|
if (te == selected_te)
|
|
{
|
|
selected_value = value;
|
|
have_selected = true;
|
|
}
|
|
}
|
|
}
|
|
if (!identical && have_selected)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (have_first || have_selected)
|
|
{
|
|
res = selected_value;
|
|
}
|
|
return identical;
|
|
}
|
|
|
|
// Templates
|
|
//-----------------------------------------------------------------------------
|
|
// isMultipleTEValue iterate through all TEs and test for uniqueness
|
|
// with certain return value ignored when performing the test.
|
|
// e.g. when testing if the selection has a unique non-empty homeurl :
|
|
// you can set ignore_value = "" and it will only compare among the non-empty
|
|
// homeUrls and ignore the empty ones.
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T> bool LLObjectSelection::isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value)
|
|
{
|
|
bool have_first = false;
|
|
T selected_value = T();
|
|
|
|
// Now iterate through all TEs to test for sameness
|
|
bool unique = true;
|
|
for (iterator iter = begin(); iter != end(); iter++)
|
|
{
|
|
LLSelectNode* node = *iter;
|
|
LLViewerObject* object = node->getObject();
|
|
for (S32 te = 0; te < object->getNumTEs(); ++te)
|
|
{
|
|
if (!node->isTESelected(te))
|
|
{
|
|
continue;
|
|
}
|
|
T value = func->get(object, te);
|
|
if(value == ignore_value)
|
|
{
|
|
continue;
|
|
}
|
|
if (!have_first)
|
|
{
|
|
have_first = true;
|
|
}
|
|
else
|
|
{
|
|
if (value !=selected_value )
|
|
{
|
|
unique = false;
|
|
return !unique;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return !unique;
|
|
}
|
|
|
|
|
|
#endif
|