diff --git a/.github/workflows/sign.yml b/.github/workflows/sign.yml index 6960f5d191..19c6786537 100644 --- a/.github/workflows/sign.yml +++ b/.github/workflows/sign.yml @@ -115,7 +115,7 @@ jobs: # wait-for-completion: true # output-artifact-directory: 'application-signed' - name: Azure Trusted Signing - uses: azure/trusted-signing-action@v1.2.0 + uses: azure/trusted-signing-action@v2.0.0 with: azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} diff --git a/indra/newview/ao.cpp b/indra/newview/ao.cpp index 7007707174..9fe35c274d 100644 --- a/indra/newview/ao.cpp +++ b/indra/newview/ao.cpp @@ -32,8 +32,12 @@ #include "aoset.h" #include "llcheckboxctrl.h" #include "llcombobox.h" +#include "llmenubutton.h" +#include "llmenugl.h" #include "llnotificationsutil.h" #include "llspinctrl.h" +#include "lltoggleablemenu.h" +#include "lluictrlfactory.h" #include "llviewercontrol.h" #include "utilitybar.h" @@ -42,6 +46,7 @@ FloaterAO::FloaterAO(const LLSD& key) mSetList(0), mSelectedSet(0), mSelectedState(0), + mCloneSetItem(nullptr), mCanDragAndDrop(false), mImportRunning(false), mCurrentBoldItem(nullptr), @@ -217,7 +222,7 @@ bool FloaterAO::postBuild() mSetSelector = mMainInterfacePanel->getChild("ao_set_selection_combo"); mActivateSetButton = mMainInterfacePanel->getChild("ao_activate"); - mAddButton = mMainInterfacePanel->getChild("ao_add"); + mAddButton = mMainInterfacePanel->getChild("ao_add"); mRemoveButton = mMainInterfacePanel->getChild("ao_remove"); mDefaultCheckBox = mMainInterfacePanel->getChild("ao_default"); mOverrideSitsCheckBox = mMainInterfacePanel->getChild("ao_sit_override"); @@ -248,7 +253,7 @@ bool FloaterAO::postBuild() mSetSelector->setCommitCallback(boost::bind(&FloaterAO::onSelectSet, this)); mSetSelector->setFocusLostCallback(boost::bind(&FloaterAO::onSelectSet, this)); mActivateSetButton->setCommitCallback(boost::bind(&FloaterAO::onClickActivate, this)); - mAddButton->setCommitCallback(boost::bind(&FloaterAO::onClickAdd, this)); + buildAddMenu(); mRemoveButton->setCommitCallback(boost::bind(&FloaterAO::onClickRemove, this)); mDefaultCheckBox->setCommitCallback(boost::bind(&FloaterAO::onCheckDefault, this)); mOverrideSitsCheckBox->setCommitCallback(boost::bind(&FloaterAO::onCheckOverrideSits, this)); @@ -511,15 +516,54 @@ void FloaterAO::onClickReload() updateList(); } -void FloaterAO::onClickAdd() +void FloaterAO::buildAddMenu() { - LLNotificationsUtil::add("NewAOSet", LLSD(), LLSD(), boost::bind(&FloaterAO::newSetCallback, this, _1, _2)); + LLToggleableMenu::Params menu_params; + menu_params.name("ao_add_menu"); + menu_params.visible(false); + LLToggleableMenu* addMenu = LLUICtrlFactory::create(menu_params); + + LLMenuItemCallGL::Params blank_params; + blank_params.name("ao_add_blank"); + blank_params.label(getString("ao_add_blank_label")); + blank_params.on_click.function(boost::bind(&FloaterAO::onAddSet, this, false)); + addMenu->addChild(LLUICtrlFactory::create(blank_params)); + + LLMenuItemCallGL::Params clone_params; + clone_params.name("ao_add_clone"); + clone_params.label(getString("ao_add_clone_label")); + clone_params.on_click.function(boost::bind(&FloaterAO::onAddSet, this, true)); + mCloneSetItem = LLUICtrlFactory::create(clone_params); + addMenu->addChild(mCloneSetItem); + + mAddButton->setMenu(addMenu, LLMenuButton::MP_BOTTOM_RIGHT, true); + mAddButton->setMouseDownCallback(boost::bind(&FloaterAO::onAddMenuShow, this)); +} + +void FloaterAO::onAddMenuShow() +{ + if (mCloneSetItem) + { + mCloneSetItem->setEnabled(mSelectedSet != nullptr); + } +} + +void FloaterAO::onAddSet(bool clone) +{ + if (clone && !mSelectedSet) + { + return; + } + LLSD payload; + payload["clone"] = clone; + LLNotificationsUtil::add("NewAOSet", LLSD(), payload, boost::bind(&FloaterAO::newSetCallback, this, _1, _2)); } bool FloaterAO::newSetCallback(const LLSD& notification, const LLSD& response) { std::string newSetName = response["message"].asString(); S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + bool clone = notification["payload"]["clone"].asBoolean(); LLStringUtil::trim(newSetName); @@ -547,10 +591,20 @@ bool FloaterAO::newSetCallback(const LLSD& notification, const LLSD& response) return false; } - AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id) + if (clone) { - reloading(true); - }); + if (mSelectedSet && AOEngine::instance().cloneSet(mSelectedSet, newSetName)) + { + reloading(true); + } + } + else + { + AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id) + { + reloading(true); + }); + } } return false; } diff --git a/indra/newview/ao.h b/indra/newview/ao.h index 49851d22b7..32a4584fd3 100644 --- a/indra/newview/ao.h +++ b/indra/newview/ao.h @@ -35,6 +35,8 @@ class LLButton; class LLComboBox; class LLCheckBoxCtrl; +class LLMenuButton; +class LLMenuItemCallGL; class LLScrollListCtrl; class LLScrollListItem; class LLSpinCtrl; @@ -71,7 +73,9 @@ class FloaterAO void onSelectState(); void onChangeAnimationSelection(); void onClickReload(); - void onClickAdd(); + void buildAddMenu(); + void onAddMenuShow(); + void onAddSet(bool clone); void onClickRemove(); void onClickActivate(); void onCheckDefault(); @@ -119,7 +123,8 @@ class FloaterAO LLComboBox* mSetSelector; LLButton* mActivateSetButton; - LLButton* mAddButton; + LLMenuButton* mAddButton; + LLMenuItemCallGL* mCloneSetItem; LLButton* mRemoveButton; LLCheckBoxCtrl* mDefaultCheckBox; LLCheckBoxCtrl* mOverrideSitsCheckBox; diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp index 1e4e2c4be0..9fe37789b0 100644 --- a/indra/newview/aoengine.cpp +++ b/indra/newview/aoengine.cpp @@ -1173,6 +1173,50 @@ void AOEngine::addSet(const std::string& name, inventory_func_type callback, boo } } +bool AOEngine::cloneSet(AOSet* sourceSet, std::string_view newName) +{ + if (!sourceSet) + { + return false; + } + + if (mImportSet) + { + LL_WARNS("AOEngine") << "Set import or clone already running, ignoring clone request." << LL_ENDL; + return false; + } + + if (mAOFolder.isNull()) + { + LL_WARNS("AOEngine") << ROOT_AO_FOLDER << " folder not there yet. Requesting recreation." << LL_ENDL; + tick(); + return false; + } + + LL_INFOS("AOEngine") << "cloning set " << sourceSet->getName() << " into " << newName << LL_ENDL; + mImportSet = new AOSet(sourceSet->getInventoryUUID()); + mImportSet->setName(newName); + mImportSet->setSitOverride(sourceSet->getSitOverride()); + mImportSet->setSmart(sourceSet->getSmart()); + mImportSet->setMouselookStandDisable(sourceSet->getMouselookStandDisable()); + + for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index) + { + const AOSet::AOState* sourceState = sourceSet->getState(index); + AOSet::AOState* newState = mImportSet->getState(index); + newState->mCycle = sourceState->mCycle; + newState->mRandom = sourceState->mRandom; + newState->mCycleTime = sourceState->mCycleTime; + newState->mAnimations = sourceState->mAnimations; + } + + mImportSet->setInventoryUUID(LLUUID::null); + mTimerCollection.enableImportTimer(true); + mImportRetryCount = 0; + processImport(false); + return true; +} + bool AOEngine::createAnimationLink(AOSet::AOState* state, const LLInventoryItem* item) { LL_DEBUGS("AOEngine") << "Asset ID " << item->getAssetUUID() << " inventory id " << item->getUUID() << " category id " << state->mInventoryUUID << LL_ENDL; @@ -1852,19 +1896,7 @@ void AOEngine::saveSet(const AOSet* set) return; } - std::string setParams=set->getName(); - if (set->getSitOverride()) - { - setParams += ":SO"; - } - if (set->getSmart()) - { - setParams += ":SM"; - } - if (set->getMouselookStandDisable()) - { - setParams += ":DM"; - } + std::string setParams = getSetFolderName(set); if (set == mDefaultSet) { setParams += ":**"; @@ -1902,22 +1934,45 @@ bool AOEngine::renameSet(AOSet* set, std::string_view name) return true; } -void AOEngine::saveState(const AOSet::AOState* state) +std::string AOEngine::getSetFolderName(const AOSet* set) const { - std::string stateParams = state->mName; + std::string params = set->getName(); + if (set->getSitOverride()) + { + params += ":SO"; + } + if (set->getSmart()) + { + params += ":SM"; + } + if (set->getMouselookStandDisable()) + { + params += ":DM"; + } + return params; +} + +std::string AOEngine::getStateFolderName(const AOSet::AOState* state) const +{ + std::string params = state->mName; if (state->mCycleTime > 0.0f) { - stateParams += llformat(":CT%.2f", state->mCycleTime); + params += llformat(":CT%.2f", state->mCycleTime); } if (state->mCycle) { - stateParams += ":CY"; + params += ":CY"; } if (state->mRandom) { - stateParams += ":RN"; + params += ":RN"; } + return params; +} +void AOEngine::saveState(const AOSet::AOState* state) +{ + std::string stateParams = getStateFolderName(state); bool wasProtected = gSavedPerAccountSettings.getBOOL("LockAOFolders"); gSavedPerAccountSettings.setBOOL("LockAOFolders", false); rename_category(&gInventory, state->mInventoryUUID, stateParams); @@ -2399,7 +2454,7 @@ void AOEngine::processImport(bool from_timer) if (mImportSet->getInventoryUUID().isNull()) { // create new inventory folder for this AO set, the next timer tick should pick it up - addSet(mImportSet->getName(), [this](const LLUUID& new_cat_id) + addSet(getSetFolderName(mImportSet), [this](const LLUUID& new_cat_id) { mImportSet->setInventoryUUID(new_cat_id); }, false); @@ -2440,7 +2495,7 @@ void AOEngine::processImport(bool from_timer) allComplete = false; LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL; - gInventory.createNewCategory(mImportSet->getInventoryUUID(), LLFolderType::FT_NONE, state->mName, [this, state](const LLUUID& new_cat_id) + gInventory.createNewCategory(mImportSet->getInventoryUUID(), LLFolderType::FT_NONE, getStateFolderName(state), [this, state](const LLUUID& new_cat_id) { LL_DEBUGS("AOEngine") << "new_cat_id: " << new_cat_id << LL_ENDL; state->mInventoryUUID = new_cat_id; diff --git a/indra/newview/aoengine.h b/indra/newview/aoengine.h index 196dda4978..fa3885b48e 100644 --- a/indra/newview/aoengine.h +++ b/indra/newview/aoengine.h @@ -99,6 +99,7 @@ public: const LLUUID& getAOFolder() const; void addSet(const std::string& name, inventory_func_type callback, bool reload = true); + bool cloneSet(AOSet* sourceSet, std::string_view newName); bool removeSet(AOSet* set); void addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true); @@ -172,6 +173,9 @@ protected: void saveSet(const AOSet* set); void saveState(const AOSet::AOState* state); + std::string getSetFolderName(const AOSet* set) const; + std::string getStateFolderName(const AOSet::AOState* state) const; + bool createAnimationLink(AOSet::AOState* state, const LLInventoryItem* item); bool findForeignItems(const LLUUID& uuid) const; void purgeFolder(const LLUUID& uuid) const; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6d34d8a121..192fc58e23 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -17965,6 +17965,19 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + DebugWebRTCRequireEstablishedSpatialSession + + Comment + Test for FIRE-36672 + Persist + 1 + Type + Boolean + Value + 0 + Backup + 0 + VivoxVoiceHost Comment @@ -25696,6 +25709,7 @@ Change of this parameter will affect the layout of buttons in notification toast it ja pl + pt ru zh diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 25420dc9fb..cfc57bb29a 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -60,7 +60,7 @@ Unicode true # Enable unicode support !include "%%SOURCE%%\installers\windows\lang_ja.nsi" !include "%%SOURCE%%\installers\windows\lang_it.nsi" !include "%%SOURCE%%\installers\windows\lang_pl.nsi" ; Polish is supported -##!include "%%SOURCE%%\installers\windows\lang_pt-br.nsi" +!include "%%SOURCE%%\installers\windows\lang_pt-br.nsi" !include "%%SOURCE%%\installers\windows\lang_ru.nsi" ##!include "%%SOURCE%%\installers\windows\lang_tr.nsi" !include "%%SOURCE%%\installers\windows\lang_zh.nsi" @@ -74,7 +74,7 @@ LangString LanguageCode ${LANG_FRENCH} "fr" LangString LanguageCode ${LANG_JAPANESE} "ja" LangString LanguageCode ${LANG_ITALIAN} "it" LangString LanguageCode ${LANG_POLISH} "pl" -##LangString LanguageCode ${LANG_PORTUGUESEBR} "pt" +LangString LanguageCode ${LANG_PORTUGUESEBR} "pt" LangString LanguageCode ${LANG_RUSSIAN} "ru" ##LangString LanguageCode ${LANG_TURKISH} "tr" LangString LanguageCode ${LANG_TRADCHINESE} "zh" diff --git a/indra/newview/installers/windows/language_menu.nsi b/indra/newview/installers/windows/language_menu.nsi index f445080b26..079b33a6fa 100644 Binary files a/indra/newview/installers/windows/language_menu.nsi and b/indra/newview/installers/windows/language_menu.nsi differ diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 6deebc17a2..995d50d773 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llpreviewnotecard.h" +#include "llnotecard.h" // Byte counter #include "llinventory.h" @@ -60,6 +61,7 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" #include "llviewerassetupload.h" +#include "lluistring.h" // Needed for the Byte Counter // [SL:KB] - Patch: UI-FloaterSearchReplace | Checked: 2010-11-05 (Catznip-2.3.0a) | Added: Catznip-2.3.0a #include "llfloatersearchreplace.h" @@ -77,6 +79,7 @@ LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id, // FIRE-24306: Retain cursor position when saving notecards ,mCursorPos(0) ,mScrollPos(0) + ,mByteCounterTemplate("") // Initialize empty for Byte Counter // FIRE-29425: User-selectable font and size for notecards ,mFontNameChangedCallbackConnection() ,mFontSizeChangedCallbackConnection() @@ -127,6 +130,21 @@ bool LLPreviewNotecard::postBuild() mEditBtn = getChild("Edit"); mEditBtn->setCommitCallback(boost::bind(&LLPreviewNotecard::openInExternalEditor, this)); + // Byte counter + mByteCounter = getChild("byte_counter"); + if (mByteCounter) + { + mByteCounterTemplate = mByteCounter->getText(); + if (mByteCounterTemplate.empty()) + mByteCounterTemplate = "Bytes: [BYTES] / [MAX]"; + LLUIString init_text(mByteCounterTemplate); + init_text.setArg("[BYTES]", "0"); + init_text.setArg("[MAX]", std::to_string(LLNotecard::MAX_SIZE)); + mByteCounter->setText(init_text.getString()); + } + mEditor->setKeystrokeCallback([this](LLTextEditor*) { mByteCounterDirty = true; }); + // + // FIRE-13969: Search button getChild("Search")->setClickedCallback(boost::bind(&LLPreviewNotecard::onSearchButtonClicked, this)); @@ -157,6 +175,44 @@ bool LLPreviewNotecard::saveItem() return saveIfNeeded(item); } +// Byte counter +void LLPreviewNotecard::updateByteCounter() +{ + if (!mEditor || !mByteCounter) return; + + mByteCounterDirty = false; + + const size_t MAX_BYTES = LLNotecard::MAX_SIZE; + + std::string text = mEditor->getText(); + size_t bytes = text.size(); // Assumes UTF-8 encoding where size() == bytes + + auto getColorForByteCount = [bytes]() -> LLColor4 + { + if (bytes >= MAX_BYTES) + return LLColor4::red; + + if (bytes > (MAX_BYTES * 8 / 10)) + return LLColor4::yellow; + + return LLColor4::white; + }; + mByteCounter->setColor(getColorForByteCount()); + + // Ensure template is valid + if (mByteCounterTemplate.empty()) + { + mByteCounterTemplate = "Bytes: [BYTES] / [MAX]"; + } + + LLUIString ui_text(mByteCounterTemplate); + ui_text.setArg("[BYTES]", std::to_string(bytes)); + ui_text.setArg("[MAX]", std::to_string(MAX_BYTES)); + + mByteCounter->setText(ui_text.getString()); +} +// + void LLPreviewNotecard::setEnabled(bool enabled) { if (mEditor) @@ -183,7 +239,12 @@ void LLPreviewNotecard::draw() bool changed = !mEditor->isPristine(); mSaveBtn->setEnabled(changed && getEnabled()); - + // Byte counter + if (mByteCounterDirty) + { + updateByteCounter(); + } + // LLPreview::draw(); } @@ -454,6 +515,9 @@ void LLPreviewNotecard::onLoadComplete(const LLUUID& asset_uuid, preview->setEnabled(modifiable); preview->syncExternal(); preview->mAssetStatus = PREVIEW_ASSET_LOADED; + // Byte counter + preview->updateByteCounter(); + // // FIRE-24306: Retain cursor position when saving notecards preview->mEditor->setCursorPos(preview->mCursorPos); @@ -903,6 +967,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) LLStringUtil::replaceTabsWithSpaces(text, LLTextEditor::spacesPerTab()); mEditor->setText(text); + mByteCounterDirty = true; // Byte counter delete[] buffer; return true; diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index 3f010dec8b..3ffa268b5d 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -100,6 +100,9 @@ protected: void loadAsset() override; bool saveIfNeeded(LLInventoryItem* copyitem = NULL, bool sync = true); + // Byte Counter + void updateByteCounter(); + void deleteNotecard(); static void onLoadComplete(const LLUUID& asset_uuid, @@ -138,6 +141,12 @@ protected: LLButton* mDeleteBtn = nullptr; LLUICtrl* mLockBtn = nullptr; + // Byte counter + LLTextBox* mByteCounter = nullptr; + std::string mByteCounterTemplate; + bool mByteCounterDirty = false; + // + LLUUID mAssetID; LLUUID mObjectID; diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 5782568e74..ede91032c2 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -1569,6 +1569,15 @@ void LLWebRTCVoiceClient::processChannels(bool process) bool LLWebRTCVoiceClient::inProximalChannel() { + // Test for FIRE-36672, disabled by default + // inSpatialChannel() defaults to true with no session (parcel voice disabled), which keeps the conversation voice indicator green + // Only report proximal when a spatial session is established + static LLCachedControl require_established_session(gSavedSettings, "DebugWebRTCRequireEstablishedSpatialSession", false); + if (require_established_session) + { + return mProcessChannels && mSession && mSession->isSpatial(); + } + // return inSpatialChannel(); } diff --git a/indra/newview/skins/ansastorm/xui/pt/floater_camera.xml b/indra/newview/skins/ansastorm/xui/pt/floater_camera.xml index 22c7d7c3f5..a525cc15f9 100644 --- a/indra/newview/skins/ansastorm/xui/pt/floater_camera.xml +++ b/indra/newview/skins/ansastorm/xui/pt/floater_camera.xml @@ -1,41 +1,64 @@ - + - Girar a câmera em torno do foco + Girar câmera em torno do foco - Zoom da câmera em direção ao foco + Aproximar câmera do foco - Mover a câmera para cima, para baixo, esquerda e direita + Mover câmera para cima, baixo, esquerda e direita + + + Ver objeto - - Visualizar Objeto - - Use a predefinição + Usar predefinição... + - -