Merge branch 'release/2025.05' of https://github.com/secondlife/viewer

# Conflicts:
#	autobuild.xml
#	indra/llui/llfolderviewitem.h
#	indra/llui/lltexteditor.cpp
#	indra/llui/lltexteditor.h
#	indra/newview/app_settings/settings.xml
#	indra/newview/llagent.cpp
#	indra/newview/llappviewer.cpp
#	indra/newview/llfloatermodelpreview.h
#	indra/newview/llinventorybridge.cpp
#	indra/newview/llinventorybridge.h
#	indra/newview/llinventoryfilter.cpp
#	indra/newview/llinventoryfilter.h
#	indra/newview/llmaterialeditor.cpp
#	indra/newview/lloutfitslist.cpp
#	indra/newview/lloutfitslist.h
#	indra/newview/llpanelmaininventory.cpp
#	indra/newview/llpaneloutfitedit.cpp
#	indra/newview/llpaneloutfitsinventory.cpp
#	indra/newview/llpaneloutfitsinventory.h
#	indra/newview/llpanelpermissions.cpp
#	indra/newview/llpanelpermissions.h
#	indra/newview/llpanelwearing.cpp
#	indra/newview/llpanelwearing.h
#	indra/newview/llselectmgr.h
#	indra/newview/llskinningutil.cpp
#	indra/newview/lltexturectrl.cpp
#	indra/newview/lltexturefetch.cpp
#	indra/newview/lltooldraganddrop.cpp
#	indra/newview/llviewerattachmenu.cpp
#	indra/newview/llviewerinventory.cpp
#	indra/newview/llviewerinventory.h
#	indra/newview/llviewerwindow.cpp
#	indra/newview/llvoavatar.cpp
#	indra/newview/llwearableitemslist.cpp
#	indra/newview/skins/default/textures/textures.xml
#	indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
#	indra/newview/skins/default/xui/en/floater_object_weights.xml
#	indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
#	indra/newview/skins/default/xui/en/menu_inventory.xml
#	indra/newview/skins/default/xui/en/menu_outfit_tab.xml
#	indra/newview/skins/default/xui/en/menu_wearing_tab.xml
#	indra/newview/skins/default/xui/en/notifications.xml
#	indra/newview/skins/default/xui/en/panel_main_inventory.xml
#	indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
#	indra/newview/skins/default/xui/en/panel_outfits_list.xml
#	indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
#	indra/newview/skins/default/xui/en/panel_places.xml
#	indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
#	indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml
#	indra/newview/skins/default/xui/en/sidepanel_appearance.xml
#	indra/newview/skins/default/xui/en/strings.xml
#	indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml
#	indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml
master
Ansariel 2025-04-16 17:49:47 +02:00
commit 4c355879cc
208 changed files with 4837 additions and 1357 deletions

View File

@ -2651,23 +2651,17 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
</map>
<key>threejs</key>
<map>
<key>copyright</key>
<string>Copyright © 2010-2021 three.js authors</string>
<key>license</key>
<string>MIT</string>
<key>license_file</key>
<string>LICENSES/THREEJS_LICENSE.txt</string>
<key>name</key>
<string>threejs</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>cfed00d8ea7265c035c2d86a234b28efb0b23756</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-darwin64-b8f6746.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux64</key>
<key>common</key>
<map>
<key>archive</key>
<map>
@ -2679,33 +2673,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-5da28d9/threejs-0.132.2-common-8454371083.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>4141710fccbd1ea2b3b53d00e189bdfa2ee9d441</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-windows64-b8f6746.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
<string>common</string>
</map>
</map>
<key>license</key>
<string>MIT</string>
<key>license_file</key>
<string>LICENSES/THREEJS_LICENSE.txt</string>
<key>copyright</key>
<string>Copyright © 2010-2021 three.js authors</string>
<key>version</key>
<string>0.132.2</string>
<key>name</key>
<string>threejs</string>
</map>
<key>tinygltf</key>
<map>

View File

@ -125,6 +125,8 @@ public:
virtual void addDebugText( const std::string& text ) = 0;
virtual std::string getDebugName() const { return getID().asString(); }
virtual const LLUUID& getID() const = 0;
//-------------------------------------------------------------------------
// End Interface

View File

@ -638,6 +638,14 @@ public:
{
getCPUIDInfo();
uint64_t frequency = getSysctlInt64("hw.cpufrequency");
if (!frequency)
{
auto tbfrequency = getSysctlInt64("hw.tbfrequency");
struct clockinfo clockrate;
auto clockrate_len = sizeof(clockrate);
if (!sysctlbyname("kern.clockrate", &clockrate, &clockrate_len, NULL, 0))
frequency = tbfrequency * clockrate.hz;
}
setInfo(eFrequency, (F64)frequency / (F64)1000000);
}

View File

@ -55,7 +55,7 @@ namespace LL
* ThreadPool listens for application shutdown messages on the "LLApp"
* LLEventPump. Call close() to shut down this ThreadPool early.
*/
virtual void close();
void close();
std::string getName() const { return mName; }
size_t getWidth() const { return mThreads.size(); }
@ -122,7 +122,7 @@ namespace LL
size_t threads=1,
size_t capacity=1024*1024,
bool auto_shutdown = true):
ThreadPoolBase(name, threads, new queue_t(name, capacity), auto_shutdown)
ThreadPoolBase(name, threads, new queue_t(name, capacity, false), auto_shutdown)
{}
~ThreadPoolUsing() override {}

View File

@ -30,12 +30,15 @@ using Lock = LLCoros::LockType;
/*****************************************************************************
* WorkQueueBase
*****************************************************************************/
LL::WorkQueueBase::WorkQueueBase(const std::string& name):
super(makeName(name))
LL::WorkQueueBase::WorkQueueBase(const std::string& name, bool auto_shutdown)
: super(makeName(name))
{
if (auto_shutdown)
{
// TODO: register for "LLApp" events so we can implicitly close() on
// viewer shutdown.
}
}
void LL::WorkQueueBase::runUntilClose()
{
@ -212,8 +215,8 @@ void LL::WorkQueueBase::checkCoroutine(const std::string& method)
/*****************************************************************************
* WorkQueue
*****************************************************************************/
LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
super(name),
LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity, bool auto_shutdown):
super(name, auto_shutdown),
mQueue(capacity)
{
}
@ -261,8 +264,8 @@ bool LL::WorkQueue::tryPop_(Work& work)
/*****************************************************************************
* WorkSchedule
*****************************************************************************/
LL::WorkSchedule::WorkSchedule(const std::string& name, size_t capacity):
super(name),
LL::WorkSchedule::WorkSchedule(const std::string& name, size_t capacity, bool auto_shutdown):
super(name, auto_shutdown),
mQueue(capacity)
{
}

View File

