summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2025-05-18 21:21:44 +0300
committerGitHub <noreply@github.com>2025-05-18 21:21:44 +0300
commitfdeef47611e7496ff5d5fb8f37e3b1f5240a8b14 (patch)
treeaab4b1664b82e8f49395fe3e3a75619724c9fd1c
parent3569cc1993dc03637b29fcd77fe5b01b6ea372fb (diff)
parenta9c75d8136f9df6885e525ea8f2b383fe4a22593 (diff)
Merge branch 'geenz/gltf-mesh-import' into marchcat/gltf-mesh-texture-import
-rw-r--r--indra/cmake/Python.cmake2
-rw-r--r--indra/llmessage/llproxy.cpp1
-rw-r--r--indra/llui/llchatmentionhelper.cpp9
-rw-r--r--indra/llui/llfolderviewitem.h2
-rw-r--r--indra/llui/llurlentry.cpp5
-rw-r--r--indra/llui/llurlentry.h3
-rw-r--r--indra/llui/llurlregistry.cpp27
-rw-r--r--indra/llui/llurlregistry.h2
-rw-r--r--indra/llwebrtc/llwebrtc.cpp8
-rw-r--r--indra/newview/app_settings/settings.xml35
-rw-r--r--indra/newview/gltf/llgltfloader.cpp9
-rw-r--r--indra/newview/llavatarlistitem.cpp3
-rw-r--r--indra/newview/llconversationview.cpp9
-rw-r--r--indra/newview/llconversationview.h3
-rw-r--r--indra/newview/llfloaterimcontainer.cpp4
-rw-r--r--indra/newview/llfloaterimcontainer.h2
-rw-r--r--indra/newview/llimview.cpp33
-rw-r--r--indra/newview/llinventorybridge.cpp81
-rw-r--r--indra/newview/llinventorybridge.h2
-rw-r--r--indra/newview/llinventoryfunctions.cpp74
-rw-r--r--indra/newview/llinventoryfunctions.h4
-rw-r--r--indra/newview/llinventorygallery.cpp32
-rw-r--r--indra/newview/llmeshrepository.cpp8
-rw-r--r--indra/newview/llmodelpreview.cpp18
-rw-r--r--indra/newview/lloutfitgallery.cpp11
-rw-r--r--indra/newview/lloutfitslist.cpp77
-rw-r--r--indra/newview/lloutfitslist.h2
-rw-r--r--indra/newview/llvieweraudio.cpp1
-rw-r--r--indra/newview/llviewercamera.cpp19
-rw-r--r--indra/newview/llviewercamera.h4
-rw-r--r--indra/newview/llviewermessage.cpp2
-rwxr-xr-xindra/newview/llviewerregion.cpp6
-rw-r--r--indra/newview/llviewerregion.h1
-rw-r--r--indra/newview/skins/default/colors.xml5
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_chat.xml25
35 files changed, 373 insertions, 156 deletions
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index da5d2ef22c..7cce190f6a 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -13,7 +13,7 @@ elseif (WINDOWS)
foreach(hive HKEY_CURRENT_USER HKEY_LOCAL_MACHINE)
# prefer more recent Python versions to older ones, if multiple versions
# are installed
- foreach(pyver 3.12 3.11 3.10 3.9 3.8 3.7)
+ foreach(pyver 3.13 3.12 3.11 3.10 3.9 3.8 3.7)
list(APPEND regpaths "[${hive}\\SOFTWARE\\Python\\PythonCore\\${pyver}\\InstallPath]")
endforeach()
endforeach()
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index d04ca52ad6..d79d5c3a11 100644
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -506,6 +506,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
rv = apr_socket_recv(apr_socket, datain, &maxinlen);
if (rv != APR_SUCCESS)
{
+ // if rv == 70060 it's WSAETIMEDOUT
char buf[MAX_STRING];
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL;
ll_apr_warn_status(rv);
diff --git a/indra/llui/llchatmentionhelper.cpp b/indra/llui/llchatmentionhelper.cpp
index f7769b2cbe..5745389a58 100644
--- a/indra/llui/llchatmentionhelper.cpp
+++ b/indra/llui/llchatmentionhelper.cpp
@@ -98,7 +98,14 @@ void LLChatMentionHelper::showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local
LLRect rect = av_picker_floater->getRect();
rect.setLeftTopAndSize(floater_x, floater_y + rect.getHeight(), rect.getWidth(), rect.getHeight());
av_picker_floater->setRect(rect);
- av_picker_floater->openFloater(LLSD().with("av_name", av_name));
+ if (av_picker_floater->isShown())
+ {
+ av_picker_floater->onOpen(LLSD().with("av_name", av_name));
+ }
+ else
+ {
+ av_picker_floater->openFloater(LLSD().with("av_name", av_name));
+ }
}
void LLChatMentionHelper::hideHelper(const LLUICtrl* ctrl)
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 234d0dc7f9..2ee018a90a 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -154,7 +154,7 @@ protected:
virtual bool isHighlightActive();
virtual bool isFadeItem();
virtual bool isFlashing() { return false; }
- virtual void setFlashState(bool) { }
+ virtual void setFlashState(bool, bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
const LLFontGL* getLabelFont();
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 7218211a44..bcd13b7f0b 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -630,6 +630,11 @@ LLUUID LLUrlEntryAgent::getID(const std::string &string) const
return LLUUID(getIDStringFromUrl(string));
}
+bool LLUrlEntryAgent::isAgentID(const std::string& url) const
+{
+ return sAgentID == getID(url);
+}
+
std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
{
// return a tooltip corresponding to the URL type instead of the generic one
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 740e99acfd..6e7d2fc80f 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -103,6 +103,7 @@ public:
virtual bool getSkipProfileIcon(const std::string& string) const { return false; }
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
+ virtual bool isAgentID(const std::string& url) const { return false; }
bool isLinkDisabled() const;
@@ -232,6 +233,8 @@ public:
/*virtual*/ LLStyle::Params getStyle(const std::string &url) const;
/*virtual*/ LLUUID getID(const std::string &string) const;
+ bool isAgentID(const std::string& url) const;
+
LLStyle::EUnderlineLink getUnderline(const std::string& string) const;
protected:
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 02d88c83fb..cb101d325d 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -327,3 +327,30 @@ void LLUrlRegistry::setKeybindingHandler(LLKeyBindingToStringHandler* handler)
LLUrlEntryKeybinding *entry = (LLUrlEntryKeybinding*)mUrlEntryKeybinding;
entry->setHandler(handler);
}
+
+bool LLUrlRegistry::containsAgentMention(const std::string& text)
+{
+ // avoid costly regexes if there is clearly no URL in the text
+ if (!stringHasUrl(text))
+ {
+ return false;
+ }
+
+ try
+ {
+ boost::sregex_iterator it(text.begin(), text.end(), mUrlEntryAgentMention->getPattern());
+ boost::sregex_iterator end;
+ for (; it != end; ++it)
+ {
+ if (mUrlEntryAgentMention->isAgentID(it->str()))
+ {
+ return true;
+ }
+ }
+ }
+ catch (boost::regex_error&)
+ {
+ LL_INFOS() << "Regex error for: " << text << LL_ENDL;
+ }
+ return false;
+}
diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h
index b9502f4592..592e422487 100644
--- a/indra/llui/llurlregistry.h
+++ b/indra/llui/llurlregistry.h
@@ -92,6 +92,8 @@ public:
// Set handler for url registry to be capable of parsing and populating keybindings
void setKeybindingHandler(LLKeyBindingToStringHandler* handler);
+ bool containsAgentMention(const std::string& text);
+
private:
std::vector<LLUrlEntryBase *> mUrlEntry;
LLUrlEntryBase* mUrlEntryTrusted;
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index 0daa767766..a306600f85 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -430,9 +430,7 @@ void ll_set_device_module_capture_device(rtc::scoped_refptr<webrtc::AudioDeviceM
// has it at 0
device_module->SetRecordingDevice(device + 1);
#endif
- device_module->SetStereoRecording(false);
device_module->InitMicrophone();
- device_module->InitRecording();
}
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
@@ -473,6 +471,8 @@ void LLWebRTCImpl::setCaptureDevice(const std::string &id)
ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice);
if (recording)
{
+ mPeerDeviceModule->SetStereoRecording(false);
+ mPeerDeviceModule->InitRecording();
mPeerDeviceModule->StartRecording();
}
});
@@ -494,9 +494,7 @@ void ll_set_device_module_render_device(rtc::scoped_refptr<webrtc::AudioDeviceMo
#else
device_module->SetPlayoutDevice(device + 1);
#endif
- device_module->SetStereoPlayout(true);
device_module->InitSpeaker();
- device_module->InitPlayout();
}
void LLWebRTCImpl::setRenderDevice(const std::string &id)
@@ -540,6 +538,8 @@ void LLWebRTCImpl::setRenderDevice(const std::string &id)
ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice);
if (playing)
{
+ mPeerDeviceModule->SetStereoPlayout(true);
+ mPeerDeviceModule->InitPlayout();
mPeerDeviceModule->StartPlayout();
}
});
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 1025c9299d..8cfe4f3d97 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6361,6 +6361,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>PlaySoundChatMention</key>
+ <map>
+ <key>Comment</key>
+ <string>Plays a sound when got mentioned in a chat</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>PluginAttachDebuggerToPlugins</key>
<map>
<key>Comment</key>
@@ -7830,7 +7841,7 @@
<key>RenderMinFreeMainMemoryThreshold</key>
<map>
<key>Comment</key>
- <string>Minimum of available physical memory in MB before textures get scaled down</string>
+ <string>If available free physical memory is below this value textures get agresively scaled down</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
@@ -12395,6 +12406,28 @@
<key>Value</key>
<string>2ca849ba-2885-4bc3-90ef-d4987a5b983a</string>
</map>
+ <key>UISndChatMention</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for chat mention(uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>03e77cb5-592c-5b33-d271-2e46497c3fb3</string>
+ </map>
+ <key>UISndChatPing</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for chat ping(uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>7dd36df6-2624-5438-f988-fdf8588a0ad9</string>
+ </map>
<key>UISndClick</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index c63459b172..11c1b05ee5 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -267,22 +267,18 @@ bool LLGLTFLoader::parseMeshes()
mTransform *= coord_system_rotation;
transformation = mTransform;
-
// adjust the transformation to compensate for mesh normalization
LLVector3 mesh_scale_vector;
LLVector3 mesh_translation_vector;
pModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
-
LLMatrix4 mesh_translation;
mesh_translation.setTranslation(mesh_translation_vector);
mesh_translation *= transformation;
transformation = mesh_translation;
-
LLMatrix4 mesh_scale;
mesh_scale.initScale(mesh_scale_vector);
mesh_scale *= transformation;
transformation = mesh_scale;
-
if (transformation.determinant() < 0)
{ // negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: "
@@ -467,21 +463,18 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
for (U32 i = 0; i < vertices.size(); i++)
{
LLVolumeFace::VertexData vert;
-
if (i == 0 || vertices[i].position.x > max.x)
max.x = vertices[i].position.x;
if (i == 0 || vertices[i].position.y > max.y)
max.y = vertices[i].position.y;
if (i == 0 || vertices[i].position.z > max.z)
max.z = vertices[i].position.z;
-
if (i == 0 || vertices[i].position.x < min.x)
min.x = vertices[i].position.x;
if (i == 0 || vertices[i].position.y < min.y)
min.y = vertices[i].position.y;
if (i == 0 || vertices[i].position.z < min.z)
min.z = vertices[i].position.z;
-
LLVector4a position = LLVector4a(vertices[i].position.x, vertices[i].position.y, vertices[i].position.z);
LLVector4a normal = LLVector4a(vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z);
vert.setPosition(position);
@@ -489,7 +482,6 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
vert.mTexCoord = LLVector2(vertices[i].uv0.x, vertices[i].uv0.y);
faceVertices.push_back(vert);
-
// create list of weights that influence this vertex
LLModel::weight_list weight_list;
@@ -500,7 +492,6 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
-
std::vector<LLModel::JointWeight> wght;
F32 total = 0.f;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 6ef45ed160..80c7f8beca 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -325,7 +325,8 @@ void LLAvatarListItem::setShowProfileBtn(bool show)
void LLAvatarListItem::showSpeakingIndicator(bool visible)
{
- if (mSpeakingIndicator)
+ // used only to hide indicator to not contradict with SpeakingIndicatorManager functionality
+ if (mSpeakingIndicator && !visible)
{
mSpeakingIndicator->setIsActiveChannel(visible);
mSpeakingIndicator->setShowParticipantsSpeaking(visible);
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index a1f627c8cc..0e0ab236d6 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -86,7 +86,8 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes
mHasArrow(true),
mIsInActiveVoiceChannel(false),
mFlashStateOn(false),
- mFlashStarted(false)
+ mFlashStarted(false),
+ mIsAltFlashColor(false)
{
mFlashTimer = new LLFlashTimer();
mAreChildrenInited = true; // inventory only
@@ -157,7 +158,7 @@ void LLConversationViewSession::destroyView()
LLFolderViewFolder::destroyView();
}
-void LLConversationViewSession::setFlashState(bool flash_state)
+void LLConversationViewSession::setFlashState(bool flash_state, bool alternate_color)
{
if (flash_state && !mFlashStateOn)
{
@@ -170,6 +171,7 @@ void LLConversationViewSession::setFlashState(bool flash_state)
mFlashStateOn = flash_state;
mFlashStarted = false;
+ mIsAltFlashColor = mFlashStateOn && (alternate_color || mIsAltFlashColor);
mFlashTimer->stopFlashing();
}
@@ -288,7 +290,8 @@ void LLConversationViewSession::draw()
startFlashing();
// draw highlight for selected items
- drawHighlight(show_context, true, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
+ static LLUIColor alt_color = LLUIColorTable::instance().getColor("MentionFlashBgColor", DEFAULT_WHITE);
+ drawHighlight(show_context, true, sHighlightBgColor, mIsAltFlashColor ? alt_color : sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
// Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap.
bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this) || isOpen();
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 8eb6392121..a6d240ed84 100644
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -90,7 +90,7 @@ public:
virtual void refresh();
- /*virtual*/ void setFlashState(bool flash_state);
+ /*virtual*/ void setFlashState(bool flash_state, bool alternate_color = false);
void setHighlightState(bool hihglight_state);
LLFloater* getSessionFloater();
@@ -111,6 +111,7 @@ private:
LLFlashTimer* mFlashTimer;
bool mFlashStateOn;
bool mFlashStarted;
+ bool mIsAltFlashColor;
bool mCollapsedMode;
bool mHasArrow;
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index e4b14d8df6..72d4d30dcf 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -2302,14 +2302,14 @@ bool LLFloaterIMContainer::isConversationLoggingAllowed()
return gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
}
-void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id, bool is_flashes)
+void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id, bool is_flashes, bool alternate_color)
{
//Finds the conversation line item to flash using the session_id
LLConversationViewSession * widget = dynamic_cast<LLConversationViewSession *>(get_ptr_in_map(mConversationsWidgets,session_id));
if (widget)
{
- widget->setFlashState(is_flashes);
+ widget->setFlashState(is_flashes, alternate_color);
}
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index e5486e67da..30eed8be36 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -208,7 +208,7 @@ public:
void reSelectConversation();
void updateSpeakBtnState();
static bool isConversationLoggingAllowed();
- void flashConversationItemWidget(const LLUUID& session_id, bool is_flashes);
+ void flashConversationItemWidget(const LLUUID& session_id, bool is_flashes, bool alternate_color = false);
void highlightConversationItemWidget(const LLUUID& session_id, bool is_highlighted);
bool isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget);
boost::signals2::connection mMicroChangedSignal;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 474b7b66d7..f0f25089fa 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -71,6 +71,7 @@
#include "llviewerregion.h"
#include "llcorehttputil.h"
#include "lluiusage.h"
+#include "llurlregistry.h"
#include <array>
@@ -197,6 +198,9 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
bool store_dnd_message = false; // flag storage of a dnd message
bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus();
+ bool contains_mention = LLUrlRegistry::getInstance()->containsAgentMention(msg["message"].asString());
+ static LLCachedControl<bool> play_snd_mention_pref(gSavedSettings, "PlaySoundChatMention", false);
+ bool play_snd_mention = contains_mention && play_snd_mention_pref && (msg["source_type"].asInteger() != CHAT_SOURCE_OBJECT);
if (!LLFloater::isVisible(im_box) || im_box->isMinimized())
{
conversations_floater_status = CLOSED;
@@ -230,7 +234,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
else
{
user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
- if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM")))
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM")) && !play_snd_mention)
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -241,7 +245,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
if (LLAvatarTracker::instance().isBuddy(participant_id))
{
user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
- if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM")))
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM")) && !play_snd_mention)
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -249,7 +253,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
else
{
user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
- if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM")))
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM")) && !play_snd_mention)
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -258,7 +262,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
else if (session->isAdHocSessionType())
{
user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
- if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM")))
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM")) && !play_snd_mention)
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -266,11 +270,18 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
else if(session->isGroupSessionType())
{
user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
- if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM")))
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM")) && !play_snd_mention)
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
+ if (play_snd_mention)
+ {
+ if (!gAgent.isDoNotDisturb())
+ {
+ make_ui_sound("UISndChatMention");
+ }
+ }
// actions:
@@ -323,7 +334,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
if ("openconversations" == user_preferences
|| ON_TOP == conversations_floater_status
|| ("toast" == user_preferences && ON_TOP != conversations_floater_status)
- || ("flash" == user_preferences && (CLOSED == conversations_floater_status
+ || (("flash" == user_preferences || contains_mention) && (CLOSED == conversations_floater_status
|| NOT_ON_TOP == conversations_floater_status))
|| is_dnd_msg)
{
@@ -343,7 +354,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
}
else
{
- im_box->flashConversationItemWidget(session_id, true);
+ im_box->flashConversationItemWidget(session_id, true, contains_mention);
}
}
}
@@ -3249,7 +3260,11 @@ void LLIMMgr::addMessage(
//Play sound for new conversations
if (!skip_message && !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation")))
{
- make_ui_sound("UISndNewIncomingIMSession");
+ static LLCachedControl<bool> play_snd_mention_pref(gSavedSettings, "PlaySoundChatMention", false);
+ if (!play_snd_mention_pref || !LLUrlRegistry::getInstance()->containsAgentMention(msg))
+ {
+ make_ui_sound("UISndNewIncomingIMSession");
+ }
}
}
else
@@ -3269,7 +3284,7 @@ void LLIMMgr::addMessage(
{
LLFloaterReg::showInstance("im_container");
LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")->
- flashConversationItemWidget(new_session_id, true);
+ flashConversationItemWidget(new_session_id, true, LLUrlRegistry::getInstance()->containsAgentMention(msg));
}
}
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 4018a89c5a..f9e9049119 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -2664,6 +2664,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
//
bool is_movable = true;
+ bool create_outfit = false;
if (is_movable && (marketplacelistings_id == cat_id))
{
@@ -2708,7 +2709,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory");
is_movable = false;
}
- else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ create_outfit = true;
+ }
+ else if (can_move_to_my_outfits_as_subfolder(model, inv_cat))
{
is_movable = true;
}
@@ -2742,7 +2748,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
is_movable = false;
tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
}
- else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ create_outfit = true;
+ }
+ else if (can_move_to_my_outfits_as_subfolder(model, inv_cat))
{
is_movable = true;
}
@@ -2943,7 +2954,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
if (mUUID == my_outifts_id)
{
EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id);
- if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT)
+ if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit)
{
LLInvFVBridge::changeCategoryParent(
model,
@@ -2967,15 +2978,19 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
{
case MY_OUTFITS_NO:
// Moning from outside outfits into outfits
- if (dest_res == MY_OUTFITS_SUBFOLDER)
+ if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit)
{
// turn it into outfit
- dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb);
+ dropToMyOutfitsSubfolder(inv_cat, mUUID, cb);
}
else
{
- // or link it?
- dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb);
+ LLInvFVBridge::changeCategoryParent(
+ model,
+ (LLViewerInventoryCategory*)inv_cat,
+ mUUID,
+ move_is_into_trash);
+ if (cb) cb->fire(inv_cat->getUUID());
}
break;
case MY_OUTFITS_SUBFOLDER:
@@ -4094,7 +4109,6 @@ void LLFolderBridge::perform_pasteFromClipboard()
LLInventoryObject *obj = model->getObject(item_id);
if (obj)
{
-
if (move_is_into_lost_and_found)
{
if (LLAssetType::AT_CATEGORY == obj->getType())
@@ -4104,41 +4118,57 @@ void LLFolderBridge::perform_pasteFromClipboard()
}
if (move_is_into_outfit)
{
- if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit))
+ bool handled = false;
+ if (mUUID != my_outifts_id
+ && dest_folder->getPreferredType() == LLFolderType::FT_OUTFIT
+ && item
+ && can_move_to_outfit(item, move_is_into_current_outfit))
{
- // todo: this is going to create dupplicate folders?
dropToOutfit(item, move_is_into_current_outfit, cb);
+ handled = true;
}
else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType())
{
- LLInventoryCategory* cat = model->getCategory(item_id);
+ LLViewerInventoryCategory* cat = model->getCategory(item_id);
U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
- if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear))
+ if (cat && can_move_to_my_outfits_as_outfit(model, cat, max_items_to_wear))
{
if (mUUID == my_outifts_id)
{
dropToMyOutfits(cat, cb);
+ handled = true;
}
- else if (move_is_into_my_outfits)
+ else
{
- EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id);
- if (res == MY_OUTFITS_SUBFOLDER)
+ EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id);
+ if (dest_res == MY_OUTFITS_SUBFOLDER)
{
// turn it into outfit
- dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_OUTFIT, cb);
+ dropToMyOutfitsSubfolder(cat, mUUID, cb);
+ handled = true;
+ }
+ }
+ }
+ if (!handled && cat && can_move_to_my_outfits_as_subfolder(model, cat))
+ {
+ EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id);
+ if (dest_res == MY_OUTFITS_SUBFOLDER || mUUID == my_outifts_id)
+ {
+ if (LLClipboard::instance().isCutMode())
+ {
+ changeCategoryParent(model, cat, parent_id, false);
}
else
{
- dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_NONE, cb);
+ copy_inventory_category(model, cat, parent_id);
}
+ if (cb) cb->fire(item_id);
+ handled = true;
}
}
- else
- {
- LLNotificationsUtil::add("MyOutfitsPasteFailed");
- }
}
- else
+
+ if (!handled)
{
LLNotificationsUtil::add("MyOutfitsPasteFailed");
}
@@ -4181,7 +4211,7 @@ void LLFolderBridge::perform_pasteFromClipboard()
// move_inventory_item() is not enough, as we have to update inventory locally too
if (LLAssetType::AT_CATEGORY == obj->getType())
{
- LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id);
+ LLViewerInventoryCategory* vicat = model->getCategory(item_id);
llassert(vicat);
if (vicat)
{
@@ -5478,12 +5508,11 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI
inv_cat->getThumbnailUUID());
}
-void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type, LLPointer<LLInventoryCallback> cb)
+void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLPointer<LLInventoryCallback> cb)
{
- const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel);
getInventoryModel()->createNewCategory(dest_id,
- preferred_type,
+ LLFolderType::FT_OUTFIT,
inv_cat->getName(),
func,
inv_cat->getThumbnailUUID());
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index a101c7368a..b7bdef9b21 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -369,7 +369,7 @@ protected:
void dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb = NULL);
void dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb = NULL);
void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb = NULL);
- void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLFolderType::EType preferred_type, LLPointer<LLInventoryCallback> cb = NULL);
+ void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLPointer<LLInventoryCallback> cb = NULL);
//--------------------------------------------------------------------
// Messy hacks for handling folder options
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 7fff88fba7..1077ce74ae 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -438,7 +438,13 @@ void copy_inventory_category(LLInventoryModel* model,
{
copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items);
};
- gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
+ LLFolderType::EType type = LLFolderType::FT_NONE;
+ if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+ {
+ // at the moment only permitting copy of outfits and normal folders
+ type = LLFolderType::FT_OUTFIT;
+ }
+ gInventory.createNewCategory(parent_id, type, cat->getName(), func, cat->getThumbnailUUID());
}
void copy_inventory_category(LLInventoryModel* model,
@@ -460,6 +466,25 @@ void copy_inventory_category(LLInventoryModel* model,
gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
}
+void copy_inventory_category(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& parent_id,
+ const LLUUID& root_copy_id,
+ bool move_no_copy_items,
+ LLPointer<LLInventoryCallback> callback)
+{
+ // Create the initial folder
+ inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID& new_id)
+ {
+ copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items);
+ if (callback)
+ {
+ callback.get()->fire(new_id);
+ }
+ };
+ gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
+}
+
void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id)
{
// Decrement the count in root_id since that one item won't be copied over
@@ -2314,7 +2339,7 @@ bool can_move_to_landmarks(LLInventoryItem* inv_item)
}
// Returns true if folder's content can be moved to Current Outfit or any outfit folder.
-bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
+bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
{
LLInventoryModel::cat_array_t *cats;
LLInventoryModel::item_array_t *items;
@@ -2353,6 +2378,51 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca
return true;
}
+bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth)
+{
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
+
+ if (items->size() > 0)
+ {
+ // subfolders don't allow items
+ return false;
+ }
+
+ if (inv_cat->getPreferredType() != LLFolderType::FT_NONE)
+ {
+ // only normal folders can become subfodlers
+ return false;
+ }
+
+ constexpr size_t MAX_CONTENT = 255;
+ if (cats->size() > MAX_CONTENT)
+ {
+ // don't allow massive folders
+ return false;
+ }
+
+ for (LLPointer<LLViewerInventoryCategory>& cat : *cats)
+ {
+ // outfits are valid to move, check non-outfit folders
+ if (cat->getPreferredType() != LLFolderType::FT_OUTFIT)
+ {
+ if (depth == 3)
+ {
+ // don't allow massive folders
+ return false;
+ }
+ if (!can_move_to_my_outfits_as_subfolder(model, cat, depth + 1))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
std::string get_localized_folder_name(LLUUID cat_uuid)
{
std::string localized_root_name;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 0ab045f2a0..b23f82a189 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -78,6 +78,7 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false);
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, inventory_func_type callback);
+void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, LLPointer<LLInventoryCallback> callback);
void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items);
@@ -112,7 +113,8 @@ std::string get_category_path(LLUUID cat_id);
bool can_move_to_outfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit);
bool can_move_to_landmarks(LLInventoryItem* inv_item);
-bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
+bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
+bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth = 0);
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);
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
index eb47af85fd..43d4edb069 100644
--- a/indra/newview/llinventorygallery.cpp
+++ b/indra/newview/llinventorygallery.cpp
@@ -65,7 +65,7 @@ const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value imm
bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link);
bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm);
void dropToMyOutfits(LLInventoryCategory* inv_cat);
-void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type);
+void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id);
class LLGalleryPanel: public LLPanel
{
@@ -3714,6 +3714,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
//
bool is_movable = true;
+ bool create_outfit = false;
if (is_movable && (marketplacelistings_id == cat_id))
{
@@ -3759,7 +3760,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory");
is_movable = false;
}
- else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ create_outfit = true;
+ }
+ else if (can_move_to_my_outfits_as_subfolder(model, inv_cat))
{
is_movable = true;
}
@@ -3793,7 +3799,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
is_movable = false;
tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
}
- else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ create_outfit = true;
+ }
+ else if (can_move_to_my_outfits_as_subfolder(model, inv_cat))
{
is_movable = true;
}
@@ -3928,7 +3939,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
if (dest_id == my_outifts_id)
{
EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id);
- if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT)
+ if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit)
{
gInventory.changeCategoryParent(
(LLViewerInventoryCategory*)inv_cat,
@@ -3950,14 +3961,17 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
{
case MY_OUTFITS_NO:
// Moning from outside outfits into outfits
- if (dest_res == MY_OUTFITS_SUBFOLDER)
+ if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit)
{
// turn it into outfit
- dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT);
+ dropToMyOutfitsSubfolder(inv_cat, dest_id);
}
else
{
- dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE);
+ gInventory.changeCategoryParent(
+ (LLViewerInventoryCategory*)inv_cat,
+ dest_id,
+ move_is_into_trash);
}
break;
case MY_OUTFITS_SUBFOLDER:
@@ -4136,10 +4150,10 @@ void dropToMyOutfits(LLInventoryCategory* inv_cat)
gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID());
}
-void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id, LLFolderType::EType preferred_type)
+void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id)
{
// Note: creation will take time, so passing folder id to callback is slightly unreliable,
// but so is collecting and passing descendants' ids
inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1);
- gInventory.createNewCategory(dest_id, preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID());
+ gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID());
}
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 851107b3be..e7e95034b2 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -5976,13 +5976,7 @@ bool LLMeshRepository::meshUploadEnabled()
bool LLMeshRepository::meshRezEnabled()
{
static LLCachedControl<bool> mesh_enabled(gSavedSettings, "MeshEnabled");
- LLViewerRegion *region = gAgent.getRegion();
- if(mesh_enabled &&
- region)
- {
- return region->meshRezEnabled();
- }
- return false;
+ return mesh_enabled;
}
// Threading: main thread only
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 14d23b73c9..7ccd299135 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2498,6 +2498,8 @@ void LLModelPreview::updateStatusMessages()
S32 phys_tris = 0;
S32 phys_hulls = 0;
S32 phys_points = 0;
+ S32 which_mode = 0;
+ S32 file_mode = 1;
//get the triangle count for the whole scene
for (LLModelLoader::scene::iterator iter = mScene[LLModel::LOD_PHYSICS].begin(), endIter = mScene[LLModel::LOD_PHYSICS].end(); iter != endIter; ++iter)
@@ -2619,18 +2621,16 @@ void LLModelPreview::updateStatusMessages()
fmp->childEnable("simplify_cancel");
fmp->childEnable("decompose_cancel");
}
- }
-
- LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo");
- S32 which_mode = 0;
- S32 file_mode = 1;
- if (iface)
- {
- which_mode = iface->getFirstSelectedIndex();
- file_mode = iface->getItemCount() - 1;
+ LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo");
+ if (iface)
+ {
+ which_mode = iface->getFirstSelectedIndex();
+ file_mode = iface->getItemCount() - 1;
+ }
}
+
if (which_mode == file_mode)
{
mFMP->childEnable("physics_file");
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index b1d5cd9e16..b84b0b3a8c 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -793,6 +793,17 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if (!cat) return;
+ if (!isOutfitFolder(cat))
+ {
+ // Assume a subfolder that contains or will contain outfits, track it
+ const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ mOutfitsObserver->addCategory(cat_id, [this, outfits]()
+ {
+ observerCallback(outfits);
+ });
+ return;
+ }
+
std::string name = cat->getName();
LLOutfitGalleryItem* item = buildGalleryItem(name, cat_id);
mOutfitMap.insert(LLOutfitGallery::outfit_map_value_t(cat_id, item));
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 9d8493549d..df53c66ec1 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -142,6 +142,17 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if (!cat) return;
+ if (!isOutfitFolder(cat))
+ {
+ // Assume a subfolder that contains or will contain outfits, track it
+ const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ mCategoriesObserver->addCategory(cat_id, [this, outfits]()
+ {
+ observerCallback(outfits);
+ });
+ return;
+ }
+
std::string name = cat->getName();
outfit_accordion_tab_params tab_params(get_accordion_tab_params());
@@ -819,49 +830,38 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id)
refreshList(category_id);
}
-class LLIsOutfitListFolder : public LLInventoryCollectFunctor
+bool LLOutfitListBase::isOutfitFolder(LLViewerInventoryCategory* cat) const
{
-public:
- LLIsOutfitListFolder()
+ if (!cat)
{
- mOutfitsId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ return false;
}
- virtual ~LLIsOutfitListFolder() {}
-
- bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override
+ if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)
{
- if (cat)
+ return true;
+ }
+ // assumes that folder is somewhere inside MyOutfits
+ if (cat->getPreferredType() == LLFolderType::FT_NONE)
+ {
+ LLViewerInventoryCategory* inv_cat = dynamic_cast<LLViewerInventoryCategory*>(cat);
+ if (inv_cat && inv_cat->getDescendentCount() > 3)
{
- if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
+ if (cats->empty() // protection against outfits inside
+ && items->size() > 3) // arbitrary, if doesn't have at least base parts, not an outfit
{
+ // For now assume this to be an old style outfit, not a subfolder
+ // but ideally no such 'outfits' should be left in My Outfits
+ // Todo: stop counting FT_NONE as outfits,
+ // convert obvious outfits into FT_OUTFIT
return true;
}
- if (cat->getPreferredType() == LLFolderType::FT_NONE
- && cat->getParentUUID() == mOutfitsId)
- {
- LLViewerInventoryCategory* inv_cat = dynamic_cast<LLViewerInventoryCategory*>(cat);
- if (inv_cat && inv_cat->getDescendentCount() > 3)
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
- if (cats->empty() // protection against outfits inside
- && items->size() > 3) // eyes, skin, hair and shape are required
- {
- // For now assume this to be an old style outfit, not a subfolder
- // but ideally no such 'outfits' should be left in My Outfits
- // Todo: stop counting FT_NONE as outfits,
- // convert obvious outfits into FT_OUTFIT
- return true;
- }
- }
- }
}
- return false;
}
-protected:
- LLUUID mOutfitsId;
-};
+ return false;
+}
void LLOutfitListBase::refreshList(const LLUUID& category_id)
{
@@ -872,13 +872,13 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id)
LLInventoryModel::item_array_t item_array;
// Collect all sub-categories of a given category.
- LLIsOutfitListFolder is_outfit;
+ LLIsType is_category(LLAssetType::AT_CATEGORY);
gInventory.collectDescendentsIf(
category_id,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
- is_outfit);
+ is_category);
// Memorize item names for each UUID
std::map<LLUUID, std::string> names;
@@ -1396,7 +1396,12 @@ bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
{
LLSD params;
params["inv_type"] = LLInventoryType::IT_CATEGORY;
- params["thumbnail_id"] = gInventory.getCategory(mFolderID)->getThumbnailUUID();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(mFolderID);
+ if (cat)
+ {
+ params["thumbnail_id"] = cat->getThumbnailUUID();
+ }
+ // else consider returning
params["item_id"] = mFolderID;
LLToolTipMgr::instance().show(LLToolTip::Params()
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index f581b419d9..fad0e638fb 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -118,6 +118,8 @@ protected:
void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
virtual void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) = 0;
+ bool isOutfitFolder(LLViewerInventoryCategory* cat) const;
+
static void onIdle(void* userdata);
void onIdleRefreshList();
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index 404297c58f..aa0cbac91f 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -390,6 +390,7 @@ void init_audio()
gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose")));
gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen")));
gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndRestart")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatMention")));
}
audio_update_volume(true);
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 7d777162ed..89c28ee2f9 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -73,12 +73,14 @@ LLViewerCamera::LLViewerCamera() : LLCamera()
mAverageSpeed = 0.f;
mAverageAngularSpeed = 0.f;
- mCameraAngleChangedSignal = gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2));
-}
-
-LLViewerCamera::~LLViewerCamera()
-{
- mCameraAngleChangedSignal.disconnect();
+ LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl("CameraAngle");
+ if (cntrl_ptr.notNull())
+ {
+ cntrl_ptr->getCommitSignal()->connect([](LLControlVariable* control, const LLSD& value, const LLSD& previous)
+ {
+ LLViewerCamera::getInstance()->setDefaultFOV((F32)value.asReal());
+ });
+ }
}
void LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVector3 &up_direction, const LLVector3 &point_of_interest)
@@ -814,8 +816,3 @@ bool LLViewerCamera::isDefaultFOVChanged()
return false;
}
-void LLViewerCamera::updateCameraAngle(const LLSD& value)
-{
- setDefaultFOV((F32)value.asReal());
-}
-
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index a204b85d88..91d26f09f2 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -43,7 +43,6 @@ class alignas(16) LLViewerCamera : public LLCamera, public LLSimpleton<LLViewerC
LL_ALIGN_NEW
public:
LLViewerCamera();
- ~LLViewerCamera();
typedef enum
{
@@ -66,7 +65,6 @@ public:
const LLVector3 &point_of_interest);
static void updateFrustumPlanes(LLCamera& camera, bool ortho = false, bool zflip = false, bool no_hacks = false);
- void updateCameraAngle(const LLSD& value);
void setPerspective(bool for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, bool limit_select_distance, F32 z_near = 0, F32 z_far = 0);
const LLMatrix4 &getProjection() const;
@@ -126,8 +124,6 @@ protected:
F32 mZoomFactor;
S16 mZoomSubregion;
- boost::signals2::connection mCameraAngleChangedSignal;
-
public:
};
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index bdcfec34f6..1501ba41c2 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2583,6 +2583,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
msg_notify["session_id"] = LLUUID();
msg_notify["from_id"] = chat.mFromID;
msg_notify["source_type"] = chat.mSourceType;
+ // used to check if there is agent mention in the message
+ msg_notify["message"] = mesg;
on_new_message(msg_notify);
}
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 697433148b..b9f52e11aa 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -3720,12 +3720,6 @@ bool LLViewerRegion::bakesOnMeshEnabled() const
mSimulatorFeatures["BakesOnMeshEnabled"].asBoolean());
}
-bool LLViewerRegion::meshRezEnabled() const
-{
- return (mSimulatorFeatures.has("MeshRezEnabled") &&
- mSimulatorFeatures["MeshRezEnabled"].asBoolean());
-}
-
bool LLViewerRegion::dynamicPathfindingEnabled() const
{
return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") &&
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index d0ec1fe877..244e2b7835 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -333,7 +333,6 @@ public:
void getInfo(LLSD& info);
- bool meshRezEnabled() const;
bool meshUploadEnabled() const;
bool bakesOnMeshEnabled() const;
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index f0ada22d66..5142e8ceff 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -1008,5 +1008,8 @@
value="0.82 0.91 0.98 0.15" />
<color
name="ChatSelfMentionHighlight"
- value="1 1 0 1" />
+ value="1 1 0 0.35" />
+ <color
+ name="MentionFlashBgColor"
+ value="1 1 0 0.5" />
</colors>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
index 88716c7f96..0aa1af7de6 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
@@ -409,7 +409,7 @@
layout="topleft"
left="0"
name="play_sound"
- width="100"
+ width="90"
top_pad="8"
visible="true">
Play sound:
@@ -419,10 +419,10 @@
height="16"
label="New conversation"
layout="topleft"
- left_pad="15"
+ left_pad="5"
top_pad="-10"
name="new_conversation"
- width="150" />
+ width="130" />
<check_box
control_name="PlaySoundIncomingVoiceCall"
height="16"
@@ -430,16 +430,16 @@
layout="topleft"
top_pad="6"
name="incoming_voice_call"
- width="150" />
+ width="130" />
<check_box
control_name="PlaySoundTeleportOffer"
height="16"
label="Teleport offer"
layout="topleft"
- left_pad="35"
+ left_pad="18"
top_pad="-38"
name="teleport_offer"
- width="150" />
+ width="130" />
<check_box
control_name="PlaySoundInventoryOffer"
height="16"
@@ -447,14 +447,23 @@
layout="topleft"
top_pad="6"
name="inventory_offer"
- width="150" />
+ width="130" />
+ <check_box
+ control_name="PlaySoundChatMention"
+ height="16"
+ label="Chat mention"
+ layout="topleft"
+ left_pad="7"
+ top_pad="-38"
+ name="chat_mention"
+ width="130" />
<view_border
bevel_style="none"
height="0"
layout="topleft"
left="0"
name="cost_text_border"
- top_pad="7"
+ top_pad="29"
width="492"/>
</panel>