diff options
| author | Jonathan "Geenz" Goodman <geenz@lindenlab.com> | 2025-05-16 19:05:57 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-16 19:05:57 -0400 | 
| commit | bb76eae4b814e612ff2b0c62fffc6c3263058d64 (patch) | |
| tree | 32818e0c938b465bf39c976955864a14b3bb512e /indra | |
| parent | 2efe514f14a0f0b405599301a14413edfce873ee (diff) | |
| parent | d5313e7161bb99045adc4a1a34d7f85de609d97b (diff) | |
Merge branch 'release/2025.04' into geenz/gltf-mesh-import
Diffstat (limited to 'indra')
34 files changed, 373 insertions, 147 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/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 ¢er, 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> | 