@ -51,7 +51,7 @@ namespace LL
* You may omit the WorkQueueBase name, in which case a unique name is
* synthesized; for practical purposes that makes it anonymous.
*/
WorkQueueBase(const std::string& name);
WorkQueueBase(const std::string& name, bool auto_shutdown);
/**
* Since the point of WorkQueue is to pass work to some other worker
@ -212,7 +212,7 @@ namespace LL
* You may omit the WorkQueue name, in which case a unique name is
* synthesized; for practical purposes that makes it anonymous.
*/
WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
WorkQueue(const std::string& name = std::string(), size_t capacity=1024, bool auto_shutdown = true);
/**
* Since the point of WorkQueue is to pass work to some other worker
@ -282,7 +282,7 @@ namespace LL
* You may omit the WorkSchedule name, in which case a unique name is
* synthesized; for practical purposes that makes it anonymous.
*/
WorkSchedule(const std::string& name = std::string(), size_t capacity=1024);
WorkSchedule(const std::string& name = std::string(), size_t capacity=1024, bool auto_shutdown = true);
/**
* Since the point of WorkSchedule is to pass work to some other worker

View File

@ -46,6 +46,7 @@ static const std::string INV_ITEM_ID_LABEL("item_id");
static const std::string INV_FOLDER_ID_LABEL("cat_id");
static const std::string INV_PARENT_ID_LABEL("parent_id");
static const std::string INV_THUMBNAIL_LABEL("thumbnail");
static const std::string INV_FAVORITE_LABEL("favorite");
static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
static const std::string INV_ASSET_TYPE_LABEL("type");
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
@ -59,6 +60,7 @@ static const std::string INV_LINKED_ID_LABEL("linked_id");
static const std::string INV_SALE_INFO_LABEL("sale_info");
static const std::string INV_FLAGS_LABEL("flags");
static const std::string INV_CREATION_DATE_LABEL("created_at");
static const std::string INV_TOGGLED_LABEL("toggled");
// key used by agent-inventory-service
static const std::string INV_ASSET_TYPE_LABEL_WS("type_default");
@ -82,14 +84,16 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
mParentUUID(parent_uuid),
mType(type),
mName(name),
mCreationDate(0)
mCreationDate(0),
mFavorite(false)
{
correctInventoryName(mName);
}
LLInventoryObject::LLInventoryObject()
: mType(LLAssetType::AT_NONE),
mCreationDate(0)
mCreationDate(0),
mFavorite(false)
{
}
@ -104,6 +108,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
mType = other->mType;
mName = other->mName;
mThumbnailUUID = other->mThumbnailUUID;
mFavorite = other->mFavorite;
}
const LLUUID& LLInventoryObject::getUUID() const
@ -121,6 +126,11 @@ const LLUUID& LLInventoryObject::getThumbnailUUID() const
return mThumbnailUUID;
}
bool LLInventoryObject::getIsFavorite() const
{
return mFavorite;
}
const std::string& LLInventoryObject::getName() const
{
return mName;
@ -175,6 +185,11 @@ void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid)
mThumbnailUUID = thumbnail_uuid;
}
void LLInventoryObject::setFavorite(bool favorite)
{
mFavorite = favorite;
}
void LLInventoryObject::setType(LLAssetType::EType type)
{
mType = type;
@ -247,6 +262,23 @@ bool LLInventoryObject::importLegacyStream(std::istream& input_stream)
{
setThumbnailUUID(LLUUID::null);
}
if (metadata.has("favorite"))
{
const LLSD& favorite = metadata["favorite"];
if (favorite.has("toggled"))
{
setFavorite(favorite["toggled"].asBoolean());
}
else
{
setFavorite(false);
}
}
else
{
setFavorite(false);
}
}
else if(0 == strcmp("name", keyword))
{
@ -813,6 +845,23 @@ bool LLInventoryItem::importLegacyStream(std::istream& input_stream)
{
setThumbnailUUID(LLUUID::null);
}
if (metadata.has("favorite"))
{
const LLSD& favorite = metadata["favorite"];
if (favorite.has("toggled"))
{
setFavorite(favorite["toggled"].asBoolean());
}
else
{
setFavorite(false);
}
}
else
{
setFavorite(false);
}
}
else if(0 == strcmp("inv_type", keyword))
{
@ -973,6 +1022,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
}
if (mFavorite)
{
sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite);
}
U32 mask = mPermissions.getMaskBase();
if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
|| (mAssetUUID.isNull()))
@ -1015,6 +1069,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
// TODO - figure out if this should be moved into the noclobber fields above
mThumbnailUUID.setNull();
mFavorite = false;
// iterate as map to avoid making unnecessary temp copies of everything
LLSD::map_const_iterator i, end;
@ -1060,6 +1115,17 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
continue;
}
if (i->first == INV_FAVORITE_LABEL)
{
const LLSD& favorite_map = i->second;
const std::string w = INV_TOGGLED_LABEL;
if (favorite_map.has(w))
{
mFavorite = favorite_map[w].asBoolean();
}
continue;
}
if (i->first == INV_PERMISSIONS_LABEL)
{
mPermissions = ll_permissions_from_sd(i->second);
@ -1255,6 +1321,11 @@ LLSD LLInventoryCategory::asLLSD() const
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
}
if (mFavorite)
{
sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite);
}
return sd;
}
@ -1266,11 +1337,17 @@ LLSD LLInventoryCategory::asAISCreateCatLLSD() const
S8 type = static_cast<S8>(mPreferredType);
sd[INV_ASSET_TYPE_LABEL_WS] = type;
sd[INV_NAME_LABEL] = mName;
if (mThumbnailUUID.notNull())
{
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
}
if (mFavorite)
{
sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite);
}
return sd;
}
@ -1318,6 +1395,17 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
mThumbnailUUID = sd[w];
}
}
mFavorite = false;
w = INV_FAVORITE_LABEL;
if (sd.has(w))
{
const LLSD& favorite_map = sd[w];
w = INV_TOGGLED_LABEL;
if (favorite_map.has(w))
{
mFavorite = favorite_map[w].asBoolean();
}
}
w = INV_ASSET_TYPE_LABEL;
if (sd.has(w))
{
@ -1440,6 +1528,23 @@ bool LLInventoryCategory::importLegacyStream(std::istream& input_stream)
{
setThumbnailUUID(LLUUID::null);
}
if (metadata.has("favorite"))
{
const LLSD& favorite = metadata["favorite"];
if (favorite.has("toggled"))
{
setFavorite(favorite["toggled"].asBoolean());
}
else
{
setFavorite(false);
}
}
else
{
setFavorite(false);
}
}
else
{
@ -1487,6 +1592,10 @@ LLSD LLInventoryCategory::exportLLSD() const
{
cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
}
if (mFavorite)
{
cat_data[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite);
}
return cat_data;
}
@ -1519,6 +1628,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
}
setThumbnailUUID(thumbnail_uuid);
}
if (cat_data.has(INV_FAVORITE_LABEL))
{
bool favorite = false;
const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL];
if (favorite_data.has(INV_TOGGLED_LABEL))
{
favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean();
}
setFavorite(favorite);
}
if (cat_data.has(INV_NAME_LABEL))
{
mName = cat_data[INV_NAME_LABEL].asString();

View File

@ -71,6 +71,7 @@ public:
virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
const LLUUID& getParentUUID() const;
virtual const LLUUID& getThumbnailUUID() const;
virtual bool getIsFavorite() const;
virtual const std::string& getName() const;
virtual LLAssetType::EType getType() const;
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
@ -86,6 +87,7 @@ public:
virtual void rename(const std::string& new_name);
void setParent(const LLUUID& new_parent);
virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
virtual void setFavorite(bool favorite);
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
@ -111,6 +113,7 @@ protected:
LLUUID mUUID;
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
LLUUID mThumbnailUUID;
bool mFavorite;
LLAssetType::EType mType;
std::string mName;
time_t mCreationDate; // seconds from 1/1/1970, UTC

View File

@ -329,28 +329,30 @@ void LLCoordFrame::rotate(const LLMatrix3 &rotation_matrix)
}
// Rotate 2 normalized orthogonal vectors in direction from `source` to `target`
static void rotate2(LLVector3& source, LLVector3& target, F32 angle)
{
F32 sx = source[VX], sy = source[VY], sz = source[VZ];
F32 tx = target[VX], ty = target[VY], tz = target[VZ];
F32 c = cosf(angle), s = sinf(angle);
source.set(sx * c + tx * s, sy * c + ty * s, sz * c + tz * s);
target.set(tx * c - sx * s, ty * c - sy * s, tz * c - sz * s);
}
void LLCoordFrame::roll(F32 angle)
{
LLQuaternion q(angle, mXAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
CHECK_FINITE_OBJ();
rotate2(mYAxis, mZAxis, angle);
}
void LLCoordFrame::pitch(F32 angle)
{
LLQuaternion q(angle, mYAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
CHECK_FINITE_OBJ();
rotate2(mZAxis, mXAxis, angle);
}
void LLCoordFrame::yaw(F32 angle)
{
LLQuaternion q(angle, mZAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
CHECK_FINITE_OBJ();
rotate2(mXAxis, mYAxis, angle);
}
// get*() routines

View File

@ -58,7 +58,7 @@ LLQuaternion::LLQuaternion(const LLMatrix3 &mat)
LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
{
F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]);
F32 mag = vec.length();
if (mag > FP_MAG_THRESHOLD)
{
angle *= 0.5;
@ -77,7 +77,7 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
{
F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]);
F32 mag = vec.length();
if (mag > FP_MAG_THRESHOLD)
{
angle *= 0.5;

View File

@ -67,7 +67,14 @@ F32 angle_between(const LLVector2& a, const LLVector2& b)
return angle;
}
bool are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon)
F32 signed_angle_between(const LLVector2& a, const LLVector2& b)
{
F32 angle = angle_between(a, b);
F32 rhombus_square = a[VX] * b[VY] - b[VX] * a[VY];
return rhombus_square < 0 ? -angle : angle;
}
bool are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon)
{
LLVector2 an = a;
LLVector2 bn = b;

View File

@ -107,13 +107,14 @@ class LLVector2
friend LLVector2 operator-(const LLVector2 &a); // Return vector -a
friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
};
// Non-member functions
F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b
F32 signed_angle_between(const LLVector2& a, const LLVector2& b); // Returns signed angle (radians) between a and b
bool are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel
F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b
F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b
@ -124,26 +125,22 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u); // Returns a vect
inline LLVector2::LLVector2(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
clear();
}
inline LLVector2::LLVector2(F32 x, F32 y)
{
mV[VX] = x;
mV[VY] = y;
set(x, y);
}
inline LLVector2::LLVector2(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
set(vec);
}
inline LLVector2::LLVector2(const LLVector3 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
set(vec.mV);
}
inline LLVector2::LLVector2(const LLSD &sd)
@ -155,28 +152,24 @@ inline LLVector2::LLVector2(const LLSD &sd)
inline void LLVector2::clear(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
mV[VX] = mV[VY] = 0.f;
}
inline void LLVector2::setZero(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
clear();
}
// deprecated
inline void LLVector2::clearVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
clear();
}
// deprecated
inline void LLVector2::zeroVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
clear();
}
inline void LLVector2::set(F32 x, F32 y)
@ -187,36 +180,31 @@ inline void LLVector2::set(F32 x, F32 y)
inline void LLVector2::set(const LLVector2 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
set(vec.mV);
}
inline void LLVector2::set(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
set(vec[VX], vec[VY]);
}
// deprecated
inline void LLVector2::setVec(F32 x, F32 y)
{
mV[VX] = x;
mV[VY] = y;
set(x, y);
}
// deprecated
inline void LLVector2::setVec(const LLVector2 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
set(vec);
}
// deprecated
inline void LLVector2::setVec(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
set(vec);
}
@ -224,7 +212,7 @@ inline void LLVector2::setVec(const F32 *vec)
inline F32 LLVector2::length(void) const
{
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
return sqrt(lengthSquared());
}
inline F32 LLVector2::lengthSquared(void) const
@ -234,61 +222,42 @@ inline F32 LLVector2::lengthSquared(void) const
inline F32 LLVector2::normalize(void)
{
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
F32 mag = length();
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[0] *= oomag;
mV[1] *= oomag;
*this /= mag;
}
else
{
mV[0] = 0.f;
mV[1] = 0.f;
clear();
mag = 0;
}
return (mag);
return mag;
}
// checker
inline bool LLVector2::isFinite() const
{
return (llfinite(mV[VX]) && llfinite(mV[VY]));
return llfinite(mV[VX]) && llfinite(mV[VY]);
}
// deprecated
inline F32 LLVector2::magVec(void) const
inline F32 LLVector2::magVec(void) const
{
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
return length();
}
// deprecated
inline F32 LLVector2::magVecSquared(void) const
inline F32 LLVector2::magVecSquared(void) const
{
return mV[0]*mV[0] + mV[1]*mV[1];
return lengthSquared();
}
// deprecated
inline F32 LLVector2::normVec(void)
inline F32 LLVector2::normVec(void)
{
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[0] *= oomag;
mV[1] *= oomag;
}
else
{
mV[0] = 0.f;
mV[1] = 0.f;
mag = 0;
}
return (mag);
return normalize();
}
inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec)
@ -301,11 +270,7 @@ inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec)
inline bool LLVector2::isNull()
{
if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] )
{
return true;
}
return false;
return F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY];
}
@ -337,9 +302,9 @@ inline LLVector2 operator-(const LLVector2 &a, const LLVector2 &b)
return c -= b;
}
inline F32 operator*(const LLVector2 &a, const LLVector2 &b)
inline F32 operator*(const LLVector2 &a, const LLVector2 &b)
{
return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1]);
return a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1];
}
inline LLVector2 operator%(const LLVector2 &a, const LLVector2 &b)
@ -405,10 +370,7 @@ inline const LLVector2& operator*=(LLVector2 &a, F32 k)
inline const LLVector2& operator/=(LLVector2 &a, F32 k)
{
F32 t = 1.f / k;
a.mV[0] *= t;
a.mV[1] *= t;
return a;
return a *= 1.f / k;
}
inline LLVector2 operator-(const LLVector2 &a)

View File

@ -112,24 +112,24 @@ class LLVector3
const LLVector3& setVec(const LLVector4 &vec); // deprecated
const LLVector3& setVec(const LLVector3d &vec); // deprecated
F32 length() const; // Returns magnitude of LLVector3
F32 lengthSquared() const; // Returns magnitude squared of LLVector3
F32 magVec() const; // deprecated
F32 magVecSquared() const; // deprecated
F32 length() const; // Returns magnitude of LLVector3
F32 lengthSquared() const; // Returns magnitude squared of LLVector3
F32 magVec() const; // deprecated
F32 magVecSquared() const; // deprecated
inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3
inline F32 normVec(); // deprecated
inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3
inline F32 normVec(); // deprecated
inline bool inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max
inline bool inRange(F32 min, F32 max) const; // Returns true if all values of the vector are between min and max
const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians
const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians
const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
bool isNull() const; // Returns true if vector has a _very_small_ length
bool isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; }
@ -183,23 +183,17 @@ bool box_valid_and_non_zero(const LLVector3* box);
inline LLVector3::LLVector3(void)
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
clear();
}
inline LLVector3::LLVector3(const F32 x, const F32 y, const F32 z)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
set(x, y, z);
}
inline LLVector3::LLVector3(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
mV[VZ] = vec[VZ];
set(vec);
}
inline LLVector3::LLVector3(const glm::vec3& vec)
@ -230,7 +224,7 @@ inline LLVector3::LLVector3(const LLVector3 &copy)
// checker
inline bool LLVector3::isFinite() const
{
return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]));
return llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]);
}
@ -238,30 +232,22 @@ inline bool LLVector3::isFinite() const
inline void LLVector3::clear(void)
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
set(0.f, 0.f, 0.f);
}
inline void LLVector3::setZero(void)
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
clear();
}
inline void LLVector3::clearVec(void)
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
clear();
}
inline void LLVector3::zeroVec(void)
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
clear();
}
inline void LLVector3::set(F32 x, F32 y, F32 z)
@ -273,16 +259,12 @@ inline void LLVector3::set(F32 x, F32 y, F32 z)
inline void LLVector3::set(const LLVector3 &vec)
{
mV[0] = vec.mV[0];
mV[1] = vec.mV[1];
mV[2] = vec.mV[2];
set(vec.mV[0], vec.mV[1], vec.mV[2]);
}
inline void LLVector3::set(const F32 *vec)
{
mV[0] = vec[0];
mV[1] = vec[1];
mV[2] = vec[2];
set(vec[0], vec[1], vec[2]);
}
inline void LLVector3::set(const glm::vec4& vec)
@ -302,92 +284,63 @@ inline void LLVector3::set(const glm::vec3& vec)
// deprecated
inline void LLVector3::setVec(F32 x, F32 y, F32 z)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
set(x, y, z);
}
// deprecated
inline void LLVector3::setVec(const LLVector3 &vec)
{
mV[0] = vec.mV[0];
mV[1] = vec.mV[1];
mV[2] = vec.mV[2];
set(vec);
}
// deprecated
inline void LLVector3::setVec(const F32 *vec)
{
mV[0] = vec[0];
mV[1] = vec[1];
mV[2] = vec[2];
set(vec);
}
inline F32 LLVector3::normalize(void)
{
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[0] *= oomag;
mV[1] *= oomag;
mV[2] *= oomag;
*this /= mag;
}
else
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
clear();
mag = 0;
}
return (mag);
return mag;
}
// deprecated
inline F32 LLVector3::normVec(void)
{
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[0] *= oomag;
mV[1] *= oomag;
mV[2] *= oomag;
}
else
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
mag = 0;
}
return (mag);
return normalize();
}
// LLVector3 Magnitude and Normalization Functions
inline F32 LLVector3::length(void) const
inline F32 LLVector3::length(void) const
{
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return sqrt(lengthSquared());
}
inline F32 LLVector3::lengthSquared(void) const
inline F32 LLVector3::lengthSquared() const
{
return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
}
inline F32 LLVector3::magVec(void) const
inline F32 LLVector3::magVec(void) const
{
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return length();
}
inline F32 LLVector3::magVecSquared(void) const
inline F32 LLVector3::magVecSquared(void) const
{
return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
return lengthSquared();
}
inline bool LLVector3::inRange( F32 min, F32 max ) const
@ -411,7 +364,7 @@ inline LLVector3 operator-(const LLVector3 &a, const LLVector3 &b)
inline F32 operator*(const LLVector3 &a, const LLVector3 &b)
{
return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]);
return a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2];
}
inline LLVector3 operator%(const LLVector3 &a, const LLVector3 &b)
@ -499,10 +452,7 @@ inline const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b)
inline const LLVector3& operator/=(LLVector3 &a, F32 k)
{
F32 t = 1.f / k;
a.mV[0] *= t;
a.mV[1] *= t;
a.mV[2] *= t;
a *= 1.f / k;
return a;
}
@ -522,7 +472,7 @@ inline LLVector3::operator glm::vec4() const
return glm::vec4(mV[VX], mV[VY], mV[VZ], 1.f);
}
inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
{
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
@ -530,7 +480,7 @@ inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
return (F32) sqrt( x*x + y*y + z*z );
}
inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)
inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)
{
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
@ -538,7 +488,7 @@ inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)
return x*x + y*y + z*z;
}
inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b)
inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b)
{
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
@ -552,10 +502,7 @@ inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)
{
return ((a * b) / bb) * b;
}
else
{
return b.zero;
}
return b.zero;
}
inline LLVector3 inverse_projected_vec(const LLVector3& a, const LLVector3& b)
@ -592,11 +539,7 @@ inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u)
inline bool LLVector3::isNull() const
{
if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] )
{
return true;
}
return false;
return F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
}
inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
@ -637,7 +580,7 @@ inline F32 angle_between(const LLVector3& a, const LLVector3& b)
ab = 0.0f; // get rid of negative zero
}
LLVector3 c = a % b; // crossproduct
return atan2f(sqrtf(c * c), ab); // return the angle
return atan2f(c.length(), ab); // return the angle
}
inline bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon)
@ -647,7 +590,7 @@ inline bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon)
an.normalize();
bn.normalize();
F32 dot = an * bn;
if ( (1.0f - fabs(dot)) < epsilon)
if (1.0f - fabs(dot) < epsilon)
{
return true;
}

View File

@ -118,6 +118,8 @@ class LLVector4
bool isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; }
bool isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; }
const LLVector4& rotVec(F32 angle, const LLVector4 &vec); // Rotates about vec by angle radians
const LLVector4& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat
const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q
@ -159,34 +161,22 @@ LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u); // Returns a vect
inline LLVector4::LLVector4(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
mV[VZ] = 0.f;
mV[VW] = 1.f;
clear();
}
inline LLVector4::LLVector4(F32 x, F32 y, F32 z)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
mV[VW] = 1.f;
set(x, y, z, 1.f);
}
inline LLVector4::LLVector4(F32 x, F32 y, F32 z, F32 w)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
mV[VW] = w;
set(x, y, z, w);
}
inline LLVector4::LLVector4(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
mV[VZ] = vec[VZ];
mV[VW] = vec[VW];
set(vec);
}
inline LLVector4::LLVector4(const F64 *vec)
@ -215,18 +205,12 @@ inline LLVector4::LLVector4(const LLVector2 &vec, F32 z, F32 w)
inline LLVector4::LLVector4(const LLVector3 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
mV[VZ] = vec.mV[VZ];
mV[VW] = 1.f;
set(vec, 1.f);
}
inline LLVector4::LLVector4(const LLVector3 &vec, F32 w)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
mV[VZ] = vec.mV[VZ];
mV[VW] = w;
set(vec, w);
}
inline LLVector4::LLVector4(const LLSD &sd)
@ -252,43 +236,31 @@ inline LLVector4::LLVector4(const glm::vec4& vec)
inline bool LLVector4::isFinite() const
{
return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW]));
return llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW]);
}
// Clear and Assignment Functions
inline void LLVector4::clear(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
mV[VZ] = 0.f;
mV[VW] = 1.f;
set(0.f, 0.f, 0.f, 1.f);
}
// deprecated
inline void LLVector4::clearVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
mV[VZ] = 0.f;
mV[VW] = 1.f;
clear();
}
// deprecated
inline void LLVector4::zeroVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
mV[VZ] = 0.f;
mV[VW] = 0.f;
set(0.f, 0.f, 0.f, 0.f);
}
inline void LLVector4::set(F32 x, F32 y, F32 z)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
mV[VW] = 1.f;
set(x, y, z, 1.f);
}
inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w)
@ -301,10 +273,7 @@ inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w)
inline void LLVector4::set(const LLVector4 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
mV[VZ] = vec.mV[VZ];
mV[VW] = vec.mV[VW];
set(vec.mV);
}
inline void LLVector4::set(const LLVector3 &vec, F32 w)
@ -322,7 +291,6 @@ inline void LLVector4::set(const F32 *vec)
mV[VZ] = vec[VZ];
mV[VW] = vec[VW];
}
inline void LLVector4::set(const glm::vec4& vec)
{
mV[VX] = vec.x;
@ -342,53 +310,38 @@ inline void LLVector4::set(const glm::vec3& vec, F32 w)
// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
mV[VW] = 1.f;
set(x, y, z);
}
// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)
{
mV[VX] = x;
mV[VY] = y;
mV[VZ] = z;
mV[VW] = w;
set(x, y, z, w);
}
// deprecated
inline void LLVector4::setVec(const LLVector4 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
mV[VZ] = vec.mV[VZ];
mV[VW] = vec.mV[VW];
set(vec);
}
// deprecated
inline void LLVector4::setVec(const LLVector3 &vec, F32 w)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
mV[VZ] = vec.mV[VZ];
mV[VW] = w;
set(vec, w);
}
// deprecated
inline void LLVector4::setVec(const F32 *vec)
{
mV[VX] = vec[VX];
mV[VY] = vec[VY];
mV[VZ] = vec[VZ];
mV[VW] = vec[VW];
set(vec);
}
// LLVector4 Magnitude and Normalization Functions
inline F32 LLVector4::length(void) const
{
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return sqrt(lengthSquared());
}
inline F32 LLVector4::lengthSquared(void) const
@ -398,12 +351,12 @@ inline F32 LLVector4::lengthSquared(void) const
inline F32 LLVector4::magVec(void) const
{
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return length();
}
inline F32 LLVector4::magVecSquared(void) const
{
return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
return lengthSquared();
}
// LLVector4 Operators
@ -422,7 +375,7 @@ inline LLVector4 operator-(const LLVector4 &a, const LLVector4 &b)
inline F32 operator*(const LLVector4 &a, const LLVector4 &b)
{
return (a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ]);
return a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ];
}
inline LLVector4 operator%(const LLVector4 &a, const LLVector4 &b)
@ -495,11 +448,7 @@ inline const LLVector4& operator*=(LLVector4 &a, F32 k)
inline const LLVector4& operator/=(LLVector4 &a, F32 k)
{
F32 t = 1.f / k;
a.mV[VX] *= t;
a.mV[VY] *= t;
a.mV[VZ] *= t;
return a;
return a *= 1.f / k;
}
inline LLVector4 operator-(const LLVector4 &a)
@ -527,13 +476,13 @@ inline LLVector4::operator glm::vec4() const
inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b)
{
LLVector4 vec = a - b;
return (vec.length());
return vec.length();
}
inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b)
{
LLVector4 vec = a - b;
return (vec.lengthSquared());
return vec.lengthSquared();
}
inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
@ -547,15 +496,11 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
inline F32 LLVector4::normalize(void)
{
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[VX] *= oomag;
mV[VY] *= oomag;
mV[VZ] *= oomag;
*this /= mag;
}
else
{
@ -564,34 +509,18 @@ inline F32 LLVector4::normalize(void)
mV[2] = 0.f;
mag = 0;
}
return (mag);
return mag;
}
// deprecated
inline F32 LLVector4::normVec(void)
{
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
oomag = 1.f/mag;
mV[VX] *= oomag;
mV[VY] *= oomag;
mV[VZ] *= oomag;
}
else
{
mV[0] = 0.f;
mV[1] = 0.f;
mV[2] = 0.f;
mag = 0;
}
return (mag);
return normalize();
}
// Because apparently some parts of the viewer use this for color info.
inline const LLVector4 srgbVector4(const LLVector4 &a) {
inline const LLVector4 srgbVector4(const LLVector4 &a)
{
LLVector4 srgbColor;
srgbColor.mV[0] = linearTosRGB(a.mV[0]);

View File

@ -69,7 +69,12 @@ LLModel::~LLModel()
{
if (mDecompID >= 0)
{
LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID);
// can be null on shutdown
LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
if (decomp)
{
decomp->deleteDecomposition(mDecompID);
}
}
mPhysics.mMesh.clear();
}

View File

@ -140,7 +140,7 @@ public:
S32 notify(const LLSD& info);
bool notifyChildren(const LLSD& info);
void draw();
virtual void draw();
void storeOpenCloseState();
void restoreOpenCloseState();

View File

@ -1366,9 +1366,17 @@ bool LLFlatListViewEx::getForceShowingUnmatchedItems()
return mForceShowingUnmatchedItems;
}
void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show)
void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show, bool notify_parent)
{
if (mForceShowingUnmatchedItems != show)
{
mForceShowingUnmatchedItems = show;
if (!mFilterSubString.empty())
{
updateNoItemsMessage(mFilterSubString);
filterItems(false, true);
}
}
}
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent)
@ -1436,6 +1444,7 @@ void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent)
if (visibility_changed && notify_parent)
{
rearrangeItems();
notifyParentItemsRectChanged();
}
}

View File

@ -494,7 +494,11 @@ public:
bool getForceShowingUnmatchedItems();
void setForceShowingUnmatchedItems(bool show);
/**
* Sets filtered out items to stay visible. Can result in rect changes,
* so can notify_parent if rect changes
*/
void setForceShowingUnmatchedItems(bool show, bool notify_parent);
/**
* Sets up new filter string and filters the list.

View File

@ -1787,6 +1787,11 @@ LLRect LLFolderView::getVisibleRect()
return visible_rect;
}
S32 LLFolderView::getVisibleContentWidth()
{
return (mScrollContainer ? mScrollContainer->getVisibleContentRect().getWidth() : 0);
}
bool LLFolderView::getShowSelectionContext()
{
if (mShowSelectionContext)

View File

@ -227,6 +227,7 @@ public:
void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect);
void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; }
LLRect getVisibleRect();
S32 getVisibleContentWidth();
bool search(LLFolderViewItem* first_item, const std::string &search_string, bool backward);
void setShowSelectionContext(bool show) { mShowSelectionContext = show; }

View File

@ -31,11 +31,12 @@
#include "llfolderviewitem.h"
#include "llfolderview.h"
#include "llfolderviewmodel.h"
#include "llpanel.h"
#include "llcallbacklist.h"
#include "llcriticaldamp.h"
#include "llclipboard.h"
#include "llfocusmgr.h" // gFocusMgr
#include "llnotificationsutil.h"
#include "llpanel.h"
#include "lltrans.h"
#include "llwindow.h"
@ -62,7 +63,11 @@ LLUIColor LLFolderViewItem::sProtectedColor;
S32 LLFolderViewItem::sTopPad = 0;
LLUIImagePtr LLFolderViewItem::sFolderArrowImg;
LLUIImagePtr LLFolderViewItem::sSelectionImg;
LLUIImagePtr LLFolderViewItem::sFavoriteImg;
LLUIImagePtr LLFolderViewItem::sFavoriteContentImg;
LLFontGL* LLFolderViewItem::sSuffixFont = nullptr;
LLUIColor LLFolderViewItem::sFavoriteColor;
bool LLFolderViewItem::sColorSetInitialized = false;
// only integers can be initialized in header
const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f;
@ -104,6 +109,8 @@ void LLFolderViewItem::initClass()
sTopPad = default_params.item_top_pad;
sFolderArrowImg = default_params.folder_arrow_image;
sSelectionImg = default_params.selection_image;
sFavoriteImg = default_params.favorite_image;
sFavoriteContentImg = default_params.favorite_content_image;
sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL);
// <FS:Ansariel> Make inventory selection color independent from menu color
@ -132,6 +139,8 @@ void LLFolderViewItem::cleanupClass()
sFonts.clear();
sFolderArrowImg = nullptr;
sSelectionImg = nullptr;
sFavoriteImg = nullptr;
sFavoriteContentImg = nullptr;
sSuffixFont = nullptr;
}
@ -140,13 +149,15 @@ void LLFolderViewItem::cleanupClass()
LLFolderViewItem::Params::Params()
: root(),
listener(),
favorite_image("favorite_image"),
favorite_content_image("favorite_content_image"),
folder_arrow_image("folder_arrow_image"),
folder_indentation("folder_indentation"),
selection_image("selection_image"),
item_height("item_height"),
item_top_pad("item_top_pad"),
creation_date(),
allow_wear("allow_wear", true),
marketplace_item("marketplace_item", false),
allow_drop("allow_drop", true),
font_color("font_color"),
font_highlight_color("font_highlight_color"),
@ -169,6 +180,8 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
: LLView(p),
mLabelWidth(0),
mLabelWidthDirty(false),
mIsFavorite(false),
mHasFavorites(false),
mSuffixNeedsRefresh(false),
mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT),
mParentFolder( NULL ),
@ -189,7 +202,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mRoot(p.root),
mViewModelItem(p.listener),
mIsMouseOverTitle(false),
mAllowWear(p.allow_wear),
mMarketplaceItem(p.marketplace_item),
mAllowDrop(p.allow_drop),
mFontColor(p.font_color),
mFontHighlightColor(p.font_highlight_color),
@ -206,6 +219,21 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mForInventory(p.for_inventory),
mItemTopPad(p.item_top_pad)
{
if (!sColorSetInitialized)
{
sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
sFavoriteColor = LLUIColorTable::instance().getColor("InventoryFavoriteColor", DEFAULT_WHITE);
sColorSetInitialized = true;
}
if (mViewModelItem)
{
mViewModelItem->setFolderViewItem(this);
@ -228,6 +256,7 @@ bool LLFolderViewItem::postBuild()
// getDisplayName() is expensive (due to internal getLabelSuffix() and name building)
// it also sets search strings so it requires a filter reset
mLabel = utf8str_to_wstring(vmi->getDisplayName());
mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash();
setToolTip(vmi->getName());
// Dirty the filter flag of the model from the view (CHUI-849)
@ -342,6 +371,7 @@ void LLFolderViewItem::refresh()
mLabel = utf8str_to_wstring(vmi.getDisplayName());
mLabelFontBuffer.reset();
mIsFavorite = vmi.isFavorite() && !vmi.isItemInTrash();
setToolTip(vmi.getName());
// icons are slightly expensive to get, can be optimized
// see LLInventoryIcon::getIcon()
@ -376,6 +406,8 @@ void LLFolderViewItem::refreshSuffix()
mIconOpen = vmi->getIconOpen();
mIconOverlay = vmi->getIconOverlay();
mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash();
if (mRoot->useLabelSuffix())
{
// Very Expensive!
@ -589,10 +621,15 @@ void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags)
void LLFolderViewItem::openItem( void )
{
if (mAllowWear || !getViewModelItem()->isItemWearable())
if (!mMarketplaceItem || !getViewModelItem()->isItemWearable())
{
getViewModelItem()->openItem();
}
else if (mMarketplaceItem)
{
// Wearing an object from any listing, active or not, is verbotten
LLNotificationsUtil::add("AlertMerchantListingCannotWear");
}
}
void LLFolderViewItem::rename(const std::string& new_name)
@ -837,6 +874,38 @@ void LLFolderViewItem::drawOpenFolderArrow()
}
}
void LLFolderViewItem::drawFavoriteIcon()
{
static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true);
static LLUICachedControl<bool> draw_hollow_star("InventoryFavoritesUseHollowStar", true);
LLUIImage* favorite_image = nullptr;
if (draw_star && mIsFavorite)
{
favorite_image = sFavoriteImg;
}
else if (draw_hollow_star && mHasFavorites && !isOpen())
{
favorite_image = sFavoriteContentImg;
}
if (favorite_image)
{
constexpr S32 PAD = 3;
constexpr S32 image_size = 14;
S32 width = mRoot->getVisibleContentWidth(); // star should stick to scroller's right side
if (width <= 0)
{
width = getRect().getWidth();
}
gl_draw_scaled_image(
width - image_size - PAD, getRect().getHeight() - mItemHeight + PAD,
image_size, image_size, favorite_image->getImage(), sFgColor);
}
}
/*virtual*/ bool LLFolderViewItem::isHighlightAllowed()
{
return mIsSelected;
@ -994,6 +1063,7 @@ void LLFolderViewItem::draw()
{
drawOpenFolderArrow();
}
drawFavoriteIcon();
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
@ -1065,7 +1135,20 @@ void LLFolderViewItem::draw()
}
}
LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor;
static LLUICachedControl<bool> highlight_color("InventoryFavoritesColorText", true);
LLColor4 color;
if (mIsSelected && filled)
{
color = mFontHighlightColor;
}
else if (mIsFavorite && highlight_color)
{
color = sFavoriteColor;
}
else
{
color = mFontColor;
}
if (isFadeItem())
{
@ -1203,7 +1286,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
mIsFolderComplete(false), // folder might have children that are not loaded yet.
mAreChildrenInited(false), // folder might have children that are not built yet.
mLastArrangeGeneration( -1 ),
mLastCalculatedWidth(0)
mLastCalculatedWidth(0),
mFavoritesDirtyFlags(0)
{
}
@ -1229,6 +1313,11 @@ LLFolderViewFolder::~LLFolderViewFolder( void )
// The LLView base class takes care of object destruction. make sure that we
// don't have mouse or keyboard focus
gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
if (mFavoritesDirtyFlags)
{
gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, this);
}
}
// addToFolder() returns true if it succeeds. false otherwise
@ -1872,6 +1961,140 @@ bool LLFolderViewFolder::isMovable()
return true;
}
void LLFolderViewFolder::updateHasFavorites(bool new_childs_value)
{
if (mFavoritesDirtyFlags == 0)
{
gIdleCallbacks.addFunction(&LLFolderViewFolder::onIdleUpdateFavorites, this);
}
if (new_childs_value)
{
mFavoritesDirtyFlags |= FAVORITE_ADDED;
}
else
{
mFavoritesDirtyFlags |= FAVORITE_REMOVED;
}
}
void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
{
LLFolderViewFolder* self = reinterpret_cast<LLFolderViewFolder*>(data);
if (self->mFavoritesDirtyFlags == 0)
{
// already processed either on previous run or by a different callback
gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self);
return;
}
if (self->getViewModelItem()->isItemInTrash())
{
// do not display favorite-stars in trash
self->mFavoritesDirtyFlags = 0;
gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self);
return;
}
if (self->mFavoritesDirtyFlags == FAVORITE_ADDED)
{
if (!self->mHasFavorites)
{
// propagate up, exclude root
LLFolderViewFolder* parent = self;
while (parent
&& (!parent->hasFavorites() || parent->mFavoritesDirtyFlags)
&& !parent->getViewModelItem()->isAgentInventoryRoot())
{
parent->setHasFavorites(true);
if (parent->mFavoritesDirtyFlags)
{
// Parent will remove onIdleUpdateFavorites later, don't remove now,
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
parent->mFavoritesDirtyFlags = 0;
}
parent = parent->getParentFolder();
}
}
else
{
LL_WARNS() << "FAVORITE_ADDED for a folder without favorites" << LL_ENDL;
self->mFavoritesDirtyFlags = 0;
gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self);
}
}
else if (self->mFavoritesDirtyFlags > FAVORITE_ADDED)
{
// full check
LLFolderViewFolder* parent = self;
while (parent && !parent->getViewModelItem()->isAgentInventoryRoot())
{
bool has_favorites = false;
for (items_t::iterator iter = parent->mItems.begin();
iter != parent->mItems.end();)
{
items_t::iterator iit = iter++;
if ((*iit)->isFavorite())
{
has_favorites = true;
break;
}
}
for (folders_t::iterator iter = parent->mFolders.begin();
iter != parent->mFolders.end() && !has_favorites;)
{
folders_t::iterator fit = iter++;
if ((*fit)->isFavorite() || (*fit)->hasFavorites())
{
has_favorites = true;
break;
}
}
if (!has_favorites)
{
if (parent->hasFavorites())
{
parent->setHasFavorites(false);
}
else
{
// Nothing changed
break;
}
}
else
{
// propagate up, exclude root
while (parent
&& (!parent->hasFavorites() || parent->mFavoritesDirtyFlags)
&& !parent->getViewModelItem()->isAgentInventoryRoot())
{
parent->setHasFavorites(true);
if (parent->mFavoritesDirtyFlags)
{
// Parent will remove onIdleUpdateFavorites later, don't remove now,
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
parent->mFavoritesDirtyFlags = 0;
}
parent = parent->getParentFolder();
}
break;
}
if (parent->mFavoritesDirtyFlags)
{
// Parent will remove onIdleUpdateFavorites later, don't remove now.
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
parent->mFavoritesDirtyFlags = 0;
}
parent = parent->getParentFolder();
}
}
}
bool LLFolderViewFolder::isRemovable()
{

View File

@ -50,7 +50,9 @@ class LLFolderViewItem : public LLView
public:
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<LLUIImage*> folder_arrow_image,
Optional<LLUIImage*> favorite_image,
favorite_content_image,
folder_arrow_image,
selection_image;
Mandatory<LLFolderView*> root;
Mandatory<LLFolderViewModelItem*> listener;
@ -60,7 +62,7 @@ public:
item_top_pad;
Optional<time_t> creation_date;
Optional<bool> allow_wear;
Optional<bool> marketplace_item;
Optional<bool> allow_drop;
Optional<LLUIColor> font_color;
@ -97,6 +99,8 @@ protected:
LLWString mLabel;
S32 mLabelWidth;
bool mLabelWidthDirty;
bool mIsFavorite;
bool mHasFavorites;
S32 mLabelPaddingRight;
LLFolderViewFolder* mParentFolder;
LLPointer<LLFolderViewModelItem> mViewModelItem;
@ -126,7 +130,7 @@ protected:
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
mAllowWear,
mMarketplaceItem,
mAllowDrop,
mSingleFolderMode,
mDoubleClickOverride,
@ -137,6 +141,7 @@ protected:
LLUIColor mFontColor;
LLUIColor mFontHighlightColor;
static bool sColorSetInitialized;
// <FS:Ansariel> Inventory specials
bool mForInventory;
@ -153,9 +158,11 @@ protected:
static LLUIColor sFilterTextColor;
static LLUIColor sSuffixColor;
static LLUIColor sSearchStatusColor;
static LLUIColor sFavoriteColor;
// <FS:Ansariel> Special for protected items
static LLUIColor sProtectedColor;
// this is an internal method used for adding items to folders. A
// no-op at this level, but reimplemented in derived classes.
virtual void addItem(LLFolderViewItem*) { }
@ -218,6 +225,8 @@ public:
// Returns true is this object and all of its children can be moved
virtual bool isMovable();
bool isFavorite() const { return mIsFavorite; }
// destroys this item recursively
virtual void destroyView();
@ -308,6 +317,7 @@ public:
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow();
void drawFavoriteIcon();
void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor);
void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
@ -326,6 +336,8 @@ private:
static S32 sTopPad;
static LLUIImagePtr sFolderArrowImg;
static LLUIImagePtr sSelectionImg;
static LLUIImagePtr sFavoriteImg;
static LLUIImagePtr sFavoriteContentImg;
static LLFontGL* sSuffixFont;
LLFontVertexBuffer mLabelFontBuffer;
@ -415,6 +427,18 @@ public:
// Returns true is this object and all of its children can be moved
virtual bool isMovable();
bool isFavorite() const { return mIsFavorite; }
bool hasFavorites() const { return mHasFavorites; }
void setHasFavorites(bool val) { mHasFavorites = val; }
void updateHasFavorites(bool new_childs_value);
private:
static void onIdleUpdateFavorites(void* data);
constexpr static S32 FAVORITE_ADDED = 1;
constexpr static S32 FAVORITE_REMOVED = 2;
S32 mFavoritesDirtyFlags { 0 };
public:
// destroys this folder, and all children
virtual void destroyView();
void destroyRoot();

View File

@ -163,6 +163,7 @@ public:
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0;
virtual bool isFavorite() const = 0;
virtual bool isItemWearable() const { return false; }
virtual bool isItemRenameable() const = 0;
@ -172,6 +173,7 @@ public:
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
virtual bool isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed
virtual bool isItemInTrash(void) const = 0;
virtual bool removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;
@ -184,6 +186,9 @@ public:
virtual void pasteFromClipboard() = 0;
virtual void pasteLinkFromClipboard() = 0;
virtual bool isAgentInventory() const = 0;
virtual bool isAgentInventoryRoot() const = 0;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet?

View File

@ -46,6 +46,7 @@
#include "llfocusmgr.h"
#include "llcoord.h"
#include "llwindow.h"
#include "llemojihelper.h"
#include "llcriticaldamp.h"
#include "lluictrlfactory.h"
@ -1432,6 +1433,7 @@ void LLMenuItemBranchDownGL::openMenu( void )
}
else
{
LLEmojiHelper::instance().hideHelper(nullptr, true);
if (branch->getTornOff())
{
LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent());

View File

@ -28,6 +28,7 @@
#include "llmodaldialog.h"
#include "llemojihelper.h"
#include "llfocusmgr.h"
#include "v4color.h"
#include "v2math.h"
@ -35,6 +36,7 @@
#include "llwindow.h"
#include "llkeyboard.h"
#include "llmenugl.h"
// static
std::list<LLModalDialog*> LLModalDialog::sModalStack;
@ -98,7 +100,7 @@ void LLModalDialog::onOpen(const LLSD& key)
{
if (mModal)
{
// If Modal, Hide the active modal dialog
// If Modal, hide the active modal dialog
if (!sModalStack.empty())
{
LLModalDialog* front = sModalStack.front();
@ -155,6 +157,12 @@ void LLModalDialog::setVisible( bool visible )
{
if( visible )
{
// Hide all menus currently shown
LLMenuGL::sMenuContainer->hideMenus();
// Hide EmojiPicker if it is shown
LLEmojiHelper::instance().hideHelper(nullptr, true);
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( this );
@ -301,7 +309,6 @@ void LLModalDialog::centerOnScreen()
centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY])));
}
// static
void LLModalDialog::onAppFocusLost()
{
@ -333,6 +340,7 @@ void LLModalDialog::onAppFocusGained()
}
}
// static
void LLModalDialog::shutdownModals()
{
// This method is only for use during app shutdown. ~LLModalDialog()

View File

@ -274,6 +274,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mEnableTooltipPaste(p.enable_tooltip_paste),
mPassDelete(false),
mKeepSelectionOnReturn(false),
mSelectAllOnFocusReceived(false),
mSelectedOnFocusReceived(false),
mEnableTabRemove(p.enable_tab_remove) // <FS:Ansariel> FIRE-15591: Optional tab remove
{
mSourceID.generate();
@ -448,6 +450,7 @@ void LLTextEditor::selectNext(const std::string& search_text_in, bool case_insen
// [/SL:KB]
mIsSelecting = true;
mSelectedOnFocusReceived = false;
mSelectionEnd = mCursorPos;
mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size()));
}
@ -739,6 +742,13 @@ bool LLTextEditor::canSelectAll() const
return true;
}
//virtual
void LLTextEditor::deselect()
{
LLTextBase::deselect();
mSelectedOnFocusReceived = false;
}
// virtual
void LLTextEditor::selectAll()
{
@ -757,6 +767,11 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p
endSelection();
}
void LLTextEditor::setSelectAllOnFocusReceived(bool b)
{
mSelectAllOnFocusReceived = b;
}
void LLTextEditor::insertEmoji(llwchar emoji)
{
static LLUICachedControl<bool> useBWEmojis( "FSUseBWEmojis", false); // <FS:Beq/> Add B&W emoji font support
@ -835,8 +850,16 @@ bool LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
// Delay cursor flashing
resetCursorBlink();
mSelectedOnFocusReceived = false;
if (handled && !gFocusMgr.getMouseCapture())
{
if (!mask && mSelectAllOnFocusReceived)
{
mIsSelecting = false;
mSelectionStart = getLength();
mSelectionEnd = 0;
mSelectedOnFocusReceived = true;
}
gFocusMgr.setMouseCapture( this );
}
return handled;
@ -2334,6 +2357,11 @@ void LLTextEditor::focusLostHelper()
gEditMenuHandler = NULL;
}
if (mSelectedOnFocusReceived)
{
deselect();
}
if (mCommitOnFocusLost)
{
onCommit();

View File

@ -143,8 +143,10 @@ public:
virtual bool canDoDelete() const;
virtual void selectAll();
virtual bool canSelectAll() const;
virtual void deselect();
void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos);
void setSelectAllOnFocusReceived(bool b);
virtual bool canLoadOrSaveToFile();
@ -353,6 +355,8 @@ private:
bool mEnableTooltipPaste;
bool mPassDelete;
bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter
bool mSelectAllOnFocusReceived;
bool mSelectedOnFocusReceived;
bool mEnableTabRemove; // <FS:Ansariel> FIRE-15591: Optional tab remove
LLUUID mSourceID;

