Merge branch 'release/2025.04' into geenz/gltf-mesh-import

meow-7.2.2
Jonathan "Geenz" Goodman 2025-05-16 19:05:57 -04:00 committed by GitHub
commit bb76eae4b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 379 additions and 153 deletions

View File

@ -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()

View File

@ -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);

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
}
});

View File

@ -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>

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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());

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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());
}

View File

@ -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

View File

@ -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");
if (iface)
{
which_mode = iface->getFirstSelectedIndex();
file_mode = iface->getItemCount() - 1;
}
}
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;
}
if (which_mode == file_mode)
{
mFMP->childEnable("physics_file");

View File

@ -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));

View File

@ -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);
}
virtual ~LLIsOutfitListFolder() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override
{
if (cat)
{
if (cat->getPreferredType() == LLFolderType::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;
};
if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)
{
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)
{
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;
}
}
}
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()

View File

@ -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();

View File

@ -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);

View File

@ -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());
}

View File

@ -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:
};

View File

@ -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);
}

View File

@ -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") &&

View File

@ -333,7 +333,6 @@ public:
void getInfo(LLSD& info);
bool meshRezEnabled() const;
bool meshUploadEnabled() const;
bool bakesOnMeshEnabled() const;

View File

@ -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>

View File

@ -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>