From 0f019128746d201b051b3b94287caad278d7d422 Mon Sep 17 00:00:00 2001 From: Beq Date: Mon, 12 May 2025 17:20:09 +0100 Subject: [PATCH] Make the pose overwrite confirmation a notification normalise the UI behaviour to use a notification. --- indra/newview/fsfloaterposer.cpp | 90 ++++++++++--------- indra/newview/fsfloaterposer.h | 2 + .../skins/default/xui/en/notifications.xml | 14 +++ 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp index f3d01fd6a9..22ac6d0a94 100644 --- a/indra/newview/fsfloaterposer.cpp +++ b/indra/newview/fsfloaterposer.cpp @@ -33,6 +33,7 @@ #include "llcheckboxctrl.h" #include "llcommonutils.h" #include "llcontrolavatar.h" +#include "llnotificationsutil.h" #include "lldiriterator.h" #include "llsdserialize.h" #include "llscrolllistctrl.h" @@ -61,7 +62,10 @@ constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpa constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPosingWhenClosed"; constexpr std::string_view POSER_RESETBASEROTONEDIT_SAVE_KEY = "FSPoserResetBaseRotationOnEdit"; constexpr std::string_view POSER_SAVEEXTERNALFORMAT_SAVE_KEY = "FSPoserSaveExternalFileAlso"; -constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite"; +constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite"; +constexpr char ICON_SAVE_OK[] = "icon_rotation_is_own_work"; +constexpr char ICON_SAVE_FAILED[] = "icon_save_failed_button"; + } // namespace /// @@ -368,19 +372,8 @@ void FSFloaterPoser::onPoseFileSelect() mLoadPosesBtn->setLabel(getString("LoadPoseLabel")); } -void FSFloaterPoser::onClickPoseSave() +void FSFloaterPoser::doPoseSave(LLVOAvatar* avatar, const std::string& filename) { - std::string filename = mPoseSaveNameEditor->getValue().asString(); - if (filename.empty() && hasString("icon_save_failed_button")) - { - mSavePosesBtn->setImageOverlay(getString("icon_save_failed_button"), mSavePosesBtn->getImageOverlayHAlign()); - return; - } - - if (confirmFileOverwrite(filename)) - return; - - LLVOAvatar* avatar = getUiSelectedAvatar(); if (!avatar) return; @@ -393,43 +386,60 @@ void FSFloaterPoser::onClickPoseSave() if (getSavingToBvh()) savePoseToBvh(avatar, filename); - if (hasString("icon_rotation_is_own_work")) - mSavePosesBtn->setImageOverlay(getString("icon_rotation_is_own_work"), mSavePosesBtn->getImageOverlayHAlign()); + if (hasString(ICON_SAVE_OK)) + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_OK), mSavePosesBtn->getImageOverlayHAlign()); setSavePosesButtonText(!mPoserAnimator.allBaseRotationsAreZero(avatar)); } else { - if (hasString("icon_save_failed_button")) - mSavePosesBtn->setImageOverlay(getString("icon_save_failed_button"), mSavePosesBtn->getImageOverlayHAlign()); - } + if (hasString(ICON_SAVE_FAILED)) + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign()); + } } -bool FSFloaterPoser::confirmFileOverwrite(std::string fileName) +void FSFloaterPoser::onClickPoseSave() { - if (fileName.empty()) - return false; + std::string filename = mPoseSaveNameEditor->getValue().asString(); + if (filename.empty() && hasString(ICON_SAVE_FAILED)) + { + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign()); + return; + } + + LLVOAvatar* avatar = getUiSelectedAvatar(); + if (!avatar) + return; + + // if prompts are disabled or file doesn't exist, do the save immediately: + const bool prompt = gSavedSettings.getBOOL(POSER_SAVECONFIRMREQUIRED_SAVE_KEY); - if (!gSavedSettings.getBOOL(POSER_SAVECONFIRMREQUIRED_SAVE_KEY)) - return false; + std::string fullPath = gDirUtilp->getExpandedFilename( + LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, filename + POSE_INTERNAL_FORMAT_FILE_EXT); + const bool exists = gDirUtilp->fileExists(fullPath); - if (!hasString("icon_save_query")) - return false; - - if (mSavePosesBtn->getImageOverlay().notNull() && mSavePosesBtn->getImageOverlay()->getName() == getString("icon_save_query")) - return false; - - std::string fullSavePath = - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, fileName + POSE_INTERNAL_FORMAT_FILE_EXT); - - if (!gDirUtilp->fileExists(fullSavePath)) - return false; - - mSavePosesBtn->setImageOverlay(getString("icon_save_query"), mSavePosesBtn->getImageOverlayHAlign()); - if (hasString("OverWriteLabel")) - mSavePosesBtn->setLabel(getString("OverWriteLabel")); - - return true; + if (!prompt || !exists) + { + // new file or no overwrite guard + doPoseSave(avatar, filename); + } + else + { + // show a modal dialog, passing the pose name along + LLSD args; + args["POSE_NAME"] = filename; + + LLNotificationsUtil::add("ConfirmPoserOverwrite", args, LLSD(), // no payload + [this, avatar, filename](const LLSD& notification, const LLSD& response) + { + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // user clicked β€œYes” + doPoseSave(avatar, filename); + } + // else do nothing (cancel) + }); + } } void FSFloaterPoser::onMouseLeaveSavePoseBtn() diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h index 14c7d90615..7e0e6c42e4 100644 --- a/indra/newview/fsfloaterposer.h +++ b/indra/newview/fsfloaterposer.h @@ -86,6 +86,8 @@ public: void redo() override { onRedoLastChange(); }; bool canRedo() const override { return true; } private: + // Helper function to encapsualte save logic + void doPoseSave(LLVOAvatar* avatar, const std::string& filename); bool postBuild() override; void onOpen(const LLSD& key) override; void onClose(bool app_quitting) override; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index cdda3e7c74..3f098c782f 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -14662,4 +14662,18 @@ For detailed instructions on how to whitelist [APP_NAME] - including a list of f https://wiki.firestormviewer.org/antivirus_whitelisting + + + Overwrite existing pose β€œ[POSE_NAME]”? + confirm + + +