View File

@ -350,10 +350,14 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
LLWindowWin32Thread();
void run() override;
void close() override;
// closes queue, wakes thread, waits until thread closes
void wakeAndDestroy();
// Detroys handles and window
// Either post to or call from window thread
void destroyWindow();
// Closes queue, wakes thread, waits until thread closes.
// Call from main thread
bool wakeAndDestroy();
void glReady()
{
@ -410,6 +414,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
bool mGLReady = false;
bool mGotGLBuffer = false;
LLAtomicBool mDeleteOnExit = false;
};
@ -863,6 +868,7 @@ LLWindowWin32::~LLWindowWin32()
}
delete mDragDrop;
mDragDrop = NULL;
delete [] mWindowTitle;
mWindowTitle = NULL;
@ -874,6 +880,7 @@ LLWindowWin32::~LLWindowWin32()
mWindowClassName = NULL;
delete mWindowThread;
mWindowThread = NULL;
}
void LLWindowWin32::show()
@ -992,7 +999,11 @@ void LLWindowWin32::close()
mhDC = NULL;
mWindowHandle = NULL;
mWindowThread->wakeAndDestroy();
if (mWindowThread->wakeAndDestroy())
{
// thread will delete itselfs once done
mWindowThread = NULL;
}
}
bool LLWindowWin32::isValid()
@ -1533,10 +1544,10 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
LL_INFOS("Window") << "pixel formats done." << LL_ENDL ;
S32 swap_method = 0;
S32 swap_method = 0;
S32 cur_format = 0;
const S32 max_format = (S32)num_formats - 1;
GLint swap_query = WGL_SWAP_METHOD_ARB;
GLint swap_query = WGL_SWAP_METHOD_ARB;
// SL-14705 Fix name tags showing in front of objects with AMD GPUs.
// On AMD hardware we need to iterate from the first pixel format to the end.
@ -1759,6 +1770,7 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
// important to call DestroyWindow() from the window thread
if (!destroy_window_handler(oldWindowHandle))
{
LL_WARNS("Window") << "Failed to properly close window before recreating it!"
<< LL_ENDL;
}
@ -3209,10 +3221,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
break;
}
}
else
else // (NULL == window_imp)
{
// (NULL == window_imp)
LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL;
if (u_msg == WM_DESTROY)
{
PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0
return 0;
}
}
// pass unhandled messages down to Windows
@ -4742,25 +4758,11 @@ void LLWindowWin32::getWindowChrome( U32 &aChromeW, U32 &aChromeH )
#endif // LL_WINDOWS
inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
: LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/)
: LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false)
{
LL::ThreadPool::start();
}
void LLWindowWin32::LLWindowWin32Thread::close()
{
if (!mQueue->isClosed())
{
LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL;
LL::ThreadPool::close();
// Workaround for SL-18721 in case window closes too early and abruptly
LLSplashScreen::show();
LLSplashScreen::update("..."); // will be updated later
}
}
/**
* LogChange is to log changes in status while trying to avoid spamming the
* log with repeated messages, especially in a tight loop. It refuses to log
@ -4917,6 +4919,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
{
sWindowThreadId = std::this_thread::get_id();
LogChange logger("Window");
//as good a place as any to up the MM timer resolution (see ms_sleep)
//attempt to set timer resolution to 1ms
TIMECAPS tc;
@ -4954,6 +4957,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
", ", msg.wParam, ")");
TranslateMessage(&msg);
DispatchMessage(&msg);
mMessageQueue.pushFront(msg);
}
}
@ -4973,108 +4977,105 @@ void LLWindowWin32::LLWindowWin32Thread::run()
}
#endif
}
destroyWindow();
if (mDeleteOnExit)
{
delete this;
}
}
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
void LLWindowWin32::LLWindowWin32Thread::destroyWindow()
{
if (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd))
{
if (mhDCThrd)
{
if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
{
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
}
mhDCThrd = NULL;
}
// This causes WM_DESTROY to be sent *immediately*
if (!destroy_window_handler(mWindowHandleThrd))
{
LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
}
}
else
{
// Something killed the window while we were busy destroying gl or handle somehow got broken
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
}
mWindowHandleThrd = NULL;
mhDCThrd = NULL;
}
bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{
if (mQueue->isClosed())
{
LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
return;
return false;
}
// Make sure we don't leave a blank toolbar button.
// Also hiding window now prevents user from suspending it
// via some action (like dragging it around)
ShowWindow(mWindowHandleThrd, SW_HIDE);
// Hide the window immediately to prevent user interaction during shutdown
if (mWindowHandleThrd)
{
ShowWindow(mWindowHandleThrd, SW_HIDE);
}
// Schedule destruction
mGLReady = false;
// Capture current handle before we lose it
HWND old_handle = mWindowHandleThrd;
post([this]()
{
if (IsWindow(mWindowHandleThrd))
{
if (mhDCThrd)
{
if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
{
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
}
mhDCThrd = NULL;
}
// This causes WM_DESTROY to be sent *immediately*
if (!destroy_window_handler(mWindowHandleThrd))
{
LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
}
}
else
{
// Something killed the window while we were busy destroying gl or handle somehow got broken
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
}
mWindowHandleThrd = NULL;
mhDCThrd = NULL;
mGLReady = false;
});
// Clear the user data to prevent callbacks from finding us
if (old_handle)
{
SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL);
}
// Signal thread to clean up when done
mDeleteOnExit = true;
// Close the queue first
LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
mQueue->close();
// Post a nonsense user message to wake up the thread in
// case it is waiting for a getMessage()
// Wake up the thread if it's stuck in GetMessage()
if (old_handle)
{
WPARAM wparam{ 0xB0B0 };
LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
<< ", " << WM_DUMMY_
<< ", " << wparam << ")" << std::dec << LL_ENDL;
// Use PostMessage to signal thread to wake up
PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
}
// There are cases where window will refuse to close,
// can't wait forever on join, check state instead
LLTimer timeout;
timeout.setTimerExpirySec(2.0);
while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
// Cleanly detach threads instead of joining them to avoid blocking the main thread
// This is acceptable since the thread will self-delete with mDeleteOnExit
for (auto& pair : mThreads)
{
ms_sleep(100);
try {
// Only detach if the thread is joinable
if (pair.second.joinable())
{
pair.second.detach();
}
}
catch (const std::system_error& e) {
LL_WARNS("Window") << "Exception detaching thread: " << e.what() << LL_ENDL;
}
}
if (getQueue().done() || mWindowHandleThrd == NULL)
{
// Window is closed, started closing or is cleaning up
// now wait for our single thread to die.
if (mWindowHandleThrd)
{
LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
}
else
{
LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
}
for (auto& pair : mThreads)
{
pair.second.join();
}
}
else
{
// Something suspended window thread, can't afford to wait forever
// so kill thread instead
// Ex: This can happen if user starts dragging window arround (if it
// was visible) or a modal notification pops up
LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
for (auto& pair : mThreads)
{
// very unsafe
TerminateThread(pair.second.native_handle(), 0);
pair.second.detach();
}
}
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
return true;
}
void LLWindowWin32::post(const std::function<void()>& func)

View File

@ -458,6 +458,7 @@ set(viewer_SOURCE_FILES
llhudeffectpointat.cpp
llhudeffecttrail.cpp
llhudeffectblob.cpp
llhudeffectresetskeleton.cpp
llhudicon.cpp
llhudmanager.cpp
llhudnametag.cpp
@ -1278,6 +1279,7 @@ set(viewer_HEADER_FILES
llhudeffectpointat.h
llhudeffecttrail.h
llhudeffectblob.h
llhudeffectresetskeleton.h
llhudicon.h
llhudmanager.h
llhudnametag.h

View File

@ -3630,6 +3630,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>DebugSelectionLODs</key>
<map>
<key>Comment</key>
<string>Force selection to show specific LOD, -1 for off, 0 - lowest, 4 - high.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>AnimatedObjectsAllowLeftClick</key>
<map>
<key>Comment</key>
@ -18557,10 +18568,32 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>OutfitGallerySortByName</key>
<key>OutfitGallerySortOrder</key>
<map>
<key>Comment</key>
<string>Always sort outfits by name in Outfit Gallery</string>
<string>Gallery sorting: 0 - sort outfits by name, 1 - images frst, 2 - favorites first</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>OutfitListSortOrder</key>
<map>
<key>Comment</key>
<string>How outfit list in Avatar's floater is sorted. 0 - by name 1 - favorites to top</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>OutfitListFilterFullList</key>
<map>
<key>Comment</key>
<string> 0 - show only matches. 1 - show all items in outfit as long as outfit or item inside matches.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -23246,6 +23279,50 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>InventoryFavoritesUseStar</key>
<map>
<key>Comment</key>
<string>Show star near favorited items in inventory</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>InventoryFavoritesUseHollowStar</key>
<map>
<key>Comment</key>
<string>Show star near folders that contain favorites</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>InventoryFavoritesColorText</key>
<map>
<key>Comment</key>
<string>render favorite items using InventoryFavoriteText as color</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>InventoryAddAttachmentBehavior</key>
<map>
<key>Comment</key>
<string>Defines behavior when hitting return on an inventory item</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>StatsReportMaxDuration</key>
<map>
<key>Comment</key>

View File

@ -602,7 +602,7 @@
<key>KeepConversationLogTranscripts</key>
<map>
<key>Comment</key>
<string>Keep a conversation log and transcripts</string>
<string>Keep a conversation log and transcripts 2 - both, 1 - logs, 0 - none</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>

View File

@ -220,6 +220,7 @@ void GLTFSceneManager::uploadSelection()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
LLUUID::null,
false,
finish,
failure));
@ -283,6 +284,7 @@ void GLTFSceneManager::uploadSelection()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
LLUUID::null,
false,
finish,
failure));
@ -559,6 +561,7 @@ void GLTFSceneManager::update()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
LLUUID::null,
false,
finish,
failure));

View File

@ -140,8 +140,8 @@ const F32 MIN_FIDGET_TIME = 8.f; // seconds
const F32 MAX_FIDGET_TIME = 20.f; // seconds
const S32 UI_FEATURE_VERSION = 1;
// For version 1: 1 - inventory, 2 - gltf
const S32 UI_FEATURE_FLAGS = 3;
// For version 1, flag holds: 1 - inventory thumbnails, 2 - gltf, 4 - inventory favorites
const S32 UI_FEATURE_FLAGS = 7;
// The agent instance.
LLAgent gAgent;
@ -242,7 +242,6 @@ private:
LLVector3d mPosGlobal;
};
class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation
{
public:
@ -690,7 +689,7 @@ void LLAgent::getFeatureVersionAndFlags(S32& version, S32& flags)
if (feature_version.isInteger())
{
version = feature_version.asInteger();
flags = 1; // inventory flag
flags = 3; // show 'favorites' notification
}
else if (feature_version.isMap())
{
@ -716,13 +715,8 @@ void LLAgent::showLatestFeatureNotification(const std::string key)
if (key == "inventory")
{
// Notify user about new thumbnail support
flag = 1;
}
if (key == "gltf")
{
flag = 2;
// Notify user about new favorites support
flag = 4;
}
if ((flags & flag) == 0)
@ -962,7 +956,6 @@ void LLAgent::movePitch(F32 mag)
}
}
// Does this parcel allow you to fly?
bool LLAgent::canFly()
{
@ -1061,7 +1054,6 @@ void LLAgent::setFlying(bool fly, bool fail_sound)
LLFloaterMove::setFlyingMode(fly);
}
// UI based mechanism of setting fly state
//-----------------------------------------------------------------------------
// toggleFlying()
@ -1309,7 +1301,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
mRegionChangedSignal();
}
//-----------------------------------------------------------------------------
// getRegion()
//-----------------------------------------------------------------------------
@ -1318,7 +1309,6 @@ LLViewerRegion *LLAgent::getRegion() const
return mRegionp;
}
LLHost LLAgent::getRegionHost() const
{
if (mRegionp)
@ -1349,7 +1339,6 @@ bool LLAgent::inPrelude()
return mRegionp && mRegionp->isPrelude();
}
std::string LLAgent::getRegionCapability(const std::string &name)
{
if (!mRegionp)
@ -1358,7 +1347,6 @@ std::string LLAgent::getRegionCapability(const std::string &name)
return mRegionp->getCapability(name);
}
//-----------------------------------------------------------------------------
// canManageEstate()
//-----------------------------------------------------------------------------
@ -1386,7 +1374,6 @@ void LLAgent::sendMessage()
gMessageSystem->sendMessage(mRegionp->getHost());
}
//-----------------------------------------------------------------------------
// sendReliableMessage()
//-----------------------------------------------------------------------------
@ -1420,7 +1407,6 @@ LLVector3 LLAgent::getVelocity() const
}
}
//-----------------------------------------------------------------------------
// setPositionAgent()
//-----------------------------------------------------------------------------
@ -1494,7 +1480,6 @@ const LLVector3 &LLAgent::getPositionAgent()
}
}
return mFrameAgent.getOrigin();
}
@ -1503,7 +1488,6 @@ boost::signals2::connection LLAgent::whenPositionChanged(position_signal_t::slot
return mOnPositionChanged.connect(fn);
}
//-----------------------------------------------------------------------------
// getRegionsVisited()
//-----------------------------------------------------------------------------
@ -1520,7 +1504,6 @@ F64 LLAgent::getDistanceTraveled() const
return mDistanceTraveled;
}
//-----------------------------------------------------------------------------
// getPosAgentFromGlobal()
//-----------------------------------------------------------------------------
@ -1531,7 +1514,6 @@ LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
return pos_agent;
}
//-----------------------------------------------------------------------------
// getPosGlobalFromAgent()
//-----------------------------------------------------------------------------
@ -1552,7 +1534,6 @@ void LLAgent::sitDown()
setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
}
//-----------------------------------------------------------------------------
// resetAxes()
//-----------------------------------------------------------------------------
@ -1561,7 +1542,6 @@ void LLAgent::resetAxes()
mFrameAgent.resetAxes();
}
// Copied from LLCamera::setOriginAndLookAt
// Look_at must be unit vector
//-----------------------------------------------------------------------------
@ -1590,7 +1570,6 @@ void LLAgent::resetAxes(const LLVector3 &look_at)
mFrameAgent.setAxes(look_at, left, up);
}
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@ -1599,7 +1578,6 @@ void LLAgent::rotate(F32 angle, const LLVector3 &axis)
mFrameAgent.rotate(angle, axis);
}
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@ -1608,7 +1586,6 @@ void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z)
mFrameAgent.rotate(angle, x, y, z);
}
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@ -1617,7 +1594,6 @@ void LLAgent::rotate(const LLMatrix3 &matrix)
mFrameAgent.rotate(matrix);
}
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@ -1626,7 +1602,6 @@ void LLAgent::rotate(const LLQuaternion &quaternion)
mFrameAgent.rotate(quaternion);
}
//-----------------------------------------------------------------------------
// getReferenceUpVector()
//-----------------------------------------------------------------------------
@ -1655,7 +1630,6 @@ LLVector3 LLAgent::getReferenceUpVector()
return up_vector;
}
// Radians, positive is forward into ground
//-----------------------------------------------------------------------------
// pitch()
@ -1699,7 +1673,6 @@ void LLAgent::pitch(F32 angle)
}
}
//-----------------------------------------------------------------------------
// roll()
//-----------------------------------------------------------------------------
@ -1708,7 +1681,6 @@ void LLAgent::roll(F32 angle)
mFrameAgent.roll(angle);
}
//-----------------------------------------------------------------------------
// yaw()
//-----------------------------------------------------------------------------
@ -1720,7 +1692,6 @@ void LLAgent::yaw(F32 angle)
}
}
// Returns a quat that represents the rotation of the agent in the absolute frame
//-----------------------------------------------------------------------------
// getQuat()
@ -1756,7 +1727,6 @@ void LLAgent::setControlFlags(U32 mask)
mControlFlags |= mask;
}
//-----------------------------------------------------------------------------
// clearControlFlags()
//-----------------------------------------------------------------------------
@ -2179,7 +2149,6 @@ void LLAgent::startAutoPilotGlobal(
mAutoPilotNoProgressFrameCount = 0;
}
//-----------------------------------------------------------------------------
// setAutoPilotTargetGlobal
//-----------------------------------------------------------------------------
@ -2233,7 +2202,6 @@ void LLAgent::startFollowPilot(const LLUUID &leader_id, bool allow_flying, F32 s
allow_flying);
}
//-----------------------------------------------------------------------------
// stopAutoPilot()
//-----------------------------------------------------------------------------
@ -2275,7 +2243,6 @@ void LLAgent::stopAutoPilot(bool user_cancel)
}
}
// Returns necessary agent pitch and yaw changes, radians.
//-----------------------------------------------------------------------------
// autoPilot()
@ -2464,7 +2431,6 @@ void LLAgent::autoPilot(F32 *delta_yaw)
}
}
//-----------------------------------------------------------------------------
// propagate()
//-----------------------------------------------------------------------------
@ -2485,18 +2451,19 @@ void LLAgent::propagate(const F32 dt)
}
// handle rotation based on keyboard levels
constexpr F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
F32 angle = YAW_RATE * gAgentCamera.getYawKey() * dt;
if (fabs(angle) > 0.0f)
if (fabs(dt) > 1e-6)
{
yaw(angle);
}
if (fabs(gAgentCamera.getYawKey()) > 1e-6)
{
static const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
yaw(YAW_RATE * gAgentCamera.getYawKey() * dt);
}
constexpr F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
angle = PITCH_RATE * gAgentCamera.getPitchKey() * dt;
if (fabs(angle) > 0.0f)
{
pitch(angle);
if (fabs(gAgentCamera.getPitchKey()) > 1e-6)
{
static const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
pitch(PITCH_RATE * gAgentCamera.getPitchKey() * dt);
}
}
// handle auto-land behavior
@ -2677,7 +2644,6 @@ void LLAgent::clearRenderState(U8 clearstate)
mRenderState &= ~clearstate;
}
//-----------------------------------------------------------------------------
// getRenderState()
//-----------------------------------------------------------------------------
@ -2719,6 +2685,7 @@ void LLAgent::endAnimationUpdateUI()
{
return;
}
if (gAgentCamera.getCameraMode() == gAgentCamera.getLastCameraMode())
{
// We're already done endAnimationUpdateUI for this transition.
@ -2835,7 +2802,6 @@ void LLAgent::endAnimationUpdateUI()
}
// </FS:PP>
gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
if( gMorphView )
{
@ -3557,7 +3523,6 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
}
}
void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity)
{
U8 maturity = SIM_ACCESS_MIN;
@ -3633,7 +3598,6 @@ void LLAgent::changeInterestListMode(const std::string &new_mode)
}
}
bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure)
{
if (getRegion())
@ -3988,7 +3952,6 @@ void LLAgent::sendAnimationStateReset()
sendReliableMessage();
}
// Send a message to the region to revoke sepecified permissions on ALL scripts in the region
// If the target is an object in the region, permissions in scripts on that object are cleared.
// If it is the region ID, all scripts clear the permissions for this agent
@ -5104,7 +5067,6 @@ void LLAgent::onCapabilitiesReceivedAfterTeleport()
check_merchant_status();
}
//void LLAgent::teleportRequest(
// const U64& region_handle,
// const LLVector3& pos_local,
@ -5244,7 +5206,6 @@ void LLAgent::doTeleportViaLure(const LLUUID& lure_id, bool godlike)
}
}
// James Cook, July 28, 2005
void LLAgent::teleportCancel()
{
@ -5555,7 +5516,6 @@ LLAgent::ETeleportState LLAgent::getTeleportState() const
// teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt());
//}
void LLAgent::setTeleportState(ETeleportState state)
{
if (mTeleportRequest && (state != TELEPORT_NONE) && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed))
@ -5751,7 +5711,6 @@ void LLAgent::stopFidget()
gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
}
void LLAgent::requestEnterGodMode()
{
LLMessageSystem* msg = gMessageSystem;
@ -5887,7 +5846,6 @@ void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& dire
}
}
// <FS:Ansariel> Keep this for OpenSim
//void LLAgent::updateAgentUserInfoCoro(std::string capurl, std::string directory_visibility)
void LLAgent::updateAgentUserInfoCoro(std::string capurl, bool im_via_email, std::string directory_visibility)

View File

@ -1592,13 +1592,12 @@ void LLAgentCamera::updateCamera()
// LL_INFOS() << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << LL_ENDL;
LLVector3 focus_agent = gAgent.getPosAgentFromGlobal(mFocusGlobal);
LLVector3 position_agent = gAgent.getPosAgentFromGlobal(camera_pos_global);
mCameraPositionAgent = gAgent.getPosAgentFromGlobal(camera_pos_global);
// Try to move the camera
// Move the camera
LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
//LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
if (!LLViewerCamera::getInstance()->updateCameraLocation(position_agent, mCameraUpVector, focus_agent))
return;
// Change FOV
LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
@ -1606,7 +1605,7 @@ void LLAgentCamera::updateCamera()
// follow camera when in customize mode
if (cameraCustomizeAvatar())
{
setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
setLookAt(LOOKAT_TARGET_FOCUS, NULL, position_agent);
}
// update the travel distance stat
@ -1625,8 +1624,8 @@ void LLAgentCamera::updateCamera()
LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() +
LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() +
LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation();
LLVector3 diff = mCameraPositionAgent - head_pos;
diff = diff * ~gAgentAvatarp->mRoot->getWorldRotation();
LLVector3 diff = position_agent - head_pos;
diff *= ~gAgentAvatarp->mRoot->getWorldRotation();
LLJoint* torso_joint = gAgentAvatarp->mTorsop;
LLJoint* chest_joint = gAgentAvatarp->mChestp;
@ -2580,7 +2579,8 @@ void LLAgentCamera::changeCameraToFollow(bool animate)
AOEngine::getInstance()->inMouselook(false);
// bang-in the current focus, position, and up vector of the follow cam
mFollowCam.reset(mCameraPositionAgent, LLViewerCamera::getInstance()->getPointOfInterest(), LLVector3::z_axis);
const LLViewerCamera& camera = LLViewerCamera::instance();
mFollowCam.reset(camera.getOrigin(), camera.getPointOfInterest(), LLVector3::z_axis);
if (gBasicToolset)
{

View File

@ -121,11 +121,8 @@ private:
// Preset
//--------------------------------------------------------------------
public:
// [RLVa:KB] - @setcam family
/** Determines default camera offset scale depending on the current camera preset */
ECameraPreset getCameraPreset() const { return mCameraPreset; }
// [/RLVa:KB]
void switchCameraPreset(ECameraPreset preset);
ECameraPreset getCameraPreset() const { return mCameraPreset; }
/** Determines default camera offset depending on the current camera preset */
LLVector3 getCameraOffsetInitial();
// [RLVa:KB] - @setcam_eyeoffsetscale
@ -177,8 +174,9 @@ public:
F32 getCameraMinOffGround(); // Minimum height off ground for this mode, meters
void setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; }
bool calcCameraMinDistance(F32 &obj_min_distance);
F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); }
F32 getCurrentCameraBuildOffset() const { return (F32)mCameraFocusOffset.length(); }
void clearCameraLag() { mCameraLag.clearVec(); }
const LLVector3& getCameraUpVector() const { return mCameraUpVector; }
private:
LLVector3 getAvatarRootPosition();
@ -188,7 +186,6 @@ private:
F32 mCameraCurrentFOVZoomFactor; // Interpolated fov zoom
LLVector4 mCameraCollidePlane; // Colliding plane for camera
F32 mCameraZoomFraction; // Mousewheel driven fraction of zoom
LLVector3 mCameraPositionAgent; // Camera position in agent coordinates
LLVector3 mCameraVirtualPositionAgent; // Camera virtual position (target) before performing FOV zoom
LLVector3d mCameraSmoothingLastPositionGlobal;
LLVector3d mCameraSmoothingLastPositionAgent;
@ -320,7 +317,7 @@ public:
F32 getAgentHUDTargetZoom();
void resetCameraZoomFraction();
F32 getCurrentCameraZoomFraction() { return mCameraZoomFraction; }
F32 getCurrentCameraZoomFraction() const { return mCameraZoomFraction; }
//--------------------------------------------------------------------
// Pan

View File

@ -322,9 +322,7 @@ void LLAgentPilot::moveCamera()
LLViewerCamera::getInstance()->setView(view);
LLViewerCamera::getInstance()->setOrigin(origin);
LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
LLViewerCamera::getInstance()->setAxes(mat);
}
}

View File

@ -844,7 +844,7 @@ void AISAPI::onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD&
if ( (type == UPDATECATEGORY || type == UPDATEITEM)
&& gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
dump_sequential_xml(gAgentAvatarp->getDebugName() + "_ais_update", update);
}
AISUpdate ais_update(update, type, request_body);

View File

@ -2116,7 +2116,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
}
// Moved from LLWearableList::ContextMenu for wider utility.
bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const
bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch) const
{
// TODO: investigate wearables may not be loaded at this point EXT-8231
@ -2146,7 +2146,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const
}
else
{
if (warn_on_type_mismatch)
{
LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
}
return false;
}
}
@ -2428,7 +2431,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new,
}
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents);
dump_sequential_xml(gAgentAvatarp->getDebugName() + "_slam_request", contents);
}
slam_inventory_folder(getCOF(), contents, link_waiter);
@ -4272,7 +4275,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result);
dump_sequential_xml(gAgentAvatarp->getDebugName() + "_appearance_request_ok", result);
}
} while (bRetry);
@ -4380,7 +4383,7 @@ void LLAppearanceMgr::syncCofVersionAndRefreshCoro()
/*static*/
void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content)
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
dump_sequential_xml(gAgentAvatarp->getDebugName() + "_appearance_request_error", content);
LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
<< " ================================= " << LL_ENDL;

View File

@ -107,7 +107,7 @@ public:
bool getCanReplaceCOF(const LLUUID& outfit_cat_id);
// Can we add all referenced items to the avatar?
bool canAddWearables(const uuid_vec_t& item_ids) const;
bool canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch = true) const;
// Copy all items in a category.
void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,

View File

@ -504,6 +504,12 @@ static bool app_metrics_qa_mode = false;
void idle_afk_check()
{
// Don't check AFK status during startup states
if (LLStartUp::getStartupState() < STATE_STARTED)
{
return;
}
// check idle timers
F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32();
// <FS:CR> Cache frequently hit location
@ -514,11 +520,20 @@ void idle_afk_check()
// [/RLVa:KB]
// static LLCachedControl<S32> afk_timeout(gSavedSettings, "AFKTimeout", 300);
// <FS:CR> Explicit conversions just cos.
//if (afk_timeout() && (current_idle > (F32)afk_timeout()) && !gAgent.getAFK())
if (static_cast<S32>(afk_timeout) && (current_idle > static_cast<F32>(afk_timeout)) && ! gAgent.getAFK())
//if (afk_timeout() && (current_idle > afk_timeout()) && !gAgent.getAFK())
if (static_cast<S32>(afk_timeout) && (current_idle > static_cast<F32>(afk_timeout)))
{
LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
gAgent.setAFK();
if (!gAgent.getAFK())
{
LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
gAgent.setAFK();
}
else
{
// Refresh timer so that random one click or hover won't clear the status.
// But expanding the window still should lift afk status
gAwayTimer.reset();
}
}
}
@ -2181,36 +2196,6 @@ bool LLAppViewer::cleanup()
// Clean up before GL is shut down because we might be holding on to objects with texture references
LLSelectMgr::cleanupGlobals();
LL_INFOS() << "Shutting down OpenGL" << LL_ENDL;
// Shut down OpenGL
if( gViewerWindow)
{
gViewerWindow->shutdownGL();
// Destroy window, and make sure we're not fullscreen
// This may generate window reshape and activation events.
// Therefore must do this before destroying the message system.
delete gViewerWindow;
gViewerWindow = NULL;
LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
}
LLSplashScreen::show();
LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL;
// viewer UI relies on keyboard so keep it aound until viewer UI isa gone
delete gKeyboard;
gKeyboard = NULL;
if (LLViewerJoystick::instanceExists())
{
// Turn off Space Navigator and similar devices
LLViewerJoystick::getInstance()->terminate();
}
LL_INFOS() << "Cleaning up Objects" << LL_ENDL;
LLViewerObject::cleanupVOClasses();
@ -2409,6 +2394,36 @@ bool LLAppViewer::cleanup()
sTextureFetch->shutDownTextureCacheThread() ;
LLLFSThread::sLocal->shutdown();
LL_INFOS() << "Shutting down OpenGL" << LL_ENDL;
// Shut down OpenGL
if (gViewerWindow)
{
gViewerWindow->shutdownGL();
// Destroy window, and make sure we're not fullscreen
// This may generate window reshape and activation events.
// Therefore must do this before destroying the message system.
delete gViewerWindow;
gViewerWindow = NULL;
LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
}
LLSplashScreen::show();
LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL;
// viewer UI relies on keyboard so keep it aound until viewer UI isa gone
delete gKeyboard;
gKeyboard = NULL;
if (LLViewerJoystick::instanceExists())
{
// Turn off Space Navigator and similar devices
LLViewerJoystick::getInstance()->terminate();
}
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();

View File

@ -537,11 +537,12 @@ LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::replaceList(const LL
S32 search_index;
LLSD targetList;
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
for ( search_index = 0, targetList = mLists[0];
for ( search_index = 0;
!listFound && search_index < mLists.size();
search_index += 1, targetList = mLists[search_index]
search_index += 1
)
{
targetList = mLists[search_index];
if ( targetList.isMap() )
{
if ( listNameMatches( targetList, listName) )

View File

@ -101,6 +101,12 @@ LLVOAvatar *LLControlAvatar::getAttachedAvatar()
void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const
{
static LLCachedControl<F32> anim_max_legal_offset(gSavedSettings, "AnimatedObjectsMaxLegalOffset", MAX_LEGAL_OFFSET);
F32 max_legal_offset = llmax(anim_max_legal_offset(), 0.f);
static LLCachedControl<F32> anim_max_legal_size(gSavedSettings, "AnimatedObjectsMaxLegalSize", MAX_LEGAL_SIZE);
F32 max_legal_size = llmax(anim_max_legal_size(), 1.f);
new_pos_fixup = LLVector3();
new_scale_fixup = 1.0f;
LLVector3 vol_pos = mRootVolp->getRenderPosition();
@ -125,14 +131,14 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
{
LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents);
F32 offset_dist = pos_box_offset.length();
if (offset_dist > MAX_LEGAL_OFFSET && offset_dist > 0.f)
if (offset_dist > max_legal_offset && offset_dist > 0.f)
{
F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET);
F32 target_dist = (offset_dist - max_legal_offset);
new_pos_fixup = (target_dist/offset_dist)*pos_box_offset;
}
if (new_pos_fixup != mPositionConstraintFixup)
{
LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup "
LL_DEBUGS("ConstraintFix") << getDebugName() << " pos fix, offset_dist " << offset_dist << " pos fixup "
<< new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL;
LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL;
LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL;
@ -140,11 +146,11 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
}
}
if (box_size/mScaleConstraintFixup > MAX_LEGAL_SIZE)
if (box_size/mScaleConstraintFixup > max_legal_size)
{
new_scale_fixup = mScaleConstraintFixup* MAX_LEGAL_SIZE /box_size;
LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup "
<< mScaleConstraintFixup << " max legal " << MAX_LEGAL_SIZE
new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size;
LL_DEBUGS("ConstraintFix") << getDebugName() << " scale fix, box_size " << box_size << " fixup "
<< mScaleConstraintFixup << " max legal " << max_legal_size
<< " -> new scale " << new_scale_fixup << LL_ENDL;
}
}
@ -227,7 +233,7 @@ void LLControlAvatar::matchVolumeTransform()
const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo();
if (skin_info)
{
LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
LL_DEBUGS("BindShape") << getDebugName() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(skin_info->mBindShapeMatrix));
}
#endif

View File

@ -691,7 +691,7 @@ void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD&
{
mConversations.clear();
notifyObservers();
cache();
saveToFile(getFileName());
deleteBackupLogs();
}
}

View File

@ -82,6 +82,9 @@ public:
virtual LLPointer<LLUIImage> getOpenIcon() const { return getIcon(); }
virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
virtual bool isFavorite() const { return false; }
virtual bool isAgentInventory() const { return false; }
virtual bool isAgentInventoryRoot() const { return false; }
virtual bool isItemRenameable() const { return true; }
virtual bool renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return true; }
virtual bool isItemMovable( void ) const { return false; }

View File

@ -420,17 +420,15 @@ bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification,
{
LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
// <FS:Ansariel> FIRE-31256: Add Cancel button for new auto-replace list dialog
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option != 0)
{
return false;
}
// </FS:Ansariel>
LLSD newList = notification["payload"]["list"];
if ( response.has("listname") && response["listname"].isString() )
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option != 1) // Must also match RenameAutoReplaceList
{
// user cancelled
return false;
}
else if (response.has("listname") && response["listname"].isString() )
{
std::string newName = response["listname"].asString();
LLAutoReplaceSettings::setListName(newList, newName);
@ -516,12 +514,53 @@ bool LLFloaterAutoReplaceSettings::callbackListNameConflict(const LLSD& notifica
return false;
}
bool LLFloaterAutoReplaceSettings::callbackRemoveList(const LLSD& notification, const LLSD& response)
{
std::string listName = notification["payload"]["list"];
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
switch (option)
{
case 1:
if (mSettings.removeReplacementList(listName))
{
LL_INFOS("AutoReplace") << "deleted list '" << listName << "'" << LL_ENDL;
mReplacementsList->deleteSelectedItems(); // remove from the scrolling list
mSelectedListName.clear();
updateListNames();
updateListNamesControls();
updateReplacementsList();
}
break;
case 0:
break;
default:
LL_ERRS("AutoReplace") << "invalid selected option " << option << LL_ENDL;
}
return false;
}
void LLFloaterAutoReplaceSettings::onDeleteList()
{
std::string listName = mListNames->getSelectedValue().asString();
if ( ! listName.empty() )
{
if ( mSettings.removeReplacementList(listName) )
const LLSD* mappings = mSettings.getListEntries(mSelectedListName);
if (mappings->size() > 0)
{
LLSD payload;
payload["list"] = listName;
LLSD args;
args["MAP_SIZE"] = llformat("%d",mappings->size());
args["LIST_NAME"] = listName;
LLNotificationsUtil::add("RemoveAutoReplaceList", args, payload,
boost::bind(&LLFloaterAutoReplaceSettings::callbackRemoveList, this, _1, _2));
}
else if ( mSettings.removeReplacementList(listName) )
{
LL_INFOS("AutoReplace")<<"deleted list '"<<listName<<"'"<<LL_ENDL;
mReplacementsList->deleteSelectedItems(); // remove from the scrolling list

View File

@ -105,6 +105,8 @@ private:
bool callbackNewListName(const LLSD& notification, const LLSD& response);
/// called from the RenameAutoReplaceList notification dialog
bool callbackListNameConflict(const LLSD& notification, const LLSD& response);
/// called from the RemoveAutoReplaceList notification dialog
bool callbackRemoveList(const LLSD& notification, const LLSD& response);
bool selectedListIsFirst();
bool selectedListIsLast();

View File

@ -128,8 +128,8 @@ std::string STATUS[] =
//-----------------------------------------------------------------------------
// LLFloaterBvhPreview()
//-----------------------------------------------------------------------------
LLFloaterBvhPreview::LLFloaterBvhPreview(const std::string& filename) :
LLFloaterNameDesc(filename)
LLFloaterBvhPreview::LLFloaterBvhPreview(const LLSD& args) :
LLFloaterNameDesc(args)
{
mLastMouseX = 0;
mLastMouseY = 0;
@ -1447,7 +1447,8 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata)
LLFloaterPerms::getNextOwnerPerms("Uploads"),
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost));
expected_upload_cost,
floaterp->mDestinationFolderId));
upload_new_resource(assetUploadInfo);
}

View File

@ -77,7 +77,7 @@ class LLFloaterBvhPreview : public LLFloaterNameDesc
friend class LLPreviewAnimation;
public:
LLFloaterBvhPreview(const std::string& filename);
LLFloaterBvhPreview(const LLSD& args);
virtual ~LLFloaterBvhPreview();
bool postBuild();

View File

@ -133,7 +133,8 @@ protected:
LLSettingsEditPanel() :
LLPanel(),
mIsDirty(false),
mOnDirtyChanged()
mOnDirtyChanged(),
mCanEdit(false)
{}
private:

View File

@ -85,8 +85,8 @@ constexpr F32 ALPHA_EMPTY_THRESHOLD_RATIO = 0.999f;
//-----------------------------------------------------------------------------
// LLFloaterImagePreview()
//-----------------------------------------------------------------------------
LLFloaterImagePreview::LLFloaterImagePreview(const std::string& filename) :
LLFloaterNameDesc(filename),
LLFloaterImagePreview::LLFloaterImagePreview(const LLSD& args) :
LLFloaterNameDesc(args),
mAvatarPreview(NULL),
mSculptedPreview(NULL),

View File

@ -111,7 +111,7 @@ protected:
class LLFloaterImagePreview : public LLFloaterNameDesc
{
public:
LLFloaterImagePreview(const std::string& filename);
LLFloaterImagePreview(const LLSD& args);
virtual ~LLFloaterImagePreview();
bool postBuild() override;

View File

@ -28,9 +28,14 @@
#include "llfloaterinventorysettings.h"
#include "llcolorswatch.h"
#include "llviewercontrol.h"
LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
: LLFloater(key)
{
mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", boost::bind(&LLFloaterInventorySettings::applyUIColor, this, _1, _2));
mCommitCallbackRegistrar.add("ScriptPref.getUIColor", boost::bind(&LLFloaterInventorySettings::getUIColor, this, _1, _2));
}
LLFloaterInventorySettings::~LLFloaterInventorySettings()
@ -39,6 +44,29 @@ LLFloaterInventorySettings::~LLFloaterInventorySettings()
bool LLFloaterInventorySettings::postBuild()
{
getChild<LLButton>("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
getChild<LLUICtrl>("favorites_color")->setCommitCallback(boost::bind(&LLFloaterInventorySettings::updateColorSwatch, this));
bool enable_color = gSavedSettings.getBOOL("InventoryFavoritesColorText");
getChild<LLUICtrl>("favorites_swatch")->setEnabled(enable_color);
return true;
}
void LLFloaterInventorySettings::updateColorSwatch()
{
bool val = getChild<LLUICtrl>("favorites_color")->getValue();
getChild<LLUICtrl>("favorites_swatch")->setEnabled(val);
}
void LLFloaterInventorySettings::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
{
LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
}
void LLFloaterInventorySettings::getUIColor(LLUICtrl* ctrl, const LLSD& param)
{
LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*)ctrl;
color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString()));
}

View File

@ -40,6 +40,11 @@ public:
private:
LLFloaterInventorySettings(const LLSD& key);
~LLFloaterInventorySettings();
void updateColorSwatch();
void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
void getUIColor(LLUICtrl* ctrl, const LLSD& param);
};
#endif

View File

@ -425,14 +425,14 @@ void LLFloaterModelPreview::initModelPreview()
}
//static
bool LLFloaterModelPreview::showModelPreview()
void LLFloaterModelPreview::showModelPreview(const LLUUID& dest_folder)
{
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");
if (fmp && !fmp->isModelLoading())
{
fmp->setUploadDestination(dest_folder);
fmp->loadHighLodModel();
}
return true;
}
void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl)
@ -592,7 +592,7 @@ void LLFloaterModelPreview::onClickCalculateBtn()
gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
childGetValue("upload_textures").asBoolean(),
upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,
mUploadModelUrl, false,
mUploadModelUrl, mDestinationFolderId, false,
getWholeModelFeeObserverHandle());
toggleCalculateButton(false);
@ -1850,7 +1850,7 @@ void LLFloaterModelPreview::onUpload(void* user_data)
gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
mp->childGetValue("upload_textures").asBoolean(),
upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,
mp->mUploadModelUrl,
mp->mUploadModelUrl, mp->mDestinationFolderId,
true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle());
}
@ -1973,9 +1973,15 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
|| index == LLModelPreview::GENERATE // <FS:Beq/> Improved LOD generation
|| index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
|| index == LLModelPreview::MESH_OPTIMIZER_PRECISE)
{ //rebuild LoD to update triangle counts
{
// rebuild LoD to update triangle counts
onLODParamCommit(lod, true);
}
if (index == LLModelPreview::USE_LOD_ABOVE)
{
// refresh to pick triangle counts
mModelPreview->mDirty = true;
}
}
void LLFloaterModelPreview::resetDisplayOptions()

View File

@ -73,7 +73,8 @@ public:
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
void initModelPreview();
static bool showModelPreview();
void setUploadDestination(const LLUUID& dest_folder) { mDestinationFolderId = dest_folder; }
static void showModelPreview(const LLUUID& dest_folder = LLUUID::null);
bool handleMouseDown(S32 x, S32 y, MASK mask);
bool handleMouseUp(S32 x, S32 y, MASK mask);
@ -164,9 +165,6 @@ protected:
static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata);
static void onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata);
static void onPhysicsOptimize(LLUICtrl* ctrl, void* userdata);
static void onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata);
static void onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata);
static void onSuffixStandardSelected(LLUICtrl* ctrl, void* userdata); // <FS:Beq> mesh loader suffix configuration
static void onSelectUDPhysics(LLUICtrl* ctrl, void* userdata); // <FS:Beq/> custom setter for upload preview settings tab
@ -227,6 +225,7 @@ private:
void createSmoothComboBox(LLComboBox* combo_box, float min, float max);
LLUUID mDestinationFolderId;
LLButton* mUploadBtn;
LLButton* mCalculateBtn;
LLViewerTextEditor* mUploadLogText;

View File

@ -38,7 +38,9 @@
#include "llcheckboxctrl.h"
#include "llviewerinventory.h"
#include "llenvironment.h"
#include "llnotificationsutil.h"
#include "llparcel.h"
#include "lltrans.h"
#include "llviewerparcelmgr.h"
//=========================================================================
@ -223,16 +225,13 @@ void LLFloaterMyEnvironment::onFilterEdit(const std::string& search_string)
mInventoryList->setFilterSubString(search_string);
}
void LLFloaterMyEnvironment::onDeleteSelected()
void LLFloaterMyEnvironment::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
uuid_vec_t selected;
getSelectedIds(selected);
if (selected.empty())
return;
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
for (const LLUUID& itemid: selected)
for (const LLUUID& itemid : item_ids)
{
LLInventoryItem* inv_item = gInventory.getItem(itemid);
@ -253,6 +252,27 @@ void LLFloaterMyEnvironment::onDeleteSelected()
}
gInventory.notifyObservers();
}
}
void LLFloaterMyEnvironment::onDeleteSelected()
{
uuid_vec_t selected;
getSelectedIds(selected);
if (selected.empty())
return;
LLSD args;
args["QUESTION"] = LLTrans::getString(selected.size() > 1 ? "DeleteItems" : "DeleteItem");
LLNotificationsUtil::add(
"DeleteItems",
args,
LLSD(),
[this, selected](const LLSD& notification, const LLSD& response)
{
onItemsRemovalConfirmation(notification, response, selected);
});
}
void LLFloaterMyEnvironment::onDoCreate(const LLSD &data)
@ -318,13 +338,13 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
if (context == PARAMETER_EDIT)
{
return (selected.size() == 1) && isSettingSelected(selected.front());
return (selected.size() == 1) && isSettingId(selected.front());
}
else if (context == PARAMETER_COPY)
{
for (std::vector<LLUUID>::iterator it = selected.begin(); it != selected.end(); it++)
{
if(!isSettingSelected(*it))
if(!isSettingId(*it))
{
return false;
}
@ -342,7 +362,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
LLClipboard::instance().pasteFromClipboard(ids);
for (std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
{
if (!isSettingSelected(*it))
if (!isSettingId(*it))
{
return false;
}
@ -351,7 +371,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
}
else if (context == PARAMETER_COPYUUID)
{
return (selected.size() == 1) && isSettingSelected(selected.front());
return (selected.size() == 1) && isSettingId(selected.front());
}
return false;
@ -367,16 +387,42 @@ bool LLFloaterMyEnvironment::canApply(const std::string &context)
if (context == PARAMETER_REGION)
{
return LLEnvironment::instance().canAgentUpdateRegionEnvironment();
return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateRegionEnvironment();
}
else if (context == PARAMETER_PARCEL)
{
return LLEnvironment::instance().canAgentUpdateParcelEnvironment();
return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateParcelEnvironment();
}
else
else if (context == PARAMETER_LOCAL)
{
return (context == PARAMETER_LOCAL);
return isSettingId(selected.front());
}
return false;
}
bool can_delete(const LLUUID& id)
{
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
if (id == trash_id || gInventory.isObjectDescendentOf(id, trash_id))
{
return false;
}
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
if (cat)
{
if (!get_is_category_removable(&gInventory, id))
{
return false;
}
}
else if (!get_is_item_removable(&gInventory, id, false))
{
return false;
}
return true;
}
//-------------------------------------------------------------------------
@ -389,7 +435,14 @@ void LLFloaterMyEnvironment::refreshButtonStates()
getChild<LLUICtrl>(BUTTON_GEAR)->setEnabled(settings_ok);
getChild<LLUICtrl>(BUTTON_NEWSETTINGS)->setEnabled(true);
getChild<LLUICtrl>(BUTTON_DELETE)->setEnabled(settings_ok && !selected.empty());
bool enable_delete = false;
if(settings_ok && !selected.empty())
{
enable_delete = can_delete(selected.front());
}
getChild<LLUICtrl>(BUTTON_DELETE)->setEnabled(enable_delete);
}
//-------------------------------------------------------------------------
@ -438,7 +491,7 @@ LLUUID LLFloaterMyEnvironment::findItemByAssetId(LLUUID asset_id, bool copyable_
return LLUUID::null;
}
bool LLFloaterMyEnvironment::isSettingSelected(LLUUID item_id)
bool LLFloaterMyEnvironment::isSettingId(const LLUUID& item_id)
{
LLInventoryItem* itemp = gInventory.getItem(item_id);

View File

@ -60,6 +60,7 @@ private:
void onFilterCheckChange();
void onFilterEdit(const std::string& search_string);
void onSelectionChange();
void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids);
void onDeleteSelected();
void onDoCreate(const LLSD &data);
void onDoApply(const std::string &context);
@ -69,7 +70,7 @@ private:
void getSelectedIds(uuid_vec_t& ids) const;
void refreshButtonStates();
bool isSettingSelected(LLUUID item_id);
static bool isSettingId(const LLUUID &item_id);
static LLUUID findItemByAssetId(LLUUID asset_id, bool copyable_only, bool ignore_library);
};

View File

@ -62,11 +62,20 @@ const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
//-----------------------------------------------------------------------------
// LLFloaterNameDesc()
//-----------------------------------------------------------------------------
LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& filename )
: LLFloater(filename),
mIsAudio(false)
LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& args)
: LLFloater(args)
, mIsAudio(false)
, mIsText(false)
{
mFilenameAndPath = filename.asString();
if (args.isString())
{
mFilenameAndPath = args.asString();
}
else
{
mFilenameAndPath = args["filename"].asString();
mDestinationFolderId = args["dest"].asUUID();
}
mFilename = gDirUtilp->getBaseFileName(mFilenameAndPath, false);
}
@ -203,7 +212,8 @@ void LLFloaterNameDesc::onBtnOK( )
LLFloaterPerms::getNextOwnerPerms("Uploads"),
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost));
expected_upload_cost,
mDestinationFolderId));
upload_new_resource(uploadInfo, callback, nruserdata);
}
@ -230,8 +240,8 @@ void LLFloaterNameDesc::onBtnCancel()
// LLFloaterSoundPreview()
//-----------------------------------------------------------------------------
LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& filename )
: LLFloaterNameDesc(filename)
LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& args )
: LLFloaterNameDesc(args)
{
mIsAudio = true;
}
@ -251,8 +261,8 @@ bool LLFloaterSoundPreview::postBuild()
// LLFloaterAnimPreview()
//-----------------------------------------------------------------------------
LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& filename )
: LLFloaterNameDesc(filename)
LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& args )
: LLFloaterNameDesc(args)
{
}
@ -270,8 +280,8 @@ bool LLFloaterAnimPreview::postBuild()
// LLFloaterScriptPreview()
//-----------------------------------------------------------------------------
LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& filename )
: LLFloaterNameDesc(filename)
LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& args )
: LLFloaterNameDesc(args)
{
mIsText = true;
}

View File

@ -39,7 +39,7 @@ class LLRadioGroup;
class LLFloaterNameDesc : public LLFloater
{
public:
LLFloaterNameDesc(const LLSD& filename);
LLFloaterNameDesc(const LLSD& args);
virtual ~LLFloaterNameDesc();
bool postBuild() override;
@ -58,6 +58,7 @@ protected:
std::string mFilenameAndPath;
std::string mFilename;
LLUUID mDestinationFolderId;
};
class LLFloaterSoundPreview : public LLFloaterNameDesc

View File

@ -36,6 +36,14 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
static const std::string lod_strings[4] =
{
"lowest_lod",
"low_lod",
"medium_lod",
"high_lod",
};
// virtual
bool LLCrossParcelFunctor::apply(LLViewerObject* obj)
{
@ -75,7 +83,10 @@ LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key)
mSelectedOnLand(NULL),
mRezzedOnLand(NULL),
mRemainingCapacity(NULL),
mTotalCapacity(NULL)
mTotalCapacity(NULL),
mLodLevel(nullptr),
mTrianglesShown(nullptr),
mPixelArea(nullptr)
{
}
@ -99,6 +110,10 @@ bool LLFloaterObjectWeights::postBuild()
mRemainingCapacity = getChild<LLTextBox>("remaining_capacity");
mTotalCapacity = getChild<LLTextBox>("total_capacity");
mLodLevel = getChild<LLTextBox>("lod_level");
mTrianglesShown = getChild<LLTextBox>("triangles_shown");
mPixelArea = getChild<LLTextBox>("pixel_area");
return true;
}
@ -135,6 +150,69 @@ void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reaso
toggleWeightsLoadingIndicators(false);
}
void LLFloaterObjectWeights::draw()
{
// Normally it's a bad idea to set text and visibility inside draw
// since it can cause rect updates go to different, already drawn elements,
// but floater is very simple and these elements are supposed to be isolated
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
if (selection->isEmpty())
{
const std::string text = getString("nothing_selected");
mLodLevel->setText(text);
mTrianglesShown->setText(text);
mPixelArea->setText(text);
toggleRenderLoadingIndicators(false);
}
else
{
S32 object_lod = -1;
bool multiple_lods = false;
S32 total_tris = 0;
F32 pixel_area = 0;
for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin();
iter != selection->valid_root_end(); ++iter)
{
LLViewerObject* object = (*iter)->getObject();
S32 lod = object->getLOD();
if (object_lod < 0)
{
object_lod = lod;
}
else if (object_lod != lod)
{
multiple_lods = true;
}
if (object->isRootEdit())
{
total_tris += object->recursiveGetTriangleCount();
pixel_area += object->getPixelArea();
}
}
if (multiple_lods)
{
mLodLevel->setText(getString("multiple_lods"));
toggleRenderLoadingIndicators(false);
}
else if (object_lod < 0)
{
// nodes are waiting for data
toggleRenderLoadingIndicators(true);
}
else
{
mLodLevel->setText(getString(lod_strings[object_lod]));
toggleRenderLoadingIndicators(false);
}
mTrianglesShown->setText(llformat("%d", total_tris));
mPixelArea->setText(llformat("%d", pixel_area));
}
LLFloater::draw();
}
void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel)
{
if (!parcel || LLSelectMgr::getInstance()->getSelection()->isEmpty())
@ -252,6 +330,17 @@ void LLFloaterObjectWeights::toggleLandImpactsLoadingIndicators(bool visible)
mTotalCapacity->setVisible(!visible);
}
void LLFloaterObjectWeights::toggleRenderLoadingIndicators(bool visible)
{
childSetVisible("lod_level_loading_indicator", visible);
childSetVisible("triangles_shown_loading_indicator", visible);
childSetVisible("pixel_area_loading_indicator", visible);
mLodLevel->setVisible(!visible);
mTrianglesShown->setVisible(!visible);
mPixelArea->setVisible(!visible);
}
void LLFloaterObjectWeights::updateIfNothingSelected()
{
const std::string text = getString("nothing_selected");
@ -269,6 +358,11 @@ void LLFloaterObjectWeights::updateIfNothingSelected()
mRemainingCapacity->setText(text);
mTotalCapacity->setText(text);
mLodLevel->setText(text);
mTrianglesShown->setText(text);
mPixelArea->setText(text);
toggleWeightsLoadingIndicators(false);
toggleLandImpactsLoadingIndicators(false);
toggleRenderLoadingIndicators(false);
}

View File

@ -58,21 +58,24 @@ public:
LLFloaterObjectWeights(const LLSD& key);
~LLFloaterObjectWeights();
/*virtual*/ bool postBuild();
bool postBuild() override;
/*virtual*/ void onOpen(const LLSD& key);
void onOpen(const LLSD& key) override;
/*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost);
/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
void onWeightsUpdate(const SelectionCost& selection_cost) override;
void setErrorStatus(S32 status, const std::string& reason) override;
void draw() override;
void updateLandImpacts(const LLParcel* parcel);
void refresh();
void refresh() override;
private:
/*virtual*/ void generateTransactionID();
void generateTransactionID() override;
void toggleWeightsLoadingIndicators(bool visible);
void toggleLandImpactsLoadingIndicators(bool visible);
void toggleRenderLoadingIndicators(bool visible);
void updateIfNothingSelected();
@ -88,6 +91,10 @@ private:
LLTextBox *mRezzedOnLand;
LLTextBox *mRemainingCapacity;
LLTextBox *mTotalCapacity;
LLTextBox *mLodLevel;
LLTextBox *mTrianglesShown;
LLTextBox *mPixelArea;
};
#endif //LL_LLFLOATEROBJECTWEIGHTS_H

View File

@ -3213,7 +3213,21 @@ void LLFloaterPreference::selectChatPanel()
void LLFloaterPreference::changed()
{
if (LLConversationLog::instance().getIsLoggingEnabled())
{
getChild<LLButton>("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0);
}
else
{
// onClearLog clears list, then notifies changed() and only then clears file,
// so check presence of conversations before checking file, file will cleared later.
llstat st;
bool has_logs = LLConversationLog::instance().getConversations().size() > 0
&& LLFile::stat(LLConversationLog::instance().getFileName(), &st) == 0
&& S_ISREG(st.st_mode)
&& st.st_size > 0;
getChild<LLButton>("clear_log")->setEnabled(has_logs);
}
// set 'enable' property for 'Delete transcripts...' button
updateDeleteTranscriptsButton();

View File

@ -68,9 +68,10 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return;
LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
if (modelp->getUUID().isNull()) return;
LLFolderViewModelItemInventory* sort_modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
if (sort_modelp->getUUID().isNull()) return;
bool has_favorites = false;
for (std::list<LLFolderViewFolder*>::iterator it = folder->getFoldersBegin(), end_it = folder->getFoldersEnd();
it != end_it;
++it)
@ -79,11 +80,14 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
LLFolderViewFolder* child_folderp = *it;
sort(child_folderp);
LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
has_favorites |= child_folderp->isFavorite() || child_folderp->hasFavorites();
if (child_folderp->getFoldersCount() > 0)
{
time_t most_recent_folder_time =
static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getFoldersBegin())->getViewModelItem())->getCreationDate();
LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
LLFolderViewModelItemInventory* folderp = static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getFoldersBegin())->getViewModelItem());
time_t most_recent_folder_time = folderp->getCreationDate();
if (most_recent_folder_time > modelp->getCreationDate())
{
modelp->setCreationDate(most_recent_folder_time);
@ -91,16 +95,26 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
}
if (child_folderp->getItemsCount() > 0)
{
time_t most_recent_item_time =
static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getItemsBegin())->getViewModelItem())->getCreationDate();
LLFolderViewModelItemInventory* itemp = static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getItemsBegin())->getViewModelItem());
time_t most_recent_item_time = itemp->getCreationDate();
LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
if (most_recent_item_time > modelp->getCreationDate())
{
modelp->setCreationDate(most_recent_item_time);
}
}
}
for (std::list<LLFolderViewItem*>::const_iterator it = folder->getItemsBegin(), end_it = folder->getItemsEnd();
it != end_it && !has_favorites;
++it)
{
LLFolderViewItem* child_itemp = *it;
has_favorites |= child_itemp->isFavorite();
}
if (has_favorites)
{
folder->updateHasFavorites(true);
}
base_t::sort(folder);
}

View File

@ -48,6 +48,7 @@ public:
virtual bool isItemInTrash( void) const { return false; } // TODO: make into pure virtual.
virtual bool isItemInOutfits() const { return false; }
virtual bool isAgentInventory() const { return false; }
virtual bool isAgentInventoryRoot() const { return false; }
virtual bool isUpToDate() const = 0;
virtual void addChild(LLFolderViewModelItem* child);
virtual bool hasChildren() const = 0;

View File

@ -116,6 +116,11 @@ public:
EType getType() const { return mItemType; }
S32 getItemId() const { return mItemId; }
bool isFavorite() const override { return false; }
bool isItemInTrash() const override { return false; }
bool isAgentInventory() const override { return false; }
bool isAgentInventoryRoot() const override { return false; }
private:
LLUIImagePtr pIcon;
std::string mName;

View File

@ -0,0 +1,211 @@
/**
* @file llhudeffectresetskeleton.cpp
* @brief LLHUDEffectResetSkeleton class implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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$
*/
#include "llviewerprecompiledheaders.h"
#include "llhudeffectresetskeleton.h"
#include "llagent.h"
#include "llviewerobjectlist.h"
#include "llvoavatar.h"
#include "message.h"
// packet layout
const S32 TARGET_OBJECT = 0; // This is to allow for targetting owned animesh
const S32 RESET_ANIMATIONS = 16; //This can also be a flags if needed
const S32 PKT_SIZE = 17;
//-----------------------------------------------------------------------------
// LLHUDEffectResetSkeleton()
//-----------------------------------------------------------------------------
LLHUDEffectResetSkeleton::LLHUDEffectResetSkeleton(const U8 type) :
LLHUDEffect(type)
{
}
//-----------------------------------------------------------------------------
// ~LLHUDEffectResetSkeleton()
//-----------------------------------------------------------------------------
LLHUDEffectResetSkeleton::~LLHUDEffectResetSkeleton()
{
}
//-----------------------------------------------------------------------------
// packData()
//-----------------------------------------------------------------------------
void LLHUDEffectResetSkeleton::packData(LLMessageSystem *mesgsys)
{
// Pack the default data
LLHUDEffect::packData(mesgsys);
// Pack the type-specific data. Uses a fun packed binary format. Whee!
U8 packed_data[PKT_SIZE];
memset(packed_data, 0, PKT_SIZE);
// pack both target object and position
// position interpreted as offset if target object is non-null
if (mTargetObject)
{
htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
}
else
{
htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
}
U8 resetAnimations = (U8)mResetAnimations;
htolememcpy(&(packed_data[RESET_ANIMATIONS]), &resetAnimations, MVT_U8, 1);
mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
}
//-----------------------------------------------------------------------------
// unpackData()
//-----------------------------------------------------------------------------
void LLHUDEffectResetSkeleton::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
{
LLVector3d new_target;
U8 packed_data[PKT_SIZE];
LLHUDEffect::unpackData(mesgsys, blocknum);
LLUUID source_id;
mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_AgentID, source_id, blocknum);
LLViewerObject *objp = gObjectList.findObject(source_id);
if (objp && objp->isAvatar())
{
setSourceObject(objp);
}
else
{
//LL_WARNS() << "Could not find source avatar for ResetSkeleton effect" << LL_ENDL;
return;
}
S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
if (size != PKT_SIZE)
{
LL_WARNS() << "ResetSkeleton effect with bad size " << size << LL_ENDL;
return;
}
mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
LLUUID target_id;
htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
// The purpose for having a target ID is if we want to reset animesh, or
// other things in the future.
// I implemented this, but due to issues regarding various permission
// checks, I scrapped it for now. --Chaser Zaks
// See https://github.com/secondlife/viewer/pull/1212 for additional info
if (target_id.isNull())
{
target_id = source_id;
}
objp = gObjectList.findObject(target_id);
if (objp)
{
setTargetObject(objp);
}
U8 resetAnimations = 0;
htolememcpy(&resetAnimations, &(packed_data[RESET_ANIMATIONS]), MVT_U8, 1);
// Pre-emptively assume this is going to be flags in the future.
// It isn't needed now, but this will assure that only bit 1 is set
mResetAnimations = resetAnimations & 1;
update();
}
//-----------------------------------------------------------------------------
// setTargetObjectAndOffset()
//-----------------------------------------------------------------------------
void LLHUDEffectResetSkeleton::setTargetObject(LLViewerObject *objp)
{
mTargetObject = objp;
}
//-----------------------------------------------------------------------------
// markDead()
//-----------------------------------------------------------------------------
void LLHUDEffectResetSkeleton::markDead()
{
LLHUDEffect::markDead();
}
void LLHUDEffectResetSkeleton::setSourceObject(LLViewerObject* objectp)
{
// restrict source objects to avatars
if (objectp && objectp->isAvatar())
{
LLHUDEffect::setSourceObject(objectp);
}
}
//-----------------------------------------------------------------------------
// update()
//-----------------------------------------------------------------------------
void LLHUDEffectResetSkeleton::update()
{
// If the target object is dead, set the target object to NULL
if (mTargetObject.isNull() || mTargetObject->isDead())
{
markDead();
return;
}
if (mSourceObject.isNull() || mSourceObject->isDead())
{
markDead();
return;
}
if (mTargetObject->isAvatar())
{
// Only the owner of a avatar can reset their skeleton like this
// Also allow reset if we created the effect (Local resetting)
if (mSourceObject->getID() == mTargetObject->getID() || getOriginatedHere())
{
LLVOAvatar* avatar = mTargetObject->asAvatar();
avatar->resetSkeleton(mResetAnimations);
}
}
else
{
LL_WARNS() << mSourceObject->getID() << " attempted to reset skeleton on "
<< mTargetObject->getID() << ", but it is not a avatar!" << LL_ENDL;
}
markDead();
}

View File

@ -0,0 +1,59 @@
/**
* @file llhudeffectresetskeleton.h
* @brief LLHUDEffectResetSkeleton class definition
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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_LLHUDEFFECTRESETSKELETON_H
#define LL_LLHUDEFFECTRESETSKELETON_H
#include "llhudeffect.h"
class LLViewerObject;
class LLVOAvatar;
class LLHUDEffectResetSkeleton final : public LLHUDEffect
{
public:
friend class LLHUDObject;
/*virtual*/ void markDead();
/*virtual*/ void setSourceObject(LLViewerObject* objectp);
void setTargetObject(LLViewerObject *objp);
void setResetAnimations(bool enable){ mResetAnimations = enable; };
protected:
LLHUDEffectResetSkeleton(const U8 type);
~LLHUDEffectResetSkeleton();
/*virtual*/ void packData(LLMessageSystem *mesgsys);
/*virtual*/ void unpackData(LLMessageSystem *mesgsys, S32 blocknum);
void update();
private:
bool mResetAnimations;
};
#endif // LL_LLHUDEFFECTRESETSKELETON_H

View File

@ -36,6 +36,7 @@
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
#include "llhudeffectresetskeleton.h"
#include "llhudnametag.h"
#include "llvoicevisualizer.h"
@ -263,6 +264,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_BLOB:
hud_objectp = new LLHUDEffectBlob(type);
break;
case LL_HUD_EFFECT_RESET_SKELETON:
hud_objectp = new LLHUDEffectResetSkeleton(type);
break;
default:
LL_WARNS() << "Unknown type of hud effect:" << (U32) type << LL_ENDL;
}

View File

@ -101,7 +101,8 @@ public:
LL_HUD_EFFECT_POINTAT,
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
LL_HUD_NAME_TAG,
LL_HUD_EFFECT_BLOB
LL_HUD_EFFECT_BLOB,
LL_HUD_EFFECT_RESET_SKELETON
};
protected:
static void sortObjects();

View File

@ -1906,6 +1906,8 @@ bool LLIMModel::logToFile(const std::string& file_name, const std::string& from,
}
else
{
// will check KeepConversationLogTranscripts on its own
LLConversationLog::instance().cache();
return false;
}
}

View File

@ -122,7 +122,6 @@ public:
protected:
LLPointer<LLViewerFetchedTexture> m_Image;
S32 mImageBoostLevel = LLGLTexture::BOOST_NONE;
std::string mLoadingText;
};
@ -135,12 +134,8 @@ LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p)
LLTexturePreviewView::~LLTexturePreviewView()
{
if (m_Image)
{
m_Image->setBoostLevel(mImageBoostLevel);
m_Image = nullptr;
}
}
void LLTexturePreviewView::draw()
{
@ -160,18 +155,18 @@ void LLTexturePreviewView::draw()
bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0);
if (isLoading)
LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, rctClient.mLeft + 3, rctClient.mTop - 25, LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight()));
m_Image->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
}
}
void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
{
m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_THUMBNAIL);
if (m_Image)
{
mImageBoostLevel = m_Image->getBoostLevel();
m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
m_Image->forceToSaveRawImage(0);
m_Image->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) )
{
if (m_Image->isInFastCacheList())

View File

@ -874,6 +874,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
{
const LLInventoryObject *obj = getInventoryObject();
bool single_folder_root = (mRoot == NULL);
bool is_cof = isCOFFolder();
bool is_inbox = isInboxFolder();
if (obj)
{
@ -891,7 +893,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Copy"));
}
if (isAgentInventory() && !single_folder_root && !isMarketplaceListingsFolder())
bool is_agent_inventory = isAgentInventory();
if (is_agent_inventory && !single_folder_root && !is_cof && !is_inbox)
{
items.push_back(std::string("New folder from selected"));
items.push_back(std::string("Subfolder Separator"));
@ -904,6 +907,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
}
if (isFavorite())
{
items.push_back(std::string("Remove from Favorites"));
}
else if (is_agent_inventory && !gInventory.isObjectDescendentOf(mUUID, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
{
items.push_back(std::string("Add to Favorites"));
if (gInventory.getRootFolderID() == mUUID)
{
disabled_items.push_back(std::string("Add to Favorites"));
}
}
if (obj->getIsLinkType())
{
items.push_back(std::string("Find Original"));
@ -916,6 +932,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
disabled_items.push_back(std::string("New folder from selected"));
}
}
else
@ -925,7 +942,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
items.push_back(std::string("Find Links"));
}
if (!isInboxFolder() && !single_folder_root)
if (!is_inbox && !single_folder_root)
{
items.push_back(std::string("Rename"));
// <FS> Locked folder
@ -968,6 +985,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
disabled_items.push_back(std::string("New folder from selected"));
}
if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder())
@ -993,8 +1011,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
// <FS:Ansariel> Enable paste for inbox; doesn't actually makes much sense,
// but since we are not prevented from pasting via shortcut,
// we enable it in the context menu, too.
//if (!isCOFFolder() && !isInboxFolder()
if (!isCOFFolder()
//if (!is_cof && !is_inbox)
if (!is_cof
// <FS:TT> Client LSL Bridge (also for #AO)
&& !isLockedFolder())
// </FS:TT>
@ -1435,6 +1453,13 @@ bool LLInvFVBridge::isAgentInventory() const
return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
}
bool LLInvFVBridge::isAgentInventoryRoot() const
{
const LLInventoryModel* model = getInventoryModel();
if(!model) return false;
return gInventory.getRootFolderID() == mUUID;
}
// [SL:KB] - Patch: Inventory-Misc | Checked: 2011-05-28 (Catznip-2.6.0a) | Added: Catznip-2.6.0a
bool LLInvFVBridge::isLibraryInventory() const
{
@ -2520,7 +2545,21 @@ const LLUUID& LLItemBridge::getThumbnailUUID() const
return LLUUID::null;
}
// virtual
bool LLItemBridge::isFavorite() const
{
LLViewerInventoryItem* item = NULL;
LLInventoryModel* model = getInventoryModel();
if (model)
{
item = model->getItem(mUUID);
}
if (item)
{
return get_is_favorite(item);
}
return false;
}
bool LLItemBridge::isItemPermissive() const
{
if (LLViewerInventoryItem* item = getItem())
@ -2693,6 +2732,16 @@ const LLUUID& LLFolderBridge::getThumbnailUUID() const
return LLUUID::null;
}
bool LLFolderBridge::isFavorite() const
{
LLViewerInventoryCategory* cat = getCategory();
if (cat)
{
return cat->getIsFavorite();
}
return false;
}
void LLFolderBridge::update()
{
// we know we have children but haven't fetched them (doesn't obey filter)
@ -4693,6 +4742,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
}
disabled_items.push_back(std::string("New Folder"));
disabled_items.push_back(std::string("upload_options"));
// <FS:Ansariel> Undo weird menu design
disabled_items.push_back(std::string("New Script"));
disabled_items.push_back(std::string("New Note"));
@ -4727,6 +4777,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
{
disabled_items.push_back(std::string("New Folder"));
disabled_items.push_back(std::string("New Listing Folder"));
disabled_items.push_back(std::string("upload_options"));
// <FS:Ansariel> Undo weird menu design
disabled_items.push_back(std::string("New Script"));
disabled_items.push_back(std::string("New Note"));
@ -4808,6 +4859,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
if (!isMarketplaceListingsFolder() && !model->isObjectDescendentOf(mUUID, outfits_id))
// </FS:Ansariel>
{
items.push_back(std::string("upload_options"));
items.push_back(std::string("upload_def"));
//items.push_back(std::string("create_new")); // <FS:Ansariel> Undo weird menu design
items.push_back(std::string("New Script"));
@ -4841,6 +4893,15 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.push_back(std::string("Rename"));
items.push_back(std::string("thumbnail"));
if (cat->getIsFavorite())
{
items.push_back(std::string("Remove from Favorites"));
}
else
{
items.push_back(std::string("Add to Favorites"));
}
addDeleteContextMenuOptions(items, disabled_items);
// EXT-4030: disallow deletion of currently worn outfit
const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
@ -7658,16 +7719,13 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
item = (LLViewerInventoryItem*)gInventory.getItem(object_id);
if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID()))
{
rez_attachment(item, NULL, true); // Replace if "Wear"ing.
static LLCachedControl<bool> replace_item(gSavedSettings, "InventoryAddAttachmentBehavior", false);
rez_attachment(item, NULL, ("attach" == action) ? replace_item() : true); // Replace if "Wear"ing.
}
else if(item && item->isFinished())
{
// must be in library. copy it to our inventory and put it on.
// LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0));
// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2013-02-04 (Catznip-3.4)
// "Wear" from inventory replaces, so library items should too
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, true));
// [/SL;KB]
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
@ -8906,7 +8964,8 @@ void LLObjectBridgeAction::attachOrDetach()
else
{
// <FS:Ansariel> Double-click add/replace option
//LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
//static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryAddAttachmentBehavior", false);
//LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, inventory_linking()); // Don't replace if adding.
LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, !gSavedSettings.getBOOL("FSDoubleClickAddInventoryObjects")); // Don't replace if adding.
}
}
@ -9100,6 +9159,7 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
buildContextMenuOptions(flags, items, disabled_items);
items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end());
hide_context_entries(menu, items, disabled_items);
}
@ -9134,6 +9194,51 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge(
return new_listener;
}
/************************************************************************/
/* Favorites Inventory Panel related classes */
/************************************************************************/
void LLFavoritesFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
// todo: consider things that should be disabled
menuentry_vec_t disabled_items, items;
buildContextMenuOptions(flags, items, disabled_items);
items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end());
hide_context_entries(menu, items, disabled_items);
}
LLInvFVBridge* LLFavoritesInventoryBridgeBuilder::createBridge(
LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
LLFolderViewModelInventory* view_model,
LLFolderView* root,
const LLUUID& uuid,
U32 flags /*= 0x00*/) const
{
LLInvFVBridge* new_listener = NULL;
if (asset_type == LLAssetType::AT_CATEGORY
&& actual_asset_type != LLAssetType::AT_LINK_FOLDER)
{
new_listener = new LLFavoritesFolderBridge(inv_type, inventory, root, uuid);
}
else
{
new_listener = LLInventoryFolderViewModelBuilder::createBridge(asset_type,
actual_asset_type,
inv_type,
inventory,
view_model,
root,
uuid,
flags);
}
return new_listener;
}
LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge()
{
}
@ -9145,8 +9250,8 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ
if (get_selection_item_uuids(selected_items, ids))
{
// <FS:Ansariel> Fix broken add wearable check
//if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids))
if (!canWearSelected(ids) || !LLAppearanceMgr::instance().canAddWearables(ids))
//if (!LLAppearanceMgr::instance().canAddWearables(ids, false) && canWearSelected(ids))
if (!canWearSelected(ids) || !LLAppearanceMgr::instance().canAddWearables(ids, false))
{
disabled_items.push_back(std::string("Wearable And Object Wear"));
disabled_items.push_back(std::string("Wearable Add"));

View File

@ -86,6 +86,7 @@ public:
//--------------------------------------------------------------------
virtual const LLUUID& getUUID() const { return mUUID; }
virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
virtual bool isFavorite() const { return false; }
virtual void clearDisplayName() { mDisplayName.clear(); }
virtual void restoreItem() {}
virtual void restoreToWorld() {}
@ -182,6 +183,7 @@ protected:
bool isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory?
bool isAgentInventory() const; // false if lost or in the inventory library
bool isAgentInventoryRoot() const; // true if worn by agent
bool isCOFFolder() const; // true if COF or descendant of
bool isInboxFolder() const; // true if COF or descendant of marketplace inbox
@ -277,6 +279,7 @@ public:
LLViewerInventoryItem* getItem() const;
virtual const LLUUID& getThumbnailUUID() const;
virtual bool isFavorite() const;
protected:
bool confirmRemoveItem(const LLSD& notification, const LLSD& response);
@ -319,6 +322,7 @@ public:
virtual std::string getLabelSuffix() const;
virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual const LLUUID& getThumbnailUUID() const;
virtual bool isFavorite() const;
void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;}
@ -780,6 +784,45 @@ public:
U32 flags = 0x00) const;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Favorites Inventory Panel related classes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Overridden version of the Inventory-Folder-View-Bridge for Folders
class LLFavoritesFolderBridge : public LLFolderBridge
{
friend class LLInvFVBridgeAction;
public:
// Creates context menu for Folders related to Recent Inventory Panel.
// Uses base logic and than removes from visible items "New..." menu items.
LLFavoritesFolderBridge(LLInventoryType::EType type,
LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid) :
LLFolderBridge(inventory, root, uuid)
{
mInvType = type;
}
/*virtual*/ void buildContextMenu(LLMenuGL& menu, U32 flags);
};
// Bridge builder to create Inventory-Folder-View-Bridge for Recent Inventory Panel
class LLFavoritesInventoryBridgeBuilder : public LLInventoryFolderViewModelBuilder
{
public:
LLFavoritesInventoryBridgeBuilder() {}
// Overrides FolderBridge for Recent Inventory Panel.
// It use base functionality for bridges other than FolderBridge.
virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
LLFolderViewModelInventory* view_model,
LLFolderView* root,
const LLUUID& uuid,
U32 flags = 0x00) const;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Worn Inventory Panel related classes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -844,7 +887,7 @@ private:
void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment,
bool replace = false);
bool replace);
// Move items from an in-world object's "Contents" folder to a specified
// folder in agent inventory.

View File

@ -72,6 +72,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p)
mFilterUUID(p.uuid),
mFilterLinks(p.links),
mFilterThumbnails(p.thumbnails),
mFilterFavorites(p.favorites),
mCoalescedObjectsOnly(p.coalesced_objects_only), // <FS:Zi> FIRE-31369: Add inventory filter for coalesced objects
mSearchVisibility(p.search_visibility)
{
@ -178,6 +179,7 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
passed = passed && checkAgainstCreator(listener);
passed = passed && checkAgainstSearchVisibility(listener);
passed = passed && checkAgainstFilterFavorites(listener->getUUID());
passed = passed && checkAgainstFilterThumbnails(listener->getUUID());
return passed;
@ -240,6 +242,19 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
return false;
}
const LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
if (cat && cat->getIsFavorite())
{
if (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES)
{
return true;
}
if (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES)
{
return false;
}
}
// Marketplace folder filtering
const U32 filterTypes = mFilterOps.mFilterTypes;
const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE |
@ -292,6 +307,16 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
}
}
if (filterTypes & FILTERTYPE_NO_TRASH_ITEMS)
{
const LLUUID trash_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
// If not a descendant of the marketplace listings root, then the nesting depth is -1 by definition
if (gInventory.isObjectDescendentOf(folder_id, trash_uuid))
{
return false;
}
}
// show folder links
LLViewerInventoryItem* item = gInventory.getItem(folder_id);
if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER)
@ -671,6 +696,24 @@ bool LLInventoryFilter::checkAgainstFilterThumbnails(const LLUUID& object_id) co
return true;
}
bool LLInventoryFilter::checkAgainstFilterFavorites(const LLUUID& object_id) const
{
const LLInventoryObject* object = gInventory.getObject(object_id);
if (!object) return true;
if (mFilterOps.mFilterFavorites != FILTER_INCLUDE_FAVORITES)
{
bool is_favorite = get_is_favorite(object);
if (is_favorite && (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES))
return false;
if (!is_favorite && (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES))
return false;
}
return true;
}
bool LLInventoryFilter::checkAgainstCreator(const LLFolderViewModelItemInventory* listener) const
{
if (!listener)
@ -905,6 +948,32 @@ void LLInventoryFilter::setFilterThumbnails(U64 filter_thumbnails)
mFilterOps.mFilterThumbnails = filter_thumbnails;
}
void LLInventoryFilter::setFilterFavorites(U64 filter_favorites)
{
if (mFilterOps.mFilterFavorites != filter_favorites)
{
if (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES
&& filter_favorites == FILTER_ONLY_FAVORITES)
{
setModified(FILTER_RESTART);
}
else if (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES
&& filter_favorites == FILTER_EXCLUDE_FAVORITES)
{
setModified(FILTER_RESTART);
}
else if (mFilterOps.mFilterFavorites == FILTER_INCLUDE_FAVORITES)
{
setModified(FILTER_MORE_RESTRICTIVE);
}
else
{
setModified(FILTER_LESS_RESTRICTIVE);
}
}
mFilterOps.mFilterFavorites = filter_favorites;
}
void LLInventoryFilter::setFilterEmptySystemFolders()
{
mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS;
@ -1017,6 +1086,11 @@ void LLInventoryFilter::toggleSearchVisibilityLibrary()
}
}
void LLInventoryFilter::setFilterNoTrashFolder()
{
mFilterOps.mFilterTypes |= FILTERTYPE_NO_TRASH_ITEMS;
}
void LLInventoryFilter::setFilterNoMarketplaceFolder()
{
mFilterOps.mFilterTypes |= FILTERTYPE_NO_MARKETPLACE_ITEMS;
@ -1856,6 +1930,11 @@ U64 LLInventoryFilter::getFilterThumbnails() const
return mFilterOps.mFilterThumbnails;
}
U64 LLInventoryFilter::getFilterFavorites() const
{
return mFilterOps.mFilterFavorites;
}
bool LLInventoryFilter::hasFilterString() const
{
return mFilterSubString.size() > 0;

View File

@ -60,7 +60,8 @@ public:
FILTERTYPE_MARKETPLACE_LISTING_FOLDER = 0x1 << 9, // pass iff folder is a listing folder
FILTERTYPE_NO_MARKETPLACE_ITEMS = 0x1 << 10, // pass iff folder is not under the marketplace
FILTERTYPE_WORN = 0x1 << 11, // pass if item is worn
FILTERTYPE_SETTINGS = 0x1 << 12 // pass if the item is a settings object
FILTERTYPE_SETTINGS = 0x1 << 12, // pass if the item is a settings object
FILTERTYPE_NO_TRASH_ITEMS = 0x1 << 13 // pass iff folder is not under the marketplace
};
enum EFilterDateDirection
@ -83,6 +84,13 @@ public:
FILTER_ONLY_THUMBNAILS
};
enum EFilterFavorite
{
FILTER_INCLUDE_FAVORITES,
FILTER_EXCLUDE_FAVORITES,
FILTER_ONLY_FAVORITES
};
enum ESortOrderType
{
SO_NAME = 0, // Sort inventory by name
@ -150,6 +158,7 @@ public:
Optional<PermissionMask> permissions;
Optional<EFilterCreatorType> creator_type;
Optional<EFilterThumbnail> thumbnails;
Optional<EFilterFavorite> favorites;
Optional<bool> coalesced_objects_only; // <FS:Zi> FIRE-31369: Add inventory filter for coalesced objects
Params()
@ -158,6 +167,7 @@ public:
wearable_types("wearable_types", 0xffffFFFFffffFFFFULL),
settings_types("settings_types", 0xffffFFFFffffFFFFULL),
thumbnails("thumbnails", FILTER_INCLUDE_THUMBNAILS),
favorites("favorites", FILTER_INCLUDE_FAVORITES),
category_types("category_types", 0xffffFFFFffffFFFFULL),
links("links", FILTERLINK_INCLUDE_LINKS),
search_visibility("search_visibility", 0xFFFFFFFF),
@ -180,6 +190,7 @@ public:
mFilterWearableTypes,
mFilterSettingsTypes, // for _SETTINGS
mFilterThumbnails,
mFilterFavorites,
mFilterLinks,
mFilterCategoryTypes; // For _CATEGORY
LLUUID mFilterUUID; // for UUID
@ -225,6 +236,7 @@ public:
U64 getFilterSettingsTypes() const;
U64 getSearchVisibilityTypes() const;
U64 getFilterThumbnails() const;
U64 getFilterFavorites() const;
bool isFilterObjectTypesWith(LLInventoryType::EType t) const;
void setFilterObjectTypes(U64 types);
@ -239,8 +251,10 @@ public:
void setFilterMarketplaceInactiveFolders();
void setFilterMarketplaceUnassociatedFolders();
void setFilterMarketplaceListingFolders(bool select_only_listing_folders);
void setFilterNoTrashFolder();
void setFilterNoMarketplaceFolder();
void setFilterThumbnails(U64 filter_thumbnails);
void setFilterFavorites(U64 filter_favorites);
void updateFilterTypes(U64 types, U64& current_types);
void setSearchType(ESearchType type);
ESearchType getSearchType() { return mSearchType; }
@ -361,6 +375,7 @@ public:
LLInventoryFilter& operator =(const LLInventoryFilter& other);
bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
bool checkAgainstFilterFavorites(const LLUUID& object_id) const;
private:
bool areDateLimitsSet();

View File

@ -51,6 +51,7 @@
#include "lldirpicker.h"
#include "lldonotdisturbnotificationstorage.h"
#include "llfloatermarketplacelistings.h"
#include "llfloatermodelpreview.h"
#include "llfloatersidepanelcontainer.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
@ -62,6 +63,7 @@
#include "llinventorymodel.h"
#include "llinventorypanel.h"
#include "lllineeditor.h"
#include "llmaterialeditor.h"
#include "llmarketplacenotifications.h"
#include "llmarketplacefunctions.h"
#include "llmenugl.h"
@ -86,6 +88,7 @@
#include "llviewermessage.h"
#include "llviewerfoldertype.h"
#include "llviewerobjectlist.h"
#include "llviewermenufile.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
@ -2575,6 +2578,143 @@ void ungroup_folder_items(const LLUUID& folder_id)
}); // <FS:Ansariel> FIRE-32736: Add confirmation before ungrouping folder
}
class LLUpdateFavorite : public LLInventoryCallback
{
public:
LLUpdateFavorite(const LLUUID& inv_item_id)
: mInvItemID(inv_item_id)
{}
/* virtual */ void fire(const LLUUID& inv_item_id) override
{
gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, mInvItemID);
LLInventoryModel::item_array_t items;
LLInventoryModel::cat_array_t cat_array;
LLLinkedItemIDMatches matches(mInvItemID);
gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
cat_array,
items,
LLInventoryModel::INCLUDE_TRASH,
matches);
std::set<LLUUID> link_ids;
for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
{
LLPointer<LLViewerInventoryItem> item = *it;
gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, item->getUUID());
}
gInventory.notifyObservers();
}
private:
LLUUID mInvItemID;
};
void favorite_send(LLInventoryObject* obj, const LLUUID& obj_id, bool favorite)
{
LLSD updates;
if (favorite)
{
updates["favorite"] = LLSD().with("toggled", true);
}
else
{
updates["favorite"] = LLSD();
}
LLPointer<LLInventoryCallback> cb = new LLUpdateFavorite(obj_id);
LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
if (view_folder)
{
update_inventory_category(obj_id, updates, cb);
}
LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
if (view_item)
{
update_inventory_item(obj_id, updates, cb);
}
}
bool get_is_favorite(const LLInventoryObject* object)
{
if (object->getIsLinkType())
{
LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID());
return obj && obj->getIsFavorite();
}
return object->getIsFavorite();
}
bool get_is_favorite(const LLUUID& obj_id)
{
LLInventoryObject* object = gInventory.getObject(obj_id);
if (object && object->getIsLinkType())
{
LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID());
return obj && obj->getIsFavorite();
}
return object->getIsFavorite();
}
void set_favorite(const LLUUID& obj_id, bool favorite)
{
LLInventoryObject* obj = gInventory.getObject(obj_id);
if (obj && obj->getIsLinkType())
{
if (!favorite && obj->getIsFavorite())
{
// Links currently aren't supposed to be favorites,
// instead should show state of the original
LL_INFOS("Inventory") << "Recovering proper 'favorites' state of a link " << obj_id << LL_ENDL;
favorite_send(obj, obj_id, false);
}
obj = gInventory.getObject(obj->getLinkedUUID());
}
if (obj && obj->getIsFavorite() != favorite)
{
favorite_send(obj, obj->getUUID(), favorite);
}
}
void toggle_favorite(const LLUUID& obj_id)
{
LLInventoryObject* obj = gInventory.getObject(obj_id);
if (obj && obj->getIsLinkType())
{
obj = gInventory.getObject(obj->getLinkedUUID());
}
if (obj)
{
favorite_send(obj, obj->getUUID(), !obj->getIsFavorite());
}
}
void toggle_favorites(const uuid_vec_t& ids)
{
if (ids.size() == 0)
{
return;
}
if (ids.size() == 1)
{
toggle_favorite(ids[0]);
return;
}
bool new_val = !get_is_favorite(ids.front());
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
set_favorite(*it, new_val);
}
}
std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id)
{
if (model)
@ -2874,6 +3014,20 @@ bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryIt
return false;
}
bool LLFavoritesCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if (item && item->getIsFavorite())
{
return true;
}
if (cat && cat->getIsFavorite())
{
return true;
}
return false;
}
bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
@ -3790,6 +3944,20 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
ungroup_folder_items(*ids.begin());
}
}
else if ("add_to_favorites" == action)
{
for (const LLUUID& id : ids)
{
set_favorite(id, true);
}
}
else if ("remove_from_favorites" == action)
{
for (const LLUUID& id : ids)
{
set_favorite(id, false);
}
}
else if ("thumbnail" == action)
{
if (selected_items.size() > 0)
@ -3912,6 +4080,54 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root)
}
}
void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::string& action)
{
if (action == "def_model")
{
gSavedPerAccountSettings.setString("ModelUploadFolder", dest_id.asString());
}
else if (action == "def_texture")
{
gSavedPerAccountSettings.setString("TextureUploadFolder", dest_id.asString());
}
else if (action == "def_sound")
{
gSavedPerAccountSettings.setString("SoundUploadFolder", dest_id.asString());
}
else if (action == "def_animation")
{
gSavedPerAccountSettings.setString("AnimationUploadFolder", dest_id.asString());
}
else if (action == "def_pbr_material")
{
gSavedPerAccountSettings.setString("PBRUploadFolder", dest_id.asString());
}
else if (action == "upload_texture")
{
LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_IMAGE, false);
}
else if (action == "upload_sound")
{
LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_WAV, false);
}
else if (action == "upload_animation")
{
LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_ANIM, false);
}
else if (action == "upload_model")
{
LLFloaterModelPreview::showModelPreview(dest_id);
}
else if (action == "upload_pbr_material")
{
LLMaterialEditor::importMaterial(dest_id);
}
else if (action == "upload_bulk")
{
LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, true, dest_id), LLFilePicker::FFLOAD_ALL, true);
}
}
void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);

View File

@ -123,6 +123,11 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca
std::string get_localized_folder_name(LLUUID cat_uuid);
void new_folder_window(const LLUUID& folder_id);
void ungroup_folder_items(const LLUUID& folder_id);
bool get_is_favorite(const LLInventoryObject* object);
bool get_is_favorite(const LLUUID& obj_id);
void set_favorite(const LLUUID& obj_id, bool favorite);
void toggle_favorite(const LLUUID& obj_id);
void toggle_favorites(const uuid_vec_t& ids);
std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id);
std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id);
std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);
@ -350,6 +355,18 @@ protected:
LLUUID mGroupID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFavoritesCollector
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFavoritesCollector : public LLInventoryCollectFunctor
{
public:
LLFavoritesCollector() {}
virtual ~LLFavoritesCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLBuddyCollector
//
@ -624,6 +641,7 @@ struct LLInventoryAction
static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action);
static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root);
static void removeItemFromDND(LLFolderView* root);
static void fileUploadLocation(const LLUUID& dest_id, const std::string& action);
static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);

View File

@ -634,7 +634,7 @@ void LLInventoryGallery::removeFromLastRow(LLInventoryGalleryItem* item)
mItemPanels.pop_back();
}
LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn)
LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn, bool is_favorite)
{
LLInventoryGalleryItem::Params giparams;
giparams.visible = true;
@ -645,6 +645,7 @@ LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, L
gitem->setUUID(item_id);
gitem->setGallery(this);
gitem->setType(type, inventory_type, flags, is_link);
gitem->setFavorite(is_favorite);
gitem->setLoadImmediately(mLoadThumbnailsImmediately);
gitem->setThumbnail(thumbnail_id);
gitem->setWorn(is_worn);
@ -937,8 +938,19 @@ bool LLInventoryGallery::updateAddedItem(LLUUID item_id)
}
bool res = false;
bool is_favorite = get_is_favorite(obj);
LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, inventory_type, misc_flags, obj->getCreationDate(), obj->getIsLinkType(), is_worn);
LLInventoryGalleryItem* item = buildGalleryItem(
name,
item_id,
obj->getType(),
thumbnail_id,
inventory_type,
misc_flags,
obj->getCreationDate(),
obj->getIsLinkType(),
is_worn,
is_favorite);
mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
if (mGalleryCreated)
{
@ -975,7 +987,7 @@ void LLInventoryGallery::updateRemovedItem(LLUUID item_id)
mItemBuildQuery.erase(item_id);
}
void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
void LLInventoryGallery::updateChangedItemData(LLUUID item_id, std::string name, bool is_favorite)
{
gallery_item_map_t::iterator iter = mItemMap.find(item_id);
if (iter != mItemMap.end())
@ -984,6 +996,7 @@ void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
if (item)
{
item->setItemName(name);
item->setFavorite(is_favorite);
}
}
}
@ -2339,7 +2352,7 @@ void LLInventoryGallery::refreshList(const LLUUID& category_id)
return;
}
updateChangedItemName(*items_iter, obj->getName());
updateChangedItemData(*items_iter, obj->getName(), get_is_favorite(obj));
mNeedsArrange = true;
}
@ -2855,6 +2868,14 @@ void LLInventoryGalleryItem::setType(LLAssetType::EType type, LLInventoryType::E
getChild<LLIconCtrl>("link_overlay")->setVisible(is_link);
}
void LLInventoryGalleryItem::setFavorite(bool is_favorite)
{
getChild<LLIconCtrl>("fav_icon")->setVisible(is_favorite);
static const LLUIColor text_color = LLUIColorTable::instance().getColor("LabelTextColor", LLColor4::white);
static const LLUIColor favorite_color = LLUIColorTable::instance().getColor("InventoryFavoriteColor", LLColor4::white);
mNameText->setReadOnlyColor(is_favorite ? favorite_color : text_color);
}
void LLInventoryGalleryItem::setThumbnail(LLUUID id)
{
mDefaultImage = id.isNull();

View File

@ -102,7 +102,7 @@ public:
void getCurrentCategories(uuid_vec_t& vcur);
bool updateAddedItem(LLUUID item_id); // returns true if added item is visible
void updateRemovedItem(LLUUID item_id);
void updateChangedItemName(LLUUID item_id, std::string name);
void updateChangedItemData(LLUUID item_id, std::string name, bool is_favorite);
void updateItemThumbnail(LLUUID item_id);
void updateWornItem(LLUUID item_id, bool is_worn);
@ -227,7 +227,7 @@ private:
bool updateRowsIfNeeded();
void updateGalleryWidth();
LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn);
LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn, bool is_favorite);
LLInventoryGalleryItem* getItem(const LLUUID& id) const;
void buildGalleryPanel(int row_count);
@ -343,6 +343,7 @@ public:
void setHidden(bool hidden) {mHidden = hidden;}
void setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
void setFavorite(bool is_favorite);
LLAssetType::EType getAssetType() { return mType; }
void setThumbnail(LLUUID id);
void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }

View File

@ -250,6 +250,20 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
{
ungroup_folder_items(mUUIDs.front());
}
else if ("add_to_favorites" == action)
{
for (const LLUUID& id : mUUIDs)
{
set_favorite(id, true);
}
}
else if ("remove_from_favorites" == action)
{
for (const LLUUID& id : mUUIDs)
{
set_favorite(id, false);
}
}
else if ("replaceoutfit" == action)
{
modify_outfit(false, mUUIDs.front(), &gInventory);
@ -484,22 +498,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS
void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
{
const std::string param = userdata.asString();
if (param == "model")
{
gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString());
}
else if (param == "texture")
{
gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString());
}
else if (param == "sound")
{
gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString());
}
else if (param == "animation")
{
gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString());
}
LLInventoryAction::fileUploadLocation(mUUIDs.front(), param);
}
bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
@ -778,6 +777,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
items.push_back(std::string("New Folder"));
}
items.push_back(std::string("upload_options"));
items.push_back(std::string("upload_def"));
}
@ -786,6 +786,18 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
items.push_back(std::string("New Outfit"));
}
if (!is_trash && !is_in_trash && gInventory.getRootFolderID() != selected_id)
{
if (get_is_favorite(obj))
{
items.push_back(std::string("Remove from Favorites"));
}
else
{
items.push_back(std::string("Add to Favorites"));
}
}
items.push_back(std::string("Subfolder Separator"));
if (!is_system_folder && !isRootFolder())
{
@ -831,6 +843,17 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
if(is_agent_inventory)
{
items.push_back(std::string("Cut"));
if (!is_in_trash)
{
if (get_is_favorite(obj))
{
items.push_back(std::string("Remove from Favorites"));
}
else
{
items.push_back(std::string("Add to Favorites"));
}
}
if (!is_link || !is_cof || !get_is_item_worn(selected_id))
{
items.push_back(std::string("Delete"));
@ -967,6 +990,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
disabled_items.push_back(std::string("New Folder"));
disabled_items.push_back(std::string("upload_options"));
disabled_items.push_back(std::string("upload_def"));
disabled_items.push_back(std::string("create_new"));
}
@ -1017,6 +1041,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
disabled_items.push_back(std::string("Marketplace Move"));
}
}
if (get_is_favorite(obj))
{
items.push_back(std::string("Remove from Favorites"));
}
else if (is_agent_inventory)
{
items.push_back(std::string("Add to Favorites"));
}
}
hide_context_entries(*menu, items, disabled_items);

View File

@ -115,7 +115,7 @@ void LLInventoryItemsList::doIdle()
{
if (mRefreshState == REFRESH_COMPLETE) return;
if (isInVisibleChain() || mForceRefresh )
if (isInVisibleChain() || mForceRefresh || !getFilterSubString().empty())
{
refresh();

View File

@ -94,7 +94,7 @@
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
const S32 LLInventoryModel::sCurrentInvCacheVersion = 3;
const S32 LLInventoryModel::sCurrentInvCacheVersion = 4;
bool LLInventoryModel::sFirstTimeInViewer2 = true;
S32 LLInventoryModel::sPendingSystemFolders = 0;
@ -3044,8 +3044,9 @@ bool LLInventoryModel::loadSkeleton(
cached_ids.insert(tcat->getUUID());
// At the moment download does not provide a thumbnail
// uuid, use the one from cache
// uuid or favorite, use values from cache
tcat->setThumbnailUUID(cat->getThumbnailUUID());
tcat->setFavorite(cat->getIsFavorite());
}
}

View File

@ -786,6 +786,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask)
cat_changed = true;
}
bool is_favorite = category->getIsFavorite();
if (cat_data.mIsFavorite != is_favorite)
{
cat_data.mIsFavorite = is_favorite;
cat_changed = true;
}
// If anything has changed above, fire the callback.
if (cat_changed)
cat_data.mCallback();
@ -803,6 +810,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
bool can_be_added = true;
bool favorite = false;
LLUUID thumbnail_id;
LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
@ -816,6 +824,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
// to a category have been made.
version = category->getVersion();
thumbnail_id = category->getThumbnailUUID();
favorite = category->getIsFavorite();
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
@ -841,11 +850,11 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
if(init_name_hash)
{
digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash)));
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents,item_name_hash)));
}
else
{
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents)));
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents)));
}
}
@ -858,25 +867,37 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents)
const LLUUID& cat_id,
const LLUUID& thumbnail_id,
bool is_favorite,
callback_t cb,
S32 version,
S32 num_descendents)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
, mThumbnailId(thumbnail_id)
, mIsFavorite(is_favorite)
, mIsNameHashInitialized(false)
{
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
const LLUUID& cat_id,
const LLUUID& thumbnail_id,
bool is_favorite,
callback_t cb, S32 version,
S32 num_descendents,
const digest_t& name_hash)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
, mThumbnailId(thumbnail_id)
, mIsFavorite(is_favorite)
, mIsNameHashInitialized(true)
, mItemNameHash(name_hash)
{

View File

@ -60,6 +60,7 @@ public:
CREATE = 512, // With ADD, item has just been created.
// unfortunately a particular message is still associated with some unique semantics.
UPDATE_CREATE = 1024, // With ADD, item added via UpdateCreateInventoryItem
UPDATE_FAVORITE = 2048, // With ADD, item added via UpdateCreateInventoryItem
ALL = 0xffffffff
};
LLInventoryObserver();
@ -276,12 +277,26 @@ protected:
typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
struct LLCategoryData
{
LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents);
LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
LLCategoryData(
const LLUUID& cat_id,
const LLUUID& thumbnail_id,
bool is_favorite,
callback_t cb,
S32 version,
S32 num_descendents);
LLCategoryData(
const LLUUID& cat_id,
const LLUUID& thumbnail_id,
bool is_favorite,
callback_t cb,
S32 version,
S32 num_descendents,
const digest_t& name_hash);
callback_t mCallback;
S32 mVersion;
S32 mDescendentsCount;
digest_t mItemNameHash;
bool mIsFavorite;
bool mIsNameHashInitialized;
LLUUID mCatID;
LLUUID mThumbnailId;

View File

@ -61,11 +61,13 @@
// [/RLVa:KB]
#include "fsfloaterpartialinventory.h"
class LLInventoryFavoritesItemsPanel;
class LLInventoryRecentItemsPanel;
class LLAssetFilteredInventoryPanel;
static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
static LLDefaultChildRegistry::Register<LLInventoryFavoritesItemsPanel> t_favorites_inventory_panel("favorites_inventory_panel");
static LLDefaultChildRegistry::Register<LLAssetFilteredInventoryPanel> t_asset_filtered_inv_panel("asset_filtered_inv_panel");
const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
@ -690,6 +692,19 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
}
}
if (mask & LLInventoryObserver::UPDATE_FAVORITE)
{
if (view_item)
{
view_item->refresh();
LLFolderViewFolder* parent = view_item->getParentFolder();
if (parent)
{
parent->updateHasFavorites(get_is_favorite(model_item));
}
}
}
// We don't typically care which of these masks the item is actually flagged with, since the masks
// may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into
// Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks
@ -718,6 +733,16 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
setSelection(item_id, false);
}
updateFolderLabel(model_item->getParentUUID());
if (get_is_favorite(model_item))
{
LLFolderViewFolder* new_parent = getFolderByID(model_item->getParentUUID());
if (new_parent)
{
new_parent->updateHasFavorites(true);
}
}
}
//////////////////////////////
@ -731,9 +756,11 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
{
LLFolderViewModelItem* old_parent_vmi = old_parent->getViewModelItem();
LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent_vmi);
LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID());
// Item has been moved.
if (old_parent != new_parent)
LLFolderViewFolder* new_parent = getFolderByID(model_item->getParentUUID());
if (old_parent != new_parent // Item has been moved.
&& (new_parent != NULL || !isInRootContent(item_id, view_item)) // item is not or shouldn't be in root content
)
{
if (new_parent != NULL)
{
@ -768,6 +795,18 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
{
old_parent_vmi->dirtyDescendantsFilter();
}
if (view_item->isFavorite())
{
if (old_parent)
{
old_parent->updateHasFavorites(false); // favorite was removed
}
if (new_parent)
{
new_parent->updateHasFavorites(true); // favorite was added
}
}
}
}
}
@ -793,6 +832,10 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
updateFolderLabel(viewmodel_folder->getUUID());
}
}
if (view_item->isFavorite())
{
parent->updateHasFavorites(false); // favorite was removed
}
}
}
}
@ -910,7 +953,23 @@ void LLInventoryPanel::idle(void* user_data)
bool in_visible_chain = panel->isInVisibleChain();
if (!panel->mBuildViewsQueue.empty())
if (!panel->mBuildRootQueue.empty())
{
const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms
F64 curent_time = LLTimer::getTotalSeconds();
panel->mBuildViewsEndTime = curent_time + max_time;
while (curent_time < panel->mBuildViewsEndTime
&& !panel->mBuildRootQueue.empty())
{
LLUUID item_id = panel->mBuildRootQueue.back();
panel->mBuildRootQueue.pop_back();
panel->findAndInitRootContent(item_id);
curent_time = LLTimer::getTotalSeconds();
}
}
else if (!panel->mBuildViewsQueue.empty())
{
const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms
F64 curent_time = LLTimer::getTotalSeconds();
@ -992,20 +1051,9 @@ void LLInventoryPanel::initializeViews(F64 max_time)
mBuildViewsEndTime = curent_time + max_time;
// init everything
LLUUID root_id = getRootFolderID();
if (root_id.notNull())
{
buildNewViews(getRootFolderID());
}
else
{
// Default case: always add "My Inventory" root first, "Library" root second
// If we run out of time, this still should create root folders
buildNewViews(gInventory.getRootFolderID()); // My Inventory
buildNewViews(gInventory.getLibraryRootFolderID()); // Library
}
initRootContent();
if (mBuildViewsQueue.empty())
if (mBuildViewsQueue.empty() && mBuildRootQueue.empty())
{
mViewsInitialized = VIEWS_INITIALIZED;
}
@ -1036,6 +1084,22 @@ void LLInventoryPanel::initializeViews(F64 max_time)
}
}
void LLInventoryPanel::initRootContent()
{
LLUUID root_id = getRootFolderID();
if (root_id.notNull())
{
buildNewViews(getRootFolderID());
}
else
{
// Default case: always add "My Inventory" root first, "Library" root second
// If we run out of time, this still should create root folders
buildNewViews(gInventory.getRootFolderID()); // My Inventory
buildNewViews(gInventory.getLibraryRootFolderID()); // Library
}
}
LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop)
{
@ -1939,26 +2003,8 @@ bool LLInventoryPanel::beginIMSession()
void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
{
const std::string param = userdata.asString();
if (param == "model")
{
gSavedPerAccountSettings.setString("ModelUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
}
else if (param == "texture")
{
gSavedPerAccountSettings.setString("TextureUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
}
else if (param == "sound")
{
gSavedPerAccountSettings.setString("SoundUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
}
else if (param == "animation")
{
gSavedPerAccountSettings.setString("AnimationUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
}
else if (param == "pbr_material")
{
gSavedPerAccountSettings.setString("PBRUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
}
const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID();
LLInventoryAction::fileUploadLocation(dest, param);
}
void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
@ -2531,6 +2577,273 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
}
/************************************************************************/
/* Favorites Inventory Panel related class */
/************************************************************************/
static const LLFavoritesInventoryBridgeBuilder FAVORITES_BUILDER;
class LLInventoryFavoritesItemsPanel : public LLInventoryPanel
{
public:
struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
{};
void initFromParams(const Params& p)
{
LLInventoryPanel::initFromParams(p);
// turn off trash
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_TRASH));
getFilter().setFilterNoTrashFolder();
// turn off marketplace for favorites
getFilter().setFilterNoMarketplaceFolder();
}
void removeItemID(const LLUUID& id) override;
bool isInRootContent(const LLUUID& id, LLFolderViewItem* view_item) override;
protected:
LLInventoryFavoritesItemsPanel(const Params&);
friend class LLUICtrlFactory;
void findAndInitRootContent(const LLUUID& folder_id) override;
void initRootContent() override;
// removeFavorite removes item from root, does not readd favorited children if present
bool removeFavorite(const LLUUID& id, const LLInventoryObject* model_item);
void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override;
std::set<LLUUID> mRootContentIDs;
};
LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& params)
: LLInventoryPanel(params)
{
// replace bridge builder to have necessary View bridges.
mInvFVBridgeBuilder = &FAVORITES_BUILDER;
}
void LLInventoryFavoritesItemsPanel::removeItemID(const LLUUID& id)
{
std::set<LLUUID>::iterator found = mRootContentIDs.find(id);
if (found != mRootContentIDs.end())
{
mRootContentIDs.erase(found);
// check content for favorites
mBuildRootQueue.emplace_back(id);
}
LLInventoryPanel::removeItemID(id);
}
bool LLInventoryFavoritesItemsPanel::isInRootContent(const LLUUID& id, LLFolderViewItem* view_item)
{
if (!view_item->isFavorite())
{
return false;
}
std::set<LLUUID>::iterator found = mRootContentIDs.find(id);
return found != mRootContentIDs.end();
}
void LLInventoryFavoritesItemsPanel::findAndInitRootContent(const LLUUID& id)
{
F64 curent_time = LLTimer::getTotalSeconds();
if (mBuildViewsEndTime < curent_time)
{
mBuildRootQueue.emplace_back(id);
return;
}
LLViewerInventoryCategory::cat_array_t* categories;
LLViewerInventoryItem::item_array_t* items;
mInventory->lockDirectDescendentArrays(id, categories, items);
if (categories)
{
S32 count = static_cast<S32>(categories->size());
for (S32 i = 0; i < count; ++i)
{
LLViewerInventoryCategory* cat = categories->at(i);
if (cat->getPreferredType() == LLFolderType::FT_TRASH)
{
continue;
}
else if (cat->getIsFavorite())
{
LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID());
if (!folder_view_item)
{
const LLUUID& parent_id = cat->getParentUUID();
mRootContentIDs.emplace(cat->getUUID());
buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT);
}
}
else
{
findAndInitRootContent(cat->getUUID());
}
}
}
if (items)
{
S32 count = static_cast<S32>(items->size());
for (S32 i = 0; i < count; ++i)
{
LLViewerInventoryItem* item = items->at(i);
const LLUUID item_id = item->getUUID();
if (item->getIsFavorite() && typedViewsFilter(item_id, item))
{
LLFolderViewItem* folder_view_item = getItemByID(id);
if (!folder_view_item)
{
const LLUUID& parent_id = item->getParentUUID();
mRootContentIDs.emplace(item_id);
buildViewsTree(item_id, parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT);
}
}
}
}
mInventory->unlockDirectDescendentArrays(id);
}
void LLInventoryFavoritesItemsPanel::initRootContent()
{
findAndInitRootContent(gInventory.getRootFolderID()); // My Inventory
}
bool LLInventoryFavoritesItemsPanel::removeFavorite(const LLUUID& id, const LLInventoryObject* model_item)
{
std::set<LLUUID>::iterator found = mRootContentIDs.find(id);
if (found == mRootContentIDs.end())
{
return false;
}
mRootContentIDs.erase(found);
// This item is in root's content, remove item's UI.
LLFolderViewItem* view_item = getItemByID(id);
if (view_item)
{
LLFolderViewFolder* parent = view_item->getParentFolder();
LLFolderViewModelItemInventory* viewmodel_item = static_cast<LLFolderViewModelItemInventory*>(view_item->getViewModelItem());
if (viewmodel_item)
{
removeItemID(viewmodel_item->getUUID());
}
view_item->destroyView();
if (parent)
{
parent->getViewModelItem()->dirtyDescendantsFilter();
LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(parent->getViewModelItem());
if (viewmodel_folder)
{
updateFolderLabel(viewmodel_folder->getUUID());
}
if (view_item->isFavorite())
{
parent->updateHasFavorites(false); // favorite was removed
}
}
}
return true;
}
void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, const LLInventoryObject* model_item)
{
if (!model_item && !getItemByID(id))
{
// remove operation, but item is not in panel already
return;
}
bool handled = false;
if (mask & (LLInventoryObserver::UPDATE_FAVORITE |
LLInventoryObserver::STRUCTURE |
LLInventoryObserver::ADD |
LLInventoryObserver::REMOVE))
{
// specifically exlude links and not get_is_favorite(model_item)
if (model_item && model_item->getIsFavorite())
{
LLFolderViewItem* view_item = getItemByID(id);
if (!view_item)
{
const LLViewerInventoryCategory* cat = dynamic_cast<const LLViewerInventoryCategory*>(model_item);
if (cat)
{
// New favorite folder
if (cat->getPreferredType() != LLFolderType::FT_TRASH)
{
// If any descendants were in the list, remove them
// Todo: Consider implementing and checking hasFavorites to save on search
LLFavoritesCollector is_favorite;
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
gInventory.collectDescendentsIf(id, cat_array, item_array, false, is_favorite);
for (LLInventoryModel::cat_array_t::const_iterator it = cat_array.begin(); it != cat_array.end(); ++it)
{
removeFavorite((*it)->getUUID(), *it);
}
for (LLInventoryModel::item_array_t::const_iterator it = item_array.begin(); it != item_array.end(); ++it)
{
removeFavorite((*it)->getUUID(), *it);
}
LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID());
if (!folder_view_item)
{
const LLUUID& parent_id = cat->getParentUUID();
mRootContentIDs.emplace(cat->getUUID());
buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_ONE_FOLDER);
}
}
}
else
{
// New favorite item
if (model_item->getIsFavorite() && typedViewsFilter(id, model_item))
{
const LLUUID& parent_id = model_item->getParentUUID();
mRootContentIDs.emplace(id);
buildViewsTree(id, parent_id, model_item, NULL, mFolderRoot.get(), BUILD_ONE_FOLDER);
}
}
handled = true;
}
}
else
{
handled = removeFavorite(id, model_item);
if (handled)
{
const LLViewerInventoryCategory* cat = dynamic_cast<const LLViewerInventoryCategory*>(model_item);
// Todo: Consider implementing and checking hasFavorites to save on search
if (cat)
{
// re-add any favorited children
mBuildRootQueue.emplace_back(id);
}
}
}
}
if (!handled)
{
LLInventoryPanel::itemChanged(id, mask, model_item);
}
}
/************************************************************************/
/* LLInventorySingleFolderPanel */
/************************************************************************/
static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)

View File

@ -269,7 +269,8 @@ public:
bool reset_filter = false);
static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
virtual void removeItemID(const LLUUID& id);
virtual bool isInRootContent(const LLUUID& id, LLFolderViewItem* view_item) { return false; }
LLFolderViewItem* getItemByID(const LLUUID& id);
LLFolderViewFolder* getFolderByID(const LLUUID& id);
void setSelectionByID(const LLUUID& obj_id, bool take_keyboard_focus);
@ -353,6 +354,8 @@ public:
protected:
// Builds the UI. Call this once the inventory is usable.
void initializeViews(F64 max_time);
virtual void initRootContent();
virtual void findAndInitRootContent(const LLUUID& root_id) {};
// Specific inventory colors
static bool sColorSetInitialized;
@ -390,7 +393,7 @@ protected:
virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge);
boost::function<void(const std::deque<LLFolderViewItem*>& items, bool user_action)> mSelectionCallback;
private:
// buildViewsTree does not include some checks and is meant
// for recursive use, use buildNewViews() for first call
LLFolderViewItem* buildViewsTree(const LLUUID& id,
@ -413,6 +416,8 @@ private:
EViewsInitializationState mViewsInitialized; // Whether views have been generated
F64 mBuildViewsEndTime; // Stop building views past this timestamp
std::deque<LLUUID> mBuildViewsQueue;
std::deque<LLUUID> mBuildRootQueue;
};

View File

@ -1417,7 +1417,7 @@ bool LLMaterialEditor::saveIfNeeded()
}
std::string res_desc = buildMaterialDescription();
createInventoryItem(buffer, mMaterialName, res_desc, local_permissions);
createInventoryItem(buffer, mMaterialName, res_desc, local_permissions, mUploadFolder);
// We do not update floater with uploaded asset yet, so just close it.
closeFloater();
@ -1587,12 +1587,12 @@ private:
std::string mNewName;
};
void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions)
void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder)
{
// gen a new uuid for this asset
LLTransactionID tid;
tid.generate(); // timestamp-based randomization + uniquification
LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL);
LLUUID parent = upload_folder.isNull() ? gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) : upload_folder;
const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ?
LLPointer<LLObjectsMaterialItemCallback> cb = new LLObjectsMaterialItemCallback(permissions, buffer, name);
@ -1906,7 +1906,11 @@ static void pack_textures(
}
}
void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model_in, S32 index)
void LLMaterialEditor::uploadMaterialFromModel(
const std::string& filename,
tinygltf::Model& model_in,
S32 index,
const LLUUID& dest)
{
if (index < 0 || !LLMaterialEditor::capabilitiesAvailable())
{
@ -1929,12 +1933,13 @@ void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tiny
// This uses 'filename' to make sure multiple bulk uploads work
// instead of fighting for a single instance.
LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor", LLSD().with("filename", filename).with("index", LLSD::Integer(index)));
me->mUploadFolder = dest;
me->loadMaterial(model_in, filename, index, false);
me->saveIfNeeded();
}
void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index)
void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index, const LLUUID& dest_folder)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
@ -2434,17 +2439,17 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati
return;
}
createInventoryItem(str.str(), new_name, std::string(), permissions);
createInventoryItem(str.str(), new_name, std::string(), permissions, LLUUID::null);
}
const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k);
void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k, const LLUUID& dest);
void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename, S32 index, bool open_floater)
{
if (index == model_in.materials.size())
{
// bulk upload all the things
upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL, true);
upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL, true, LLUUID::null);
return;
}
@ -2857,10 +2862,10 @@ void LLMaterialEditor::setFromGltfMetaData(const std::string& filename, const ti
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
// </FS:Zi>
void LLMaterialEditor::importMaterial()
void LLMaterialEditor::importMaterial(const LLUUID dest_folder)
{
LLFilePickerReplyThread::startPicker(
[](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
[dest_folder](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
{
if (LLAppViewer::instance()->quitRequested())
{
@ -2870,7 +2875,7 @@ void LLMaterialEditor::importMaterial()
{
if (filenames.size() > 0)
{
LLMaterialEditor::loadMaterialFromFile(filenames[0], -1);
LLMaterialEditor::loadMaterialFromFile(filenames[0], -1, dest_folder);
}
}
catch (std::bad_alloc&)
@ -3563,6 +3568,7 @@ void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, con
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
mUploadFolder,
false,
cb,
failed_upload));

View File

@ -94,7 +94,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void setFromGltfMetaData(const std::string& filename, const tinygltf::Model& model, S32 index);
// open a file dialog and select a gltf/glb file for import
static void importMaterial();
static void importMaterial(const LLUUID dest_folder = LLUUID::null);
// for live preview, apply current material to currently selected object
void applyToSelection();
@ -105,8 +105,11 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void loadAsset() override;
// @index if -1 and file contains more than one material,
// will promt to select specific one
static void uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model, S32 index);
static void loadMaterialFromFile(const std::string& filename, S32 index = -1);
static void uploadMaterialFromModel(const std::string& filename,
tinygltf::Model& model,
S32 index,
const LLUUID& dest_folder_id = LLUUID::null);
static void loadMaterialFromFile(const std::string& filename, S32 index = -1, const LLUUID& dest_folder = LLUUID::null);
void onSelectionChanged(); // live overrides selection changes
@ -134,8 +137,6 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void onClickSave();
void getGLTFModel(tinygltf::Model& model);
std::string getEncodedAsset();
bool decodeAsset(const std::vector<char>& buffer);
@ -239,7 +240,7 @@ private:
static void saveObjectsMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions, const LLUUID& object_id /* = LLUUID::null */, const LLUUID& item /* = LLUUID::null */);
static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id);
static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions);
static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder);
void setFromGLTFMaterial(LLGLTFMaterial* mat);
bool setFromSelection();
@ -249,6 +250,7 @@ private:
friend class LLMaterialFilePicker;
LLUUID mAssetID;
LLUUID mUploadFolder;
LLTextureCtrl* mBaseColorTextureCtrl;
LLTextureCtrl* mMetallicTextureCtrl;

View File

@ -772,8 +772,12 @@ public:
};
void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
const char * const stage, const std::string & model_name)
void log_upload_error(
LLCore::HttpStatus status,
const LLSD& content,
const char * const stage,
const std::string & model_name,
const std::vector<std::string> & texture_filenames)
{
// Add notification popup.
LLSD args;
@ -831,6 +835,20 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
error_num++;
}
}
if (err.has("TextureIndex"))
{
S32 texture_index = err["TextureIndex"].asInteger();
if (texture_index < texture_filenames.size())
{
args["MESSAGE"] = message + "\n" + texture_filenames[texture_index];
}
else
{
llassert(false); // figure out why or how texture wasn't in the list
args["MESSAGE"] = message + llformat("\nTexture index: %d", texture_index);
}
}
}
else
{
@ -2579,7 +2597,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
const std::string & upload_url, bool do_upload,
const std::string & upload_url, LLUUID destination_folder_id, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer,
LLHandle<LLWholeModelUploadObserver> upload_observer)
: LLThread("mesh upload"),
@ -2587,6 +2605,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mDiscarded(false),
mDoUpload(do_upload),
mWholeModelUploadURL(upload_url),
mDestinationFolderId(destination_folder_id),
mFeeObserverHandle(fee_observer),
mUploadObserverHandle(upload_observer)
{
@ -2703,13 +2722,21 @@ LLSD llsd_from_file(std::string filename)
return result;
}
void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>& texture_list_dest, bool include_textures)
{
LLSD result;
LLSD res;
if (mDestinationFolderId.isNull())
{
result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT);
result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
}
else
{
result["folder_id"] = mDestinationFolderId;
result["texture_folder_id"] = mDestinationFolderId;
}
result["asset_type"] = "mesh";
result["inventory_type"] = "object";
result["description"] = "(No Description)";
@ -2852,7 +2879,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
if (!upload_file.isNull() && upload_file->getDataSize())
if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid())
{
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
@ -2866,6 +2893,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
texture_index[texture] = texture_num;
std::string str = texture_str.str();
res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
// store indexes for error handling;
texture_list_dest.push_back(material.mDiffuseMapFilename);
texture_num++;
}
@ -3130,7 +3159,8 @@ void LLMeshUploadThread::doWholeModelUpload()
LL_DEBUGS(LOG_MESH) << "Hull generation completed." << LL_ENDL;
mModelData = LLSD::emptyMap();
wholeModelToLLSD(mModelData, true);
mTextureFiles.clear();
wholeModelToLLSD(mModelData, mTextureFiles, true);
LLSD body = mModelData["asset_resources"];
dump_llsd_to_file(body, make_dump_name("whole_model_body_", dump_num));
@ -3183,7 +3213,8 @@ void LLMeshUploadThread::requestWholeModelFee()
generateHulls();
mModelData = LLSD::emptyMap();
wholeModelToLLSD(mModelData, false);
mTextureFiles.clear();
wholeModelToLLSD(mModelData, mTextureFiles, false);
dump_llsd_to_file(mModelData, make_dump_name("whole_model_fee_request_", dump_num));
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
mHttpPolicyClass,
@ -3249,7 +3280,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
body["error"] = LLSD::emptyMap();
body["error"]["message"] = reason;
body["error"]["identifier"] = "NetworkError"; // from asset-upload/upload_util.py
log_upload_error(status, body, "upload", mModelData["name"].asString());
log_upload_error(status, body, "upload", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@ -3284,7 +3315,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
else
{
LL_WARNS(LOG_MESH) << "Upload failed. Not in expected 'complete' state." << LL_ENDL;
log_upload_error(status, body, "upload", mModelData["name"].asString());
log_upload_error(status, body, "upload", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@ -3309,7 +3340,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
body["error"] = LLSD::emptyMap();
body["error"]["message"] = reason;
body["error"]["identifier"] = "NetworkError"; // from asset-upload/upload_util.py
log_upload_error(status, body, "fee", mModelData["name"].asString());
log_upload_error(status, body, "fee", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@ -3342,7 +3373,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
else
{
LL_WARNS(LOG_MESH) << "Fee request failed. Not in expected 'upload' state." << LL_ENDL;
log_upload_error(status, body, "fee", mModelData["name"].asString());
log_upload_error(status, body, "fee", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@ -5176,12 +5207,12 @@ LLUUID LLMeshRepoThread::getCreatorFromHeader(const LLUUID& mesh_id)
void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
std::string upload_url, bool do_upload,
std::string upload_url, const LLUUID& destination_folder_id, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
{
LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures,
upload_skin, upload_joints, lock_scale_if_joint_position,
upload_url, do_upload, fee_observer, upload_observer);
upload_url, destination_folder_id, do_upload, fee_observer, upload_observer);
mUploadWaitList.push_back(thread);
}

View File

@ -665,10 +665,13 @@ public:
LLHost mHost;
std::string mWholeModelFeeCapability;
std::string mWholeModelUploadURL;
LLUUID mDestinationFolderId;
LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
const std::string & upload_url, bool do_upload = true,
const std::string & upload_url,
const LLUUID destination_folder_id = LLUUID::null,
bool do_upload = true,
LLHandle<LLWholeModelFeeObserver> fee_observer = (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
~LLMeshUploadThread();
@ -684,7 +687,7 @@ public:
void doWholeModelUpload();
void requestWholeModelFee();
void wholeModelToLLSD(LLSD& dest, bool include_textures);
void wholeModelToLLSD(LLSD& dest, std::vector<std::string>& texture_list_dest, bool include_textures);
void decomposeMeshMatrix(LLMatrix4& transformation,
LLVector3& result_pos,
@ -705,6 +708,7 @@ private:
bool mDoUpload; // if false only model data will be requested, otherwise the model will be uploaded
LLSD mModelData;
std::vector<std::string> mTextureFiles;
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
@ -830,7 +834,9 @@ public:
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
std::string upload_url, bool do_upload = true,
std::string upload_url,
const LLUUID& destination_folder_id = LLUUID::null,
bool do_upload = true,
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));

View File

@ -3228,7 +3228,7 @@ void LLModelPreview::updateStatusMessages()
if (lod != lod_high)
{
if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
if (total_submeshes[lod] && total_submeshes[lod] > total_submeshes[lod_high])
{ //number of submeshes is different
message = "mesh_status_submesh_mismatch";
upload_status[lod] = 2;
@ -4431,7 +4431,6 @@ bool LLModelPreview::render()
fmp->setViewOptionEnabled("show_skin_weight", show_skin_weight);
}
}
//if (this) return TRUE;
if (upload_skin && !has_skin_weights)
{ //can't upload skin weights if model has no skin weights

View File

@ -88,9 +88,16 @@ LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p)
mItemsInRow(p.items_in_row),
mRowPanWidthFactor(p.row_panel_width_factor),
mGalleryWidthFactor(p.gallery_width_factor),
mTextureSelected(NULL)
mTextureSelected(NULL),
mSortMenu(nullptr)
{
updateGalleryWidth();
LLControlVariable* ctrl = gSavedSettings.getControl("InventoryFavoritesColorText");
if (ctrl)
{
mSavedSettingInvFavColor = ctrl->getSignal()->connect(boost::bind(&LLOutfitGallery::handleInvFavColorChange, this));
}
}
LLOutfitGallery::Params::Params()
@ -421,19 +428,28 @@ void LLOutfitGallery::updateRowsIfNeeded()
bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2)
{
static LLCachedControl<bool> outfit_gallery_sort_by_name(gSavedSettings, "OutfitGallerySortByName");
if(outfit_gallery_sort_by_name ||
((item1->isDefaultImage() && item2->isDefaultImage()) || (!item1->isDefaultImage() && !item2->isDefaultImage())))
static LLCachedControl<S32> sort_by_name(gSavedSettings, "OutfitGallerySortOrder", 0);
switch (sort_by_name())
{
std::string name1 = item1->getItemName();
std::string name2 = item2->getItemName();
case 2:
if (item1->isFavorite() != item2->isFavorite())
{
return item1->isFavorite();
}
break;
case 1:
if (item1->isDefaultImage() != item2->isDefaultImage())
{
return item2->isDefaultImage();
}
break;
default:
break;
}
return (LLStringUtil::compareDict(name1, name2) < 0);
}
else
{
return item2->isDefaultImage();
}
std::string name1 = item1->getItemName();
std::string name2 = item2->getItemName();
return (LLStringUtil::compareDict(name1, name2) < 0);
}
void LLOutfitGallery::reArrangeRows(S32 row_diff)
@ -476,6 +492,20 @@ void LLOutfitGallery::updateGalleryWidth()
mGalleryWidth = mGalleryWidthFactor * mItemsInRow - mItemHorizontalGap;
}
void LLOutfitGallery::handleInvFavColorChange()
{
for (outfit_map_t::iterator iter = mOutfitMap.begin();
iter != mOutfitMap.end();
++iter)
{
if (!iter->second) continue;
LLOutfitGalleryItem* item = (LLOutfitGalleryItem*)iter->second;
// refresh font color
item->setOutfitFavorite(item->isFavorite());
}
}
LLPanel* LLOutfitGallery::addLastRow()
{
mRowCount++;
@ -627,7 +657,7 @@ void LLOutfitGallery::removeFromLastRow(LLOutfitGalleryItem* item)
mItemPanels.pop_back();
}
LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID outfit_id)
LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID outfit_id, bool is_favorite)
{
LLOutfitGalleryItem::Params giparams;
LLOutfitGalleryItem* gitem = LLUICtrlFactory::create<LLOutfitGalleryItem>(giparams);
@ -636,6 +666,7 @@ LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID
gitem->setFollowsLeft();
gitem->setFollowsTop();
gitem->setOutfitName(name);
gitem->setOutfitFavorite(is_favorite);
gitem->setUUID(outfit_id);
gitem->setGallery(this);
return gitem;
@ -793,8 +824,7 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if (!cat) return;
std::string name = cat->getName();
LLOutfitGalleryItem* item = buildGalleryItem(name, cat_id);
LLOutfitGalleryItem* item = buildGalleryItem(cat->getName(), cat_id, cat->getIsFavorite());
mOutfitMap.insert(LLOutfitGallery::outfit_map_value_t(cat_id, item));
item->setRightMouseDownCallback(boost::bind(&LLOutfitListBase::outfitRightClickCallBack, this,
_1, _2, _3, cat_id));
@ -863,6 +893,7 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat,
if (item)
{
item->setOutfitName(name);
item->setOutfitFavorite(cat->getIsFavorite());
}
}
}
@ -943,6 +974,10 @@ LLOutfitListGearMenuBase* LLOutfitGallery::createGearMenu()
static LLDefaultChildRegistry::Register<LLOutfitGalleryItem> r("outfit_gallery_item");
bool LLOutfitGalleryItem::sColorSetInitialized = false;
LLUIColor LLOutfitGalleryItem::sDefaultTextColor;
LLUIColor LLOutfitGalleryItem::sDefaultFavoriteColor;
LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
: LLPanel(p),
mGallery(nullptr),
@ -954,6 +989,12 @@ LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
mUUID(LLUUID())
{
buildFromFile("panel_outfit_gallery_item.xml");
if (!sColorSetInitialized)
{
sDefaultTextColor = LLUIColorTable::instance().getColor("White", LLColor4::white);
sDefaultFavoriteColor = LLUIColorTable::instance().getColor("InventoryFavoriteColor", LLColor4::white);
sColorSetInitialized = true;
}
}
LLOutfitGalleryItem::~LLOutfitGalleryItem()
@ -1000,6 +1041,19 @@ void LLOutfitGalleryItem::draw()
gl_draw_scaled_image(interior.mLeft - 1, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
}
static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true);
if(mFavorite && draw_star())
{
const S32 HPAD = 3;
const S32 VPAD = 6; // includes padding for text and for the image
const S32 image_size = 14;
static LLPointer<LLUIImage> fav_img = LLRender2D::getInstance()->getUIImage("Inv_Favorite_Star_Full");
const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
gl_draw_scaled_image(
border.getWidth() - image_size - HPAD, image_size + VPAD + mOutfitNameText->getRect().getHeight(),
image_size, image_size, fav_img->getImage(), UI_VERTEX_COLOR % alpha);
}
}
void LLOutfitGalleryItem::setOutfitName(std::string name)
@ -1009,18 +1063,28 @@ void LLOutfitGalleryItem::setOutfitName(std::string name)
mOutfitName = name;
}
void LLOutfitGalleryItem::setOutfitFavorite(bool is_favorite)
{
mFavorite = is_favorite;
static LLCachedControl<bool> use_color(gSavedSettings, "InventoryFavoritesColorText");
mOutfitNameText->setReadOnlyColor((mFavorite && use_color()) ? sDefaultFavoriteColor : sDefaultTextColor);
}
void LLOutfitGalleryItem::setOutfitWorn(bool value)
{
mWorn = value;
LLStringUtil::format_map_t worn_string_args;
std::string worn_string = getString("worn_string", worn_string_args);
LLUIColor text_color = LLUIColorTable::instance().getColor("White", LLColor4::white);
mOutfitWornText->setReadOnlyColor(text_color);
mOutfitNameText->setReadOnlyColor(text_color);
mOutfitWornText->setReadOnlyColor(sDefaultTextColor.get());
mOutfitNameText->setReadOnlyColor(sDefaultTextColor.get());
mOutfitWornText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
mOutfitNameText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
mOutfitWornText->setValue(value ? worn_string : "");
mOutfitNameText->setText(mOutfitName); // refresh LLTextViewModel to pick up font changes
static LLCachedControl<bool> use_color(gSavedSettings, "InventoryFavoritesColorText");
mOutfitNameText->setReadOnlyColor((mFavorite && use_color()) ? sDefaultFavoriteColor : sDefaultTextColor);
}
void LLOutfitGalleryItem::setSelected(bool value)
@ -1172,6 +1236,7 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));
registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));
registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id));
registrar.add("Outfit.Favorite", boost::bind(&LLOutfitGalleryContextMenu::onFavorite, this, selected_id));
registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));
enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));
@ -1210,24 +1275,11 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
bool have_selection = getSelectedOutfitID().notNull();
mMenu->setItemVisible("expand", false);
mMenu->setItemVisible("collapse", false);
mMenu->setItemVisible("thumbnail", have_selection);
mMenu->setItemVisible("sort_folders_by_name", true);
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
}
void LLOutfitGalleryGearMenu::onChangeSortOrder()
{
bool sort_by_name = !gSavedSettings.getBOOL("OutfitGallerySortByName");
gSavedSettings.setBOOL("OutfitGallerySortByName", sort_by_name);
LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
if (gallery)
{
gallery->reArrangeRows();
}
}
bool LLOutfitGalleryGearMenu::hasDefaultImage()
{
LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
@ -1344,6 +1396,15 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)
}
}
LLToggleableMenu* LLOutfitGallery::getSortMenu()
{
if (!mSortMenu)
{
mSortMenu = new LLOutfitGallerySortMenu(this);
}
return mSortMenu->getMenu();
}
LLUUID LLOutfitGallery::getPhotoAssetId(const LLUUID& outfit_id)
{
outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
@ -1359,3 +1420,84 @@ LLUUID LLOutfitGallery::getDefaultPhoto()
return LLUUID();
}
//////////////////// LLOutfitGallerySortMenu ////////////////////
LLOutfitGallerySortMenu::LLOutfitGallerySortMenu(LLOutfitListBase* parent_panel)
: mPanelHandle(parent_panel->getHandle())
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("Sort.OnSort", boost::bind(&LLOutfitGallerySortMenu::onSort, this, _2));
enable_registrar.add("Sort.OnEnable", boost::bind(&LLOutfitGallerySortMenu::onEnable, this, _2));
mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_outfit_gallery_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
llassert(mMenu);
}
LLToggleableMenu* LLOutfitGallerySortMenu::getMenu()
{
return mMenu;
}
void LLOutfitGallerySortMenu::updateItemsVisibility()
{
onUpdateItemsVisibility();
}
void LLOutfitGallerySortMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
}
bool LLOutfitGallerySortMenu::onEnable(LLSD::String param)
{
static LLCachedControl<S32> sort_order(gSavedSettings, "OutfitGallerySortOrder", 0);
if ("favorites_to_top" == param)
{
return sort_order == 2;
}
else if ("images_to_top" == param)
{
return sort_order == 1;
}
else if ("by_name" == param)
{
return sort_order == 0;
}
return false;
}
void LLOutfitGallerySortMenu::onSort(LLSD::String param)
{
S32 sort_order = gSavedSettings.getS32("OutfitGallerySortOrder");
S32 new_sort_order = 0;
if ("favorites_to_top" == param)
{
new_sort_order = 2;
}
else if ("images_to_top" == param)
{
new_sort_order = 1;
}
else if ("by_name" == param)
{
new_sort_order = 0;
}
if (sort_order == new_sort_order)
{
new_sort_order = sort_order ? 0 : 1;
}
gSavedSettings.setS32("OutfitGallerySortOrder", new_sort_order);
LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mPanelHandle.get());
if (gallery)
{
gallery->reArrangeRows();
}
}

View File

@ -42,11 +42,13 @@ class LLOutfitGalleryItem;
class LLOutfitListGearMenuBase;
class LLOutfitGalleryGearMenu;
class LLOutfitGalleryContextMenu;
class LLOutfitGallerySortMenu;
class LLOutfitGallery : public LLOutfitListBase
{
public:
friend class LLOutfitGalleryGearMenu;
friend class LLOutfitGallerySortMenu;
friend class LLOutfitGalleryContextMenu;
friend class LLUpdateGalleryOnPhotoLinked;
@ -102,10 +104,12 @@ public:
/*virtual*/ bool getHasExpandableFolders() { return false; }
/*virtual*/ void onChangeSortOrder(const LLSD& userdata) {};
void updateMessageVisibility();
bool hasDefaultImage(const LLUUID& outfit_cat_id);
void refreshOutfit(const LLUUID& category_id);
virtual LLToggleableMenu* getSortMenu();
protected:
/*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
@ -133,8 +137,9 @@ private:
void reArrangeRows(S32 row_diff = 0);
void updateRowsIfNeeded();
void updateGalleryWidth();
void handleInvFavColorChange();
LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id);
LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id, bool is_favorite);
LLOutfitGalleryItem* getSelectedItem() const;
LLOutfitGalleryItem* getItem(const LLUUID& id) const;
@ -176,6 +181,7 @@ private:
int mGalleryWidthFactor;
LLListContextMenu* mOutfitGalleryMenu;
LLOutfitGallerySortMenu* mSortMenu;
typedef std::map<LLUUID, LLOutfitGalleryItem*> outfit_map_t;
typedef outfit_map_t::value_type outfit_map_value_t;
@ -187,6 +193,8 @@ private:
LLInventoryCategoriesObserver* mOutfitsObserver;
boost::signals2::connection mSavedSettingInvFavColor;
};
class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
{
@ -213,8 +221,6 @@ public:
protected:
/*virtual*/ void onUpdateItemsVisibility();
private:
/*virtual*/ void onChangeSortOrder();
bool hasDefaultImage();
};
@ -243,6 +249,7 @@ public:
bool setImageAssetId(LLUUID asset_id);
LLUUID getImageAssetId();
void setOutfitName(std::string name);
void setOutfitFavorite(bool is_favorite);
void setOutfitWorn(bool value);
void setSelected(bool value);
void setUUID(const LLUUID &outfit_id) {mUUID = outfit_id;}
@ -250,6 +257,7 @@ public:
std::string getItemName() {return mOutfitName;}
bool isDefaultImage() {return mDefaultImage;}
bool isFavorite() { return mFavorite; }
bool isHidden() {return mHidden;}
void setHidden(bool hidden) {mHidden = hidden;}
@ -267,7 +275,29 @@ private:
bool mWorn;
bool mDefaultImage;
bool mHidden;
bool mFavorite;
std::string mOutfitName;
static bool sColorSetInitialized;
static LLUIColor sDefaultTextColor;
static LLUIColor sDefaultFavoriteColor;
};
class LLOutfitGallerySortMenu
{
public:
LLOutfitGallerySortMenu(LLOutfitListBase* parent_panel);
LLToggleableMenu* getMenu();
void updateItemsVisibility();
private:
void onUpdateItemsVisibility();
bool onEnable(LLSD::String param);
void onSort(LLSD::String param);
LLToggleableMenu* mMenu;
LLHandle<LLPanel> mPanelHandle;
};
#endif // LL_LLOUTFITGALLERYCTRL_H

View File

@ -35,6 +35,7 @@
#include "llaccordionctrltab.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llappviewer.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llinspecttexture.h"
@ -45,6 +46,7 @@
#include "lloutfitobserver.h"
#include "lltoggleablemenu.h"
#include "lltransutil.h"
#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
@ -61,14 +63,24 @@
static bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y);
static const LLOutfitTabNameComparator OUTFIT_TAB_NAME_COMPARATOR;
static const LLOutfitTabFavComparator OUTFIT_TAB_FAV_COMPARATOR;
/*virtual*/
bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const
{
std::string name1 = tab1->getTitle();
std::string name2 = tab2->getTitle();
return (LLStringUtil::compareDict(tab1->getTitle(), tab2->getTitle()) < 0);
}
return (LLStringUtil::compareDict(name1, name2) < 0);
bool LLOutfitTabFavComparator::compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const
{
LLOutfitAccordionCtrlTab* taba = (LLOutfitAccordionCtrlTab*)tab1;
LLOutfitAccordionCtrlTab* tabb = (LLOutfitAccordionCtrlTab*)tab2;
if (taba->getFavorite() != tabb->getFavorite())
{
return taba->getFavorite();
}
return (LLStringUtil::compareDict(tab1->getTitle(), tab2->getTitle()) < 0);
}
struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLOutfitAccordionCtrlTab::Params>
@ -88,6 +100,9 @@ const outfit_accordion_tab_params& get_accordion_tab_params()
{
initialized = true;
LLOutfitAccordionCtrlTab::sFavoriteIcon = LLUI::getUIImage("Inv_Favorite_Star_Full");
LLOutfitAccordionCtrlTab::sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255));
LLXMLNodePtr xmlNode;
if (LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode))
{
@ -111,11 +126,20 @@ LLOutfitsList::LLOutfitsList()
, mAccordion(NULL)
, mListCommands(NULL)
, mItemSelected(false)
, mSortMenu(nullptr)
{
LLControlVariable* ctrl = gSavedSettings.getControl("InventoryFavoritesColorText");
if (ctrl)
{
mSavedSettingInvFavColor = ctrl->getSignal()->connect(boost::bind(&LLOutfitsList::handleInvFavColorChange, this));
}
}
LLOutfitsList::~LLOutfitsList()
{
delete mSortMenu;
mSavedSettingInvFavColor.disconnect();
mGearMenuConnection.disconnect();
}
bool LLOutfitsList::postBuild()
@ -123,9 +147,25 @@ bool LLOutfitsList::postBuild()
mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
initComparator();
return LLOutfitListBase::postBuild();
}
void LLOutfitsList::initComparator()
{
S32 mode = gSavedSettings.getS32("OutfitListSortOrder");
if (mode == 0)
{
mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
}
else
{
mAccordion->setComparator(&OUTFIT_TAB_FAV_COMPARATOR);
}
sortOutfits();
}
//virtual
void LLOutfitsList::onOpen(const LLSD& info)
{
@ -163,6 +203,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
tab->setName(name);
tab->setTitle(name);
tab->setFavorite(cat->getIsFavorite());
// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
tab->setDisplayChildren(false);
@ -196,8 +237,9 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));
// force showing list items that don't match current filter(EXT-7158)
list->setForceShowingUnmatchedItems(true);
// Depending on settings, force showing list items that don't match current filter(EXT-7158)
static LLCachedControl<bool> list_filter(gSavedSettings, "OutfitListFilterFullList");
list->setForceShowingUnmatchedItems(list_filter(), false);
// Setting list commit callback to monitor currently selected wearable item.
list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1));
@ -315,13 +357,11 @@ void LLOutfitsList::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id)
{
if (mOutfitsMap[prev_id])
{
mOutfitsMap[prev_id]->setTitleFontStyle("NORMAL");
mOutfitsMap[prev_id]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
((LLOutfitAccordionCtrlTab*)mOutfitsMap[prev_id])->setOutfitSelected(false);
}
if (mOutfitsMap[base_id])
{
mOutfitsMap[base_id]->setTitleFontStyle("BOLD");
mOutfitsMap[base_id]->setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));
((LLOutfitAccordionCtrlTab*)mOutfitsMap[base_id])->setOutfitSelected(true);
}
}
@ -383,6 +423,11 @@ void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid)
}
}
void LLOutfitListBase::onAction(const LLSD& userdata)
{
performAction(userdata.asString());
}
// virtual
bool LLOutfitListBase::isActionEnabled(const LLSD& userdata)
{
@ -495,11 +540,12 @@ void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, st
if (outfits_iter != mOutfitsMap.end())
{
// Update tab name with the new category name.
LLAccordionCtrlTab* tab = outfits_iter->second;
LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*) outfits_iter->second;
if (tab)
{
tab->setName(name);
tab->setTitle(name);
tab->setFavorite(cat->getIsFavorite());
}
}
}
@ -591,7 +637,7 @@ void LLOutfitsList::onFilterSubStringChanged(const std::string& new_string, cons
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
if (list)
{
list->setFilterSubString(new_string, tab->getDisplayChildren());
list->setFilterSubString(new_string, true);
}
if (old_string.empty())
@ -808,6 +854,75 @@ void LLOutfitsList::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUI
}
}
void LLOutfitsList::handleInvFavColorChange()
{
for (outfits_map_t::iterator iter = mOutfitsMap.begin();
iter != mOutfitsMap.end();
++iter)
{
if (!iter->second) continue;
LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*)iter->second;
// refresh font color
tab->setFavorite(tab->getFavorite());
}
}
void LLOutfitsList::onChangeSortOrder(const LLSD& userdata)
{
std::string sort_data = userdata.asString();
if (sort_data == "favorites_to_top")
{
// at the moment this is a toggle
S32 val = gSavedSettings.getS32("OutfitListSortOrder");
gSavedSettings.setS32("OutfitListSortOrder", (val ? 0 : 1));
initComparator();
}
else if (sort_data == "show_entire_outfit")
{
bool new_val = !gSavedSettings.getBOOL("OutfitListFilterFullList");
gSavedSettings.setBOOL("OutfitListFilterFullList", new_val);
if (!getFilterSubString().empty())
{
for (outfits_map_t::value_type& outfit : mOutfitsMap)
{
LLAccordionCtrlTab* tab = outfit.second;
const LLUUID& category_id = outfit.first;
if (!tab) continue;
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
if (list)
{
list->setForceRefresh(true);
list->setForceShowingUnmatchedItems(new_val, tab->getDisplayChildren());
}
applyFilterToTab(category_id, tab, getFilterSubString());
}
mAccordion->arrange();
}
}
}
LLToggleableMenu* LLOutfitsList::getSortMenu()
{
if (!mSortMenu)
{
mSortMenu = new LLOutfitListSortMenu(this);
}
return mSortMenu->getMenu();
}
void LLOutfitsList::updateMenuItemsVisibility()
{
if (mSortMenu)
{
mSortMenu->updateItemsVisibility();
}
LLOutfitListBase::updateMenuItemsVisibility();
}
LLOutfitListGearMenuBase* LLOutfitsList::createGearMenu()
{
return new LLOutfitListGearMenu(this);
@ -825,11 +940,11 @@ bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
LLOutfitListBase::LLOutfitListBase()
: LLPanelAppearanceTab()
, mIsInitialized(false)
, mGearMenu(nullptr)
, mAvatarComplexityLabel(NULL) // <FS:Ansariel> Show avatar complexity in appearance floater
{
mCategoriesObserver = new LLInventoryCategoriesObserver();
mOutfitMenu = new LLOutfitContextMenu(this);
//mGearMenu = createGearMenu();
}
LLOutfitListBase::~LLOutfitListBase()
@ -892,6 +1007,10 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id)
void LLOutfitListBase::refreshList(const LLUUID& category_id)
{
if (LLAppViewer::instance()->quitRequested())
{
return;
}
bool wasNull = mRefreshListState.CategoryUUID.isNull();
mRefreshListState.CategoryUUID.setNull();
@ -987,8 +1106,18 @@ void LLOutfitListBase::onIdle(void* userdata)
void LLOutfitListBase::onIdleRefreshList()
{
if (mRefreshListState.CategoryUUID.isNull())
if (LLAppViewer::instance()->quitRequested())
{
mRefreshListState.CategoryUUID.setNull();
gIdleCallbacks.deleteFunction(onIdle, this);
return;
}
if (mRefreshListState.CategoryUUID.isNull())
{
LL_WARNS() << "Called onIdleRefreshList without id" << LL_ENDL;
gIdleCallbacks.deleteFunction(onIdle, this);
return;
}
const F64 MAX_TIME = 0.05f;
F64 curent_time = LLTimer::getTotalSeconds();
@ -1143,15 +1272,8 @@ void LLOutfitListBase::ChangeOutfitSelection(LLWearableItemsList* list, const LL
bool LLOutfitListBase::postBuild()
{
mGearMenu = createGearMenu();
// <FS:Ansariel> Show avatar complexity in appearance floater
mAvatarComplexityLabel = getChild<LLTextBox>("avatar_complexity_label");
LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenuBase::updateItemsVisibility, mGearMenu));
menu_gear_btn->setMenu(mGearMenu->getMenu());
return true;
}
@ -1165,6 +1287,20 @@ void LLOutfitListBase::expandAllFolders()
onExpandAllFolders();
}
void LLOutfitListBase::updateMenuItemsVisibility()
{
mGearMenu->updateItemsVisibility();
}
LLToggleableMenu* LLOutfitListBase::getGearMenu()
{
if (!mGearMenu)
{
mGearMenu = createGearMenu();
}
return mGearMenu->getMenu();
};
void LLOutfitListBase::deselectOutfit(const LLUUID& category_id)
{
// Reset selection if the outfit is selected.
@ -1202,6 +1338,7 @@ LLContextMenu* LLOutfitContextMenu::createMenu()
registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id));
registrar.add("Outfit.Favorite", boost::bind(&LLOutfitContextMenu::onFavorite, this, selected_id));
registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));
@ -1252,6 +1389,16 @@ bool LLOutfitContextMenu::onVisible(LLSD::String param)
{
return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
}
else if ("favorites_add" == param)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id);
return cat && !cat->getIsFavorite();
}
else if ("favorites_remove" == param)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id);
return cat && cat->getIsFavorite();
}
return true;
}
@ -1276,6 +1423,14 @@ void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id)
}
}
void LLOutfitContextMenu::onFavorite(const LLUUID& outfit_cat_id)
{
if (outfit_cat_id.notNull())
{
toggle_favorite(outfit_cat_id);
}
}
void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id)
{
if (outfit_cat_id.notNull())
@ -1306,14 +1461,13 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenuBase::onRename, this));
registrar.add("Gear.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenuBase::onCreate, this, _2));
registrar.add("Gear.Collapse", boost::bind(&LLOutfitListBase::onCollapseAllFolders, mOutfitList));
registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList));
registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this));
registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));
registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
registrar.add("Gear.Favorite", boost::bind(&LLOutfitListGearMenuBase::onFavorite, this));
registrar.add("Gear.SortByImage", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenuBase::onVisible, this, _2));
@ -1447,6 +1601,16 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
{
return false;
}
else if ("favorites_add" == param)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
return cat && !cat->getIsFavorite();
}
else if ("favorites_remove" == param)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
return cat && cat->getIsFavorite();
}
return true;
}
@ -1458,6 +1622,12 @@ void LLOutfitListGearMenuBase::onThumbnail()
LLFloaterReg::showInstance("change_item_thumbnail", data);
}
void LLOutfitListGearMenuBase::onFavorite()
{
const LLUUID& selected_outfit_id = getSelectedOutfitID();
toggle_favorite(selected_outfit_id);
}
void LLOutfitListGearMenuBase::onChangeSortOrder()
{
@ -1473,13 +1643,79 @@ LLOutfitListGearMenu::~LLOutfitListGearMenu()
void LLOutfitListGearMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
mMenu->setItemVisible("expand", true);
mMenu->setItemVisible("collapse", true);
mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull());
mMenu->setItemVisible("favorite", getSelectedOutfitID().notNull());
mMenu->setItemVisible("sepatator3", false);
mMenu->setItemVisible("sort_folders_by_name", false);
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
}
//////////////////// LLOutfitListSortMenu ////////////////////
LLOutfitListSortMenu::LLOutfitListSortMenu(LLOutfitListBase* parent_panel)
: mPanelHandle(parent_panel->getHandle())
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("Sort.Collapse", boost::bind(&LLOutfitListBase::onCollapseAllFolders, parent_panel));
registrar.add("Sort.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, parent_panel));
registrar.add("Sort.OnSort", boost::bind(&LLOutfitListBase::onChangeSortOrder, parent_panel, _2));
enable_registrar.add("Sort.OnEnable", boost::bind(&LLOutfitListSortMenu::onEnable, this, _2));
mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_outfit_list_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
llassert(mMenu);
}
LLToggleableMenu* LLOutfitListSortMenu::getMenu()
{
return mMenu;
}
void LLOutfitListSortMenu::updateItemsVisibility()
{
onUpdateItemsVisibility();
}
void LLOutfitListSortMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
mMenu->setItemVisible("expand", true);
mMenu->setItemVisible("collapse", true);
mMenu->setItemVisible("sort_favorites_to_top", true);
mMenu->setItemVisible("show_entire_outfit_in_search", true);
}
bool LLOutfitListSortMenu::onEnable(LLSD::String param)
{
if ("favorites_to_top" == param)
{
static LLCachedControl<S32> sort_order(gSavedSettings, "OutfitListSortOrder", 0);
return sort_order == 1;
}
else if ("show_entire_outfit" == param)
{
static LLCachedControl<bool> filter_mode(gSavedSettings, "OutfitListFilterFullList", 0);
return filter_mode;
}
return false;
}
//////////////////// LLOutfitAccordionCtrlTab ////////////////////
LLUIImage* LLOutfitAccordionCtrlTab::sFavoriteIcon;
LLUIColor LLOutfitAccordionCtrlTab::sFgColor;
void LLOutfitAccordionCtrlTab::draw()
{
LLAccordionCtrlTab::draw();
drawFavoriteIcon();
}
bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
{
// <FS:Ansariel> Make thumbnail tooltip work properly
@ -1513,4 +1749,54 @@ bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
return LLAccordionCtrlTab::handleToolTip(x, y, mask);
}
void LLOutfitAccordionCtrlTab::setFavorite(bool is_favorite)
{
mIsFavorite = is_favorite;
updateTitleColor();
}
void LLOutfitAccordionCtrlTab::setOutfitSelected(bool val)
{
mIsSelected = val;
setTitleFontStyle(mIsSelected ? "BOLD" : "NORMAL");
updateTitleColor();
}
void LLOutfitAccordionCtrlTab::updateTitleColor()
{
static LLUICachedControl<bool> highlight_color("InventoryFavoritesColorText", true);
if (mIsFavorite && highlight_color())
{
setTitleColor(LLUIColorTable::instance().getColor("InventoryFavoriteColor"));
}
else if (mIsSelected)
{
setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));
}
else
{
setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
}
}
void LLOutfitAccordionCtrlTab::drawFavoriteIcon()
{
if (!mIsFavorite)
{
return;
}
static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true);
if (!draw_star)
{
return;
}
const S32 PAD = 2;
const S32 image_size = 18;
gl_draw_scaled_image(
getRect().getWidth() - image_size - PAD, getRect().getHeight() - image_size - PAD,
image_size, image_size, sFavoriteIcon->getImage(), sFgColor);
}
// EOF

View File

@ -41,6 +41,7 @@
class LLAccordionCtrlTab;
class LLInventoryCategoriesObserver;
class LLOutfitListGearMenuBase;
class LLOutfitListSortMenuBase;
class LLWearableItemsList;
class LLListContextMenu;
class LLTextBox;
@ -62,6 +63,17 @@ public:
/*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
};
class LLOutfitTabFavComparator : public LLAccordionCtrl::LLTabComparator
{
LOG_CLASS(LLOutfitTabFavComparator);
public:
LLOutfitTabFavComparator() {};
virtual ~LLOutfitTabFavComparator() {};
/*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
};
class LLOutfitListBase : public LLPanelAppearanceTab
{
public:
@ -94,6 +106,7 @@ public:
boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
void outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
void onAction(const LLSD& userdata);
virtual bool isActionEnabled(const LLSD& userdata);
virtual void performAction(std::string action);
virtual bool hasItemSelected() = 0;
@ -111,6 +124,12 @@ public:
virtual bool getHasExpandableFolders() = 0;
virtual void onChangeSortOrder(const LLSD& userdata) = 0;
virtual void updateMenuItemsVisibility();
virtual LLToggleableMenu* getGearMenu();
virtual bool getTrashMenuVisible() { return true; };
// <FS:Ansariel> Show avatar complexity in appearance floater
void updateAvatarComplexity(U32 complexity);
@ -144,6 +163,7 @@ protected:
selection_change_signal_t mSelectionChangeSignal;
LLListContextMenu* mOutfitMenu;
LLOutfitListGearMenuBase* mGearMenu;
boost::signals2::connection mGearMenuConnection;
// <FS:Ansariel> Show avatar complexity in appearance floater
LLTextBox* mAvatarComplexityLabel;
};
@ -162,7 +182,6 @@ protected:
/* virtual */ LLContextMenu* createMenu();
bool onEnable(LLSD::String param);
bool onVisible(LLSD::String param);
static void editOutfit();
@ -170,6 +189,7 @@ protected:
static void renameOutfit(const LLUUID& outfit_cat_id);
void onThumbnail(const LLUUID &outfit_cat_id);
void onFavorite(const LLUUID& outfit_cat_id);
void onSave(const LLUUID &outfit_cat_id);
private:
@ -189,6 +209,7 @@ public:
protected:
virtual void onUpdateItemsVisibility();
virtual void onThumbnail();
virtual void onFavorite();
virtual void onChangeSortOrder();
const LLUUID& getSelectedOutfitID();
@ -209,6 +230,23 @@ private:
bool onVisible(LLSD::String param);
};
class LLOutfitListSortMenu
{
public:
LLOutfitListSortMenu(LLOutfitListBase* parent_panel);
LLToggleableMenu* getMenu();
void updateItemsVisibility();
private:
void onUpdateItemsVisibility();
bool onEnable(LLSD::String param);
LLToggleableMenu* mMenu;
LLHandle<LLPanel> mPanelHandle;
};
class LLOutfitListGearMenu : public LLOutfitListGearMenuBase
{
public:
@ -228,8 +266,16 @@ public:
Params() : cat_id("cat_id") {}
};
virtual void draw();
virtual bool handleToolTip(S32 x, S32 y, MASK mask);
void setFavorite(bool is_favorite);
bool getFavorite() const { return mIsFavorite; }
void setOutfitSelected(bool val);
static LLUIImage* sFavoriteIcon;
static LLUIColor sFgColor;
protected:
LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p)
: LLAccordionCtrlTab(p),
@ -237,7 +283,12 @@ public:
{}
friend class LLUICtrlFactory;
void updateTitleColor();
void drawFavoriteIcon();
LLUUID mFolderID;
bool mIsFavorite = false;
bool mIsSelected = false;
};
/**
* @class LLOutfitsList
@ -256,6 +307,7 @@ public:
virtual ~LLOutfitsList();
/*virtual*/ bool postBuild();
void initComparator();
/*virtual*/ void onOpen(const LLSD& info);
@ -294,6 +346,10 @@ public:
/*virtual*/ bool getHasExpandableFolders() { return true; }
/*virtual*/ void onChangeSortOrder(const LLSD& userdata);
virtual LLToggleableMenu* getSortMenu();
void updateMenuItemsVisibility();
protected:
LLOutfitListGearMenuBase* createGearMenu();
@ -365,6 +421,8 @@ private:
static void onOutfitRename(const LLSD& notification, const LLSD& response);
void handleInvFavColorChange();
// <FS:Ansariel> FIRE-22484: Double-click wear in outfits list
void onDoubleClick(LLWearableItemsList* list);
@ -385,13 +443,15 @@ private:
// Used to monitor COF changes for updating items worn state. See EXT-8636.
uuid_vec_t mCOFLinkedItems;
//LLOutfitListGearMenu* mGearMenu;
LLOutfitListSortMenu* mSortMenu;
//bool mIsInitialized;
/**
* True if there is a selection inside currently selected outfit
*/
bool mItemSelected;
boost::signals2::connection mSavedSettingInvFavColor;
};
#endif //LL_LLOUTFITSLIST_H

View File

@ -29,6 +29,8 @@
#include "llpanel.h"
class LLToggleableMenu;
class LLPanelAppearanceTab : public LLPanel
{
public:
@ -47,6 +49,11 @@ public:
const std::string& getFilterSubString() { return mFilterSubString; }
virtual void updateMenuItemsVisibility() = 0;
virtual LLToggleableMenu* getGearMenu() = 0;
virtual LLToggleableMenu* getSortMenu() = 0;
virtual bool getTrashMenuVisible() = 0;
protected:
/**

View File

@ -527,10 +527,6 @@ LLPanelFace::~LLPanelFace()
void LLPanelFace::onVisibilityChange(bool new_visibility)
{
if (new_visibility)
{
gAgent.showLatestFeatureNotification("gltf");
}
LLPanel::onVisibilityChange(new_visibility);
}

View File

@ -90,6 +90,7 @@ bool LLPanelGroupCreate::postBuild()
mInsignia = getChild<LLTextureCtrl>("insignia", true);
mInsignia->setAllowLocalTexture(false);
mInsignia->setBakeTextureEnabled(false);
mInsignia->setCanApplyImmediately(false);
return true;

View File

@ -262,6 +262,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)
{
mInsignia->setCommitCallback(onCommitAny, this);
mInsignia->setAllowLocalTexture(false);
mInsignia->setBakeTextureEnabled(false);
}
mFounderName = getChild<LLTextBox>("founder_name");

View File

@ -77,6 +77,7 @@ const std::string FILTERS_FILENAME("filters.xml");
const std::string ALL_ITEMS("All Items");
const std::string RECENT_ITEMS("Recent Items");
const std::string WORN_ITEMS("Worn Items");
const std::string FAVORITES("Favorites");
static LLPanelInjector<LLPanelMainInventory> t_inventory("panel_main_inventory");
@ -313,6 +314,17 @@ bool LLPanelMainInventory::postBuild()
}
// </FS:Ansariel>
}
LLInventoryPanel* favorites_panel = getChild<LLInventoryPanel>(FAVORITES);
if (favorites_panel)
{
favorites_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER));
LLInventoryFilter& favorites_filter = favorites_panel->getFilter();
favorites_filter.setEmptyLookupMessage("InventoryNoMatchingFavorites");
favorites_filter.markDefault();
favorites_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, favorites_panel, _1, _2));
}
// <FS:Ansariel> Only if we actually have it!
//mSearchTypeCombo = getChild<LLComboBox>("search_type");
mSearchTypeCombo = findChild<LLComboBox>("search_type");
@ -716,7 +728,8 @@ void LLPanelMainInventory::doCreate(const LLSD& userdata)
}
else
{
menu_create_inventory_item(getPanel(), NULL, userdata);
selectAllItemsPanel();
menu_create_inventory_item(mAllItemsPanel, NULL, userdata);
}
}

Some files were not shown because too many files have changed in this diff Show More