diff options
261 files changed, 4671 insertions, 5408 deletions
diff --git a/autobuild.xml b/autobuild.xml index 8642d74b0f..c519579637 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -462,9 +462,11 @@ <key>archive</key> <map> <key>hash</key> - <string>7ac35da9b1b5c9a05954edeef3fe8e54</string> + <string>52c41a4547d2d9aceb4a9a1e9e1680c71e5ffa79</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113242/980233/emoji_shortcodes-6.1.0.579438-darwin64-579438.tar.bz2</string> + <string>https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-darwin64-5413f58.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -474,9 +476,11 @@ <key>archive</key> <map> <key>hash</key> - <string>087ce7e6d93dcd88b477b10d8e1ab259</string> + <string>3137e06d376767a631bc9626832d558c4d5e5aa9</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113243/980244/emoji_shortcodes-6.1.0.579438-windows64-579438.tar.bz2</string> + <string>https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-windows64-5413f58.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -489,7 +493,7 @@ <key>copyright</key> <string>Copyright 2017-2019 Miles Johnson.</string> <key>version</key> - <string>6.1.0.579438</string> + <string>6.1.0.5413f58</string> <key>name</key> <string>emoji_shortcodes</string> <key>canonical_repo</key> @@ -955,54 +959,6 @@ <key>description</key> <string>Havok source code for libs and demos</string> </map> - <key>icu4c</key> - <map> - <key>platforms</key> - <map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>47bc32b991385f1a6530e4c6179b07f64ca6edc7</string> - <key>hash_algorithm</key> - <string>sha1</string> - <key>url</key> - <string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-darwin64-7d08d82.tar.zst</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>windows64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>b7db881dac80302e4d9010af34c0bf6ca9897df9</string> - <key>hash_algorithm</key> - <string>sha1</string> - <key>url</key> - <string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-windows64-7d08d82.tar.zst</string> - </map> - <key>name</key> - <string>windows64</string> - </map> - </map> - <key>license</key> - <string>ICU, permissive non-copyleft free software license</string> - <key>license_file</key> - <string>LICENSES/icu.txt</string> - <key>copyright</key> - <string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string> - <key>version</key> - <string>4.8.1-7d08d82</string> - <key>name</key> - <string>icu4c</string> - <key>canonical_repo</key> - <string>https://bitbucket.org/lindenlab/3p-icu4c</string> - <key>description</key> - <string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string> - </map> <key>jpegencoderbasic</key> <map> <key>platforms</key> @@ -1668,6 +1624,18 @@ <key>name</key> <string>linux64</string> </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>2e5f1f7046a49d8b0bc295aa878116bc</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> </map> <key>license</key> <string>internal</string> @@ -2739,11 +2707,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>eb1316584188dafb591f80b46b357c737f90d1a7</string> + <string>8a04e6b3c6ff7f645219955a1389035565eb10d8</string> <key>hash_algorithm</key> <string>sha1</string> <key>url</key> - <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-darwin64-08bf5ee.tar.zst</string> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-darwin64-f14b5ec.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2753,11 +2721,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>f4677b0ebd9880f29c118af51ada50883dd0a1e4</string> + <string>a1e467c08ecbe6ab24fc8756a815a431a9b00f62</string> <key>hash_algorithm</key> <string>sha1</string> <key>url</key> - <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-linux64-08bf5ee.tar.zst</string> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-linux64-f14b5ec.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2767,11 +2735,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>7426c5a1d7eb231b476625637a1f2daba0a6bc55</string> + <string>56b613decdd36b2a17646bf3e2cfc2fed8456b8c</string> <key>hash_algorithm</key> <string>sha1</string> <key>url</key> - <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-08bf5ee/viewer_manager-3.0-08bf5ee-windows64-08bf5ee.tar.zst</string> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-windows64-f14b5ec.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -2783,8 +2751,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <string>LICENSE</string> <key>copyright</key> <string>Copyright (c) 2000-2012, Linden Research, Inc.</string> - <key>version</key> - <string>3.0-08bf5ee</string> <key>name</key> <string>viewer-manager</string> <key>description</key> @@ -2793,6 +2759,8 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <string>https://bitbucket.org/lindenlab/vmp-standalone</string> <key>source_type</key> <string>hg</string> + <key>version</key> + <string>3.0-f14b5ec</string> </map> <key>vlc-bin</key> <map> diff --git a/doc/contributions.txt b/doc/contributions.txt index 15aec5e282..024ca90d2f 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -245,7 +245,8 @@ Ansariel Hiller SL-19623 SL-4126 SL-20224 - https://github.com/secondlife/viewer/issues/1051 + SL-20524 + secondlife/viewer#1051 Aralara Rajal Arare Chantilly CHUIBUG-191 @@ -389,6 +390,7 @@ Chaser Zaks BUG-225599 BUG-227485 SL-16874 + SL-20442 Cherry Cheevers ChickyBabes Zuzu Chorazin Allen diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index da7e4be464..df05032172 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES GoogleMock.cmake Havok.cmake Hunspell.cmake - ICU4C.cmake JsonCpp.cmake LLAddBuildTest.cmake LLAppearance.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 262cd5813d..7938d4f54b 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -50,7 +50,7 @@ if(WINDOWS) endif (ADDRESS_SIZE EQUAL 64) #******************************* - # Misc shared libs + # Misc shared libs set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") set(release_files @@ -62,15 +62,6 @@ if(WINDOWS) uriparser.dll ) - # ICU4C (same filenames for 32 and 64 bit builds) - set(release_files ${release_files} icudt48.dll) - set(release_files ${release_files} icuin48.dll) - set(release_files ${release_files} icuio48.dll) - set(release_files ${release_files} icule48.dll) - set(release_files ${release_files} iculx48.dll) - set(release_files ${release_files} icutu48.dll) - set(release_files ${release_files} icuuc48.dll) - # OpenSSL if(ADDRESS_SIZE EQUAL 64) set(release_files ${release_files} libcrypto-1_1-x64.dll) diff --git a/indra/cmake/ICU4C.cmake b/indra/cmake/ICU4C.cmake deleted file mode 100644 index 7b27665483..0000000000 --- a/indra/cmake/ICU4C.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -include_guard() - -add_library( ll::icu4c INTERFACE IMPORTED ) - - -use_system_binary(icu4c) -use_prebuilt_binary(icu4c) -if (WINDOWS) - target_link_libraries( ll::icu4c INTERFACE icuuc) -elseif(DARWIN) - target_link_libraries( ll::icu4c INTERFACE icuuc) -#elseif(LINUX) -## target_link_libraries( ll::icu4c INTERFACE ) -else() - message(FATAL_ERROR "Invalid platform") -endif() - -target_include_directories( ll::icu4c SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/unicode ) - -use_prebuilt_binary(dictionaries) diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index ff222c0e89..d73be024cf 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -494,70 +494,45 @@ void LLAvatarAppearance::computeBodySize() mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale(); mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition(); - LLVector3 pelvis_scale = mPelvisp->getScale(); - - // some of the joints have not been cached - LLVector3 skull = mSkullp->getPosition(); - //LLVector3 skull_scale = mSkullp->getScale(); - - LLVector3 neck = mNeckp->getPosition(); - LLVector3 neck_scale = mNeckp->getScale(); - - LLVector3 chest = mChestp->getPosition(); - LLVector3 chest_scale = mChestp->getScale(); - - // the rest of the joints have been cached - LLVector3 head = mHeadp->getPosition(); - LLVector3 head_scale = mHeadp->getScale(); - - LLVector3 torso = mTorsop->getPosition(); - LLVector3 torso_scale = mTorsop->getScale(); - - LLVector3 hip = mHipLeftp->getPosition(); - LLVector3 hip_scale = mHipLeftp->getScale(); - - LLVector3 knee = mKneeLeftp->getPosition(); - LLVector3 knee_scale = mKneeLeftp->getScale(); - - LLVector3 ankle = mAnkleLeftp->getPosition(); - LLVector3 ankle_scale = mAnkleLeftp->getScale(); - - LLVector3 foot = mFootLeftp->getPosition(); - + F32 old_height = mBodySize.mV[VZ]; F32 old_offset = mAvatarOffset.mV[VZ]; - mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER); - - mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - - knee.mV[VZ] * hip_scale.mV[VZ] - - ankle.mV[VZ] * knee_scale.mV[VZ] - - foot.mV[VZ] * ankle_scale.mV[VZ]; + // TODO: Measure the real depth and width + mPelvisToFoot = computePelvisToFoot(); + F32 new_height = computeBodyHeight(); + mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height); + F32 new_offset = getVisualParamWeight(AVATAR_HOVER); + mAvatarOffset.set(0, 0, new_offset); - LLVector3 new_body_size; - new_body_size.mV[VZ] = mPelvisToFoot + - // the sqrt(2) correction below is an approximate - // correction to get to the top of the head - F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + - head.mV[VZ] * neck_scale.mV[VZ] + - neck.mV[VZ] * chest_scale.mV[VZ] + - chest.mV[VZ] * torso_scale.mV[VZ] + - torso.mV[VZ] * pelvis_scale.mV[VZ]; - - // TODO -- measure the real depth and width - new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; - new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; - - mAvatarOffset.mV[VX] = 0.0f; - mAvatarOffset.mV[VY] = 0.0f; - - if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) + if (mBodySize.mV[VZ] != old_height || new_offset != old_offset) { - mBodySize = new_body_size; - compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); } } +F32 LLAvatarAppearance::computeBodyHeight() +{ + F32 result = mPelvisToFoot + + // all these relative positions usually are positive + mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] + + mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] + + mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] + + mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] + + mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2; + return result; +} + +F32 LLAvatarAppearance::computePelvisToFoot() +{ + F32 result = + // all these relative positions usually are negative + mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] + + mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] + + mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] + + mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2; + return -result; +} + //----------------------------------------------------------------------------- // parseSkeletonFile() //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 435ce8bc49..9dd1ddffad 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -146,7 +146,9 @@ public: joint_state_map_t mCurrBodySizeState; void compareJointStateMaps(joint_state_map_t& last_state, joint_state_map_t& curr_state); - void computeBodySize(); + void computeBodySize(); + F32 computeBodyHeight(); + F32 computePelvisToFoot(); public: typedef std::vector<LLAvatarJoint*> avatar_joint_list_t; diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 9254062e29..f04bae3d62 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -550,7 +550,7 @@ void LLWearable::revertValues() if(param) { F32 value = vp_pair.second; - setVisualParamWeight(id, value); + param->setWeight(value); mSavedVisualParamMap[id] = param->getWeight(); } } diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp index cb153ba827..e5ca051f82 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -42,16 +42,6 @@ const S32 GESTURE_VERSION = 2; // LLMultiGesture //--------------------------------------------------------------------------- LLMultiGesture::LLMultiGesture() -: mKey(), - mMask(), - mName(), - mTrigger(), - mReplaceText(), - mSteps(), - mPlaying(FALSE), - mCurrentStep(0), - mDoneCallback(NULL), - mCallbackData(NULL) { reset(); } @@ -67,8 +57,11 @@ void LLMultiGesture::reset() mPlaying = FALSE; mCurrentStep = 0; mWaitTimer.reset(); - mWaitingTimer = FALSE; mWaitingAnimations = FALSE; + mWaitingKeyRelease = FALSE; + mWaitingTimer = FALSE; + mTriggeredByKey = FALSE; + mKeyReleased = FALSE; mWaitingAtEnd = FALSE; mRequestedAnimIDs.clear(); mPlayingAnimIDs.clear(); diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h index acb0bc7cb2..bc9963f2b1 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -59,8 +59,8 @@ protected: const LLMultiGesture& operator=(const LLMultiGesture& rhs); public: - KEY mKey; - MASK mMask; + KEY mKey { 0 }; + MASK mMask { 0 }; // This name can be empty if the inventory item is not around and // the gesture manager has not yet set the name @@ -75,25 +75,34 @@ public: std::vector<LLGestureStep*> mSteps; // Is the gesture currently playing? - BOOL mPlaying; + BOOL mPlaying { FALSE }; // "instruction pointer" for steps - S32 mCurrentStep; + S32 mCurrentStep { 0 }; // We're waiting for triggered animations to stop playing - BOOL mWaitingAnimations; + BOOL mWaitingAnimations { FALSE }; + + // We're waiting for key release + BOOL mWaitingKeyRelease { FALSE }; // We're waiting a fixed amount of time - BOOL mWaitingTimer; + BOOL mWaitingTimer { FALSE }; + + // We're waiting for triggered animations to stop playing + BOOL mTriggeredByKey { FALSE }; + + // Has the key been released? + BOOL mKeyReleased { FALSE }; // Waiting after the last step played for all animations to complete - BOOL mWaitingAtEnd; + BOOL mWaitingAtEnd { FALSE }; // Timer for waiting LLFrameTimer mWaitTimer; - void (*mDoneCallback)(LLMultiGesture* gesture, void* data); - void* mCallbackData; + void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL }; + void* mCallbackData { NULL }; // Animations that we requested to start std::set<LLUUID> mRequestedAnimIDs; @@ -210,6 +219,7 @@ public: const U32 WAIT_FLAG_TIME = 0x01; const U32 WAIT_FLAG_ALL_ANIM = 0x02; +const U32 WAIT_FLAG_KEY_RELEASE = 0x04; class LLGestureStepWait : public LLGestureStep { diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c947184dc8..5f4ed2fffa 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,7 +3,6 @@ project(llcommon) include(00-Common) -include(ICU4C) include(LLCommon) include(bugsplat) include(Linking) @@ -283,7 +282,6 @@ target_link_libraries( ll::uriparser ll::oslibraries ll::tracy - ll::icu4c ) target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index a743ae1589..6512bbc392 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -30,7 +30,6 @@ #include "llerror.h" #include "llfasttimer.h" #include "llsd.h" -#include <unicode/uchar.h> #include <vector> #if LL_WINDOWS @@ -758,6 +757,43 @@ std::string utf8str_showBytesUTF8(const std::string& utf8str) return result; } +// Search for any emoji symbol, return true if found +bool wstring_has_emoji(const LLWString& wstr) +{ + for (const llwchar& wch : wstr) + { + if (LLStringOps::isEmoji(wch)) + return true; + } + + return false; +} + +// Cut emoji symbols if exist +bool wstring_remove_emojis(LLWString& wstr) +{ + bool found = false; + for (size_t i = 0; i < wstr.size(); ++i) + { + if (LLStringOps::isEmoji(wstr[i])) + { + wstr.erase(i--, 1); + found = true; + } + } + return found; +} + +// Cut emoji symbols if exist +bool utf8str_remove_emojis(std::string& utf8str) +{ + LLWString wstr = utf8str_to_wstring(utf8str); + if (!wstring_remove_emojis(wstr)) + return false; + utf8str = wstring_to_utf8str(wstr); + return true; +} + #if LL_WINDOWS unsigned int ll_wstring_default_code_page() { @@ -971,40 +1007,18 @@ std::string LLStringOps::sAM; std::string LLStringOps::sPM; // static -bool LLStringOps::isEmoji(llwchar wch) -{ - int ublock = ublock_getCode(wch); - switch (ublock) - { - case UBLOCK_GENERAL_PUNCTUATION: - case UBLOCK_LETTERLIKE_SYMBOLS: - case UBLOCK_ARROWS: - case UBLOCK_MISCELLANEOUS_TECHNICAL: - case UBLOCK_ENCLOSED_ALPHANUMERICS: - case UBLOCK_GEOMETRIC_SHAPES: - case UBLOCK_MISCELLANEOUS_SYMBOLS: - case UBLOCK_DINGBATS: - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: - case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: - case UBLOCK_EMOTICONS: - case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: -#if U_ICU_VERSION_MAJOR_NUM > 56 - // Boost uses ICU so we can't update it independently - case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - return true; - default: -#if U_ICU_VERSION_MAJOR_NUM > 56 - return false; +bool LLStringOps::isEmoji(llwchar a) +{ +#if 0 // Do not consider special characters that might have a corresponding + // glyph in the monochorme fallback fonts as a "genuine" emoji. HB + return a == 0xa9 || a == 0xae || (a >= 0x2000 && a < 0x3300) || + (a >= 0x1f000 && a < 0x20000); #else - // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs - return wch >= 0x1F900 && wch <= 0x1F9FF; -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - } + // These are indeed "genuine" emojis, we *do want* rendered as such. HB + return a >= 0x1f000 && a < 0x20000; +#endif } - S32 LLStringOps::collate(const llwchar* a, const llwchar* b) { #if LL_WINDOWS diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 3829978ddf..6503da2e77 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -189,7 +189,8 @@ public: static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static bool isEmoji(llwchar wch); + // Returns true when 'a' corresponds to a "genuine" emoji. HB + static bool isEmoji(llwchar a); static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); @@ -747,6 +748,12 @@ LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str); +LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr); + +LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr); + +LL_COMMON_API bool utf8str_remove_emojis(std::string& utf8str); + #if LL_WINDOWS /* @name Windows string helpers */ diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 47868b3fca..b7ffddc023 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -1350,6 +1350,10 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) } while(gzeof(src) == 0); fclose(dst); dst = NULL; +#if LL_WINDOWS + // Rename in windows needs the dstfile to not exist. + LLFile::remove(dstfile, ENOENT); +#endif if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ retval = TRUE; err: diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 864315d0ff..da5b531857 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -585,8 +585,7 @@ static void bilinear_scale(const U8 *src, U32 srcW, U32 srcH, U32 srcCh, U32 src //--------------------------------------------------------------------------- //static -std::string LLImage::sLastErrorMessage; -LLMutex* LLImage::sMutex = NULL; +thread_local std::string LLImage::sLastThreadErrorMessage; bool LLImage::sUseNewByteRange = false; S32 LLImage::sMinimalReverseByteRangePercent = 75; @@ -595,28 +594,24 @@ void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_ { sUseNewByteRange = use_new_byte_range; sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent; - sMutex = new LLMutex(); } //static void LLImage::cleanupClass() { - delete sMutex; - sMutex = NULL; } //static -const std::string& LLImage::getLastError() +const std::string& LLImage::getLastThreadError() { static const std::string noerr("No Error"); - return sLastErrorMessage.empty() ? noerr : sLastErrorMessage; + return sLastThreadErrorMessage.empty() ? noerr : sLastThreadErrorMessage; } //static void LLImage::setLastError(const std::string& message) { - LLMutexLock m(sMutex); - sLastErrorMessage = message; + sLastThreadErrorMessage = message; } //--------------------------------------------------------------------------- diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index a5f05d4380..9b16711b85 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -96,15 +96,14 @@ public: static void initClass(bool use_new_byte_range = false, S32 minimal_reverse_byte_range_percent = 75); static void cleanupClass(); - static const std::string& getLastError(); + static const std::string& getLastThreadError(); static void setLastError(const std::string& message); static bool useNewByteRange() { return sUseNewByteRange; } static S32 getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; } protected: - static LLMutex* sMutex; - static std::string sLastErrorMessage; + static thread_local std::string sLastThreadErrorMessage; static bool sUseNewByteRange; static S32 sMinimalReverseByteRangePercent; }; diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 29a86f77f6..4d081ce169 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "stdtypes.h" #include "llerror.h" +#include "llexception.h" #include "llimage.h" #include "llpngwrapper.h" @@ -51,30 +52,45 @@ bool LLImagePNG::updateData() { resetLastError(); - // Check to make sure that this instance has been initialized with data - if (!getData() || (0 == getDataSize())) + try { - setLastError("Uninitialized instance of LLImagePNG"); - return false; + // Check to make sure that this instance has been initialized with data + if (!getData() || (0 == getDataSize())) + { + setLastError("Uninitialized instance of LLImagePNG"); + return false; + } + + // Decode the PNG data and extract sizing information + LLPngWrapper pngWrapper; + if (!pngWrapper.isValidPng(getData())) + { + setLastError("LLImagePNG data does not have a valid PNG header!"); + return false; + } + + LLPngWrapper::ImageInfo infop; + if (!pngWrapper.readPng(getData(), getDataSize(), NULL, &infop)) + { + setLastError(pngWrapper.getErrorMessage()); + return false; + } + + setSize(infop.mWidth, infop.mHeight, infop.mComponents); } - - // Decode the PNG data and extract sizing information - LLPngWrapper pngWrapper; - if (!pngWrapper.isValidPng(getData())) + catch (const LLContinueError& msg) { - setLastError("LLImagePNG data does not have a valid PNG header!"); + setLastError(msg.what()); + LOG_UNHANDLED_EXCEPTION(""); return false; } - - LLPngWrapper::ImageInfo infop; - if (! pngWrapper.readPng(getData(), getDataSize(), NULL, &infop)) + catch (...) { - setLastError(pngWrapper.getErrorMessage()); + setLastError("LLImagePNG"); + LOG_UNHANDLED_EXCEPTION(""); return false; } - setSize(infop.mWidth, infop.mHeight, infop.mComponents); - return true; } diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 553e5cd7bf..587f25dc1b 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -58,6 +58,7 @@ private: BOOL mDecodedRaw; BOOL mDecodedAux; LLPointer<LLImageDecodeThread::Responder> mResponder; + std::string mErrorString; }; @@ -156,6 +157,7 @@ bool ImageRequest::processRequest() LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; const F32 decode_time_slice = 0.f; //disable time slicing bool done = true; + mErrorString.clear(); if (!mDecodedRaw && mFormattedImage.notNull()) { // Decode primary channels @@ -164,10 +166,13 @@ bool ImageRequest::processRequest() // parse formatted header if (!mFormattedImage->updateData()) { + // Pick up errors from updateData + mErrorString = LLImage::getLastThreadError(); return true; // done (failed) } if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) { + mErrorString = "Invalid image size"; return true; // done (failed) } if (mDiscardLevel >= 0) @@ -181,6 +186,9 @@ bool ImageRequest::processRequest() done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // some decoders are removing data when task is complete and there were errors mDecodedRaw = done && mDecodedImageRaw->getData(); + + // Pick up errors from decoding + mErrorString = LLImage::getLastThreadError(); } if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) { @@ -193,6 +201,9 @@ bool ImageRequest::processRequest() } done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); mDecodedAux = done && mDecodedImageAux->getData(); + + // Pick up errors from decoding + mErrorString = LLImage::getLastThreadError(); } return done; @@ -204,7 +215,7 @@ void ImageRequest::finishRequest(bool completed) if (mResponder.notNull()) { bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); - mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux, mRequestId); + mResponder->completed(success, mErrorString, mDecodedImageRaw, mDecodedImageAux, mRequestId); } // Will automatically be deleted } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 92d70b451d..8c43a7c32c 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -39,7 +39,7 @@ public: protected: virtual ~Responder(); public: - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0; + virtual void completed(bool success, const std::string& error_message, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0; }; public: diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 6167ba5b43..24b6d34fe2 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -216,6 +216,13 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf releaseResources(); return (FALSE); } + catch (...) + { + mErrorMessage = "LLPngWrapper"; + releaseResources(); + LOG_UNHANDLED_EXCEPTION(""); + return (FALSE); + } // Clean up and return releaseResources(); diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 1e332e0154..e14b2f25ed 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -725,7 +725,7 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position) dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199); - dfltsetting[SETTING_CLOUD_SCROLL_RATE] = llsd::array(0.0f, 0.0f); + dfltsetting[SETTING_CLOUD_SCROLL_RATE] = llsd::array(0.2, 0.01); dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699); dfltsetting[SETTING_CLOUD_VARIANCE] = LLSD::Real(0.0); diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 088d3d1339..1657e9324e 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -118,7 +118,7 @@ const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f; const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE; const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE; -const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e"; +const LLUUID SCULPT_DEFAULT_TEXTURE("be293869-d0d9-0a69-5989-ad27f1946fd4"); // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e"; // Texture rotations are sent over the wire as a S16. This is used to scale the actual float // value to a S16. Don't use 7FFF as it introduces some odd rounding with 180 since it @@ -2086,7 +2086,7 @@ bool LLFlexibleObjectData::fromLLSD(LLSD& sd) LLSculptParams::LLSculptParams() { mType = PARAMS_SCULPT; - mSculptTexture.set(SCULPT_DEFAULT_TEXTURE); + mSculptTexture = SCULPT_DEFAULT_TEXTURE; mSculptType = LL_SCULPT_TYPE_SPHERE; } @@ -2172,7 +2172,7 @@ void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type) U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK; if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX) { - mSculptTexture.set(SCULPT_DEFAULT_TEXTURE); + mSculptTexture = SCULPT_DEFAULT_TEXTURE; mSculptType = LL_SCULPT_TYPE_SPHERE; } else diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 6078abf67e..82881dce4e 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -89,7 +89,7 @@ extern const F32 OBJECT_REV_MIN; extern const F32 OBJECT_REV_MAX; extern const F32 OBJECT_REV_INC; -extern const char *SCULPT_DEFAULT_TEXTURE; +extern const LLUUID SCULPT_DEFAULT_TEXTURE; //============================================================================ diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 1e5e441689..92b373c835 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -354,11 +354,10 @@ void LLFontFreetype::clearFontStreams() } #endif -void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor) +void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, + const char_functor_t& functor) { - // Insert functor fallbacks before generic fallbacks - mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(), - std::make_pair(fallback_font, functor)); + mFallbackFonts.emplace_back(fallback_font, functor); } F32 LLFontFreetype::getLineHeight() const @@ -450,50 +449,95 @@ BOOL LLFontFreetype::hasGlyph(llwchar wch) const LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const { - if (mFTFace == NULL) - return FALSE; + if (!mFTFace) + { + return NULL; + } llassert(!mIsFallback); llassert(glyph_type < EFontGlyphType::Count); //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; - FT_UInt glyph_index; - - // Fallback fonts with a functor have precedence over everything else - fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin(); - /* This leads to a bug SL-19831 "Check marks in the menu are less visible." - ** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render" - for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback) + // Initialize char to glyph map + FT_UInt glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) { - if (it_fallback->second(wch)) + // No corresponding glyph in this font: look for a glyph in fallback + // fonts. + size_t count = mFallbackFonts.size(); + if (LLStringOps::isEmoji(wch)) + { + // This is a "genuine" emoji (in the range 0x1f000-0x20000): print + // it using the emoji font(s) if possible. HB + for (size_t i = 0; i < count; ++i) + { + const fallback_font_t& pair = mFallbackFonts[i]; + if (!pair.second || !pair.second(wch)) + { + // If this font does not have a functor, or the character + // does not pass the functor, reject it. Note: we keep the + // functor test (despite the fact we already tested for + // LLStringOps::isEmoji(wch) above), in case we would use + // different, more restrictive or partionned functors in + // the future with several different emoji fonts. HB + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + } + // Then try and find a monochrome fallback font that could print this + // glyph: such fonts do *not* have a functor. We give priority to + // monochrome fonts for non-genuine emojis so that UI elements which + // used to render with them before the emojis font introduction (e.g. + // check marks in menus, or LSL dialogs text and buttons) do render the + // same way as they always did. HB + std::vector<size_t> emoji_fonts_idx; + for (size_t i = 0; i < count; ++i) { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); + const fallback_font_t& pair = mFallbackFonts[i]; + if (pair.second) + { + // If this font got a functor, remember the index for later and + // try the next fallback font. HB + emoji_fonts_idx.push_back(i); + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); if (glyph_index) { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); } } - } - */ - - // Initialize char to glyph map - glyph_index = FT_Get_Char_Index(mFTFace, wch); - if (glyph_index == 0) - { - //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL; - for (; it_fallback != mFallbackFonts.cend(); ++it_fallback) + // Everything failed so far: this character is not a genuine emoji, + // neither a special character known from our monochrome fallback + // fonts: make a last try, using the emoji font(s), but ignoring the + // functor to render using whatever (colorful) glyph that might be + // available in such fonts for this character. HB + for (size_t j = 0, count2 = emoji_fonts_idx.size(); j < count2; ++j) { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); + const fallback_font_t& pair = mFallbackFonts[emoji_fonts_idx[j]]; + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); if (glyph_index) { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); } } } - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + auto range_it = mCharGlyphInfoMap.equal_range(wch); char_glyph_info_map_t::iterator iter = - std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); + std::find_if(range_it.first, range_it.second, + [&glyph_type](const char_glyph_info_map_t::value_type& entry) + { + return entry.second->mGlyphType == glyph_type; + }); if (iter == range_it.second) { return addGlyphFromFont(this, wch, glyph_index, glyph_type); diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 8d0fed7829..3714bb1883 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -276,6 +276,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons LLColor4U colors[GLYPH_BATCH_SIZE * 4]; LLColor4U text_color(color); + // Preserve the transparency to render fading emojis in fading text (e.g. + // for the chat console)... HB + LLColor4U emoji_color(255, 255, 255, text_color.mV[VW]); std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1); S32 glyph_count = 0; @@ -344,7 +347,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons glyph_count = 0; } - drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength); + const LLColor4U& col = + bitmap_entry.first == EFontGlyphType::Grayscale ? text_color + : emoji_color; + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, + col, style_to_add, shadow, drop_shadow_strength); chars_drawn++; cur_x += fgi->mXAdvance; @@ -1030,7 +1037,21 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name) } //static -LLFontGL* LLFontGL::getFontEmoji() +LLFontGL* LLFontGL::getFontEmojiSmall() +{ + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Small", 0)); + return fontp;; +} + +//static +LLFontGL* LLFontGL::getFontEmojiMedium() +{ + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Medium", 0)); + return fontp;; +} + +//static +LLFontGL* LLFontGL::getFontEmojiLarge() { static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0)); return fontp;; diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 2e1d04a2b9..65f0a8cbfd 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -194,7 +194,9 @@ public: static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } - static LLFontGL* getFontEmoji(); + static LLFontGL* getFontEmojiSmall(); + static LLFontGL* getFontEmojiMedium(); + static LLFontGL* getFontEmojiLarge(); static LLFontGL* getFontEmojiHuge(); static LLFontGL* getFontMonospace(); static LLFontGL* getFontSansSerifSmall(); diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 89969acb1b..3feb989ed5 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -936,3 +936,20 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl expanded_tab_height /= num_expanded; return expanded_tab_height; } + +void LLAccordionCtrl::collapseAllTabs() +{ + if (mAccordionTabs.size() > 0) + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab *tab = mAccordionTabs[i]; + + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } + arrange(); + } +} diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 182c8cfe04..2741db24e8 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -122,6 +122,8 @@ public: void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } void sort(); + void collapseAllTabs(); + /** * Sets filter substring as a search_term for help text when there are no any visible tabs. */ diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 8803d751d0..16b58dcc5b 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -58,10 +58,11 @@ static LLDefaultChildRegistry::Register<LLButton> r("button"); template class LLButton* LLView::getChild<class LLButton>( const std::string& name, BOOL recurse) const; -// globals loaded from settings.xml -S32 LLBUTTON_H_PAD = 0; -S32 BTN_HEIGHT_SMALL= 0; -S32 BTN_HEIGHT = 0; +// globals +S32 LLBUTTON_H_PAD = 4; +S32 BTN_HEIGHT_SMALL= 23; +S32 BTN_HEIGHT = 23; +S32 BTN_DROP_SHADOW = 2; LLButton::Params::Params() : label_selected("label_selected"), // requires is_toggle true @@ -92,8 +93,8 @@ LLButton::Params::Params() image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), flash_color("flash_color"), - pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), - pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), + pad_right("pad_right", LLBUTTON_H_PAD), + pad_left("pad_left", LLBUTTON_H_PAD), pad_bottom("pad_bottom"), click_callback("click_callback"), mouse_down_callback("mouse_down_callback"), diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 7054074fd8..8ac42596e4 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -43,10 +43,10 @@ // // PLEASE please use these "constants" when building your own buttons. -// They are loaded from settings.xml at run time. extern S32 LLBUTTON_H_PAD; extern S32 BTN_HEIGHT_SMALL; extern S32 BTN_HEIGHT; +extern S32 BTN_DROP_SHADOW; // // Helpful functions @@ -251,7 +251,7 @@ public: void setFont(const LLFontGL *font) { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); } const LLFontGL* getFont() const { return mGLFont; } - + const std::string& getText() const { return getCurrentLabel().getString(); } S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; } bool labelIsTruncated() const; diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 43e887fab6..f2b61db308 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -117,7 +117,7 @@ public: std::string getLabel() const; void setFont( const LLFontGL* font ) { mFont = font; } - const LLFontGL* getFont() { return mFont; } + const LLFontGL* getFont() const { return mFont; } virtual void setControlName(const std::string& control_name, LLView* context); diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 1573ccb0d7..71dd93d07d 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -188,6 +188,8 @@ LLComboBox::~LLComboBox() // explicitly disconect this signal, since base class destructor might fire top lost mTopLostSignalConnection.disconnect(); mImageLoadedConnection.disconnect(); + + LLUI::getInstance()->removePopup(this); } @@ -482,8 +484,6 @@ void LLComboBox::onFocusLost() void LLComboBox::setButtonVisible(BOOL visible) { - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); - mButton->setVisible(visible); if (mTextEntry) { @@ -491,7 +491,7 @@ void LLComboBox::setButtonVisible(BOOL visible) if (visible) { S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); @@ -530,19 +530,18 @@ void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled) void LLComboBox::createLineEditor(const LLComboBox::Params& p) { - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); LLRect rect = getLocalRect(); if (mAllowTextEntry) { S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - S32 shadow_size = drop_shadow_button; + S32 shadow_size = BTN_DROP_SHADOW; mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); mButton->setHAlign(LLFontGL::HCENTER); LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; // clear label on button std::string cur_label = mButton->getLabelSelected(); LLLineEditor::Params params = p.combo_editor; @@ -1081,13 +1080,11 @@ void LLComboBox::onSetHighlight() const void LLComboBox::imageLoaded() { - static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0); - if (mAllowTextEntry) { LLRect rect = getLocalRect(); S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - S32 shadow_size = drop_shadow_button; + S32 shadow_size = BTN_DROP_SHADOW; mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); if (mButton->getVisible()) @@ -1096,7 +1093,7 @@ void LLComboBox::imageLoaded() if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button; + text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * BTN_DROP_SHADOW; mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); } } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 96d9e31f4c..75254f80d8 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2039,10 +2039,9 @@ void LLFloater::drawShadow(LLPanel* panel) S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH; S32 bottom = LLPANEL_BORDER_WIDTH; - static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0); static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow"); LLColor4 shadow_color = shadow_color_cached; - F32 shadow_offset = (F32)shadow_offset_S32; + F32 shadow_offset = (F32)DROP_SHADOW_FLOATER; if (!panel->isBackgroundOpaque()) { @@ -2477,7 +2476,8 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) void LLFloaterView::restoreAll() { // make sure all subwindows aren't minimized - for (auto child : *getChildList()) + child_list_t child_list = *(getChildList()); + for (LLView* child : child_list) { LLFloater* floaterp = dynamic_cast<LLFloater*>(child); if (floaterp) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 7fcbd5c5ec..dcc9af4c6e 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -61,6 +61,10 @@ const BOOL CLOSE_NO = FALSE; const BOOL ADJUST_VERTICAL_YES = TRUE; const BOOL ADJUST_VERTICAL_NO = FALSE; +const F32 CONTEXT_CONE_IN_ALPHA = 0.f; +const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; +const F32 CONTEXT_CONE_FADE_TIME = .08f; + namespace LLFloaterEnums { enum EOpenPositioning diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index fa6128cc25..33921cf4f0 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -220,7 +220,7 @@ LLFolderView::LLFolderView(const Params& p) params.font(getLabelFontForStyle(LLFontGL::NORMAL)); params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN); params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); - params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe); + params.prevalidator(&LLTextValidate::validateASCIIPrintableNoPipe); params.commit_on_focus_lost(true); params.visible(false); mRenamer = LLUICtrlFactory::create<LLLineEditor> (params); @@ -256,7 +256,13 @@ LLFolderView::LLFolderView(const Params& p) // Destroys the object LLFolderView::~LLFolderView( void ) { - closeRenamer(); + mRenamerTopLostSignalConnection.disconnect(); + if (mRenamer) + { + // instead of using closeRenamer remove it directly, + // since it might already be hidden + LLUI::getInstance()->removePopup(mRenamer); + } // The release focus call can potentially call the // scrollcontainer, which can potentially be called with a partly @@ -335,9 +341,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height ) void LLFolderView::filter( LLFolderViewFilter& filter ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); - filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100)); + const S32 TIME_VISIBLE = 10; // in milliseconds + const S32 TIME_INVISIBLE = 1; + filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? TIME_VISIBLE : TIME_INVISIBLE), 1, 100)); // Note: we filter the model, not the view getViewModelItem()->filter(filter); @@ -765,7 +771,7 @@ void LLFolderView::removeSelectedItems() } else { - LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL; + LL_DEBUGS() << "Cannot delete " << item->getName() << LL_ENDL; return; } } @@ -1072,7 +1078,10 @@ void LLFolderView::startRenamingSelectedItem( void ) mRenamer->setVisible( TRUE ); // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); - mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); + if (!mRenamerTopLostSignalConnection.connected()) + { + mRenamerTopLostSignalConnection = mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); + } LLUI::getInstance()->addPopup(mRenamer); } } @@ -1598,7 +1607,11 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLFolderView::deleteAllChildren() { - closeRenamer(); + mRenamerTopLostSignalConnection.disconnect(); + if (mRenamer) + { + LLUI::getInstance()->removePopup(mRenamer); + } if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); mPopupMenuHandle.markDead(); mScrollContainer = NULL; diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 1ad7e9f58c..ca78bd3072 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -345,6 +345,8 @@ protected: LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar; + boost::signals2::connection mRenamerTopLostSignalConnection; + bool mForceArrange; public: diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 40bb6832d4..a9e1171444 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -605,15 +605,13 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) { - static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3); - mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); if( hasMouseCapture() && isMovable() ) { LLFolderView* root = getRoot(); - if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold() + if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD && root->getAllowDrag() && root->getCurSelectedItem() && root->startDrag()) diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index c7ed65bdfa..d9e6567cd6 100644 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -48,8 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder) void LLFolderViewModelCommon::filter() { - static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - getFilter().resetTime(llclamp(max_time(), 1, 100)); + const S32 MAX_FILTER_TIME = 10; + getFilter().resetTime(MAX_FILTER_TIME); mFolderView->getViewModelItem()->filter(getFilter()); } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 53ae2bd97f..f02c1e3883 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -170,7 +170,7 @@ public: virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder virtual void move( LLFolderViewModelItem* parent_listener ) = 0; - virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed + virtual BOOL isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed virtual BOOL removeItem() = 0; virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index eefba0d186..6dc68b4de2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -83,8 +83,8 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>( LLLineEditor::Params::Params() : max_length(""), keystroke_callback("keystroke_callback"), - prevalidate_callback("prevalidate_callback"), - prevalidate_input_callback("prevalidate_input_callback"), + prevalidator("prevalidator"), + input_prevalidator("input_prevalidator"), background_image("background_image"), background_image_disabled("background_image_disabled"), background_image_focused("background_image_focused"), @@ -96,6 +96,7 @@ LLLineEditor::Params::Params() commit_on_focus_lost("commit_on_focus_lost", true), ignore_tab("ignore_tab", true), is_password("is_password", false), + allow_emoji("allow_emoji", true), cursor_color("cursor_color"), use_bg_color("use_bg_color", false), bg_color("bg_color"), @@ -111,6 +112,8 @@ LLLineEditor::Params::Params() default_text("default_text") { changeDefault(mouse_opaque, true); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(input_prevalidator, "prevalidate_input_callback"); addSynonym(select_on_focus, "select_all_on_focus_received"); addSynonym(border, "border"); addSynonym(label, "watermark_text"); @@ -142,6 +145,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mIgnoreArrowKeys( FALSE ), mIgnoreTab( p.ignore_tab ), mDrawAsterixes( p.is_password ), + mAllowEmoji( p.allow_emoji ), mSpellCheck( p.spellcheck ), mSpellCheckStart(-1), mSpellCheckEnd(-1), @@ -157,6 +161,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mUseBgColor(p.use_bg_color), mHaveHistory(FALSE), mReplaceNewlinesWithSpaces( TRUE ), + mPrevalidator(p.prevalidator()), + mInputPrevalidator(p.input_prevalidator()), mLabel(p.label), mCursorColor(p.cursor_color()), mBgColor(p.bg_color()), @@ -210,8 +216,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) } mSpellCheckTimer.reset(); - setPrevalidateInput(p.prevalidate_input_callback()); - setPrevalidate(p.prevalidate_callback()); + updateAllowingLanguageInput(); } LLLineEditor::~LLLineEditor() @@ -416,6 +421,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived); std::string truncated_utf8 = new_text; + if (!mAllowEmoji) + { + // Cut emoji symbols if exist + utf8str_remove_emojis(truncated_utf8); + } if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes) { truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes); @@ -589,13 +599,21 @@ void LLLineEditor::replaceWithSuggestion(U32 index) { if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) { + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + if (!mAllowEmoji) + { + // Cut emoji symbols if exist + wstring_remove_emojis(suggestion); + } + if (suggestion.empty()) + return; + deselect(); // Delete the misspelled word mText.erase(it->first, it->second - it->first); // Insert the suggestion in its place - LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); mText.insert(it->first, suggestion); setCursor(it->first + (S32)suggestion.length()); @@ -958,9 +976,11 @@ void LLLineEditor::removeChar() } } - void LLLineEditor::addChar(const llwchar uni_char) { + if (!mAllowEmoji && LLStringOps::isEmoji(uni_char)) + return; + llwchar new_c = uni_char; if (hasSelection()) { @@ -1193,11 +1213,12 @@ void LLLineEditor::cut() deleteSelection(); // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -1260,6 +1281,11 @@ void LLLineEditor::pasteHelper(bool is_primary) if (!paste.empty()) { + if (!mAllowEmoji) + { + wstring_remove_emojis(paste); + } + if (!prevalidateInput(paste)) return; @@ -1321,11 +1347,12 @@ void LLLineEditor::pasteHelper(bool is_primary) deselect(); // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -1568,19 +1595,27 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) deselect(); } - BOOL need_to_rollback = FALSE; + bool prevalidator_failed = false; // If read-only, don't allow changes - need_to_rollback |= (mReadOnly && (mText.getString() == rollback.getText())); + bool need_to_rollback = mReadOnly && (mText.getString() == rollback.getText()); // Validate new string and rollback the keystroke if needed. - need_to_rollback |= (mPrevalidateFunc && !mPrevalidateFunc(mText.getWString())); + if (!need_to_rollback && mPrevalidator) + { + prevalidator_failed = !mPrevalidator.validate(mText.getWString()); + need_to_rollback |= prevalidator_failed; + } if (need_to_rollback) { rollback.doRollback(this); LLUI::getInstance()->reportBadKeystroke(); + if (prevalidator_failed) + { + mPrevalidator.showLastErrorUsingTimeout(); + } } // Notify owner if requested @@ -1627,20 +1662,18 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) deselect(); - BOOL need_to_rollback = FALSE; - // Validate new string and rollback the keystroke if needed. - need_to_rollback |= ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - - if( need_to_rollback ) + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } // Notify owner if requested - if( !need_to_rollback && handled ) + if (!need_to_rollback && handled) { // HACK! The only usage of this callback doesn't do anything with the character. // We'll have to do something about this if something ever changes! - Doug @@ -1683,11 +1716,12 @@ void LLLineEditor::doDelete() } // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { - rollback.doRollback( this ); + rollback.doRollback(this); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -1740,19 +1774,6 @@ void LLLineEditor::drawBackground() } //virtual -const std::string LLLineEditor::getToolTip() const -{ - if (sDebugUnicode) - { - std::string text = getText(); - std::string tooltip = utf8str_showBytesUTF8(text); - return tooltip; - } - - return LLUICtrl::getToolTip(); -} - -//virtual void LLLineEditor::draw() { F32 alpha = getDrawContext().mAlpha; @@ -2232,7 +2253,7 @@ void LLLineEditor::setFocus( BOOL new_state ) // fine on 1.15.0.2, since all prevalidate func reject any // non-ASCII characters. I'm not sure on future versions, // however. - getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL); + getWindow()->allowLanguageTextInput(this, !mPrevalidator); } } @@ -2251,26 +2272,21 @@ void LLLineEditor::setRect(const LLRect& rect) } } -void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidate(LLTextValidate::Validator validator) { - mPrevalidateFunc = func; + mPrevalidator = validator; updateAllowingLanguageInput(); } -void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidateInput(LLTextValidate::Validator validator) { - mPrevalidateInputFunc = func; + mInputPrevalidator = validator; updateAllowingLanguageInput(); } bool LLLineEditor::prevalidateInput(const LLWString& wstr) { - if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr)) - { - return false; - } - - return true; + return mInputPrevalidator.validate(wstr); } // static @@ -2412,7 +2428,7 @@ void LLLineEditor::updateAllowingLanguageInput() // test app, no window available return; } - if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) + if (hasFocus() && !mReadOnly && !mDrawAsterixes && !mPrevalidator) { window->allowLanguageTextInput(this, TRUE); } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 65afa54d04..340308535f 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -76,8 +76,8 @@ public: Optional<MaxLength> max_length; Optional<keystroke_callback_t> keystroke_callback; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_input_callback; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator; Optional<LLViewBorder::Params> border; @@ -93,6 +93,7 @@ public: bg_image_always_focused, show_label_focused, is_password, + allow_emoji, use_bg_color; // colors @@ -175,7 +176,6 @@ public: void onSpellCheckSettingsChange(); // view overrides - /*virtual*/ const std::string getToolTip() const override; /*virtual*/ void draw() override; /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; /*virtual*/ void onFocusReceived() override; @@ -203,7 +203,7 @@ public: void setText(const LLStringExplicit &new_text); - const std::string& getText() const { return mText.getString(); } + const std::string& getText() const override { return mText.getString(); } LLWString getWText() const { return mText.getWString(); } LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines @@ -235,12 +235,13 @@ public: const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); } const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); } - const LLFontGL* getFont() const { return mGLFont; } + const LLFontGL* getFont() const override { return mGLFont; } void setFont(const LLFontGL* font); void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; } void setIgnoreTab(BOOL b) { mIgnoreTab = b; } void setPassDelete(BOOL b) { mPassDelete = b; } + void setAllowEmoji(BOOL b) { mAllowEmoji = b; } void setDrawAsterixes(BOOL b); // get the cursor position of the beginning/end of the prev/next word in the text @@ -267,12 +268,12 @@ public: void setTextPadding(S32 left, S32 right); // Prevalidation controls which keystrokes can affect the editor - void setPrevalidate( LLTextValidate::validate_func_t func ); + void setPrevalidate(LLTextValidate::Validator validator); // This method sets callback that prevents from: // - deleting, selecting, typing, cutting, pasting characters that are not valid. // Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed // symbols, before existing text is modified, but setPrevalidate validates line after it was modified. - void setPrevalidateInput(LLTextValidate::validate_func_t func); + void setPrevalidateInput(LLTextValidate::Validator validator); static BOOL postvalidateFloat(const std::string &str); bool prevalidateInput(const LLWString& wstr); @@ -374,8 +375,8 @@ protected: std::list<std::pair<U32, U32> > mMisspellRanges; std::vector<std::string> mSuggestionList; - LLTextValidate::validate_func_t mPrevalidateFunc; - LLTextValidate::validate_func_t mPrevalidateInputFunc; + LLTextValidate::Validator mPrevalidator; + LLTextValidate::Validator mInputPrevalidator; LLFrameTimer mKeystrokeTimer; LLTimer mTripleClickTimer; @@ -403,6 +404,7 @@ protected: BOOL mShowImageFocused; BOOL mShowLabelFocused; + bool mAllowEmoji; bool mUseBgColor; LLWString mPreeditWString; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 79d0fbd1b4..8fcb558aae 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -65,8 +65,8 @@ LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; view_listener_t::listener_map_t view_listener_t::sListeners; -S32 MENU_BAR_HEIGHT = 0; -S32 MENU_BAR_WIDTH = 0; +S32 MENU_BAR_HEIGHT = 18; +S32 MENU_BAR_WIDTH = 410; ///============================================================================ /// Local function declarations, constants, enums, and typedefs @@ -3234,10 +3234,9 @@ void LLMenuGL::draw( void ) } if (mDropShadowed && !mTornOff) { - static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0); static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, drop_shadow_floater ); + color_drop_shadow, DROP_SHADOW_FLOATER); } if( mBgVisible ) diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp index b2be33b266..eac43900f6 100644 --- a/indra/llui/llmodaldialog.cpp +++ b/indra/llui/llmodaldialog.cpp @@ -67,6 +67,8 @@ LLModalDialog::~LLModalDialog() { LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL; } + + LLUI::getInstance()->removePopup(this); } // virtual @@ -284,10 +286,9 @@ BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask ) void LLModalDialog::draw() { static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); - static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0); gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0, - shadow_color, shadow_lines); + shadow_color, DROP_SHADOW_FLOATER); LLFloater::draw(); diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index 5319b0d3b6..b0598b4388 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -138,7 +138,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.font(p.font); params.max_length.bytes(MAX_STRING_LENGTH); params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit); - params.prevalidate_callback(&LLTextValidate::validateFloat); + params.prevalidator(&LLTextValidate::validateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 875be5bc6f..2fbae73b65 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -87,6 +87,7 @@ LLNotificationForm::FormInput::FormInput() : type("type"), text("text"), max_length_chars("max_length_chars"), + allow_emoji("allow_emoji"), width("width", 0), value("value") {} @@ -1551,6 +1552,11 @@ bool LLNotifications::loadTemplates() // specific skin. std::vector<std::string> search_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + if (search_paths.empty()) + { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL; + } std::string base_filename = search_paths.front(); LLXMLNodePtr root; diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 99f67c06e5..ab4f009a80 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -201,6 +201,7 @@ public: Mandatory<std::string> type; Optional<S32> width; Optional<S32> max_length_chars; + Optional<bool> allow_emoji; Optional<std::string> text; Optional<std::string> value; diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 0073ac4ead..ea2327961a 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -81,7 +81,7 @@ public: alt_value("alt_value", ""), label("label"), tool_tip("tool_tip", ""), - font("font", LLFontGL::getFontSansSerifSmall()), + font("font", LLFontGL::getFontEmojiSmall()), font_color("font_color", LLColor4::black), color("color", LLColor4::white), font_halign("halign", LLFontGL::LEFT) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 5b9944d3e0..7fb732eca3 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1810,7 +1810,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask) // display tooltip exactly over original cell, in same font LLToolTipMgr::instance().show(LLToolTip::Params() .message(hit_cell->getToolTip()) - .font(LLFontGL::getFontSansSerifSmall()) + .font(LLFontGL::getFontEmojiSmall()) .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6)) .delay_time(0.2f) .sticky_rect(sticky_rect)); @@ -3294,7 +3294,7 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E item_params.value(entry_id); item_params.columns.add() .value(value) - .font(LLFontGL::getFontSansSerifSmall()); + .font(LLFontGL::getFontEmojiSmall()); return addRow(item_params, pos); } diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 53eb667a1d..e16ba9408e 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -167,7 +167,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) } line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit); - line_p.prevalidate_callback(&LLTextValidate::validateFloat); + line_p.prevalidator(&LLTextValidate::validateFloat); mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 46f60508b2..78c4f3c03c 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -225,7 +225,8 @@ LLTabContainer::Params::Params() tabs_flashing_color("tabs_flashing_color"), tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), use_ellipses("use_ellipses"), - font_halign("halign") + font_halign("halign"), + use_tab_offset("use_tab_offset", false) {} LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) @@ -264,7 +265,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mTabIconCtrlPad(p.tab_icon_ctrl_pad), mEnableTabsFlashing(p.enable_tabs_flashing), mTabsFlashingColor(p.tabs_flashing_color), - mUseTabEllipses(p.use_ellipses) + mUseTabEllipses(p.use_ellipses), + mUseTabOffset(p.use_tab_offset) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -1023,10 +1025,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) } else { - tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3, - tab_panel_top, - getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2, - tab_panel_bottom ); + S32 left_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 3 : LLPANEL_BORDER_WIDTH; + S32 right_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 2 : LLPANEL_BORDER_WIDTH; + tab_panel_rect = LLRect(left_offset, tab_panel_top, getRect().getWidth() - right_offset, tab_panel_bottom); } child->setFollowsAll(); child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 0604785e7a..626255be8c 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -121,6 +121,8 @@ public: */ Optional<S32> tab_icon_ctrl_pad; + Optional<bool> use_tab_offset; + Params(); }; @@ -321,6 +323,8 @@ private: S32 mTabIconCtrlPad; bool mUseTabEllipses; LLFrameTimer mMouseDownTimer; + + bool mUseTabOffset; }; #endif // LL_TABCONTAINER_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 1460bb85b6..c1eedf93a7 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -168,6 +168,7 @@ LLTextBase::Params::Params() trusted_content("trusted_content", true), always_show_icons("always_show_icons", false), use_ellipses("use_ellipses", false), + use_emoji("use_emoji", true), use_color("use_color", true), parse_urls("parse_urls", false), force_urls_external("force_urls_external", false), @@ -227,6 +228,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mPlainText ( p.plain_text ), mWordWrap(p.wrap), mUseEllipses( p.use_ellipses ), + mUseEmoji(p.use_emoji), mUseColor(p.use_color), mParseHTML(p.parse_urls), mForceUrlsExternal(p.force_urls_external), @@ -903,6 +905,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } // Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) + if (mUseEmoji) { LLStyleSP emoji_style; LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; @@ -915,7 +918,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s if (!emoji_style) { emoji_style = new LLStyle(getStyleParams()); - emoji_style->setFont(LLFontGL::getFontEmoji()); + emoji_style->setFont(LLFontGL::getFontEmojiLarge()); } S32 new_seg_start = pos + text_kitty; @@ -1287,19 +1290,6 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) } //virtual -const std::string LLTextBase::getToolTip() const -{ - if (sDebugUnicode) - { - std::string text = getText(); - std::string tooltip = utf8str_showBytesUTF8(text); - return tooltip; - } - - return LLUICtrl::getToolTip(); -} - -//virtual void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) { if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape) @@ -2182,10 +2172,10 @@ void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params& onValueChange(0, getLength()); } -//virtual -std::string LLTextBase::getText() const +// virtual +const std::string& LLTextBase::getText() const { - return getViewModel()->getValue().asString(); + return getViewModel()->getStringValue(); } // IDEVO - icons can be UI image names or UUID sent from diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 13fb1ff397..97507fe800 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -328,6 +328,7 @@ public: plain_text, wrap, use_ellipses, + use_emoji, use_color, parse_urls, force_urls_external, @@ -366,7 +367,6 @@ public: /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override; // LLView interface - /*virtual*/ const std::string getToolTip() const override; /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; /*virtual*/ void draw() override; @@ -408,12 +408,15 @@ public: virtual void onSpellCheckPerformed(){} // used by LLTextSegment layout code - bool getWordWrap() { return mWordWrap; } - bool getUseEllipses() { return mUseEllipses; } - bool getUseColor() { return mUseColor; } + bool getWordWrap() const { return mWordWrap; } + bool getUseEllipses() const { return mUseEllipses; } + bool getUseEmoji() const { return mUseEmoji; } + void setUseEmoji(bool value) { mUseEmoji = value; } + bool getUseColor() const { return mUseColor; } + void setUseColor(bool value) { mUseColor = value; } bool truncate(); // returns true of truncation occurred - bool isContentTrusted() {return mTrustedContent;} + bool isContentTrusted() const { return mTrustedContent; } void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; } // TODO: move into LLTextSegment? @@ -422,7 +425,7 @@ public: // Text accessors // TODO: add optional style parameter virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style - virtual std::string getText() const; + /*virtual*/ const std::string& getText() const override; void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } S32 getMaxTextLength() { return mMaxTextByteLength; } @@ -495,7 +498,7 @@ public: bool scrolledToStart(); bool scrolledToEnd(); - const LLFontGL* getFont() const { return mFont; } + const LLFontGL* getFont() const override { return mFont; } virtual void appendLineBreakSegment(const LLStyle::Params& style_params); virtual void appendImageSegment(const LLStyle::Params& style_params); @@ -716,6 +719,7 @@ protected: bool mParseHighlights; // highlight user-defined keywords bool mWordWrap; bool mUseEllipses; + bool mUseEmoji; bool mUseColor; bool mTrackEnd; // if true, keeps scroll position at end of document during resize bool mReadOnly; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 4fd650f2da..e030861f20 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -232,7 +232,7 @@ private: /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() : default_text("default_text"), - prevalidate_callback("prevalidate_callback"), + prevalidator("prevalidator"), embedded_items("embedded_items", false), ignore_tab("ignore_tab", true), auto_indent("auto_indent", true), @@ -242,7 +242,8 @@ LLTextEditor::Params::Params() show_emoji_helper("show_emoji_helper"), enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(prevalidator, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : @@ -253,16 +254,17 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mLastCmd( NULL ), mDefaultColor( p.default_color() ), mAutoIndent(p.auto_indent), + mParseOnTheFly(false), mCommitOnFocusLost( p.commit_on_focus_lost), mAllowEmbeddedItems( p.embedded_items ), mMouseDownX(0), mMouseDownY(0), mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), + mPrevalidator(p.prevalidator()), mShowContextMenu(p.show_context_menu), mShowEmojiHelper(p.show_emoji_helper), mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), + mPassDelete(false), mKeepSelectionOnReturn(false) { mSourceID.generate(); @@ -278,7 +280,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : addChild( mBorder ); setText(p.default_text()); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) @@ -319,11 +321,13 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { // validate incoming text if necessary - if (mPrevalidateFunc) + if (mPrevalidator) { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) + if (!mPrevalidator.validate(utf8str)) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + // not valid text, nothing to do return; } @@ -332,9 +336,9 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param blockUndo(); deselect(); - mParseOnTheFly = FALSE; + mParseOnTheFly = false; LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; resetDirty(); } @@ -609,7 +613,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces ) // Disabling parsing on the fly to avoid updating text segments // until all indentation commands are executed. - mParseOnTheFly = FALSE; + mParseOnTheFly = false; // Find each start-of-line and indent it do @@ -636,7 +640,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces ) } while( cur < right ); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; if( (right < getLength()) && (text[right] == '\n') ) { @@ -685,7 +689,7 @@ void LLTextEditor::insertEmoji(llwchar emoji) { LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); + styleParams.font = LLFontGL::getFontEmojiLarge(); auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); insert(mCursorPos, LLWString(1, emoji), false, segment); setCursorPos(mCursorPos + 1); @@ -986,10 +990,12 @@ S32 LLTextEditor::execute( TextCmd* cmd ) mUndoStack.push_front(cmd); mLastCmd = cmd; - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay()); if (need_to_rollback) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + // get rid of this last command and clean up undo stack undo(); @@ -1125,16 +1131,15 @@ void LLTextEditor::removeChar() // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength) { - make_ui_sound("UISndBadKeystroke"); + LLUI::getInstance()->reportBadKeystroke(); return 0; } if (mLastCmd && mLastCmd->canExtend(pos)) { - S32 delta = 0; - if (mPrevalidateFunc) + if (mPrevalidator) { // get a copy of current text contents LLWString test_string(getViewModel()->getDisplay()); @@ -1142,28 +1147,31 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) // modify text contents as if this addChar succeeded llassert(pos <= (S32)test_string.size()); test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) + if (!mPrevalidator.validate(test_string)) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); return 0; } } + + S32 delta = 0; mLastCmd->extendAndExecute(this, pos, wc, &delta); return delta; } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) + if (!getEnabled()) { return; } - if( hasSelection() ) + + if (hasSelection()) { deleteSelection(TRUE); } @@ -1508,7 +1516,13 @@ void LLTextEditor::pastePrimary() // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; + struct BoolReset + { + BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; } + ~BoolReset() { *mValuePtr = true; } + bool* mValuePtr; + } reset(mParseOnTheFly); + bool can_paste_it; if (is_primary) { @@ -1550,7 +1564,6 @@ void LLTextEditor::pasteHelper(bool is_primary) deselect(); onKeyStroke(); - mParseOnTheFly = TRUE; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index e965848ce1..e917f65fbd 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -54,7 +54,7 @@ public: struct Params : public LLInitParam::Block<Params, LLTextBase::Params> { Optional<std::string> default_text; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; Optional<bool> embedded_items, ignore_tab, @@ -337,7 +337,7 @@ private: LLCoordGL mLastIMEPosition; // Last position of the IME editor keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + LLTextValidate::Validator mPrevalidator; LLHandle<LLContextMenu> mContextMenuHandle; }; // end class LLTextEditor diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 07f8ac01a1..9e27ed6232 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltextvalidate.cpp * @brief Text validation helper functions * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,328 +29,450 @@ #include "linden_common.h" #include "lltextvalidate.h" + +#include "llnotificationsutil.h" +#include "lltrans.h" + #include "llresmgr.h" // for LLLocale namespace LLTextValidate { - void ValidateTextNamedFuncs::declareValues() + +static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); } +static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); } + +static LLSD llsd(const std::string& str) { return LLSD(str); } +static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); } +template <class CHAR> +LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(1, ch)); } + +void ValidatorImpl::setLastErrorShowTime() +{ + mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime(); +} + +void Validator::showLastErrorUsingTimeout(U32 timeout) +{ + if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout) { - declare("ascii", validateASCII); - declare("float", validateFloat); - declare("int", validateInt); - declare("positive_s32", validatePositiveS32); - declare("non_negative_s32", validateNonNegativeS32); - declare("alpha_num", validateAlphaNum); - declare("alpha_num_space", validateAlphaNumSpace); - declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); - declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); - declare("ascii_with_newline", validateASCIIWithNewLine); + mImpl->setLastErrorShowTime(); + std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues()); + LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason)); } +} - // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateFloat(const LLWString &str) +// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorFloat : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) { LLLocale locale(LLLocale::USER_LOCALE); - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); S32 len = trimmed.length(); - if( 0 < len ) + if (0 < len) { // May be a comma or period, depending on the locale - llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint(); + CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint(); S32 i = 0; // First character can be a negative sign - if( '-' == trimmed[0] ) + if ('-' == trimmed.front()) { i++; } - for( ; i < len; i++ ) + for (; i < len; i++) { - if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) ) + CHAR ch = trimmed[i]; + if ((decimal_point != ch) && !LLStringOps::isDigit(ch)) { - success = FALSE; - break; + return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch))); } } } - return success; + return resetError(); } - // Limits what characters can be used to [1234567890-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateInt(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorFloatImpl; +Validator validateFloat(validatorFloatImpl); + +// Limits what characters can be used to [1234567890-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorInt : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) { LLLocale locale(LLLocale::USER_LOCALE); - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); S32 len = trimmed.length(); - if( 0 < len ) + if (0 < len) { S32 i = 0; // First character can be a negative sign - if( '-' == trimmed[0] ) + if ('-' == trimmed.front()) { i++; } - for( ; i < len; i++ ) + for (; i < len; i++) { - if( !LLStringOps::isDigit( trimmed[i] ) ) + CHAR ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) { - success = FALSE; - break; + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); } } } - return success; + return resetError(); } - bool validatePositiveS32(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorIntImpl; +Validator validateInt(validatorIntImpl); + +class ValidatorPositiveS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { LLLocale locale(LLLocale::USER_LOCALE); - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) + if (0 < len) { - if(('-' == trimmed[0]) || ('0' == trimmed[0])) + CHAR ch = trimmed.front(); + + if (('-' == ch) || ('0' == ch)) { - success = FALSE; + return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch))); } - S32 i = 0; - while(success && (i < len)) + + for (S32 i = 0; i < len; ++i) { - if(!LLStringOps::isDigit(trimmed[i++])) + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) { - success = FALSE; + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); } } } - if (success) + + S32 val = strtol(trimmed); + if (val <= 0) { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val <= 0) - { - success = FALSE; - } + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); } - return success; + + return resetError(); } - bool validateNonNegativeS32(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorPositiveS32Impl; +Validator validatePositiveS32(validatorPositiveS32Impl); + +class ValidatorNonNegativeS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { LLLocale locale(LLLocale::USER_LOCALE); - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) + if (0 < len) { - if('-' == trimmed[0]) + CHAR ch = trimmed.front(); + + if ('-' == ch) { - success = FALSE; + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); } - S32 i = 0; - while(success && (i < len)) + + for (S32 i = 0; i < len; ++i) { - if(!LLStringOps::isDigit(trimmed[i++])) + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) { - success = FALSE; + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); } } } - if (success) + + S32 val = strtol(trimmed); + if (val < 0) { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); } - return success; + + return resetError(); } - bool validateNonNegativeS32NoSpace(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32Impl; +Validator validateNonNegativeS32(validatorNonNegativeS32Impl); + +class ValidatorNonNegativeS32NoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { LLLocale locale(LLLocale::USER_LOCALE); - LLWString test_str = str; + std::basic_string<CHAR> test_str = str; S32 len = test_str.length(); - bool success = TRUE; - if(0 < len) + if (0 < len) { - if('-' == test_str[0]) + CHAR ch = test_str.front(); + + if ('-' == ch) { - success = FALSE; + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); } - S32 i = 0; - while(success && (i < len)) + + for (S32 i = 0; i < len; ++i) { - if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++])) + ch = test_str[i]; + if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch)) { - success = FALSE; + return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch))); } } } - if (success) + + S32 val = strtol(test_str); + if (val < 0) { - S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str))); } - return success; + + return resetError(); } - bool validateAlphaNum(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32NoSpaceImpl; +Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl); + +class ValidatorAlphaNum : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { LLLocale locale(LLLocale::USER_LOCALE); - bool rv = TRUE; S32 len = str.length(); - if(len == 0) return rv; - while(len--) + while (len--) { - if( !LLStringOps::isAlnum((char)str[len]) ) + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch)) { - rv = FALSE; - break; + return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } - bool validateAlphaNumSpace(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumImpl; +Validator validateAlphaNum(validatorAlphaNumImpl); + +class ValidatorAlphaNumSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { LLLocale locale(LLLocale::USER_LOCALE); - bool rv = TRUE; S32 len = str.length(); - if(len == 0) return rv; - while(len--) + while (len--) { - if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len]))) + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch) && (' ' != ch)) { - rv = FALSE; - break; + return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } - // Used for most names of things stored on the server, due to old file-formats - // that used the pipe (|) for multiline text storage. Examples include - // inventory item names, parcel names, object names, etc. - bool validateASCIIPrintableNoPipe(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumSpaceImpl; +Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl); + +// Used for most names of things stored on the server, due to old file-formats +// that used the pipe (|) for multiline text storage. Examples include +// inventory item names, parcel names, object names, etc. +class ValidatorASCIIPrintableNoPipe : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { - bool rv = TRUE; S32 len = str.length(); - if(len == 0) return rv; - while(len--) + while (len--) { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || wc == '|') - { - rv = FALSE; - break; - } - if(!(wc == ' ' - || LLStringOps::isAlnum((char)wc) - || LLStringOps::isPunct((char)wc) ) ) + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f || ch == '|' || + (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) { - rv = FALSE; - break; + return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoPipeImpl; +Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl); - // Used for avatar names - bool validateASCIIPrintableNoSpace(const LLWString &str) +// Used for avatar names +class ValidatorASCIIPrintableNoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { - bool rv = TRUE; S32 len = str.length(); - if(len == 0) return rv; - while(len--) + while (len--) { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || LLStringOps::isSpace(wc)) - { - rv = FALSE; - break; - } - if( !(LLStringOps::isAlnum((char)str[len]) || - LLStringOps::isPunct((char)str[len]) ) ) + CHAR ch = str[len]; + + if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) || + (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) { - rv = FALSE; - break; + return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } - bool validateASCII(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoSpaceImpl; +Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl); + +class ValidatorASCII : public ValidatorImpl +{ +protected: + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { - bool rv = TRUE; S32 len = str.length(); - while(len--) + while (len--) { - if (str[len] < 0x20 || str[len] > 0x7f) + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f) { - rv = FALSE; - break; + return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } - bool validateASCIINoLeadingSpace(const LLWString &str) +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIImpl; +Validator validateASCII(validatorASCIIImpl); + +class ValidatorASCIINoLeadingSpace : public ValidatorASCII +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { - if (LLStringOps::isSpace(str[0])) + if (LLStringOps::isSpace(str.front())) { - return FALSE; + return false; } - return validateASCII(str); + + return ValidatorASCII::validate<CHAR>(str); } +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIINoLeadingSpaceImpl; +Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl); + +class ValidatorASCIIWithNewLine : public ValidatorImpl +{ // Used for multiline text stored on the server. // Example is landmark description in Places SP. - bool validateASCIIWithNewLine(const LLWString &str) + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) { - bool rv = TRUE; S32 len = str.length(); - while(len--) + while (len--) { - if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f) + CHAR ch = str[len]; + + if ((ch < 0x20 && ch != 0xA) || ch > 0x7f) { - rv = FALSE; - break; + return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); } } - return rv; + + return resetError(); } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIWithNewLineImpl; +Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl); + +void Validators::declareValues() +{ + declare("ascii", validateASCII); + declare("float", validateFloat); + declare("int", validateInt); + declare("positive_s32", validatePositiveS32); + declare("non_negative_s32", validateNonNegativeS32); + declare("alpha_num", validateAlphaNum); + declare("alpha_num_space", validateAlphaNumSpace); + declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); + declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); + declare("ascii_with_newline", validateASCIIWithNewLine); } + +} // namespace LLTextValidate diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index 0dfec1b612..2c2941de7f 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -1,4 +1,4 @@ -/** +/** * @file lltextbase.h * @author Martin Reddy * @brief The base class of text box/editor, providing Url handling support @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,27 +34,68 @@ namespace LLTextValidate { - typedef boost::function<BOOL (const LLWString &wstr)> validate_func_t; + class ValidatorImpl + { + public: + ValidatorImpl() {} + virtual ~ValidatorImpl() {} + + virtual bool validate(const std::string& str) = 0; + virtual bool validate(const LLWString& str) = 0; + + bool setError(std::string name, LLSD values = LLSD()) { return mLastErrorName = name, mLastErrorValues = values, false; } + bool resetError() { return mLastErrorName.clear(), mLastErrorValues.clear(), true; } + const std::string& getLastErrorName() const { return mLastErrorName; } + const LLSD& getLastErrorValues() const { return mLastErrorValues; } + + void setLastErrorShowTime(); + U32 getLastErrorShowTime() const { return mLastErrorShowTime; } + + protected: + std::string mLastErrorName; + LLSD mLastErrorValues; + U32 mLastErrorShowTime { 0 }; + }; - struct ValidateTextNamedFuncs - : public LLInitParam::TypeValuesHelper<validate_func_t, ValidateTextNamedFuncs> + class Validator { - static void declareValues(); + public: + Validator() : mImpl(nullptr) {} + Validator(ValidatorImpl& impl) : mImpl(&impl) {} + Validator(const Validator& validator) : mImpl(validator.mImpl) {} + Validator(const Validator* validator) : mImpl(validator->mImpl) {} + + bool validate(const std::string& str) const { return !mImpl || mImpl->validate(str); } + bool validate(const LLWString& str) const { return !mImpl || mImpl->validate(str); } + + operator bool() const { return mImpl; } + + static const U32 SHOW_LAST_ERROR_TIMEOUT_SEC = 30; + void showLastErrorUsingTimeout(U32 timeout = SHOW_LAST_ERROR_TIMEOUT_SEC); + + private: + ValidatorImpl* mImpl; }; - bool validateFloat(const LLWString &str ); - bool validateInt(const LLWString &str ); - bool validatePositiveS32(const LLWString &str); - bool validateNonNegativeS32(const LLWString &str); - bool validateNonNegativeS32NoSpace(const LLWString &str); - bool validateAlphaNum(const LLWString &str ); - bool validateAlphaNumSpace(const LLWString &str ); - bool validateASCIIPrintableNoPipe(const LLWString &str); - bool validateASCIIPrintableNoSpace(const LLWString &str); - bool validateASCII(const LLWString &str); - bool validateASCIINoLeadingSpace(const LLWString &str); - bool validateASCIIWithNewLine(const LLWString &str); -} + // Available validators + extern Validator validateFloat; + extern Validator validateInt; + extern Validator validatePositiveS32; + extern Validator validateNonNegativeS32; + extern Validator validateNonNegativeS32NoSpace; + extern Validator validateAlphaNum; + extern Validator validateAlphaNumSpace; + extern Validator validateASCIIPrintableNoPipe; + extern Validator validateASCIIPrintableNoSpace; + extern Validator validateASCII; + extern Validator validateASCIINoLeadingSpace; + extern Validator validateASCIIWithNewLine; + // Add available validators to the internal map + struct Validators : public LLInitParam::TypeValuesHelper<Validator, Validators> + { + static void declareValues(); + }; +}; #endif diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp index ca9c05bb6a..3d404293c6 100644 --- a/indra/llui/lltimectrl.cpp +++ b/indra/llui/lltimectrl.cpp @@ -49,6 +49,36 @@ const U32 HOURS_MAX = 12; const U32 MINUTES_PER_HOUR = 60; const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR; +class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl +{ +public: + // virtual + bool validate(const std::string& str) override + { + std::string hours = LLTimeCtrl::getHoursString(str); + if (!LLTimeCtrl::isHoursStringValid(hours)) + return setError("ValidatorInvalidHours", LLSD().with("STR", hours)); + + std::string minutes = LLTimeCtrl::getMinutesString(str); + if (!LLTimeCtrl::isMinutesStringValid(minutes)) + return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes)); + + std::string ampm = LLTimeCtrl::getAMPMString(str); + if (!LLTimeCtrl::isPMAMStringValid(ampm)) + return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm)); + + return resetError(); + } + + // virtual + bool validate(const LLWString& wstr) override + { + std::string str = wstring_to_utf8str(wstr); + + return validate(str); + } +} validateTimeImpl; +LLTextValidate::Validator validateTime(validateTimeImpl); LLTimeCtrl::Params::Params() : label_width("label_width"), @@ -111,7 +141,7 @@ LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p) params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1)); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); - mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1)); + mEditor->setPrevalidate(validateTime); mEditor->setText(LLStringExplicit("12:00 AM")); addChild(mEditor); @@ -247,15 +277,6 @@ void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor) mTime = h24 * MINUTES_PER_HOUR + m; } -bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr) -{ - std::string str = wstring_to_utf8str(wstr); - - return isHoursStringValid(getHoursString(str)) && - isMinutesStringValid(getMinutesString(str)) && - isPMAMStringValid(getAMPMString(str)); -} - void LLTimeCtrl::increaseMinutes() { mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin); diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h index ff46bc76ca..a2c016ab6f 100644 --- a/indra/llui/lltimectrl.h +++ b/indra/llui/lltimectrl.h @@ -60,6 +60,18 @@ public: void setTime24(F32 time); // 0.0 - 23.98(3) + static std::string getHoursString(const std::string& str); + static std::string getMinutesString(const std::string& str); + static std::string getAMPMString(const std::string& str); + + static bool isHoursStringValid(const std::string& str); + static bool isMinutesStringValid(const std::string& str); + static bool isPMAMStringValid(const std::string& str); + + static U32 parseHours(const std::string& str); + static U32 parseMinutes(const std::string& str); + static bool parseAMPM(const std::string& str); + protected: LLTimeCtrl(const Params&); friend class LLUICtrlFactory; @@ -87,8 +99,6 @@ private: void onDownBtn(); void onTextEntry(LLLineEditor* line_editor); - bool isTimeStringValid(const LLWString& wstr); - void increaseMinutes(); void increaseHours(); @@ -102,18 +112,6 @@ private: EEditingPart getEditingPart(); - static std::string getHoursString(const std::string& str); - static std::string getMinutesString(const std::string& str); - static std::string getAMPMString(const std::string& str); - - static bool isHoursStringValid(const std::string& str); - static bool isMinutesStringValid(const std::string& str); - static bool isPMAMStringValid(const std::string& str); - - static U32 parseHours(const std::string& str); - static U32 parseMinutes(const std::string& str); - static bool parseAMPM(const std::string& str); - class LLTextBox* mLabelBox; class LLLineEditor* mEditor; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 87b5b8b9af..8a6cb683d2 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1133,8 +1133,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask) BOOL handled = FALSE; S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); - static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3); - if (mouse_distance_squared > drag_threshold * drag_threshold + if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD && hasMouseCapture() && mStartDragItemCallback && mHandleDragItemCallback) { diff --git a/indra/llui/llui.h b/indra/llui/llui.h index de1a87f17c..471602515d 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -53,7 +53,7 @@ class LLWindow; class LLView; class LLHelp; - +const S32 DRAG_N_DROP_DISTANCE_THRESHOLD = 3; // this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim) enum EDragAndDropType { diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 5a66009b78..69093393d9 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -80,7 +80,7 @@ LLUICtrl::Params::Params() mouseenter_callback("mouseenter_callback"), mouseleave_callback("mouseleave_callback"), control_name("control_name"), - font("font", LLFontGL::getFontSansSerif()), + font("font", LLFontGL::getFontEmojiMedium()), font_halign("halign"), font_valign("valign"), length("length"), // ignore LLXMLNode cruft diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index afe8493501..d21e8dc1c6 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -41,6 +41,7 @@ const BOOL TAKE_FOCUS_YES = TRUE; const BOOL TAKE_FOCUS_NO = FALSE; +const S32 DROP_SHADOW_FLOATER = 5; class LLUICtrl : public LLView, public boost::signals2::trackable diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index a41b7ba4a8..877585cbef 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -898,6 +898,34 @@ F32 LLView::getTooltipTimeout() : tooltip_delay); } +// virtual +const std::string LLView::getToolTip() const +{ + if (sDebugUnicode) + { + std::string text = getText(); + if (!text.empty()) + { + const std::string& name = getName(); + std::string tooltip = llformat("Name: \"%s\"", name.c_str()); + + if (const LLFontGL* font = getFont()) + { + tooltip += llformat("\nFont: %s (%s)", + font->getFontDesc().getName().c_str(), + font->getFontDesc().getSize().c_str() + ); + } + + tooltip += "\n\n" + utf8str_showBytesUTF8(text); + + return tooltip; + } + } + + return mToolTipMsg.getString(); +} + BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 321afdab31..fefdd83bd4 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -244,7 +244,9 @@ public: ECursorType getHoverCursor() { return mHoverCursor; } static F32 getTooltipTimeout(); - virtual const std::string getToolTip() const { return mToolTipMsg.getString(); } + virtual const std::string getToolTip() const; + virtual const std::string& getText() const { return LLStringUtil::null; } + virtual const LLFontGL* getFont() const { return nullptr; } void sendChildToFront(LLView* child); void sendChildToBack(LLView* child); diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp index 3847d073b4..93106b344f 100644 --- a/indra/llui/llviewmodel.cpp +++ b/indra/llui/llviewmodel.cpp @@ -81,7 +81,7 @@ void LLTextViewModel::setValue(const LLSD& value) { // approximate LLSD storage usage LLViewModel::setValue(value); - mDisplay = utf8str_to_wstring(value.asString()); + mDisplay = utf8str_to_wstring(mStringValue = value.asString()); // mDisplay and mValue agree mUpdateFromDisplay = false; @@ -101,23 +101,34 @@ void LLTextViewModel::setDisplay(const LLWString& value) mUpdateFromDisplay = true; } -LLSD LLTextViewModel::getValue() const +inline void updateFromDisplayIfNeeded(const LLTextViewModel* model) { - // Has anyone called setDisplay() since the last setValue()? If so, have - // to convert mDisplay back to UTF8. - if (mUpdateFromDisplay) + // Has anyone called setDisplay() since the last setValue()? + // If so, have to convert mDisplay back to UTF8. + if (model->mUpdateFromDisplay) { - // The fact that we're lazily updating fields in this object should be - // transparent to clients, which is why this method is left - // conventionally const. Nor do we particularly want to make these - // members mutable. Just cast away constness in this one place. - LLTextViewModel* nthis = const_cast<LLTextViewModel*>(this); + // The fact that we're lazily updating fields + // in this object should be transparent to clients, + // which is why this method is left conventionally const. + // Nor do we particularly want to make these members mutable. + // Just cast away constness in this one place. + LLTextViewModel* nthis = const_cast<LLTextViewModel*>(model); nthis->mUpdateFromDisplay = false; - nthis->mValue = wstring_to_utf8str(mDisplay); + nthis->mValue = nthis->mStringValue = wstring_to_utf8str(model->mDisplay); } - return LLViewModel::getValue(); } +LLSD LLTextViewModel::getValue() const +{ + updateFromDisplayIfNeeded(this); + return mValue; +} + +const std::string& LLTextViewModel::getStringValue() const +{ + updateFromDisplayIfNeeded(this); + return mStringValue; +} //////////////////////////////////////////////////////////////////////////// diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index de6749f490..6cf2200a81 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -100,6 +100,7 @@ public: // LLViewModel functions virtual void setValue(const LLSD& value); virtual LLSD getValue() const; + const std::string& getStringValue() const; // New functions /// Get the stored value in string form @@ -114,12 +115,17 @@ public: void setDisplay(const LLWString& value); private: + std::string mStringValue; + /// To avoid converting every widget's stored value from LLSD to LLWString /// every frame, cache the converted value LLWString mDisplay; + /// As the user edits individual characters (setDisplay()), defer /// LLWString-to-UTF8 conversions until s/he's done. bool mUpdateFromDisplay; + + friend void updateFromDisplayIfNeeded(const LLTextViewModel* model); }; /** diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 8ccda101c1..aff9334cb6 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -199,7 +199,13 @@ public: // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; - virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; }; + virtual bool getInputDevices(U32 device_type_filter, + std::function<bool(std::string&, LLSD&, void*)> osx_callback, + void* win_callback, + void* userdata) + { + return false; + }; virtual S32 getRefreshRate() { return mRefreshRate; } protected: diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 690fe058db..2e75d309ea 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -27,6 +27,7 @@ #include <AppKit/AppKit.h> #include <Cocoa/Cocoa.h> +#include <errno.h> #include "llopenglview-objc.h" #include "llwindowmacosx-objc.h" #include "llappdelegate-objc.h" diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 34ec85bcf6..453905b19b 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -43,6 +43,13 @@ #include <CoreServices/CoreServices.h> #include <CoreGraphics/CGDisplayConfiguration.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOMessage.h> +#include <IOKit/hid/IOHIDUsageTables.h> +#include <IOKit/hid/IOHIDLib.h> +#include <IOKit/usb/IOUSBLib.h> + extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; @@ -212,13 +219,16 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) { - if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) - { - key = gKeyboard->inverseTranslateKey('Y'); - } - else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + //if (mask!=MASK_NONE) { - key = gKeyboard->inverseTranslateKey('Z'); + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } } mRawKeyEvent = event; @@ -1841,6 +1851,486 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) } } +// String should match ndof, so string mapping code was copied as is +static char mapChar( char c ) +{ + unsigned char uc = ( unsigned char ) c; + + switch( uc ) + { + case '/': return '-'; // use dash instead of slash + + case 0x7F: return ' '; + case 0x80: return 'A'; + case 0x81: return 'A'; + case 0x82: return 'C'; + case 0x83: return 'E'; + case 0x84: return 'N'; + case 0x85: return 'O'; + case 0x86: return 'U'; + case 0x87: return 'a'; + case 0x88: return 'a'; + case 0x89: return 'a'; + case 0x8A: return 'a'; + case 0x8B: return 'a'; + case 0x8C: return 'a'; + case 0x8D: return 'c'; + case 0x8E: return 'e'; + case 0x8F: return 'e'; + case 0x90: return ' '; + case 0x91: return ' '; // ? ' + case 0x92: return ' '; // ? ' + case 0x93: return ' '; // ? " + case 0x94: return ' '; // ? " + case 0x95: return ' '; + case 0x96: return ' '; + case 0x97: return ' '; + case 0x98: return ' '; + case 0x99: return ' '; + case 0x9A: return ' '; + case 0x9B: return 0x27; + case 0x9C: return 0x22; + case 0x9D: return ' '; + case 0x9E: return ' '; + case 0x9F: return ' '; + case 0xA0: return ' '; + case 0xA1: return ' '; + case 0xA2: return ' '; + case 0xA3: return ' '; + case 0xA4: return ' '; + case 0xA5: return ' '; + case 0xA6: return ' '; + case 0xA7: return ' '; + case 0xA8: return ' '; + case 0xA9: return ' '; + case 0xAA: return ' '; + case 0xAB: return ' '; + case 0xAC: return ' '; + case 0xAD: return ' '; + case 0xAE: return ' '; + case 0xAF: return ' '; + case 0xB0: return ' '; + case 0xB1: return ' '; + case 0xB2: return ' '; + case 0xB3: return ' '; + case 0xB4: return ' '; + case 0xB5: return ' '; + case 0xB6: return ' '; + case 0xB7: return ' '; + case 0xB8: return ' '; + case 0xB9: return ' '; + case 0xBA: return ' '; + case 0xBB: return ' '; + case 0xBC: return ' '; + case 0xBD: return ' '; + case 0xBE: return ' '; + case 0xBF: return ' '; + case 0xC0: return ' '; + case 0xC1: return ' '; + case 0xC2: return ' '; + case 0xC3: return ' '; + case 0xC4: return ' '; + case 0xC5: return ' '; + case 0xC6: return ' '; + case 0xC7: return ' '; + case 0xC8: return ' '; + case 0xC9: return ' '; + case 0xCA: return ' '; + case 0xCB: return 'A'; + case 0xCC: return 'A'; + case 0xCD: return 'O'; + case 0xCE: return ' '; + case 0xCF: return ' '; + case 0xD0: return '-'; + case 0xD1: return '-'; + case 0xD2: return 0x22; + case 0xD3: return 0x22; + case 0xD4: return 0x27; + case 0xD5: return 0x27; + case 0xD6: return '-'; // use dash instead of slash + case 0xD7: return ' '; + case 0xD8: return 'y'; + case 0xD9: return 'Y'; + case 0xDA: return '-'; // use dash instead of slash + case 0xDB: return ' '; + case 0xDC: return '<'; + case 0xDD: return '>'; + case 0xDE: return ' '; + case 0xDF: return ' '; + case 0xE0: return ' '; + case 0xE1: return ' '; + case 0xE2: return ','; + case 0xE3: return ','; + case 0xE4: return ' '; + case 0xE5: return 'A'; + case 0xE6: return 'E'; + case 0xE7: return 'A'; + case 0xE8: return 'E'; + case 0xE9: return 'E'; + case 0xEA: return 'I'; + case 0xEB: return 'I'; + case 0xEC: return 'I'; + case 0xED: return 'I'; + case 0xEE: return 'O'; + case 0xEF: return 'O'; + case 0xF0: return ' '; + case 0xF1: return 'O'; + case 0xF2: return 'U'; + case 0xF3: return 'U'; + case 0xF4: return 'U'; + case 0xF5: return '|'; + case 0xF6: return ' '; + case 0xF7: return ' '; + case 0xF8: return ' '; + case 0xF9: return ' '; + case 0xFA: return '.'; + case 0xFB: return ' '; + case 0xFC: return ' '; + case 0xFD: return 0x22; + case 0xFE: return ' '; + case 0xFF: return ' '; + } + return c; +} + +// String should match ndof for manufacturer based search to work +static void sanitizeString( char* inCStr ) +{ + char* charIt = inCStr; + while ( *charIt ) + { + *charIt = mapChar( *charIt ); + charIt++; + } +} + +struct HidDevice +{ + long mAxis; + long mLocalID; + char mProduct[256]; + char mManufacturer[256]; + long mUsage; + long mUsagePage; +}; + +static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) +{ + CFMutableDictionaryRef io_properties = nil; + io_registry_entry_t entry1; + io_registry_entry_t entry2; + kern_return_t rc; + + // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + // try to get parent1 + rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); + + IOObjectRelease( entry1 ); + + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); + // either way, release parent2 + IOObjectRelease( entry2 ); + } + } + if ( KERN_SUCCESS == rc ) + { + // IORegistryEntryCreateCFProperties() succeeded + if ( io_properties != nil ) + { + CFTypeRef dict_element = 0; + // get device info + // try hid dictionary first, if fail then go to usb dictionary + + + dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + sanitizeString(devicep->mProduct); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + sanitizeString(devicep->mManufacturer); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); + } + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); + if ( dict_element ) + { + if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) + { + LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; + } + } + } + + //Add axis, because ndof lib checks sutability by axises as well as other elements + devicep->mAxis = 0; + CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); + if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) + { + long count = CFArrayGetCount( (CFArrayRef) hid_elements ); + for (int i = 0; i < count; ++i) + { + CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); + if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) + { + long type = 0, usage_page = 0, usage = 0; + + CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); + } + if ( type != 0 + && type != kIOHIDElementTypeCollection + && usage_page == kHIDPage_GenericDesktop) + { + switch( usage ) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + devicep->mAxis++; + break; + default: + break; + } + } + } + } + } + + CFRelease(io_properties); + } + else + { + LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; + } + } +} + +HidDevice populate_device( io_object_t io_obj ) +{ + void* interfacep = nullptr; + HidDevice device; + memset( &device, 0, sizeof( HidDevice ) ); + CFMutableDictionaryRef device_dic = 0; + kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); + + if ( KERN_SUCCESS == result + && device_dic ) + { + IOReturn io_result = kIOReturnSuccess; + HRESULT query_result = S_OK; + SInt32 the_score = 0; + IOCFPlugInInterface **the_interface = NULL; + + + io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &the_interface, &the_score ); + if ( io_result == kIOReturnSuccess ) + { + query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); + if ( query_result != S_OK ) + { + LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; + } + IODestroyPlugInInterface( the_interface ); + } + else + { + LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; + } + + if ( interfacep ) + { + result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); + + if ( result != kIOReturnSuccess) + { + LL_WARNS("Joystick") << "open failed" << LL_ENDL; + } + } + // extract needed fields + populate_device_info( io_obj, device_dic, &device ); + + // Release interface + if ( interfacep ) + { + ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); + + ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); + + interfacep = NULL; + } + + CFRelease( device_dic ); + } + else + { + LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; + } + + return device; +} + +static void get_devices(std::list<HidDevice> &list_of_devices, + io_iterator_t inIODeviceIterator) +{ + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + io_object_t io_obj = 0; + + while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) + { + HidDevice device = populate_device( io_obj ); + + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } + else + { + LL_DEBUGS("Joystick"); + list_of_devices.push_back(device); + LL_CONT << "Device axes: " << (S32)device.mAxis + << " Device HIDUsepage: " << (S32)device.mUsagePage + << " Device HIDUsage: " << (S32)device.mUsage; + LL_ENDL; + } + + + // release the device object, it is no longer needed + result = IOObjectRelease( io_obj ); + if ( KERN_SUCCESS != result ) + { + LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; + } + } +} + +bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, + std::function<bool(std::string&, LLSD&, void*)> osx_callback, + void* win_callback, + void* userdata) +{ + bool return_value = false; + CFMutableDictionaryRef device_dict_ref; + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + + // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. + + // A dictionary to match devices to? + device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); + + // BUG FIX! one reference is consumed by IOServiceGetMatchingServices + CFRetain( device_dict_ref ); + io_iterator_t io_iter = 0; + + // create an IO object iterator + result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + if ( kIOReturnSuccess != result ) + { + LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; + } + + if ( io_iter ) + { + // add all existing devices + std::list<HidDevice> device_list; + + get_devices(device_list, io_iter); + + std::list<HidDevice>::iterator iter; + + for (iter = device_list.begin(); iter != device_list.end(); ++iter) + { + std::string label(iter->mProduct); + LLSD data; + data["manufacturer"] = std::string(iter->mManufacturer); + data["product"] = label; + + if (osx_callback(label, data, userdata)) + { + break; //found device + } + } + return_value = true; + } + + CFRelease( device_dict_ref ); + return return_value; +} + LLSD LLWindowMacOSX::getNativeKeyData() { LLSD result = LLSD::emptyMap(); diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 196a284ac3..5e09e58a99 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -116,6 +116,11 @@ public: void spawnWebBrowser(const std::string& escaped_url, bool async) override; F32 getSystemUISize() override; + bool getInputDevices(U32 device_type_filter, + std::function<bool(std::string&, LLSD&, void*)> osx_callback, + void* win_callback, + void* userdata) override; + static std::vector<std::string> getDisplaysResolutionList(); static std::vector<std::string> getDynamicFallbackFontList(); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 8670298f46..d6b93b93d9 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1642,7 +1642,9 @@ const S32 max_format = (S32)num_formats - 1; } else { - LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr")); + // mWindowHandle is 0, going to crash either way + LL_ERRS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL; } // Verify what pixel format we actually received. @@ -1895,12 +1897,16 @@ void LLWindowWin32::destroySharedContext(void* contextPtr) void LLWindowWin32::toggleVSync(bool enable_vsync) { - if (!enable_vsync && wglSwapIntervalEXT) + if (wglSwapIntervalEXT == nullptr) + { + LL_INFOS("Window") << "VSync: wglSwapIntervalEXT not initialized" << LL_ENDL; + } + else if (!enable_vsync) { LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(0); } - else if (wglSwapIntervalEXT) + else { LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(1); @@ -4464,7 +4470,10 @@ void* LLWindowWin32::getDirectInput8() return &gDirectInput8; } -bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata) +bool LLWindowWin32::getInputDevices(U32 device_type_filter, + std::function<bool(std::string&, LLSD&, void*)> osx_callback, + void * di8_devices_callback, + void* userdata) { if (gDirectInput8 != NULL) { diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 6598215f97..33fa67ba50 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -131,7 +131,10 @@ public: static void setDPIAwareness(); /*virtual*/ void* getDirectInput8(); - /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); + /*virtual*/ bool getInputDevices(U32 device_type_filter, + std::function<bool(std::string&, LLSD&, void*)> osx_callback, + void* win_callback, + void* userdata); U32 getRawWParam() { return mRawWParam; } diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 264bf0c5b4..5b6d197e52 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1497,8 +1497,6 @@ DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"]; DECL_LLCC(LLSD, test_llsd); -static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment"); - void test_cached_control() { #define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL @@ -1515,8 +1513,6 @@ void test_cached_control() TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); //There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - - if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; } #endif // TEST_CACHED_CONTROL diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index cf2bc4476e..2298dc22e7 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -837,7 +837,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, if (!LLXMLNode::parseFile(filename, root, NULL)) { - LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; + LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL; return false; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 738d8e540d..c2869eedfd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -18,7 +18,6 @@ include(DragDrop) include(EXPAT) include(FMODSTUDIO) include(Hunspell) -include(ICU4C) include(JPEGEncoderBasic) include(JsonCpp) include(LLAppearance) @@ -1616,6 +1615,8 @@ set(viewer_APPSETTINGS_FILES app_settings/autoreplace.xml app_settings/cmd_line.xml app_settings/commands.xml + app_settings/emoji_groups.xml + app_settings/foldertypes.xml app_settings/grass.xml app_settings/ignorable_dialogs.xml app_settings/key_bindings.xml @@ -1931,7 +1932,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLPHYSICSEXTENSIONS_LIBRARIES} ll::bugsplat ll::tracy - ll::icu4c ) if( TARGET ll::intel_memops ) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 2380dcfd47..2fe040f424 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.7 +7.1.8 diff --git a/indra/newview/app_settings/camera/Front.xml b/indra/newview/app_settings/camera/Front.xml index 39f44e11a8..f96d3bc779 100644 --- a/indra/newview/app_settings/camera/Front.xml +++ b/indra/newview/app_settings/camera/Front.xml @@ -1,16 +1,5 @@ <llsd> <map> - <key>AppearanceCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AvatarSitRotation</key> <map> <key>Comment</key> @@ -90,17 +79,6 @@ <key>Value</key> <real>0.90322577953338623</real> </map> - <key>EditCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering build mode, camera moves up above avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FocusOffsetRearView</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/camera/Rear.xml b/indra/newview/app_settings/camera/Rear.xml index 8dc36353ce..7eda566e48 100644 --- a/indra/newview/app_settings/camera/Rear.xml +++ b/indra/newview/app_settings/camera/Rear.xml @@ -1,16 +1,5 @@ <llsd> <map> - <key>AppearanceCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AvatarSitRotation</key> <map> <key>Comment</key> @@ -90,17 +79,6 @@ <key>Value</key> <real>0.90322577953338623</real> </map> - <key>EditCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering build mode, camera moves up above avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FocusOffsetRearView</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/camera/Side.xml b/indra/newview/app_settings/camera/Side.xml index 089ab93a8f..77f73f1df1 100644 --- a/indra/newview/app_settings/camera/Side.xml +++ b/indra/newview/app_settings/camera/Side.xml @@ -1,16 +1,5 @@ <llsd> <map> - <key>AppearanceCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AvatarSitRotation</key> <map> <key>Comment</key> @@ -90,17 +79,6 @@ <key>Value</key> <real>0.90322577953338623</real> </map> - <key>EditCameraMovement</key> - <map> - <key>Comment</key> - <string>When entering build mode, camera moves up above avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FocusOffsetRearView</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e1eeefa755..7513c8e3d3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -137,17 +137,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>AdvanceOutfitSnapshot</key> - <map> - <key>Comment</key> - <string>Display advanced parameter settings in outfit snaphot interface</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AgentPause</key> <map> <key>Comment</key> @@ -214,17 +203,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>AnimationDebug</key> - <map> - <key>Comment</key> - <string>Show active animations in a bubble above avatars head</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>AppearanceCameraMovement</key> <map> <key>Comment</key> @@ -269,17 +247,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AskedAboutCrashReports</key> - <map> - <key>Comment</key> - <string>Turns off dialog asking if you want to enable crash reporting</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>AuctionShowFence</key> <map> <key>Comment</key> @@ -302,17 +269,6 @@ <key>Value</key> <real>0.5</real> </map> - <key>AudioLevelDoppler</key> - <map> - <key>Comment</key> - <string>Scale of doppler effect on moving audio sources (1.0 = normal, <1.0 = diminished doppler effect, >1.0 = enhanced doppler effect)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1.0</real> - </map> <key>AudioLevelMaster</key> <map> <key>Comment</key> @@ -357,28 +313,6 @@ <key>Value</key> <real>0.3</real> </map> - <key>AudioLevelRolloff</key> - <map> - <key>Comment</key> - <string>Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1.0</real> - </map> - <key>AudioLevelUnderwaterRolloff</key> - <map> - <key>Comment</key> - <string>Controls the distance-based dropoff of audio volume underwater(fraction or multiple of default audio rolloff)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>5.0</real> - </map> <key>AudioLevelSFX</key> <map> <key>Comment</key> @@ -412,17 +346,6 @@ <key>Value</key> <real>0.5</real> </map> - <key>AudioLevelWind</key> - <map> - <key>Comment</key> - <string>Audio level of wind noise when standing still</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.5</real> - </map> <key>AudioStreamingMedia</key> <map> <key>Comment</key> @@ -456,7 +379,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>AutoAcceptNewInventory</key> + <key>AutoAcceptNewInventory</key> <map> <key>Comment</key> <string>Automatically accept new notecards/textures/landmarks</string> @@ -478,17 +401,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>AutoLoadWebProfiles</key> - <map> - <key>Comment</key> - <string>Automatically load ALL profile webpages without asking first.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>AutoLogin</key> <map> <key>Comment</key> @@ -687,17 +599,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>AvatarBacklight</key> - <map> - <key>Comment</key> - <string>Add rim lighting to avatar rendering to approximate shininess of skin</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AvatarFeathering</key> <map> <key>Comment</key> @@ -709,32 +610,6 @@ <key>Value</key> <real>16.0</real> </map> - <key>AvatarPickerSortOrder</key> - <map> - <key>Comment</key> - <string>Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>2</integer> - </map> - <key>AvatarPosFinalOffset</key> - <map> - <key>Comment</key> - <string>After-everything-else fixup for avatar position.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3</string> - <key>Value</key> - <array> - <real>0.0</real> - <real>0.0</real> - <real>0.0</real> - </array> - </map> <key>AvatarPickerURL</key> <map> <key>Comment</key> @@ -746,50 +621,6 @@ <key>Value</key> <string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/avatars.html</string> </map> - <key>AvatarRotateThresholdSlow</key> - <map> - <key>Comment</key> - <string>Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving slowly (degrees)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <integer>60</integer> - </map> - <key>AvatarRotateThresholdFast</key> - <map> - <key>Comment</key> - <string>Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving fast (degrees)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <integer>2</integer> - </map> - <key>AvatarBakedTextureUploadTimeout</key> - <map> - <key>Comment</key> - <string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>60</integer> - </map> - <key>AvatarBakedLocalTextureUpdateTimeout</key> - <map> - <key>Comment</key> - <string>Specifes the maximum time in seconds to wait before updating your appearance during appearance mode.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>10</integer> - </map> <key>AvatarPhysics</key> <map> <key>Comment</key> @@ -823,28 +654,6 @@ <key>Value</key> <integer>40</integer> </map> - <key>BottomPanelNew</key> - <map> - <key>Comment</key> - <string>Enable the new bottom panel</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>BrowserHomePage</key> - <map> - <key>Comment</key> - <string>[NOT USED]</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>http://www.secondlife.com</string> - </map> <key>BrowserIgnoreSSLCertErrors</key> <map> <key>Comment</key> @@ -878,17 +687,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>BlockSomeAvatarAppearanceVisualParams</key> - <map> - <key>Comment</key> - <string>Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>BrowserProxyAddress</key> <map> <key>Comment</key> @@ -911,17 +709,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>BrowserProxyExclusions</key> - <map> - <key>Comment</key> - <string>[NOT USED]</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string /> - </map> <key>BrowserProxyPort</key> <map> <key>Comment</key> @@ -933,17 +720,6 @@ <key>Value</key> <integer>3128</integer> </map> - <key>BrowserProxySocks45</key> - <map> - <key>Comment</key> - <string>[NOT USED]</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>5</integer> - </map> <key>Socks5ProxyEnabled</key> <map> <key>Comment</key> @@ -1329,39 +1105,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ButtonHPad</key> - <map> - <key>Comment</key> - <string>Default horizontal spacing between buttons (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>4</integer> - </map> - <key>ButtonHeight</key> - <map> - <key>Comment</key> - <string>Default height for normal buttons (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>23</integer> - </map> - <key>ButtonHeightSmall</key> - <map> - <key>Comment</key> - <string>Default height for small buttons (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>23</integer> - </map> <key>EnableDiskCacheDebugInfo</key> <map> <key>Comment</key> @@ -1417,17 +1160,6 @@ <key>Value</key> <string /> </map> - <key>CacheNumberOfRegionsForObjects</key> - <map> - <key>Comment</key> - <string>Controls number of regions to be cached for objects.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>128</integer> - </map> <key>CacheSize</key> <map> <key>Comment</key> @@ -1513,51 +1245,6 @@ <real>0.75</real> </array> </map> - <key>CameraOffsetFrontView</key> - <map> - <key>Comment</key> - <string>Initial camera offset from avatar in Front View</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3</string> - <key>Value</key> - <array> - <real>2.2</real> - <real>0.0</real> - <real>0.0</real> - </array> - </map> - <key>CameraOffsetGroupView</key> - <map> - <key>Comment</key> - <string>Initial camera offset from avatar in Group View</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3</string> - <key>Value</key> - <array> - <real>-1.0</real> - <real>0.7</real> - <real>0.5</real> - </array> - </map> - <key>CameraOffsetCustomPreset</key> - <map> - <key>Comment</key> - <string>Initial camera offset from avatar for the custom camera preset</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3</string> - <key>Value</key> - <array> - <real>-3.0</real> - <real>0.0</real> - <real>0.75</real> - </array> - </map> <key>CameraOffsetScale</key> <map> <key>Comment</key> @@ -1712,17 +1399,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ChatBarStealsFocus</key> - <map> - <key>Comment</key> - <string>Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>LetterKeysFocusChatBar</key> <map> <key>Comment</key> @@ -1767,17 +1443,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ChatHistoryTornOff</key> - <map> - <key>Comment</key> - <string>Show chat history window separately from Communicate window.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>ChatLoadGroupMaxMembers</key> <map> <key>Comment</key> @@ -1789,17 +1454,6 @@ <key>Value</key> <integer>100</integer> </map> - <key>ChatLoadGroupTimeout</key> - <map> - <key>Comment</key> - <string>Time we give the server to send group participants before we hit the server for group info (seconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>10.0</real> - </map> <key>ChatOnlineNotification</key> <map> <key>Comment</key> @@ -1811,28 +1465,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ChatPersistTime</key> - <map> - <key>Comment</key> - <string>Time for which chat stays visible in console (seconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>20.0</real> - </map> - <key>ChatShowTimestamps</key> - <map> - <key>Comment</key> - <string>Show timestamps in chat</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>CheesyBeacon</key> <map> <key>Comment</key> @@ -1855,50 +1487,6 @@ <key>Value</key> <string /> </map> - <key>ContextConeInAlpha</key> - <map> - <key>Comment</key> - <string>Cone In Alpha</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.0</real> - </map> - <key>ContextConeOutAlpha</key> - <map> - <key>Comment</key> - <string>Cone Out Alpha</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1.0</real> - </map> - <key>ContextConeFadeTime</key> - <map> - <key>Comment</key> - <string>Cone Fade Time</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>.08</real> - </map> - <key>ConversationHistoryPageSize</key> - <map> - <key>Comment</key> - <string>Chat history of conversation opened from call log is displayed by pages. So this is number of entries per page.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>100</integer> - </map> <key>ConversationSortOrder</key> <map> <key>Comment</key> @@ -2077,17 +1665,6 @@ <key>Value</key> <integer>40</integer> </map> - <key>ContactsTornOff</key> - <map> - <key>Comment</key> - <string>Show contacts window separately from Communicate window.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>CookiesEnabled</key> <map> <key>Comment</key> @@ -2132,17 +1709,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ChatBarCustomWidth</key> - <map> - <key>Comment</key> - <string>Stores customized width of chat bar.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>CoroutineStackSize</key> <map> <key>Comment</key> @@ -2209,17 +1775,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>CurlMaximumNumberOfHandles</key> - <map> - <key>Comment</key> - <string>Maximum number of handles curl can use (requires restart)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>256</integer> - </map> <key>CurlRequestTimeOut</key> <map> <key>Comment</key> @@ -2231,17 +1786,6 @@ <key>Value</key> <real>120.0</real> </map> - <key>CurlUseMultipleThreads</key> - <map> - <key>Comment</key> - <string>Use background threads for executing curl_multi_perform (requires restart)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>Cursor3D</key> <map> <key>Comment</key> @@ -2264,17 +1808,6 @@ <key>Value</key> <string></string> </map> - <key>CustomServer</key> - <map> - <key>Comment</key> - <string>Specifies IP address or hostname of grid to which you connect</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string /> - </map> <key>DebugAnimatedObjects</key> <map> <key>Comment</key> @@ -2297,17 +1830,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AnimatedObjectsIgnoreLimits</key> - <map> - <key>Comment</key> - <string>Ignore server-enforced limits on animated objects. This is only useful for server testing.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>AnimatedObjectsAllowLeftClick</key> <map> <key>Comment</key> @@ -2319,17 +1841,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AnimatedObjectsGlobalScale</key> - <map> - <key>Comment</key> - <string>Temporary testing: allow an extra scale factor to be forced on animated objects.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1.00</real> - </map> <key>AnimatedObjectsMaxLegalOffset</key> <map> <key>Comment</key> @@ -2352,17 +1863,6 @@ <key>Value</key> <real>64.0</real> </map> - <key>AvatarBoundingBoxComplexity</key> - <map> - <key>Comment</key> - <string>How many aspects to consider for avatar bounding box</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>3</integer> - </map> <key>DebugAvatarAppearanceMessage</key> <map> <key>Comment</key> @@ -2473,17 +1973,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>DebugInventoryFilters</key> - <map> - <key>Comment</key> - <string>Turn on debugging display for inventory filtering</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>DebugPermissions</key> <map> <key>Comment</key> @@ -2550,18 +2039,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>DebugShowPrivateMem</key> - <!-- deprecated (see MAINT-8091) --> - <map> - <key>Comment</key> - <string>(Deprecated) Show Private Mem Info</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>DebugShowRenderInfo</key> <map> <key>Comment</key> @@ -2628,435 +2105,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>DebugSlshareLogTag</key> - <map> - <key>Comment</key> - <string>Request slshare-service debug logging</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string/> - </map> - <key>DebugStatModeFPS</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeBandwidth</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModePacketLoss</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatMode</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeKTrisDrawnFr</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeKTrisDrawnSec</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeTotalObjs</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeNewObjs</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeTextureCount</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeRawCount</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeGLMem</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeFormattedMem</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeRawMem</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeBoundMem</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModePacketsIn</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModePacketsOut</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeObjects</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeTexture</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeAsset</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeLayers</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeActualIn</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeActualOut</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeTimeDialation</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimFPS</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModePhysicsFPS</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModePinnedObjects</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeLowLODObjects</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeMemoryAllocated</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeAgentUpdatesSec</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeMainAgents</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeChildAgents</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimObjects</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimActiveObjects</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimActiveScripts</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimScriptEvents</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimInPPS</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimOutPPS</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> - <key>DebugStatModeSimPendingDownloads</key> - <map> - <key>Comment</key> - <string>Mode of stat in Statistics floater</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>-1</integer> - </map> <key>SimPendingUploads</key> <map> <key>Comment</key> @@ -3277,17 +2325,6 @@ <key>Value</key> <string>Male Shape & Outfit</string> </map> - <key>DefaultUploadCost</key> - <map> - <key>Comment</key> - <string>Default sound/image/file upload cost(in case economy data is not available).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>10</integer> - </map> <key>DestinationGuideURL</key> <map> <key>Comment</key> @@ -3387,94 +2424,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnableIMChatPopups</key> - <map> - <key>Comment</key> - <string>Enable Incoming IM Chat Popups</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayAvatarAgentTarget</key> - <map> - <key>Comment</key> - <string>Show avatar positioning locators (animation debug)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>DisplayChat</key> - <map> - <key>Comment</key> - <string>Display Latest Chat message on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayDebug</key> - <map> - <key>Comment</key> - <string>Display Network Information on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayDebugConsole</key> - <map> - <key>Comment</key> - <string>Display Console Debug Information on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayIM</key> - <map> - <key>Comment</key> - <string>Display Latest IM message on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayLinden</key> - <map> - <key>Comment</key> - <string>Display Account Information on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>DisplayRegion</key> - <map> - <key>Comment</key> - <string>Display Location information on LCD</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>DisplayTimecode</key> <map> <key>Comment</key> @@ -3508,28 +2457,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ClickActionBuyEnabled</key> - <map> - <key>Comment</key> - <string>Enable click to buy actions in tool pie menu</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>ClickActionPayEnabled</key> - <map> - <key>Comment</key> - <string>Enable click to pay actions in tool pie menu</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>DoubleClickAutoPilot</key> <map> <key>Comment</key> @@ -3563,72 +2490,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>DragAndDropToolTipDelay</key> - <map> - <key>Comment</key> - <string>Seconds before displaying tooltip when performing drag and drop operation</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.10000000149</real> - </map> - <key>DragAndDropDistanceThreshold</key> - <map> - <key>Comment</key> - <string>Number of pixels that mouse should move before triggering drag and drop mode</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>3</integer> - </map> - <key>DropShadowButton</key> - <map> - <key>Comment</key> - <string>Drop shadow width for buttons (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>2</integer> - </map> - <key>DropShadowFloater</key> - <map> - <key>Comment</key> - <string>Drop shadow width for floaters (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>5</integer> - </map> - <key>DropShadowSlider</key> - <map> - <key>Comment</key> - <string>Drop shadow width for sliders (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>3</integer> - </map> - <key>DropShadowTooltip</key> - <map> - <key>Comment</key> - <string>Drop shadow width for tooltips (pixels)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>4</integer> - </map> <key>DynamicCameraStrength</key> <map> <key>Comment</key> @@ -3662,17 +2523,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>IncludeEnhancedSkeleton</key> - <map> - <key>Comment</key> - <string>Include extended skeleton joints when rendering skinned meshes.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>MinObjectsForUnlinkConfirm</key> <map> <key>Comment</key> @@ -3772,39 +2622,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnergyFromTop</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>20</integer> - </map> - <key>EnergyHeight</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>40</integer> - </map> - <key>EnergyWidth</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>175</integer> - </map> <key>EventURL</key> <map> <key>Comment</key> @@ -3816,61 +2633,6 @@ <key>Value</key> <string>http://events.[GRID]/viewer/embed/event/[EVENT_ID]</string> </map> - <key>FastCacheFetchEnabled</key> - <map> - <key>Comment</key> - <string>Enable texture fast cache fetching if set</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <string>1</string> - </map> - <key>FeatureManagerHTTPTable</key> - <map> - <key>Comment</key> - <string>Deprecated</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string></string> - </map> - <key>FPSLogFrequency</key> - <map> - <key>Comment</key> - <string>Seconds between display of FPS in log (0 for never)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>10.0</real> - </map> - <key>FilterItemsMaxTimePerFrameVisible</key> - <map> - <key>Comment</key> - <string>Max time devoted to items filtering per frame for visible inventory listings (in milliseconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>10</integer> - </map> - <key>FilterItemsMaxTimePerFrameUnvisible</key> - <map> - <key>Comment</key> - <string>Max time devoted to items filtering per frame for non visible inventory listings (in milliseconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>1</integer> - </map> <key>MainWorkTime</key> <map> <key>Comment</key> @@ -3882,72 +2644,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>QueueInventoryFetchTimeout</key> - <map> - <key>Comment</key> - <string>Max time llcompilequeue will wait for inventory fetch to complete (in seconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>300.0</real> - </map> - <key>FindLandArea</key> - <map> - <key>Comment</key> - <string>Enables filtering of land search results by area</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>FindLandPrice</key> - <map> - <key>Comment</key> - <string>Enables filtering of land search results by price</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FindLandType</key> - <map> - <key>Comment</key> - <string>Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale")</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>All</string> - </map> - <key>FindPeopleOnline</key> - <map> - <key>Comment</key> - <string>Limits people search to only users who are logged on</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FindPlacesPictures</key> - <map> - <key>Comment</key> - <string>Display only results of find places that have pictures</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>FirstName</key> <map> <key>Comment</key> @@ -4339,17 +3035,6 @@ <key>Value</key> <real>16.0</real> </map> - <key>FlycamZoomDirect</key> - <map> - <key>Comment</key> - <string>Map flycam zoom axis directly to camera zoom.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FlyingAtExit</key> <map> <key>Comment</key> @@ -4376,51 +3061,6 @@ <real>1.0</real> </array> </map> - <key>FocusOffsetFrontView</key> - <map> - <key>Comment</key> - <string>Initial focus point offset relative to avatar for the camera preset Front View</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3D</string> - <key>Value</key> - <array> - <real>0.0</real> - <real>0.0</real> - <real>0.0</real> - </array> - </map> - <key>FocusOffsetGroupView</key> - <map> - <key>Comment</key> - <string>Initial focus point offset relative to avatar for the camera preset Group View</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3D</string> - <key>Value</key> - <array> - <real>1.5</real> - <real>0.7</real> - <real>1.0</real> - </array> - </map> - <key>FocusOffsetCustomPreset</key> - <map> - <key>Comment</key> - <string>Initial focus point offset relative to avatar for the custom camera preset (x-axis is forward)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Vector3D</string> - <key>Value</key> - <array> - <real>1.0</real> - <real>0.0</real> - <real>1.0</real> - </array> - </map> <key>AvatarSitRotation</key> <map> <key>Comment</key> @@ -4463,17 +3103,6 @@ <key>Value</key> <real>0.75</real> </map> - <key>FolderLoadingMessageWaitTime</key> - <map> - <key>Comment</key> - <string>Seconds to wait before showing the LOADING... text in folder views</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.5</real> - </map> <key>FontScreenDPI</key> <map> <key>Comment</key> @@ -4529,17 +3158,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>ForceMandatoryUpdate</key> - <map> - <key>Comment</key> - <string>For QA: On next startup, forces the auto-updater to run</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FreezeTime</key> <map> <key>Comment</key> @@ -4661,28 +3279,6 @@ <key>Value</key> <integer>32</integer> </map> - <key>GroupNotifyBoxHeight</key> - <map> - <key>Comment</key> - <string>Height of group notice messages</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>260</integer> - </map> - <key>GroupNotifyBoxWidth</key> - <map> - <key>Comment</key> - <string>Width of group notice messages</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>305</integer> - </map> <key>HelpURLFormat</key> <map> <key>Comment</key> @@ -4771,17 +3367,6 @@ <key>Value</key> <string /> </map> - <key>HtmlHelpLastPage</key> - <map> - <key>Comment</key> - <string>Last URL visited via help system</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string /> - </map> <key>HttpPipelining</key> <map> <key>Comment</key> @@ -4804,17 +3389,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>IMShowTimestamps</key> - <map> - <key>Comment</key> - <string>Show timestamps in IM</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>IMShowControlPanel</key> <map> <key>Comment</key> @@ -4826,17 +3400,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>IMShowContentPanel</key> - <map> - <key>Comment</key> - <string>Show Toolbar and Body Panels</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>IgnoreFOVZoomForLODs</key> <map> <key>Comment</key> @@ -4903,28 +3466,6 @@ <key>Value</key> <real>0.0</real> </map> - <key>InspectorFadeTime</key> - <map> - <key>Comment</key> - <string>Fade out timing for inspectors</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.5</real> - </map> - <key>InspectorShowTime</key> - <map> - <key>Comment</key> - <string>Stay timing for inspectors</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>3.0</real> - </map> <key>InstallLanguage</key> <map> <key>Comment</key> @@ -4991,17 +3532,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>InventoryOutboxDisplayBoth</key> - <map> - <key>Comment</key> - <string>(Deprecated) Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>InventoryOutboxLogging</key> <map> <key>Comment</key> @@ -5251,7 +3781,7 @@ <key>Persist</key> <integer>1</integer> <key>Type</key> - <string>String</string> + <string>LLSD</string> <key>Value</key> <string /> </map> @@ -5332,17 +3862,6 @@ <key>Value</key> <real>2.0</real> </map> - <key>LCDDestination</key> - <map> - <key>Comment</key> - <string>Which LCD to use</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>LeapCommand</key> <map> <key>Comment</key> @@ -5564,105 +4083,6 @@ <string>0.0.0</string> </map> - <key>LastSnapshotToProfileHeight</key> - <map> - <key>Comment</key> - <string>The height of the last profile snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>768</integer> - </map> - <key>LastSnapshotToEmailHeight</key> - <map> - <key>Comment</key> - <string>The height of the last email snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>768</integer> - </map> - <key>LastSnapshotToProfileWidth</key> - <map> - <key>Comment</key> - <string>The width of the last profile snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>1024</integer> - </map> - <key>LastSnapshotToEmailWidth</key> - <map> - <key>Comment</key> - <string>The width of the last email snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>1024</integer> - </map> - <key>LastSnapshotToDiskHeight</key> - <map> - <key>Comment</key> - <string>The height of the last disk snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>768</integer> - </map> - <key>LastSnapshotToDiskWidth</key> - <map> - <key>Comment</key> - <string>The width of the last disk snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>1024</integer> - </map> - <key>LastSnapshotToInventoryHeight</key> - <map> - <key>Comment</key> - <string>The height of the last texture snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>512</integer> - </map> - <key>LastSnapshotToInventoryWidth</key> - <map> - <key>Comment</key> - <string>The width of the last texture snapshot, in px</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>512</integer> - </map> - <key>LeftClickShowMenu</key> - <map> - <key>Comment</key> - <string>Unused obsolete setting</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>LimitDragDistance</key> <map> <key>Comment</key> @@ -5829,17 +4249,6 @@ <key>Value</key> <real>40.0</real> </map> - <key>LoginSRVPump</key> - <map> - <key>Comment</key> - <string>(Deprecated) Name of the message pump that handles SRV request)</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>LLAres</string> - </map> <key>LogMessages</key> <map> <key>Comment</key> @@ -5928,17 +4337,6 @@ <key>Value</key> <real>60.0</real> </map> - <key>MapOverlayIndex</key> - <map> - <key>Comment</key> - <string>Currently selected world map type</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>MapScale</key> <map> <key>Comment</key> @@ -6678,28 +5076,6 @@ <key>Value</key> <real>0.25</real> </map> - <key>MenuBarHeight</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>18</integer> - </map> - <key>MenuBarWidth</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>410</integer> - </map> <key>MePanelOpened</key> <map> <key>Comment</key> @@ -7154,28 +5530,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>NotifyBoxHeight</key> - <map> - <key>Comment</key> - <string>Height of notification messages</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>200</integer> - </map> - <key>NotifyBoxWidth</key> - <map> - <key>Comment</key> - <string>Width of notification messages</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>305</integer> - </map> <key>NotificationConferenceIMOptions</key> <map> <key>Comment</key> @@ -7353,17 +5707,6 @@ <key>Value</key> <integer>90</integer> </map> - <key>ChannelBottomPanelMargin</key> - <map> - <key>Comment</key> - <string>Space from a lower toast to the Bottom Tray</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>35</integer> - </map> <key>NotificationChannelRightMargin</key> <map> <key>Comment</key> @@ -8064,17 +6407,6 @@ <key>Value</key> <real>6.0</real> </map> - <key>ClothingLoadingDelay</key> - <map> - <key>Comment</key> - <string>Time to wait for avatar appearance to resolve before showing world (seconds)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>10.0</real> - </map> <key>PreferredMaturity</key> <map> <key>Comment</key> @@ -8517,17 +6849,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>RadioLandBrushSize</key> - <map> - <key>Comment</key> - <string>Size of land modification brush (0 = small, 1 = medium, 2 = large)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>LandBrushForce</key> <map> <key>Comment</key> @@ -8539,17 +6860,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>MediaBrowserWindowLimit</key> - <map> - <key>Comment</key> - <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>5</integer> - </map> <key>WebContentWindowLimit</key> <map> <key>Comment</key> @@ -8828,17 +7138,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>RenderAvatar</key> - <map> - <key>Comment</key> - <string>Render Avatars</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>RenderAvatarCloth</key> <map> <key>Comment</key> @@ -10788,7 +9087,7 @@ <key>Value</key> <real>1.0</real> </map> - <key>RendeSkyAutoAdjustBlueHorizonScale</key> + <key>RenderSkyAutoAdjustBlueHorizonScale</key> <map> <key>Comment</key> <string>Blue Horizon Scale value to use when auto-adjusting legacy skies</string> @@ -10799,7 +9098,7 @@ <key>Value</key> <real>1.0</real> </map> - <key>RendeSkyAutoAdjustBlueDensityScale</key> + <key>RenderSkyAutoAdjustBlueDensityScale</key> <map> <key>Comment</key> <string>Blue Horizon Scale value to use when auto-adjusting legacy skies</string> @@ -11774,17 +10073,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>SecondLifeEnterprise</key> - <map> - <key>Comment</key> - <string>Enables Second Life Enterprise features</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>SelectMovableOnly</key> <map> <key>Comment</key> @@ -12060,17 +10348,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>ShowEmptyFoldersWhenSearching</key> - <map> - <key>Comment</key> - <string>Shows folders that do not have any visible contents when applying a filter to inventory</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>ShowEventRecorderMenuItems</key> <map> <key>Comment</key> @@ -12412,136 +10689,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ShowPGSearchAll</key> - <map> - <key>Comment</key> - <string>Display results of search All that are flagged as general</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>ShowMatureSearchAll</key> - <map> - <key>Comment</key> - <string>Display results of search All that are flagged as moderate</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowAdultSearchAll</key> - <map> - <key>Comment</key> - <string>Display results of search All that are flagged as adult</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowPGGroups</key> - <map> - <key>Comment</key> - <string>Display results of find groups that are flagged as general</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>ShowMatureGroups</key> - <map> - <key>Comment</key> - <string>Display results of find groups that are flagged as moderate</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowAdultGroups</key> - <map> - <key>Comment</key> - <string>Display results of find groups that are flagged as adult</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowPGClassifieds</key> - <map> - <key>Comment</key> - <string>Display results of find classifieds that are flagged as general</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>ShowMatureClassifieds</key> - <map> - <key>Comment</key> - <string>Display results of find classifieds that are flagged as moderate</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowAdultClassifieds</key> - <map> - <key>Comment</key> - <string>Display results of find classifieds that are flagged as adult</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>ShowPGEvents</key> - <map> - <key>Comment</key> - <string>Display results of find events that are flagged as general</string> - <key>Persist</key> - <integer>1</integer> - <key>HideFromEditor</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>ShowMatureEvents</key> <map> <key>Comment</key> @@ -12778,17 +10925,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>ShowToolBar</key> - <map> - <key>Comment</key> - <string>Show toolbar at bottom of screen</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>ShowTutorial</key> <map> <key>Comment</key> @@ -13230,28 +11366,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>TexturePickerShowFolders</key> - <map> - <key>Comment</key> - <string>Show folders with no texures in texture picker</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>TexturePickerSortOrder</key> - <map> - <key>Comment</key> - <string>Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>2</integer> - </map> <key>TextureReverseByteRange</key> <map> <key>Comment</key> @@ -13301,17 +11415,6 @@ <key>Value</key> <real>3000.0</real> </map> - <key>UpdaterMaximumBandwidth</key> - <map> - <key>Comment</key> - <string>Obsolete: this parameter is no longer used.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>500.0</real> - </map> <key>ToolTipDelay</key> <map> <key>Comment</key> @@ -13444,17 +11547,6 @@ <key>Value</key> <string></string> </map> - <key>BingTranslateAPIKey</key> - <map> - <key>Comment</key> - <string>(Deprecated) Bing AppID to use with the Microsoft Translator API</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string></string> - </map> <key>AzureTranslateAPIKey</key> <map> <key>Comment</key> @@ -13521,28 +11613,6 @@ <key>Value</key> <integer>6</integer> </map> - <key>UICheckboxctrlBtnSize</key> - <map> - <key>Comment</key> - <string>UI Checkbox Control Button Size</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>13</integer> - </map> - <key>UICheckboxctrlHeight</key> - <map> - <key>Comment</key> - <string>UI Checkbox Control Height</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>16</integer> - </map> <key>UICheckboxctrlHPad</key> <map> <key>Comment</key> @@ -13774,50 +11844,6 @@ <key>Value</key> <string>5748decc-f629-461c-9a36-a35a221fe21f</string> </map> - <key>StartUpChannelUUID</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>B56AF90D-6684-48E4-B1E4-722D3DEB2CB6</string> - </map> - <key>NearByChatChannelUUID</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>E1158BD6-661C-4981-9DAD-4DCBFF062502</string> - </map> - <key>NotificationChannelUUID</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>AEED3193-8709-4693-8558-7452CCA97AE5</string> - </map> - <key>AlertChannelUUID</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>F3E07BC8-A973-476D-8C7F-F3B7293975D1</string> - </map> <key>UILineEditorCursorThickness</key> <map> <key>Comment</key> @@ -14005,17 +12031,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>LastSystemUIScaleFactor</key> - <map> - <key>Comment</key> - <string>OBSOLETE: System UI scale factor is now automatically and independently from UIScaleFactor applied</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1.0</real> - </map> <key>UIScrollbarSize</key> <map> <key>Comment</key> @@ -14335,17 +12350,6 @@ <key>Value</key> <integer>16</integer> </map> - <key>UISpinctrlDefaultLabelWidth</key> - <map> - <key>Comment</key> - <string>UI spin control default label width</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>10</integer> - </map> <key>UISpinctrlSpacing</key> <map> <key>Comment</key> @@ -14467,39 +12471,6 @@ <key>Value</key> <integer>3</integer> </map> - <key>UpdaterServiceCheckPeriod</key> - <map> - <key>Comment</key> - <string>Obsolete; no longer used.</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>3600</integer> - </map> - <key>UpdaterServiceURL</key> - <map> - <key>Comment</key> - <string>Obsolete; no longer used.</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>https://update.secondlife.com</string> - </map> - <key>UpdaterServicePath</key> - <map> - <key>Comment</key> - <string>Obsolete: no longer used</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>update</string> - </map> <key>UpdaterWillingToTest</key> <map> <key>Comment</key> @@ -14632,17 +12603,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>UseEnvironmentFromRegion</key> - <map> - <key>Comment</key> - <string>Choose whether to use the region's environment settings, or override them with the local settings.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>EnvironmentPersistAcrossLogin</key> <map> <key>Comment</key> @@ -14654,62 +12614,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>UseDayCycle</key> - <map> - <key>Comment</key> - <string>Whether to use use a day cycle or a fixed sky.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>WaterPresetName</key> - <map> - <key>Comment</key> - <string>Water preset to use. May be superseded by region settings.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Default</string> - </map> - <key>SkyPresetName</key> - <map> - <key>Comment</key> - <string>Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Default</string> - </map> - <key>DayCycleName</key> - <map> - <key>Comment</key> - <string>Day cycle to use. May be superseded by region settings.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>Default</string> - </map> - <key>UseExternalBrowser</key> - <!-- deprecated (see MAINT-4127) --> - <map> - <key>Comment</key> - <string>(Deprecated) Use default browser when opening web pages instead of in-world browser.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <boolean>1</boolean> - </map> <key>PreferredBrowserBehavior</key> <map> <key>Comment</key> @@ -14765,6 +12669,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RenderDelayVBUpdate</key> + <map> + <key>Comment</key> + <string>Delay vertex buffer updates until just before rendering</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>SocialPhotoResolution</key> <map> <key>Comment</key> @@ -15570,17 +13485,6 @@ <key>Value</key> <real>-1.0</real> </map> - <key>ForcePeriodicRenderingTime</key> - <map> - <key>Comment</key> - <string>Periodically enable all rendering masks for a single frame.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>-1.0</real> - </map> <key>ZoomDirect</key> <map> <key>Comment</key> @@ -15746,17 +13650,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AssetStorageLogFrequency</key> - <map> - <key>Comment</key> - <string>Seconds between display of AssetStorage info in log (0 for never)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>60.0</real> - </map> <key>LogWearableAssetSave</key> <map> <key>Comment</key> @@ -15994,28 +13887,6 @@ <key>Value</key> <real>120.0</real> </map> - <key>DestinationGuideHintTimeout</key> - <map> - <key>Comment</key> - <string>Number of seconds to wait before telling resident about destination guide.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>1200.0</real> - </map> - <key>SidePanelHintTimeout</key> - <map> - <key>Comment</key> - <string>Number of seconds to wait before telling resident about side panel.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>300.0</real> - </map> <key>GroupMembersSortOrder</key> <map> <key>Comment</key> @@ -16060,17 +13931,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AvatarInspectorTooltipDelay</key> - <map> - <key>Comment</key> - <string>Seconds before displaying avatar inspector tooltip</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>0.35</real> - </map> <key>ObjectInspectorTooltipDelay</key> <map> <key>Comment</key> @@ -16104,17 +13964,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnableGroupInfo</key> - <map> - <key>Comment</key> - <string>Enable viewing and editing of group info from web link</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>EnablePlaceProfile</key> <map> <key>Comment</key> @@ -16126,28 +13975,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnablePicks</key> - <map> - <key>Comment</key> - <string>Enable editing of picks from web link</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>EnableWorldMap</key> - <map> - <key>Comment</key> - <string>Enable opening world map from web link</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>EnableAvatarPay</key> <map> <key>Comment</key> @@ -16159,17 +13986,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnableVoiceCall</key> - <map> - <key>Comment</key> - <string>Enable voice calls from web link</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>EnableAvatarShare</key> <map> <key>Comment</key> @@ -16192,17 +14008,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>EnableSearch</key> - <map> - <key>Comment</key> - <string>Enable opening search from web link</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>EnableAppearance</key> <map> <key>Comment</key> @@ -16280,17 +14085,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>AllowBottomTrayButtonReordering</key> - <map> - <key>Comment</key> - <string>Allow user to move and hide bottom tray buttons</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>AllowSelectAvatar</key> <map> <key>Comment</key> @@ -17193,28 +14987,6 @@ <key>Value</key> <integer>1000</integer> </map> - <key>FMODExStreamBufferSize</key> - <map> - <key>Comment</key> - <string>Sets the streaming buffer size (in milliseconds) for FMOD Ex or FMOD Studio</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>7000</integer> - </map> - <key>DisablePrecacheDelayAfterTeleporting</key> - <map> - <key>Comment</key> - <string>Disables the artificial delay in the viewer that precaches some incoming assets</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>VersionChannelName</key> <map> <key>Comment</key> diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 63608cdbf8..d1dab94a76 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -397,8 +397,18 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \ # Other shortcuts
SetOutPath "$INSTDIR"
-CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
+
+Push $0
+${GetParameters} $COMMANDLINE
+${GetOptionsS} $COMMANDLINE "/marker" $0
+# Returns error if option does not exist
+IfErrors 0 DESKTOP_SHORTCUT_DONE
+ # "/marker" is set by updater, do not recreate desktop shortcut
+ CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+
+DESKTOP_SHORTCUT_DONE:
+Pop $0
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 38fa4477b3..82124b7412 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -58,16 +58,19 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, try { + LLAccountingCostManager* self = LLAccountingCostManager::getInstance(); uuid_set_t diffSet; - std::set_difference(mObjectList.begin(), mObjectList.end(), - mPendingObjectQuota.begin(), mPendingObjectQuota.end(), - std::inserter(diffSet, diffSet.begin())); + std::set_difference(self->mObjectList.begin(), + self->mObjectList.end(), + self->mPendingObjectQuota.begin(), + self->mPendingObjectQuota.end(), + std::inserter(diffSet, diffSet.begin())); if (diffSet.empty()) return; - mObjectList.clear(); + self->mObjectList.clear(); std::string keystr; if (selectionType == Roots) @@ -91,18 +94,25 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, objectList.append(*it); } - mPendingObjectQuota.insert(diffSet.begin(), diffSet.end()); + self->mPendingObjectQuota.insert(diffSet.begin(), diffSet.end()); LLSD dataToPost = LLSD::emptyMap(); dataToPost[keystr.c_str()] = objectList; - LLAccountingCostObserver* observer = NULL; - LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost); LLSD httpResults = results["http_result"]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (LLApp::isQuitting() + || observerHandle.isDead() + || !LLAccountingCostManager::instanceExists()) + { + return; + } + + LLAccountingCostObserver* observer = NULL; + // do/while(false) allows error conditions to break out of following // block while normal flow goes forward once. do @@ -159,7 +169,8 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, throw; } - mPendingObjectQuota.clear(); + // self can be obsolete by this point + LLAccountingCostManager::getInstance()->mPendingObjectQuota.clear(); } //=============================================================================== @@ -172,7 +183,7 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, { std::string coroname = LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro", - boost::bind(&LLAccountingCostManager::accountingCostCoro, this, url, selectionType, observer_handle)); + boost::bind(accountingCostCoro, url, selectionType, observer_handle)); LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL; } diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index a147d8bdbf..1883a709a1 100644 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -70,7 +70,7 @@ private: //a fetch has been instigated. uuid_set_t mPendingObjectQuota; - void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle); + static void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle); }; //=============================================================================== diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 70ff7f1941..1912d9d1d5 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1932,7 +1932,8 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) } else { - target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f; + LLCachedControl<F32> dynamic_camera_strength(gSavedSettings, "DynamicCameraStrength"); + target_lag = vel * dynamic_camera_strength / 30.f; } mCameraLag = lerp(mCameraLag, target_lag, lag_interp); diff --git a/indra/newview/llagentpicksinfo.cpp b/indra/newview/llagentpicksinfo.cpp index 288d04d9a0..17464dcef9 100644 --- a/indra/newview/llagentpicksinfo.cpp +++ b/indra/newview/llagentpicksinfo.cpp @@ -49,10 +49,10 @@ public: void sendAgentPicksRequest() { - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID()); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID()); } - typedef boost::function<void(LLAvatarPicks*)> server_respond_callback_t; + typedef boost::function<void(LLAvatarData*)> server_respond_callback_t; void setServerRespondCallback(const server_respond_callback_t& cb) { @@ -61,10 +61,10 @@ public: virtual void processProperties(void* data, EAvatarProcessorType type) { - if(APT_PICKS == type) + if(APT_PROPERTIES == type) { - LLAvatarPicks* picks = static_cast<LLAvatarPicks*>(data); - if(picks && gAgent.getID() == picks->target_id) + LLAvatarData* picks = static_cast<LLAvatarData*>(data); + if(picks && gAgent.getID() == picks->avatar_id) { if(mServerRespondCallback) { @@ -115,7 +115,7 @@ bool LLAgentPicksInfo::isPickLimitReached() return getNumberOfPicks() >= getMaxNumberOfPicks(); } -void LLAgentPicksInfo::onServerRespond(LLAvatarPicks* picks) +void LLAgentPicksInfo::onServerRespond(LLAvatarData* picks) { if(!picks) { diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h index 19d593bab5..edd41d8746 100644 --- a/indra/newview/llagentpicksinfo.h +++ b/indra/newview/llagentpicksinfo.h @@ -29,7 +29,7 @@ #include "llsingleton.h" -struct LLAvatarPicks; +struct LLAvatarData; /** * Class that provides information about Agent Picks @@ -74,7 +74,7 @@ public: void decrementNumberOfPicks() { --mNumberOfPicks; } - void onServerRespond(LLAvatarPicks* picks); + void onServerRespond(LLAvatarData* picks); private: diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index ceeefd7415..97e1c1e6ee 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1398,7 +1398,7 @@ const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview"; const LLUUID LLAppearanceMgr::getCOF() const { - return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + return mCOFID; } S32 LLAppearanceMgr::getCOFVersion() const @@ -1414,6 +1414,11 @@ S32 LLAppearanceMgr::getCOFVersion() const } } +void LLAppearanceMgr::initCOFID() +{ + mCOFID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); +} + const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() { const LLUUID& current_outfit_cat = getCOF(); @@ -3762,6 +3767,14 @@ LLSD LLAppearanceMgr::dumpCOF() const return result; } +void LLAppearanceMgr::cleanup() +{ + mIsInUpdateAppearanceFromCOF = false; + mOutstandingAppearanceBakeRequest = false; + mRerequestAppearanceBake = false; + mCOFID.setNull(); +} + // static void LLAppearanceMgr::onIdle(void *) { @@ -4130,7 +4143,7 @@ void LLAppearanceMgr::wearBaseOutfit() updateCOF(base_outfit_id); } -void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) +void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, nullary_func_t post_update_func) { LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL; LLUIUsage::instance().logCommand("Avatar.RemoveItem"); @@ -4140,7 +4153,7 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; return; } - LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(true, true, post_update_func); for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { const LLUUID& id_to_remove = *it; @@ -4159,11 +4172,11 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) } } -void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove, nullary_func_t post_update_func) { uuid_vec_t ids_to_remove; ids_to_remove.push_back(id_to_remove); - removeItemsFromAvatar(ids_to_remove); + removeItemsFromAvatar(ids_to_remove, post_update_func); } @@ -4400,20 +4413,45 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const return FALSE; } -BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const +bool LLAppearanceMgr::getIsInCOF(const LLInventoryObject* obj) const +{ + const LLUUID& cof = getCOF(); + if (obj->getUUID() == cof) + return true; + if (obj && obj->getParentUUID() == cof) + return true; + return false; +} + +bool LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const { - if (!getIsInCOF(obj_id)) return FALSE; + if (!getIsInCOF(obj_id)) return false; // If a non-link somehow ended up in COF, allow deletion. const LLInventoryObject *obj = gInventory.getObject(obj_id); if (obj && !obj->getIsLinkType()) { - return FALSE; + return false; + } + + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return true; +} + +bool LLAppearanceMgr::getIsProtectedCOFItem(const LLInventoryObject* obj) const +{ + if (!getIsInCOF(obj)) return false; + + // If a non-link somehow ended up in COF, allow deletion. + if (obj && !obj->getIsLinkType()) + { + return false; } // For now, don't allow direct deletion from the COF. Instead, force users // to choose "Detach" or "Take Off". - return TRUE; + return true; } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index ae23022513..e5de92b653 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -111,9 +111,11 @@ public: // Find the Current Outfit folder. const LLUUID getCOF() const; S32 getCOFVersion() const; + void initCOFID(); // Debugging - get truncated LLSD summary of COF contents. LLSD dumpCOF() const; + void cleanup(); // Finds the folder link to the currently worn outfit const LLViewerInventoryItem *getBaseOutfitLink(); @@ -195,8 +197,8 @@ public: bool updateBaseOutfit(); //Remove clothing or detach an object from the agent (a bodypart cannot be removed) - void removeItemsFromAvatar(const uuid_vec_t& item_ids); - void removeItemFromAvatar(const LLUUID& item_id); + void removeItemsFromAvatar(const uuid_vec_t& item_ids, nullary_func_t post_update_func = no_op); + void removeItemFromAvatar(const LLUUID& item_id, nullary_func_t post_update_func = no_op); void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); @@ -276,6 +278,7 @@ private: attachments_changed_signal_t mAttachmentsChangeSignal; LLUUID mCOFImageID; + LLUUID mCOFID; std::unique_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; @@ -290,8 +293,10 @@ private: public: // Is this in the COF? BOOL getIsInCOF(const LLUUID& obj_id) const; + bool getIsInCOF(const LLInventoryObject* obj) const; // Is this in the COF and can the user delete it from the COF? - BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; + bool getIsProtectedCOFItem(const LLUUID& obj_id) const; + bool getIsProtectedCOFItem(const LLInventoryObject* obj) const; // Outfits will prioritize textures with such name to use for preview in gallery static const std::string sExpectedTextureName; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 617cd18e9f..1626af74e2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -528,13 +528,6 @@ bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* ba // or for things that are performance critical. JC static void settings_to_globals() { - LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad"); - BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); - BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); - - MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); - MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); - LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); #if LL_DARWIN @@ -4312,7 +4305,8 @@ bool LLAppViewer::initCache() LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); - LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); + const U32 CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS = 128; + LLVOCache::getInstance()->initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS, getObjectCacheVersion()); return true; } diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index 07e544a1ca..28b6e6dbf6 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -245,7 +245,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value) // messages. People API already hits the user table. LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); app->addObserver(mAvatarId, this); - app->sendAvatarPropertiesRequest(mAvatarId); + app->sendAvatarLegacyPropertiesRequest(mAvatarId); } else if (gAgentID == mAvatarId) { @@ -299,9 +299,15 @@ bool LLAvatarIconCtrl::updateFromCache() //virtual void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type) { - if (APT_PROPERTIES == type) + // Both APT_PROPERTIES_LEGACY and APT_PROPERTIES have icon data. + // 'Legacy' is cheaper to request so LLAvatarIconCtrl issues that, + // but own icon should track any source for the sake of timely updates. + // + // If this needs to change, make sure to update onCommitProfileImage + // to issue right kind of request + if (APT_PROPERTIES_LEGACY == type) { - LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + LLAvatarLegacyData* avatar_data = static_cast<LLAvatarLegacyData*>(data); if (avatar_data) { if (avatar_data->avatar_id != mAvatarId) @@ -313,6 +319,20 @@ void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type) updateFromCache(); } } + else if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + if (avatar_data) + { + if (avatar_data->avatar_id != mAvatarId) + { + return; + } + + LLAvatarIconIDCache::getInstance()->add(mAvatarId, avatar_data->image_id); + updateFromCache(); + } + } } void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index f28cb6147e..72bdbb6975 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -52,24 +52,23 @@ LLAvatarPropertiesProcessor::~LLAvatarPropertiesProcessor() void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) { + if (!observer) + return; + // Check if that observer is already in mObservers for that avatar_id - observer_multimap_t::iterator it; + using pair = std::pair<LLUUID, LLAvatarPropertiesObserver*>; + observer_multimap_t::iterator begin = mObservers.begin(); + observer_multimap_t::iterator end = mObservers.end(); + observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p) + { + return p.first == avatar_id && p.second == observer; + }); // IAN BUG this should update the observer's UUID if this is a dupe - sent to PE - it = mObservers.find(avatar_id); - while (it != mObservers.end()) + if (it == end) { - if (it->second == observer) - { - return; - } - else - { - ++it; - } + mObservers.emplace(avatar_id, observer); } - - mObservers.insert(std::pair<LLUUID, LLAvatarPropertiesObserver*>(avatar_id, observer)); } void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) @@ -79,19 +78,18 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat return; } - observer_multimap_t::iterator it; - it = mObservers.find(avatar_id); - while (it != mObservers.end()) - { - if (it->second == observer) - { - mObservers.erase(it); - break; - } - else + // Check if that observer is in mObservers for that avatar_id + using pair = std::pair<LLUUID, LLAvatarPropertiesObserver*>; + observer_multimap_t::iterator begin = mObservers.begin(); + observer_multimap_t::iterator end = mObservers.end(); + observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p) { - ++it; - } + return p.first == avatar_id && p.second == observer; + }); + + if (it != end) + { + mObservers.erase(it); } } @@ -116,32 +114,30 @@ void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarPr return; } - std::string cap; - - switch (type) + // Try to send HTTP request if cap_url is available + if (type == APT_PROPERTIES) { - case APT_PROPERTIES: - // indicate we're going to make a request - sendAvatarPropertiesRequestMessage(avatar_id); - // can use getRegionCapability("AgentProfile"), but it is heavy - // initAgentProfileCapRequest(avatar_id, cap); - break; - case APT_PICKS: - case APT_GROUPS: - case APT_NOTES: - if (cap.empty()) + std::string cap_url = gAgent.getRegionCapability("AgentProfile"); + if (!cap_url.empty()) { - // indicate we're going to make a request - sendGenericRequest(avatar_id, type, method); + initAgentProfileCapRequest(avatar_id, cap_url, type); } else { - initAgentProfileCapRequest(avatar_id, cap); + // Don't sent UDP request for APT_PROPERTIES + LL_WARNS() << "No cap_url for APT_PROPERTIES, request for " << avatar_id << " is not sent" << LL_ENDL; } - break; - default: + return; + } + + // Send UDP request + if (type == APT_PROPERTIES_LEGACY) + { + sendAvatarPropertiesRequestMessage(avatar_id); + } + else + { sendGenericRequest(avatar_id, type, method); - break; } } @@ -150,33 +146,29 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA // indicate we're going to make a request addPendingRequest(avatar_id, type); - std::vector<std::string> strings; - strings.push_back(avatar_id.asString()); + std::vector<std::string> strings{ avatar_id.asString() }; send_generic_message(method, strings); } void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id) { - addPendingRequest(avatar_id, APT_PROPERTIES); + addPendingRequest(avatar_id, APT_PROPERTIES_LEGACY); LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_AvatarPropertiesRequest); msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); msg->addUUIDFast(_PREHASH_AvatarID, avatar_id); gAgent.sendReliableMessage(); } -void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url) +void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type) { - addPendingRequest(avatar_id, APT_PROPERTIES); - addPendingRequest(avatar_id, APT_PICKS); - addPendingRequest(avatar_id, APT_GROUPS); - addPendingRequest(avatar_id, APT_NOTES); + addPendingRequest(avatar_id, type); LLCoros::instance().launch("requestAgentUserInfoCoro", - boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id)); + [cap_url, avatar_id, type]() { requestAvatarPropertiesCoro(cap_url, avatar_id, type); }); } void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) @@ -184,19 +176,9 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avat sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest"); } -void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) +void LLAvatarPropertiesProcessor::sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id) { - sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); -} - -void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id) -{ - sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest"); -} - -void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id) -{ - sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest"); + sendRequest(avatar_id, APT_PROPERTIES_LEGACY, "AvatarPropertiesRequest"); } void LLAvatarPropertiesProcessor::sendAvatarTexturesRequest(const LLUUID& avatar_id) @@ -211,42 +193,6 @@ void LLAvatarPropertiesProcessor::sendAvatarClassifiedsRequest(const LLUUID& ava sendGenericRequest(avatar_id, APT_CLASSIFIEDS, "avatarclassifiedsrequest"); } -void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props) -{ - if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null)) - { - LL_WARNS() << "Sending avatarinfo update DENIED - invalid agent" << LL_ENDL; - return; - } - - LL_WARNS() << "Sending avatarinfo update. This trims profile descriptions!!!" << LL_ENDL; - - // This value is required by sendAvatarPropertiesUpdate method. - //A profile should never be mature. (From the original code) - BOOL mature = FALSE; - - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast (_PREHASH_AvatarPropertiesUpdate); - msg->nextBlockFast (_PREHASH_AgentData); - msg->addUUIDFast (_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast (_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast (_PREHASH_PropertiesData); - - msg->addUUIDFast (_PREHASH_ImageID, avatar_props->image_id); - msg->addUUIDFast (_PREHASH_FLImageID, avatar_props->fl_image_id); - msg->addStringFast (_PREHASH_AboutText, avatar_props->about_text); - msg->addStringFast (_PREHASH_FLAboutText, avatar_props->fl_about_text); - - msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish); - msg->addBOOL(_PREHASH_MaturePublish, mature); - msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url); - - gAgent.sendReliableMessage(); -} - - - //static std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_data) { @@ -271,19 +217,21 @@ std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data) { // Special accounts like M Linden don't have payment info revealed. - if (!avatar_data->caption_text.empty()) return ""; + if (!avatar_data->caption_text.empty()) + return ""; // Linden employees don't have payment info revealed - const S32 LINDEN_EMPLOYEE_INDEX = 3; - if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return ""; + constexpr S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) + return ""; - BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED); - BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED); + bool transacted = (avatar_data->flags & AVATAR_TRANSACTED); + bool identified = (avatar_data->flags & AVATAR_IDENTIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations //BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED); const char* payment_text; - if(transacted) + if (transacted) { payment_text = "PaymentInfoUsed"; } @@ -302,18 +250,22 @@ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_ bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avatar_data) { // Special accounts like M Linden don't have payment info revealed. - if (!avatar_data->caption_text.empty()) return true; + if (!avatar_data->caption_text.empty()) + return true; // Linden employees don't have payment info revealed - const S32 LINDEN_EMPLOYEE_INDEX = 3; - if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return true; + constexpr S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) + return true; return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED)); } // static -void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id) +void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type) { + LLAvatarPropertiesProcessor& inst = instance(); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy)); @@ -323,104 +275,104 @@ void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_ur LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); httpOpts->setFollowRedirects(true); - std::string finalUrl = cap_url + "/" + agent_id.asString(); + std::string finalUrl = cap_url + "/" + avatar_id.asString(); LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); + // Response is being processed, no longer pending is required + inst.removePendingRequest(avatar_id, type); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status || !result.has("id") - || agent_id != result["id"].asUUID()) + || avatar_id != result["id"].asUUID()) { - LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL; - LLAvatarPropertiesProcessor* self = getInstance(); - self->removePendingRequest(agent_id, APT_PROPERTIES); - self->removePendingRequest(agent_id, APT_PICKS); - self->removePendingRequest(agent_id, APT_GROUPS); - self->removePendingRequest(agent_id, APT_NOTES); + LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << avatar_id + << (!status ? " (no HTTP status)" : !result.has("id") ? " (no result.id)" : + std::string(" (result.id=") + result["id"].asUUID().asString() + ")") + << LL_ENDL; return; } - // Avatar Data - LLAvatarData avatar_data; + std::string birth_date; - avatar_data.agent_id = agent_id; - avatar_data.avatar_id = agent_id; + avatar_data.agent_id = gAgentID; + avatar_data.avatar_id = avatar_id; avatar_data.image_id = result["sl_image_id"].asUUID(); avatar_data.fl_image_id = result["fl_image_id"].asUUID(); avatar_data.partner_id = result["partner_id"].asUUID(); avatar_data.about_text = result["sl_about_text"].asString(); avatar_data.fl_about_text = result["fl_about_text"].asString(); avatar_data.born_on = result["member_since"].asDate(); - avatar_data.profile_url = getProfileURL(agent_id.asString()); + // TODO: SL-20163 Remove the "has" check when SRV-684 is done + // and the field "hide_age" is included to the http response + inst.mIsHideAgeSupportedByServer = result.has("hide_age"); + avatar_data.hide_age = inst.isHideAgeSupportedByServer() && result["hide_age"].asBoolean(); + avatar_data.profile_url = getProfileURL(avatar_id.asString()); + avatar_data.customer_type = result["customer_type"].asString(); + avatar_data.notes = result["notes"].asString(); avatar_data.flags = 0; - avatar_data.caption_index = 0; - - LLAvatarPropertiesProcessor* self = getInstance(); - // Request processed, no longer pending - self->removePendingRequest(agent_id, APT_PROPERTIES); - self->notifyObservers(agent_id, &avatar_data, APT_PROPERTIES); - - // Picks - - LLSD picks_array = result["picks"]; - LLAvatarPicks avatar_picks; - avatar_picks.agent_id = agent_id; // Not in use? - avatar_picks.target_id = agent_id; - - for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) + if (result["online"].asBoolean()) { - const LLSD& pick_data = *it; - avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); + avatar_data.flags |= AVATAR_ONLINE; + } + if (result["allow_publish"].asBoolean()) + { + avatar_data.flags |= AVATAR_ALLOW_PUBLISH; + } + if (result["identified"].asBoolean()) + { + avatar_data.flags |= AVATAR_IDENTIFIED; + } + if (result["transacted"].asBoolean()) + { + avatar_data.flags |= AVATAR_TRANSACTED; } - // Request processed, no longer pending - self->removePendingRequest(agent_id, APT_PICKS); - self->notifyObservers(agent_id, &avatar_picks, APT_PICKS); + avatar_data.caption_index = 0; + if (result.has("charter_member")) // won't be present if "caption" is set + { + avatar_data.caption_index = result["charter_member"].asInteger(); + } + else if (result.has("caption")) + { + avatar_data.caption_text = result["caption"].asString(); + } // Groups - LLSD groups_array = result["groups"]; - LLAvatarGroups avatar_groups; - avatar_groups.agent_id = agent_id; // Not in use? - avatar_groups.avatar_id = agent_id; // target_id - for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it) { const LLSD& group_info = *it; - LLAvatarGroups::LLGroupData group_data; + LLAvatarData::LLGroupData group_data; group_data.group_powers = 0; // Not in use? group_data.group_title = group_info["name"].asString(); // Missing data, not in use? group_data.group_id = group_info["id"].asUUID(); group_data.group_name = group_info["name"].asString(); group_data.group_insignia_id = group_info["image_id"].asUUID(); - avatar_groups.group_list.push_back(group_data); + avatar_data.group_list.push_back(group_data); } - self->removePendingRequest(agent_id, APT_GROUPS); - self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS); - - // Notes - LLAvatarNotes avatar_notes; - - avatar_notes.agent_id = agent_id; - avatar_notes.target_id = agent_id; - avatar_notes.notes = result["notes"].asString(); + // Picks + LLSD picks_array = result["picks"]; + for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) + { + const LLSD& pick_data = *it; + avatar_data.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); + } - // Request processed, no longer pending - self->removePendingRequest(agent_id, APT_NOTES); - self->notifyObservers(agent_id, &avatar_notes, APT_NOTES); + inst.notifyObservers(avatar_id, &avatar_data, type); } -void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) +void LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**) { - LLAvatarData avatar_data; + LLAvatarLegacyData avatar_data; std::string birth_date; msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_data.agent_id); @@ -434,51 +386,35 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg->getString( _PREHASH_PropertiesData, _PREHASH_ProfileURL, avatar_data.profile_url); msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_Flags, avatar_data.flags); - LLDateUtil::dateFromPDTString(avatar_data.born_on, birth_date); avatar_data.caption_index = 0; S32 charter_member_size = 0; charter_member_size = msg->getSize(_PREHASH_PropertiesData, _PREHASH_CharterMember); - if(1 == charter_member_size) + if (1 == charter_member_size) { msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember, &avatar_data.caption_index, 1); } - else if(1 < charter_member_size) + else if (1 < charter_member_size) { msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text); } LLAvatarPropertiesProcessor* self = getInstance(); // Request processed, no longer pending - self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES); - self->notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES); + self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES_LEGACY); + self->notifyObservers(avatar_data.avatar_id, &avatar_data, APT_PROPERTIES_LEGACY); } void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**) { /* AvatarInterestsReply is automatically sent by the server in response to the - AvatarPropertiesRequest sent when the panel is opened (in addition to the AvatarPropertiesReply message). + AvatarPropertiesRequest (in addition to the AvatarPropertiesReply message). If the interests panel is no longer part of the design (?) we should just register the message to a handler function that does nothing. That will suppress the warnings and be compatible with old server versions. WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply */ - - LLInterestsData interests_data; - - msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id ); - msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, interests_data.want_to_mask ); - msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, interests_data.want_to_text ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, interests_data.skills_mask ); - msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, interests_data.skills_text ); - msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, interests_data.languages_text ); - - LLAvatarPropertiesProcessor* self = getInstance(); - // Request processed, no longer pending - self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO); - self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO); } void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**) @@ -497,7 +433,7 @@ void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, data.classified_id, n); msg->getString(_PREHASH_Data, _PREHASH_Name, data.name, n); - classifieds.classifieds_list.push_back(data); + classifieds.classifieds_list.emplace_back(data); } LLAvatarPropertiesProcessor* self = getInstance(); @@ -537,39 +473,17 @@ void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* ms void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**) { - LLAvatarNotes avatar_notes; - - msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_notes.agent_id); - msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id); - msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes); - - LLAvatarPropertiesProcessor* self = getInstance(); - // Request processed, no longer pending - self->removePendingRequest(avatar_notes.target_id, APT_NOTES); - self->notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES); + // Deprecated, new "AgentProfile" allows larger notes } void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**) { - LLAvatarPicks avatar_picks; - msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id); - msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id); - - S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data); - for (int block = 0; block < block_count; ++block) - { - LLUUID pick_id; - std::string pick_name; - - msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block); - msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block); + LLUUID agent_id; + LLUUID target_id; + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, target_id); - avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name)); - } - LLAvatarPropertiesProcessor* self = getInstance(); - // Request processed, no longer pending - self->removePendingRequest(avatar_picks.target_id, APT_PICKS); - self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); + LL_DEBUGS("AvatarProperties") << "Received AvatarPicksReply for " << target_id << LL_ENDL; } void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) @@ -604,44 +518,30 @@ void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, voi void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**) { - LLAvatarGroups avatar_groups; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, avatar_groups.agent_id ); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_groups.avatar_id ); - - S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); - for(S32 i = 0; i < group_count; ++i) - { - LLAvatarGroups::LLGroupData group_data; + /* + AvatarGroupsReply is automatically sent by the server in response to the + AvatarPropertiesRequest in addition to the AvatarPropertiesReply message. + */ + LLUUID agent_id; + LLUUID avatar_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id); - msg->getU64( _PREHASH_GroupData, _PREHASH_GroupPowers, group_data.group_powers, i ); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_data.group_title, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_data.group_id, i); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_data.group_name, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_data.group_insignia_id, i ); - - avatar_groups.group_list.push_back(group_data); - } - - LLAvatarPropertiesProcessor* self = getInstance(); - self->removePendingRequest(avatar_groups.avatar_id, APT_GROUPS); - self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); + LL_DEBUGS("AvatarProperties") << "Received AvatarGroupsReply for " << avatar_id << LL_ENDL; } -void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type) +void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id, void* data, EAvatarProcessorType type) { // Copy the map (because observers may delete themselves when updated?) LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers; - observer_multimap_t::iterator oi = observers.begin(); - observer_multimap_t::iterator end = observers.end(); - for (; oi != end; ++oi) + for (const auto& [agent_id, observer] : observers) { // only notify observers for the same agent, or if the observer // didn't know the agent ID and passed a NULL id. - const LLUUID &agent_id = oi->first; if (agent_id == id || agent_id.isNull()) { - oi->second->processProperties(data,type); + observer->processProperties(data, type); } } } @@ -655,8 +555,8 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 // setup message header msg->newMessageFast(_PREHASH_GrantUserRights); msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlockFast(_PREHASH_Rights); msg->addUUID(_PREHASH_AgentRelated, avatar_id); @@ -666,34 +566,13 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 } } -void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes) -{ - if(!avatar_id.isNull()) - { - LLMessageSystem* msg = gMessageSystem; - - // setup message header - msg->newMessageFast(_PREHASH_AvatarNotesUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_Data); - msg->addUUID(_PREHASH_TargetID, avatar_id); - msg->addString(_PREHASH_Notes, notes); - - gAgent.sendReliableMessage(); - } -} - - void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) { LLMessageSystem* msg = gMessageSystem; msg->newMessage(_PREHASH_PickDelete); msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlock(_PREHASH_Data); msg->addUUID(_PREHASH_PickID, pick_id); gAgent.sendReliableMessage(); @@ -709,8 +588,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_ msg->newMessage(_PREHASH_ClassifiedDelete); msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlock(_PREHASH_Data); msg->addUUID(_PREHASH_ClassifiedID, classified_id); @@ -718,39 +597,17 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_ gAgent.sendReliableMessage(); } -void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data) -{ - if(!interests_data) - { - return; - } - - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_AvatarInterestsUpdate); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast( _PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast( _PREHASH_PropertiesData); - msg->addU32Fast( _PREHASH_WantToMask, interests_data->want_to_mask); - msg->addStringFast( _PREHASH_WantToText, interests_data->want_to_text); - msg->addU32Fast( _PREHASH_SkillsMask, interests_data->skills_mask); - msg->addStringFast( _PREHASH_SkillsText, interests_data->skills_text); - msg->addString( _PREHASH_LanguagesText, interests_data->languages_text); - - gAgent.sendReliableMessage(); -} - void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) { - if (!new_pick) return; + if (!new_pick) + return; LLMessageSystem* msg = gMessageSystem; msg->newMessage(_PREHASH_PickInfoUpdate); msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlock(_PREHASH_Data); msg->addUUID(_PREHASH_PickID, new_pick->pick_id); @@ -787,8 +644,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif msg->newMessage(_PREHASH_ClassifiedInfoUpdate); msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlock(_PREHASH_Data); msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id); @@ -809,9 +666,7 @@ void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, { // Must ask for a pick based on the creator id because // the pick database is distributed to the inventory cluster. JC - std::vector<std::string> request_params; - request_params.push_back(creator_id.asString() ); - request_params.push_back(pick_id.asString() ); + std::vector<std::string> request_params{ creator_id.asString(), pick_id.asString() }; send_generic_message("pickinforequest", request_params); } @@ -822,8 +677,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classi msg->newMessage(_PREHASH_ClassifiedInfoRequest); msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlock(_PREHASH_Data); msg->addUUID(_PREHASH_ClassifiedID, classified_id); @@ -840,7 +695,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva if (it == mRequestTimestamps.end()) return false; // We found a request, check if it has timed out - U32 now = time(NULL); + U32 now = time(nullptr); const U32 REQUEST_EXPIRE_SECS = 5; U32 expires = it->second + REQUEST_EXPIRE_SECS; @@ -854,7 +709,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) { timestamp_map_t::key_type key = std::make_pair(avatar_id, type); - U32 now = time(NULL); + U32 now = time(nullptr); // Add or update existing (expired) request mRequestTimestamps[ key ] = now; } diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index 77bf5fd51e..0a1445419e 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -50,26 +50,34 @@ class LLMessageSystem; enum EAvatarProcessorType { - APT_PROPERTIES, - APT_NOTES, - APT_GROUPS, - APT_PICKS, + APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request (Truncates data!!!) + APT_PROPERTIES, // APT_PROPERTIES via http request APT_PICK_INFO, APT_TEXTURES, - APT_INTERESTS_INFO, APT_CLASSIFIEDS, APT_CLASSIFIED_INFO }; -struct LLInterestsData +// legacy data is supposed to match AvatarPropertiesReply, +// but it is obsolete, fields like about_text will truncate +// data, if you need them, use AgenProfile cap. +// Todo: remove it once once icon ids get moved elsewhere, +// since AgentProfile is too large for bulk icon requests +struct LLAvatarLegacyData { LLUUID agent_id; LLUUID avatar_id; //target id - U32 want_to_mask; - std::string want_to_text; - U32 skills_mask; - std::string skills_text; - std::string languages_text; + LLUUID image_id; + LLUUID fl_image_id; + LLUUID partner_id; + std::string about_text; + std::string fl_about_text; + LLDate born_on; + std::string profile_url; + U8 caption_index; + std::string caption_text; + std::string customer_type; + U32 flags; }; struct LLAvatarData @@ -87,19 +95,28 @@ struct LLAvatarData std::string caption_text; std::string customer_type; U32 flags; - BOOL allow_publish; -}; + bool hide_age; + std::string notes; -struct LLAvatarPicks -{ - LLUUID agent_id; - LLUUID target_id; //target id + struct LLGroupData; + typedef std::list<LLGroupData> group_list_t; + group_list_t group_list; - typedef std::pair<LLUUID,std::string> pick_data_t; + typedef std::pair<LLUUID, std::string> pick_data_t; typedef std::list< pick_data_t> picks_list_t; picks_list_t picks_list; }; +struct LLAvatarData::LLGroupData +{ + U64 group_powers; + BOOL accept_notices; + std::string group_title; + LLUUID group_id; + std::string group_name; + LLUUID group_insignia_id; +}; + struct LLPickData { LLUUID agent_id; @@ -121,36 +138,6 @@ struct LLPickData //used only in write (update) requests LLUUID session_id; - -}; - -struct LLAvatarNotes -{ - LLUUID agent_id; - LLUUID target_id; //target id - std::string notes; -}; - -struct LLAvatarGroups -{ - LLUUID agent_id; - LLUUID avatar_id; //target id - BOOL list_in_profile; - - struct LLGroupData; - typedef std::list<LLGroupData> group_list_t; - - group_list_t group_list; - - struct LLGroupData - { - U64 group_powers; - BOOL accept_notices; - std::string group_title; - LLUUID group_id; - std::string group_name; - LLUUID group_insignia_id; - }; }; struct LLAvatarClassifieds @@ -211,9 +198,7 @@ public: // Request various types of avatar data. Duplicate requests will be // suppressed while waiting for a response from the network. void sendAvatarPropertiesRequest(const LLUUID& avatar_id); - void sendAvatarPicksRequest(const LLUUID& avatar_id); - void sendAvatarNotesRequest(const LLUUID& avatar_id); - void sendAvatarGroupsRequest(const LLUUID& avatar_id); + void sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id); void sendAvatarTexturesRequest(const LLUUID& avatar_id); void sendAvatarClassifiedsRequest(const LLUUID& avatar_id); @@ -222,21 +207,17 @@ public: void sendClassifiedInfoRequest(const LLUUID& classified_id); - void sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props); - void sendPickInfoUpdate(const LLPickData* new_pick); void sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data); void sendFriendRights(const LLUUID& avatar_id, S32 rights); - void sendNotes(const LLUUID& avatar_id, const std::string notes); - void sendPickDelete(const LLUUID& pick_id); void sendClassifiedDelete(const LLUUID& classified_id); - void sendInterestsInfoUpdate(const LLInterestsData* interests_data); + bool isHideAgeSupportedByServer() { return mIsHideAgeSupportedByServer; } // Returns translated, human readable string for account type, such // as "Resident" or "Linden Employee". Used for profiles, inspectors. @@ -249,9 +230,10 @@ public: static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data); - static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id); + static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type); - static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); + // Processing of UDP variant of properties, truncates certain fields! + static void processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**); static void processAvatarInterestsReply(LLMessageSystem* msg, void**); @@ -272,7 +254,7 @@ protected: void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method); void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method); void sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id); - void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url); + void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type); void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type); @@ -302,6 +284,9 @@ protected: // Map avatar_id+request_type -> U32 timestamp in seconds typedef std::map< std::pair<LLUUID, EAvatarProcessorType>, U32> timestamp_map_t; timestamp_map_t mRequestTimestamps; + + // Is returned by isHideAgeSupportedByServer() + bool mIsHideAgeSupportedByServer { false }; }; #endif // LL_LLAVATARPROPERTIESPROCESSOR_H diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 1b2581a03c..f66a9865fc 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -88,7 +88,7 @@ LLScreenChannel* LLChannelManager::createNotificationChannel() { // creating params for a channel LLScreenChannelBase::Params p; - p.id = LLUUID(gSavedSettings.getString("NotificationChannelUUID")); + p.id = NOTIFICATION_CHANNEL_UUID; p.channel_align = CA_RIGHT; p.toast_align = NA_TOP; @@ -108,7 +108,7 @@ void LLChannelManager::onLoginCompleted() if (!channel) continue; // don't calc notifications for Nearby Chat - if(channel->getChannelID() == LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))) + if(channel->getChannelID() == NEARBY_CHAT_CHANNEL_UUID) { continue; } @@ -130,7 +130,7 @@ void LLChannelManager::onLoginCompleted() { // create a channel for the StartUp Toast LLScreenChannelBase::Params p; - p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); + p.id = STARTUP_CHANNEL_UUID; p.channel_align = CA_RIGHT; mStartUpChannel = createChannel(p); @@ -144,8 +144,7 @@ void LLChannelManager::onLoginCompleted() // init channel's position and size S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); + mStartUpChannel->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4)); mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); @@ -164,7 +163,7 @@ void LLChannelManager::onStartUpToastClose() { mStartUpChannel->setVisible(FALSE); mStartUpChannel->closeStartUpToast(); - removeChannelByID(LLUUID(gSavedSettings.getString("StartUpChannelUUID"))); + removeChannelByID(STARTUP_CHANNEL_UUID); mStartUpChannel = NULL; } @@ -258,12 +257,12 @@ LLNotificationsUI::LLScreenChannel* LLChannelManager::getNotificationScreenChann { LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + findChannelByID(NOTIFICATION_CHANNEL_UUID)); if (channel == NULL) { - LL_WARNS() << "Can't find screen channel by NotificationChannelUUID" << LL_ENDL; - llassert(!"Can't find screen channel by NotificationChannelUUID"); + LL_WARNS() << "Can't find screen channel by Notification Channel UUID" << LL_ENDL; + llassert(!"Can't find screen channel by Notification Channel UUID"); } return channel; diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 67090772fd..c43864d85f 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -142,7 +142,7 @@ protected: registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs)); registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs)); - registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; enable_registrar.add("Attachment.OnEnable", boost::bind(&CofAttachmentContextMenu::onEnable, this, _2)); @@ -195,7 +195,7 @@ protected: LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; LLUUID selected_id = mUUIDs.back(); - registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); registrar.add("Clothing.Replace", boost::bind(replaceWearable, selected_id)); registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id)); registrar.add("Clothing.Create", boost::bind(&CofClothingContextMenu::createNew, this, selected_id)); diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index eebef4cc1c..0006a48de5 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -66,6 +66,7 @@ namespace { const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue"); + const F32 QUEUE_INVENTORY_FETCH_TIMEOUT = 300.f; // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged // callback mechanism and the LLEventPump coroutine architecture allowing the @@ -359,8 +360,6 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. // which is caught in objectScriptProcessingQueueCoro bool monocompile = floater->mMono; - F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); - // Initial test to see if we can (or should) attempt to compile the script. LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory); @@ -385,7 +384,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(), boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1)); - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, + result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true))); floater.check(); @@ -435,7 +434,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat &LLFloaterCompileQueue::handleScriptRetrieval, &userData); - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, + result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true))); } @@ -481,7 +480,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } - result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true))); + result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true))); floater.check(); @@ -736,8 +735,6 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. // This is expected if the dialog closes. LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true); - F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout"); - try { @@ -759,7 +756,7 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L args["[OBJECT_NAME]"] = (*itObj).mObjectName; floater->addStringMessage(floater->getString("LoadingObjInv", args)); - LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout, + LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true))); if (result.has("timeout")) diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index d900730e98..b7317272a1 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -137,9 +137,9 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_ { LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents); F32 offset_dist = pos_box_offset.length(); - if (offset_dist > max_legal_offset && offset_dist > 0.f) + if (offset_dist > MAX_LEGAL_OFFSET && offset_dist > 0.f) { - F32 target_dist = (offset_dist - max_legal_offset); + F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET); new_pos_fixup = (target_dist/offset_dist)*pos_box_offset; } if (new_pos_fixup != mPositionConstraintFixup) @@ -152,11 +152,11 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_ } } - if (box_size/mScaleConstraintFixup > max_legal_size) + if (box_size/mScaleConstraintFixup > MAX_LEGAL_SIZE) { - new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size; + new_scale_fixup = mScaleConstraintFixup* MAX_LEGAL_SIZE /box_size; LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " - << mScaleConstraintFixup << " max legal " << max_legal_size + << mScaleConstraintFixup << " max legal " << MAX_LEGAL_SIZE << " -> new scale " << new_scale_fixup << LL_ENDL; } } @@ -201,8 +201,7 @@ void LLControlAvatar::matchVolumeTransform() mRoot->setWorldRotation(obj_rot * joint_rot); setRotation(mRoot->getRotation()); - F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); - setGlobalScale(global_scale * mScaleConstraintFixup); + setGlobalScale(mScaleConstraintFixup); } else { @@ -252,8 +251,7 @@ void LLControlAvatar::matchVolumeTransform() } mRoot->setPosition(vol_pos + mPositionConstraintFixup); - F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); - setGlobalScale(global_scale * mScaleConstraintFixup); + setGlobalScale(mScaleConstraintFixup); } } } diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index ecd035c23b..3a3c26f955 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -82,7 +82,7 @@ public: virtual BOOL isItemRenameable() const { return TRUE; } virtual BOOL renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return TRUE; } virtual BOOL isItemMovable( void ) const { return FALSE; } - virtual BOOL isItemRemovable( void ) const { return FALSE; } + virtual BOOL isItemRemovable(bool check_worn = true) const { return FALSE; } virtual BOOL isItemInTrash( void) const { return FALSE; } virtual BOOL removeItem() { return FALSE; } virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) { } diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 217f29bffb..1abebc996b 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -106,6 +106,8 @@ LLConversationViewSession::~LLConversationViewSession() } mFlashTimer->unset(); + delete mFlashTimer; + mFlashStateOn = false; } void LLConversationViewSession::destroyView() diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 247a487ace..3c0a523317 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2116,7 +2116,7 @@ void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environ { LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; } - else if (LLApp::isExiting()) + else if (LLApp::isExiting() || gDisconnected) { return; } diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 9e526f8c52..7ac90a04db 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -243,6 +243,12 @@ LLExpandableTextBox::LLExpandableTextBox(const Params& p) mTextBox->setCommitCallback(boost::bind(&LLExpandableTextBox::onExpandClicked, this)); } + +LLExpandableTextBox::~LLExpandableTextBox() +{ + gViewerWindow->removePopup(this); +} + void LLExpandableTextBox::draw() { if(mBGVisible && !mExpanded) diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h index 385bb35017..d992f3131a 100644 --- a/indra/newview/llexpandabletextbox.h +++ b/indra/newview/llexpandabletextbox.h @@ -121,7 +121,7 @@ public: /** * Returns text */ - virtual std::string getText() const { return mText; } + virtual const std::string& getText() const { return mText; } /** * Sets text @@ -154,6 +154,8 @@ public: */ /*virtual*/ void draw(); + virtual ~LLExpandableTextBox(); + protected: LLExpandableTextBox(const Params& p); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 96ab5da318..51b9923684 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -632,6 +632,9 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF switch(filter) { case FFLOAD_ALL: + case FFLOAD_EXE: + allowedv->push_back("app"); + allowedv->push_back("exe"); allowedv->push_back("wav"); allowedv->push_back("bvh"); allowedv->push_back("anim"); @@ -652,9 +655,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF allowedv->push_back("tpic"); allowedv->push_back("png"); break; - case FFLOAD_EXE: - allowedv->push_back("app"); - allowedv->push_back("exe"); break; case FFLOAD_WAV: allowedv->push_back("wav"); diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index cf665ca87d..f903b1bd8d 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -107,15 +107,11 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key) mCloseOnSelect(FALSE), mExcludeAgentFromSearchResults(FALSE), mContextConeOpacity (0.f), - mContextConeInAlpha(0.f), - mContextConeOutAlpha(0.f), - mContextConeFadeTime(0.f) + mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA), + mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA), + mContextConeFadeTime(CONTEXT_CONE_FADE_TIME) { mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this)); - - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } BOOL LLFloaterAvatarPicker::postBuild() diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index 7e413e35d6..8ad13367c0 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -102,9 +102,9 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show mActive ( TRUE ), mCanApplyImmediately ( show_apply_immediate ), mContextConeOpacity ( 0.f ), - mContextConeInAlpha ( 0.f ), - mContextConeOutAlpha ( 0.f ), - mContextConeFadeTime ( 0.f ) + mContextConeInAlpha (CONTEXT_CONE_IN_ALPHA), + mContextConeOutAlpha (CONTEXT_CONE_OUT_ALPHA), + mContextConeFadeTime (CONTEXT_CONE_FADE_TIME) { buildFromFile ( "floater_color_picker.xml"); @@ -116,10 +116,6 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show mApplyImmediateCheck->setEnabled(FALSE); mApplyImmediateCheck->set(FALSE); } - - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } LLFloaterColorPicker::~LLFloaterColorPicker() diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index 9960864a60..92bf91ab05 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -37,13 +37,14 @@ const std::string LL_FCP_COMPLETE_NAME("complete_name"); const std::string LL_FCP_ACCOUNT_NAME("user_name"); +const S32 CONVERSATION_HISTORY_PAGE_SIZE = 100; LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id) : LLFloater(session_id), mChatHistory(NULL), mSessionID(session_id.asUUID()), mCurrentPage(0), - mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")), + mPageSize(CONVERSATION_HISTORY_PAGE_SIZE), mAccountName(session_id[LL_FCP_ACCOUNT_NAME]), mCompleteName(session_id[LL_FCP_COMPLETE_NAME]), mMutex(), diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index 0abc14262e..78b94d1b0c 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -39,8 +39,9 @@ #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llsdserialize.h" -#include "lltextbox.h" -#include "llviewerchat.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "llviewerchat.h" namespace { // The following variables and constants are used for storing the floater state @@ -128,7 +129,7 @@ public: , const LLEmojiSearchResult& emoji) : LLScrollingPanel(panel_params) , mData(emoji) - , mText(LLWString(1, emoji.Character)) + , mChar(LLWString(1, emoji.Character)) { } @@ -138,8 +139,8 @@ public: F32 x = getRect().getWidth() / 2; F32 y = getRect().getHeight() / 2; - LLFontGL::getFontEmoji()->render( - mText, // wstr + LLFontGL::getFontEmojiLarge()->render( + mChar, // wstr 0, // begin_offset x, // x y, // y @@ -154,11 +155,11 @@ public: virtual void updatePanel(BOOL allow_modify) override {} const LLEmojiSearchResult& getData() const { return mData; } - LLWString getText() const { return mText; } + const LLWString& getChar() const { return mChar; } private: const LLEmojiSearchResult mData; - const LLWString mText; + const LLWString mChar; }; class LLEmojiPreviewPanel : public LLPanel @@ -229,7 +230,7 @@ protected: { F32 x0 = x; F32 x1 = max_pixels; - LLFontGL* font = LLFontGL::getFontEmoji(); + LLFontGL* font = LLFontGL::getFontEmojiLarge(); if (mBegin) { std::string text = mTitle.substr(0, mBegin); @@ -332,6 +333,14 @@ void LLFloaterEmojiPicker::onOpen(const LLSD& key) gFloaterView->adjustToFitScreen(this, FALSE); } +void LLFloaterEmojiPicker::onClose(bool app_quitting) +{ + if (!app_quitting) + { + LLEmojiHelper::instance().hideHelper(nullptr, true); + } +} + void LLFloaterEmojiPicker::dirtyRect() { super::dirtyRect(); @@ -388,9 +397,12 @@ void LLFloaterEmojiPicker::initialize() } else { - const std::string prompt("No emoji found for "); - std::string title(prompt + '"' + mFilterPattern.substr(1) + '"'); - mPreview->setData(EMPTY_LIST_IMAGE_INDEX, title, prompt.size() + 1, title.size() - 1); + std::size_t begin, end; + LLStringUtil::format_map_t args; + args["[FILTER]"] = mFilterPattern.substr(1); + std::string title(getString("text_no_emoji_for_filter", args)); + LLEmojiDictionary::searchInShortCode(begin, end, title, mFilterPattern); + mPreview->setData(EMPTY_LIST_IMAGE_INDEX, title, begin, end); showPreview(true); } return; @@ -423,7 +435,7 @@ void LLFloaterEmojiPicker::fillGroups() mGroupButtons.clear(); LLButton::Params params; - params.font = LLFontGL::getFontEmoji(); + params.font = LLFontGL::getFontEmojiLarge(); LLRect rect; rect.mTop = mGroups->getRect().getHeight(); @@ -485,10 +497,12 @@ void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::map<std::string, std::v auto e2d = emoji2descr.find(emoji); if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) { - const std::string shortcode(e2d->second->ShortCodes.front()); - if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + for (const std::string& shortcode : e2d->second->ShortCodes) { - emojis.emplace_back(emoji, shortcode, begin, end); + if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + { + emojis.emplace_back(emoji, shortcode, begin, end); + } } } } @@ -517,10 +531,12 @@ void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std: auto e2d = emoji2descr.find(emoji.first); if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) { - const std::string shortcode(e2d->second->ShortCodes.front()); - if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + for (const std::string& shortcode : e2d->second->ShortCodes) { - emojis.emplace_back(emoji.first, shortcode, begin, end); + if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + { + emojis.emplace_back(emoji.first, shortcode, begin, end); + } } } } @@ -553,10 +569,12 @@ void LLFloaterEmojiPicker::fillGroupEmojis(std::map<std::string, std::vector<LLE { if (!descr->ShortCodes.empty()) { - const std::string shortcode(descr->ShortCodes.front()); - if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + for (const std::string& shortcode : descr->ShortCodes) { - emojis.emplace_back(descr->Character, shortcode, begin, end); + if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) + { + emojis.emplace_back(descr->Character, shortcode, begin, end); + } } } } @@ -924,7 +942,7 @@ void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl) if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl)) { - LLSD value(wstring_to_utf8str(icon->getText())); + LLSD value(wstring_to_utf8str(icon->getChar())); setValue(value); onCommit(); diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h index 82faaf821b..05b4826e37 100644 --- a/indra/newview/llfloateremojipicker.h +++ b/indra/newview/llfloateremojipicker.h @@ -94,6 +94,7 @@ private: void unselectGridIcon(LLEmojiGridIcon* icon); void onOpen(const LLSD& key) override; + void onClose(bool app_quitting) override; virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override; class LLPanel* mGroups { nullptr }; diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp index 668143933c..93eaa6b64b 100644 --- a/indra/newview/llfloaterexperiencepicker.cpp +++ b/indra/newview/llfloaterexperiencepicker.cpp @@ -88,13 +88,10 @@ LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key ) :LLFloater(key) ,mSearchPanel(NULL) ,mContextConeOpacity(0.f) - ,mContextConeInAlpha(0.f) - ,mContextConeOutAlpha(0.f) - ,mContextConeFadeTime(0.f) + ,mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA) + ,mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA) + ,mContextConeFadeTime(CONTEXT_CONE_FADE_TIME) { - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } LLFloaterExperiencePicker::~LLFloaterExperiencePicker() diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 98842eed77..73adb2175a 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -342,55 +342,63 @@ void LLFloaterImagePreview::draw() //----------------------------------------------------------------------------- bool LLFloaterImagePreview::loadImage(const std::string& src_filename) { - std::string exten = gDirUtilp->getExtension(src_filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - - LLImageDimensionsInfo image_info; - if (!image_info.load(src_filename,codec)) + try { - mImageLoadError = image_info.getLastError(); - return false; - } + std::string exten = gDirUtilp->getExtension(src_filename); + U32 codec = LLImageBase::getCodecFromExtension(exten); - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + LLImageDimensionsInfo image_info; + if (!image_info.load(src_filename, codec)) + { + mImageLoadError = image_info.getLastError(); + return false; + } - if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) - { - LLStringUtil::format_map_t args; - args["WIDTH"] = llformat("%d", max_width); - args["HEIGHT"] = llformat("%d", max_height); + S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); + S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); - return false; - } + if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) + { + LLStringUtil::format_map_t args; + args["WIDTH"] = llformat("%d", max_width); + args["HEIGHT"] = llformat("%d", max_height); - // Load the image - LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); - if (image.isNull()) - { - return false; - } - if (!image->load(src_filename)) - { - return false; - } - // Decompress or expand it in a raw image structure - LLPointer<LLImageRaw> raw_image = new LLImageRaw; - if (!image->decode(raw_image, 0.0f)) - { - return false; + mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + return false; + } + + // Load the image + LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); + if (image.isNull()) + { + return false; + } + if (!image->load(src_filename)) + { + return false; + } + // Decompress or expand it in a raw image structure + LLPointer<LLImageRaw> raw_image = new LLImageRaw; + if (!image->decode(raw_image, 0.0f)) + { + return false; + } + // Check the image constraints + if ((image->getComponents() != 3) && (image->getComponents() != 4)) + { + image->setLastError("Image files with less than 3 or more than 4 components are not supported."); + return false; + } + + raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + mRawImagep = raw_image; } - // Check the image constraints - if ((image->getComponents() != 3) && (image->getComponents() != 4)) + catch (...) { - image->setLastError("Image files with less than 3 or more than 4 components are not supported."); + LOG_UNHANDLED_EXCEPTION(""); return false; } - raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - mRawImagep = raw_image; - return true; } diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 002dc4fa1a..e64f468cbe 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -261,7 +261,8 @@ void LLFloaterIMNearbyChat::loadHistory() void LLFloaterIMNearbyChat::removeScreenChat() { - LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( + LLNotificationsUI::NEARBY_CHAT_CHANNEL_UUID); if(chat_channel) { chat_channel->removeToastsFromChannel(); diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 9337a9b51b..77ceea19af 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -459,7 +459,7 @@ LLFloaterIMNearbyChatHandler::LLFloaterIMNearbyChatHandler() { // Getting a Channel for our notifications LLFloaterIMNearbyChatScreenChannel::Params p; - p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID")); + p.id = NEARBY_CHAT_CHANNEL_UUID; LLFloaterIMNearbyChatScreenChannel* channel = new LLFloaterIMNearbyChatScreenChannel(p); LLFloaterIMNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel; diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index ffa23df8d8..a2d1cb7036 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -653,7 +653,7 @@ void LLFloaterIMSession::setDocked(bool docked, bool pop_on_undock) // update notification channel state LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID)); if(!isChatMultiTab()) { @@ -689,7 +689,7 @@ void LLFloaterIMSession::setVisible(BOOL visible) { LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID)); LLFloaterIMSessionTab::setVisible(visible); @@ -867,7 +867,7 @@ void LLFloaterIMSession::updateMessages() // remove embedded notification from channel LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID)); if (getVisible()) { // toast will be automatically closed since it is not storable toast diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index f7cc6c495e..dc64d09f9f 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -267,9 +267,13 @@ BOOL LLFloaterIMSessionTab::postBuild() mEmojiRecentEmptyText->setToolTip(mEmojiRecentEmptyText->getText()); mEmojiRecentEmptyText->setVisible(false); + mEmojiRecentContainer = getChild<LLPanel>("emoji_recent_container"); + mEmojiRecentContainer->setVisible(false); + mEmojiRecentIconsCtrl = getChild<LLPanelEmojiComplete>("emoji_recent_icons_ctrl"); + mEmojiRecentIconsCtrl->setFocusReceivedCallback([this](LLFocusableElement*) { onEmojiRecentPanelFocusReceived(); }); + mEmojiRecentIconsCtrl->setFocusLostCallback([this](LLFocusableElement*) { onEmojiRecentPanelFocusLost(); }); mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); }); - mEmojiRecentIconsCtrl->setVisible(false); mEmojiPickerShowBtn = getChild<LLButton>("emoji_picker_show_btn"); mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); }); @@ -475,7 +479,7 @@ void LLFloaterIMSessionTab::initEmojiRecentPanel() if (recentlyUsed.empty()) { mEmojiRecentEmptyText->setVisible(TRUE); - mEmojiRecentIconsCtrl->setVisible(FALSE); + mEmojiRecentContainer->setVisible(FALSE); } else { @@ -486,10 +490,22 @@ void LLFloaterIMSessionTab::initEmojiRecentPanel() } mEmojiRecentIconsCtrl->setEmojis(emojis); mEmojiRecentEmptyText->setVisible(FALSE); - mEmojiRecentIconsCtrl->setVisible(TRUE); + mEmojiRecentContainer->setVisible(TRUE); } } +// static +void LLFloaterIMSessionTab::onEmojiRecentPanelFocusReceived() +{ + mEmojiRecentContainer->addBorder(); +} + +// static +void LLFloaterIMSessionTab::onEmojiRecentPanelFocusLost() +{ + mEmojiRecentContainer->removeBorder(); +} + void LLFloaterIMSessionTab::onRecentEmojiPicked(const LLSD& value) { LLSD::String str = value.asString(); diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index d378b2ea6b..00b43f499b 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -173,6 +173,7 @@ protected: LLLayoutPanel* mInputButtonPanel; LLLayoutPanel* mEmojiRecentPanel; LLTextBox* mEmojiRecentEmptyText; + LLPanel* mEmojiRecentContainer; LLPanelEmojiComplete* mEmojiRecentIconsCtrl; LLParticipantList* getParticipantList(); conversations_widgets_map mConversationsWidgets; @@ -218,6 +219,8 @@ private: void onEmojiRecentPanelToggleBtnClicked(); void onEmojiPickerShowBtnClicked(); void initEmojiRecentPanel(); + void onEmojiRecentPanelFocusReceived(); + void onEmojiRecentPanelFocusLost(); void onRecentEmojiPicked(const LLSD& value); bool checkIfTornOff(); diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index ca0a506802..128cf56be0 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -250,6 +250,13 @@ void LLFloaterJoystick::refresh() initFromSettings(); } +bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD& value, void* userdata) +{ + LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata; + floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); + return false; // keep searching +} + void LLFloaterJoystick::addDevice(std::string &name, LLSD& value) { mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); @@ -264,19 +271,21 @@ void LLFloaterJoystick::refreshListOfDevices() mHasDeviceList = false; + void* win_calback = nullptr; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_list_devices_callback; + win_calback = di8_list_devices_callback; +#elif LL_DARWIN + U32 device_type = 0; #else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + // On MAC it is possible to specify product + // and manufacturer in NDOF_Device for + // ndof_init_first to pick specific device U32 device_type = 0; - void* callback = NULL; #endif - if (gViewerWindow->getWindow()->getInputDevices(device_type, callback, this)) + if (gViewerWindow->getWindow()->getInputDevices(device_type, addDeviceCallback, win_calback, this)) { mHasDeviceList = true; } @@ -419,9 +428,10 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) } } - std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString(); - gSavedSettings.setString("JoystickDeviceUUID", device_id); - LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL; + LLViewerJoystick::getInstance()->saveDeviceIdToSettings(); + + std::string device_string = LLViewerJoystick::getInstance()->getDeviceUUIDString(); + LL_DEBUGS("Joystick") << "Selected " << device_string << " as joystick." << LL_ENDL; self->refreshListOfDevices(); } diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 2ed4018670..e304431153 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -46,6 +46,7 @@ public: virtual void draw(); static void setSNDefaults(); + static bool addDeviceCallback(std::string &name, LLSD& value, void* userdata); void addDevice(std::string &name, LLSD& value); protected: diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp index 94d650ddbe..28ef403cf7 100644 --- a/indra/newview/llfloaternotificationstabbed.cpp +++ b/indra/newview/llfloaternotificationstabbed.cpp @@ -154,7 +154,7 @@ LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::stri void LLFloaterNotificationsTabbed::initChannel() { LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( - LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID); mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel); if(NULL == mChannel) { diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 858a64973b..d731f1c592 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -368,9 +368,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) { - if ( APT_PROPERTIES == type ) + if ( APT_PROPERTIES_LEGACY == type ) { - const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData ); + const LLAvatarLegacyData* pAvatarData = static_cast<const LLAvatarLegacyData*>( pData ); if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH); @@ -510,9 +510,7 @@ BOOL LLFloaterPreference::postBuild() void LLFloaterPreference::updateDeleteTranscriptsButton() { - std::vector<std::string> list_of_transcriptions_file_names; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names); - getChild<LLButton>("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0); + getChild<LLButton>("delete_transcripts")->setEnabled(LLLogChat::transcriptFilesExist()); } void LLFloaterPreference::onDoNotDisturbResponseChanged() @@ -677,7 +675,6 @@ void LLFloaterPreference::cancel() void LLFloaterPreference::onOpen(const LLSD& key) { - // this variable and if that follows it are used to properly handle do not disturb mode response message static bool initialized = FALSE; // if user is logged in and we haven't initialized do not disturb mode response yet, do it @@ -704,7 +701,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) (gAgent.isMature() || gAgent.isGodlike()); LLComboBox* maturity_combo = getChild<LLComboBox>("maturity_desired_combobox"); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest( gAgent.getID() ); if (can_choose_maturity) { // if they're not adult or a god, they shouldn't see the adult selection, so delete it diff --git a/indra/newview/llfloaterprofiletexture.cpp b/indra/newview/llfloaterprofiletexture.cpp index 8b36072034..7108047a6b 100644 --- a/indra/newview/llfloaterprofiletexture.cpp +++ b/indra/newview/llfloaterprofiletexture.cpp @@ -33,39 +33,173 @@ #include "llpreview.h" // fors constants #include "lltrans.h" #include "llviewercontrol.h" -#include "lltextureview.h" #include "llviewertexture.h" #include "llviewertexturelist.h" + ////////////////////////////////////////////////////////////////////////// + // LLProfileImageCtrl + ////////////////////////////////////////////////////////////////////////// -LLFloaterProfileTexture::LLFloaterProfileTexture(LLView* owner) - : LLFloater(LLSD()) - , mUpdateDimensions(TRUE) - , mLastHeight(0) - , mLastWidth(0) +static LLDefaultChildRegistry::Register<LLProfileImageCtrl> r("profile_image"); + +LLProfileImageCtrl::LLProfileImageCtrl(const LLProfileImageCtrl::Params& p) + : LLIconCtrl(p) , mImage(NULL) , mImageOldBoostLevel(LLGLTexture::BOOST_NONE) - , mOwnerHandle(owner->getHandle()) + , mWasNoDelete(false) + , mImageLoadedSignal(NULL) { - buildFromFile("floater_profile_texture.xml"); } -LLFloaterProfileTexture::~LLFloaterProfileTexture() +LLProfileImageCtrl::~LLProfileImageCtrl() +{ + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList); + releaseTexture(); + + delete mImageLoadedSignal; +} + +void LLProfileImageCtrl::releaseTexture() { if (mImage.notNull()) { mImage->setBoostLevel(mImageOldBoostLevel); + if (!mWasNoDelete) + { + // In most cases setBoostLevel marks images as NO_DELETE + mImage->forceActive(); + } mImage = NULL; } +} + +void LLProfileImageCtrl::setValue(const LLSD& value) +{ + LLUUID id = value.asUUID(); + setImageAssetId(id); + if (id.isNull()) + { + LLIconCtrl::setValue("Generic_Person_Large", LLGLTexture::BOOST_UI); + } + else + { + // called second to not change priority before it gets saved to mImageOldBoostLevel + LLIconCtrl::setValue(value, LLGLTexture::BOOST_PREVIEW); + } +} + +void LLProfileImageCtrl::draw() +{ + if (mImage.notNull()) + { + // Pump the texture priority + mImage->addTextureStats(MAX_IMAGE_AREA); + mImage->setKnownDrawSize(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT, LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + } + LLIconCtrl::draw(); +} - LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList); +boost::signals2::connection LLProfileImageCtrl::setImageLoadedCallback(const image_loaded_signal_t::slot_type& cb) +{ + if (!mImageLoadedSignal) mImageLoadedSignal = new image_loaded_signal_t(); + + return mImageLoadedSignal->connect(cb); +} + +void LLProfileImageCtrl::setImageAssetId(const LLUUID& asset_id) +{ + if (mImageID == asset_id) + { + return; + } + + releaseTexture(); + + mImageID = asset_id; + if (mImageID.notNull()) + { + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mWasNoDelete = mImage->getTextureState() == LLGLTexture::NO_DELETE; + mImageOldBoostLevel = mImage->getBoostLevel(); + mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + mImage->setKnownDrawSize(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT, LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + mImage->forceToSaveRawImage(0); + + if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0) + { + mImage->setLoadedCallback(LLProfileImageCtrl::onImageLoaded, + 0, TRUE, FALSE, new LLHandle<LLUICtrl>(getHandle()), &mCallbackTextureList); + } + else + { + onImageLoaded(true, mImage); + } + } +} + +void LLProfileImageCtrl::onImageLoaded(bool success, LLViewerFetchedTexture* img) +{ + if (mImageLoadedSignal) + { + (*mImageLoadedSignal)(success, img); + } +} + +// static +void LLProfileImageCtrl::onImageLoaded(BOOL success, + LLViewerFetchedTexture* src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if (!userdata) return; + + LLHandle<LLUICtrl>* handle = (LLHandle<LLUICtrl>*)userdata; + + if (!handle->isDead()) + { + LLProfileImageCtrl* caller = static_cast<LLProfileImageCtrl*>(handle->get()); + if (caller && caller->mImageLoadedSignal) + { + (*caller->mImageLoadedSignal)(success, src_vi); + } + } + + if (final || !success) + { + delete handle; + } +} + + +////////////////////////////////////////////////////////////////////////// +// LLFloaterProfileTexture + ////////////////////////////////////////////////////////////////////////// + +LLFloaterProfileTexture::LLFloaterProfileTexture(LLView* owner) + : LLFloater(LLSD()) + , mLastHeight(0) + , mLastWidth(0) + , mOwnerHandle(owner->getHandle()) + , mContextConeOpacity(0.f) + , mCloseButton(NULL) + , mProfileIcon(NULL) +{ + buildFromFile("floater_profile_texture.xml"); +} + +LLFloaterProfileTexture::~LLFloaterProfileTexture() +{ } // virtual BOOL LLFloaterProfileTexture::postBuild() { - mProfileIcon = getChild<LLIconCtrl>("profile_pic"); + mProfileIcon = getChild<LLProfileImageCtrl>("profile_pic"); + mProfileIcon->setImageLoadedCallback([this](BOOL success, LLViewerFetchedTexture* imagep) {onImageLoaded(success, imagep); }); mCloseButton = getChild<LLButton>("close_btn"); mCloseButton->setCommitCallback([this](LLUICtrl*, void*) { closeFloater(); }, nullptr); @@ -83,55 +217,41 @@ void LLFloaterProfileTexture::reshape(S32 width, S32 height, BOOL called_from_pa // When we receive it, reshape the window accordingly. void LLFloaterProfileTexture::updateDimensions() { - if (mImage.isNull()) + LLPointer<LLViewerFetchedTexture> image = mProfileIcon->getImage(); + if (image.isNull()) { return; } - if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0) + if ((image->getFullWidth() * image->getFullHeight()) == 0) { return; } - S32 img_width = mImage->getFullWidth(); - S32 img_height = mImage->getFullHeight(); - - if (mAssetStatus != LLPreview::PREVIEW_ASSET_LOADED - || mLastWidth != img_width - || mLastHeight != img_height) - { - mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED; - // Asset has been fully loaded - mUpdateDimensions = TRUE; - } + S32 img_width = image->getFullWidth(); + S32 img_height = image->getFullHeight(); mLastHeight = img_height; mLastWidth = img_width; - // Reshape the floater only when required - if (mUpdateDimensions) - { - mUpdateDimensions = FALSE; - - LLRect old_floater_rect = getRect(); - LLRect old_image_rect = mProfileIcon->getRect(); - S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth; - S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight; + LLRect old_floater_rect = getRect(); + LLRect old_image_rect = mProfileIcon->getRect(); + S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth; + S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight; - const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256 + const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256 - S32 biggest_dim = llmax(width, height); - if (biggest_dim > MAX_DIMENTIONS) - { - F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim; - width *= scale_down; - height *= scale_down; - } + S32 biggest_dim = llmax(width, height); + if (biggest_dim > MAX_DIMENTIONS) + { + F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim; + width *= scale_down; + height *= scale_down; + } - //reshape floater - reshape(width, height); + //reshape floater + reshape(width, height); - gFloaterView->adjustToFitScreen(this, FALSE); - } + gFloaterView->adjustToFitScreen(this, FALSE); } void LLFloaterProfileTexture::draw() @@ -151,75 +271,18 @@ void LLFloaterProfileTexture::onOpen(const LLSD& key) void LLFloaterProfileTexture::resetAsset() { - mProfileIcon->setValue("Generic_Person_Large"); - mImageID = LLUUID::null; - if (mImage.notNull()) - { - mImage->setBoostLevel(mImageOldBoostLevel); - mImage = NULL; - } + mProfileIcon->setValue(LLUUID::null); } void LLFloaterProfileTexture::loadAsset(const LLUUID &image_id) { - if (mImageID != image_id) - { - if (mImage.notNull()) - { - mImage->setBoostLevel(mImageOldBoostLevel); - mImage = NULL; - } - } - else - { - return; - } - mProfileIcon->setValue(image_id); - mImageID = image_id; - mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - mImageOldBoostLevel = mImage->getBoostLevel(); - - if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0) - { - mImage->setLoadedCallback(LLFloaterProfileTexture::onTextureLoaded, - 0, TRUE, FALSE, new LLHandle<LLFloater>(getHandle()), &mCallbackTextureList); - - mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - mAssetStatus = LLPreview::PREVIEW_ASSET_LOADING; - } - else - { - mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED; - } - - mUpdateDimensions = TRUE; updateDimensions(); } -// static -void LLFloaterProfileTexture::onTextureLoaded( - BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata) +void LLFloaterProfileTexture::onImageLoaded(BOOL success, LLViewerFetchedTexture* imagep) { - LLHandle<LLFloater>* handle = (LLHandle<LLFloater>*)userdata; - - if (!handle->isDead()) - { - LLFloaterProfileTexture* floater = static_cast<LLFloaterProfileTexture*>(handle->get()); - if (floater && success) - { - floater->mUpdateDimensions = TRUE; - floater->updateDimensions(); - } - } - - if (final || !success) + if (success) { - delete handle; + updateDimensions(); } } diff --git a/indra/newview/llfloaterprofiletexture.h b/indra/newview/llfloaterprofiletexture.h index e0ec0b16ef..12efbab572 100644 --- a/indra/newview/llfloaterprofiletexture.h +++ b/indra/newview/llfloaterprofiletexture.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterprofiletexture.h * @brief LLFloaterProfileTexture class definition * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,11 +28,50 @@ #define LL_LLFLOATERPROFILETEXTURE_H #include "llfloater.h" +#include "lliconctrl.h" #include "llviewertexture.h" class LLButton; class LLImageRaw; -class LLIconCtrl; + +class LLProfileImageCtrl: public LLIconCtrl +{ +public: + struct Params: public LLInitParam::Block<Params, LLIconCtrl::Params> + { + }; + + LLProfileImageCtrl(const Params& p); + virtual ~LLProfileImageCtrl(); + + + virtual void setValue(const LLSD& value) override; + LLUUID getImageAssetId() { return mImageID; } + LLPointer<LLViewerFetchedTexture> getImage() {return mImage;} + void draw() override; + + typedef boost::signals2::signal<void(bool success, LLViewerFetchedTexture* imagep)> image_loaded_signal_t; + boost::signals2::connection setImageLoadedCallback(const image_loaded_signal_t::slot_type& cb); +private: + void onImageLoaded(bool success, LLViewerFetchedTexture* src_vi); + static void onImageLoaded(BOOL success, + LLViewerFetchedTexture* src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + void releaseTexture(); + + void setImageAssetId(const LLUUID& asset_id); +private: + LLPointer<LLViewerFetchedTexture> mImage; + LLUUID mImageID; + S32 mImageOldBoostLevel; + bool mWasNoDelete; + image_loaded_signal_t* mImageLoadedSignal; + LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList; +}; class LLFloaterProfileTexture : public LLFloater { @@ -46,36 +85,23 @@ public: void resetAsset(); void loadAsset(const LLUUID &image_id); - - static void onTextureLoaded( - BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata); + void onImageLoaded(BOOL success, LLViewerFetchedTexture* imagep); void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + + LLHandle<LLFloater> getHandle() const { return LLFloater::getHandle(); } protected: BOOL postBuild() override; private: void updateDimensions(); - LLUUID mImageID; - LLPointer<LLViewerFetchedTexture> mImage; - S32 mImageOldBoostLevel; - S32 mAssetStatus; F32 mContextConeOpacity; S32 mLastHeight; S32 mLastWidth; - BOOL mUpdateDimensions; LLHandle<LLView> mOwnerHandle; - LLIconCtrl* mProfileIcon; + LLProfileImageCtrl* mProfileIcon; LLButton* mCloseButton; - - LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList; }; #endif // LL_LLFLOATERPROFILETEXTURE_H diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 4eda962e8b..bd32807bb9 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -48,12 +48,6 @@ public: LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { } bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch")) - { - LLNotificationsUtil::add("NoSearch", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - const size_t parts = tokens.size(); // get the (optional) category for the search diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 65bd3d3717..f44c9ea953 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -283,9 +283,7 @@ void LLFloaterSellLandUI::refreshUI() getChild<LLUICtrl>("info_size")->setTextArg("[AREA]", llformat("%d", mParcelActualArea)); std::string price_str = getChild<LLUICtrl>("price")->getValue().asString(); - bool valid_price = false; - valid_price = (price_str != "") && LLTextValidate::validateNonNegativeS32(utf8str_to_wstring(price_str)); - + bool valid_price = !price_str.empty() && LLTextValidate::validateNonNegativeS32.validate(price_str); if (valid_price && mParcelActualArea > 0) { F32 per_meter_price = 0; @@ -299,7 +297,7 @@ void LLFloaterSellLandUI::refreshUI() { getChildView("price_per_m")->setVisible(FALSE); - if ("" == price_str) + if (price_str.empty()) { setBadge("step_price", BADGE_NOTE); } @@ -331,9 +329,7 @@ void LLFloaterSellLandUI::refreshUI() // Must select Sell To: Anybody, or User (with a specified username) std::string sell_to = getChild<LLUICtrl>("sell_to")->getValue().asString(); - bool valid_sell_to = "select" != sell_to && - ("user" != sell_to || mAuthorizedBuyer.notNull()); - + bool valid_sell_to = "select" != sell_to && ("user" != sell_to || mAuthorizedBuyer.notNull()); if (!valid_sell_to) { setBadge("step_sell_to", BADGE_NOTE); @@ -344,7 +340,6 @@ void LLFloaterSellLandUI::refreshUI() } bool valid_sell_objects = ("none" != getChild<LLUICtrl>("sell_objects")->getValue().asString()); - if (!valid_sell_objects) { setBadge("step_sell_objects", BADGE_NOTE); diff --git a/indra/newview/llfloatersimplesnapshot.cpp b/indra/newview/llfloatersimplesnapshot.cpp index 37f845b3d7..5d65bf2d0d 100644 --- a/indra/newview/llfloatersimplesnapshot.cpp +++ b/indra/newview/llfloatersimplesnapshot.cpp @@ -370,7 +370,7 @@ void LLFloaterSimpleSnapshot::onSend() else { LLSD notif_args; - notif_args["REASON"] = LLImage::getLastError().c_str(); + notif_args["REASON"] = LLImage::getLastThreadError().c_str(); LLNotificationsUtil::add("CannotUploadTexture", notif_args); } } @@ -389,7 +389,7 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, cons if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN, true)) { LLSD notif_args; - notif_args["REASON"] = LLImage::getLastError().c_str(); + notif_args["REASON"] = LLImage::getLastThreadError().c_str(); LLNotificationsUtil::add("CannotUploadTexture", notif_args); LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL; return; @@ -404,7 +404,7 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(LLPointer<LLImageRaw> raw_image, c if (!LLViewerTextureList::createUploadFile(raw_image, temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN)) { LLSD notif_args; - notif_args["REASON"] = LLImage::getLastError().c_str(); + notif_args["REASON"] = LLImage::getLastThreadError().c_str(); LLNotificationsUtil::add("CannotUploadTexture", notif_args); LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL; return; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index da1e6cca74..bb4ae7e8ab 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -146,12 +146,6 @@ public: const std::string& grid, LLMediaCtrl* web) { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) - { - LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - if (params.size() == 0) { // support the secondlife:///app/worldmap SLapp @@ -207,12 +201,6 @@ public: const std::string& grid, LLMediaCtrl* web) { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) - { - LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - //Make sure we have some parameters if (params.size() == 0) { diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 71c7606672..5671f6dd59 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -58,6 +58,9 @@ // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; +// Longest time, in seconds, to wait for a key release. +// This should be relatively long, but not too long. 10 minutes is enough +const F32 MAX_WAIT_KEY_SECS = 60.f * 10.f; // Lightweight constructor. // init() does the heavy lifting. @@ -528,12 +531,13 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id); } -void LLGestureMgr::playGesture(LLMultiGesture* gesture) +void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool fromKeyPress) { if (!gesture) return; // Reset gesture to first step gesture->mCurrentStep = 0; + gesture->mTriggeredByKey = fromKeyPress; // Add to list of playing gesture->mPlaying = TRUE; @@ -731,7 +735,8 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) if (!gesture) continue; if (gesture->mKey == key - && gesture->mMask == mask) + && gesture->mMask == mask + && gesture->mWaitingKeyRelease == FALSE) { matching.push_back(gesture); } @@ -744,13 +749,38 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) LLMultiGesture* gesture = matching[random]; - playGesture(gesture); + playGesture(gesture, TRUE); return TRUE; } return FALSE; } +BOOL LLGestureMgr::triggerGestureRelease(KEY key, MASK mask) +{ + std::vector <LLMultiGesture *> matching; + item_map_t::iterator it; + + // collect matching gestures + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + + // asset data might not have arrived yet + if (!gesture) continue; + + if (gesture->mKey == key + && gesture->mMask == mask) + { + gesture->mKeyReleased = TRUE; + } + } + + //If we found one, block. Otherwise tell them it's free to go. + return matching.size() > 0; +} + + S32 LLGestureMgr::getPlayingCount() const { return mPlaying.size(); @@ -899,6 +929,32 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) continue; } + // If we're waiting a fixed amount of time, check for timer + // expiration. + if (gesture->mWaitingKeyRelease) + { + // We're waiting for a certain amount of time to pass + if (gesture->mKeyReleased) + { + // wait is done, continue execution + gesture->mWaitingKeyRelease = FALSE; + gesture->mCurrentStep++; + } + else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_KEY_SECS) + { + LL_INFOS("GestureMgr") << "Waited too long for key release, continuing gesture." + << LL_ENDL; + gesture->mWaitingKeyRelease = FALSE; + gesture->mCurrentStep++; + } + else + { + // we're waiting, so execution is done for now + waiting = TRUE; + } + continue; + } + // If we're waiting on our animations to stop, poll for // completion. if (gesture->mWaitingAnimations) @@ -1015,7 +1071,17 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) case STEP_WAIT: { LLGestureStepWait* wait_step = (LLGestureStepWait*)step; - if (wait_step->mFlags & WAIT_FLAG_TIME) + if (gesture->mTriggeredByKey // Only wait here IF we were triggered by a key! + && gesture->mWaitingKeyRelease == FALSE // We can only do this once! Prevent gestures infinitely running + && wait_step->mFlags & WAIT_FLAG_KEY_RELEASE) + { + // Lets wait for the key release first so we don't hold up re-presses + gesture->mWaitingKeyRelease = TRUE; + gesture->mKeyReleased = FALSE; + // Use the wait timer as a deadlock breaker for key release waits. + gesture->mWaitTimer.reset(); + } + else if (wait_step->mFlags & WAIT_FLAG_TIME) { gesture->mWaitingTimer = TRUE; gesture->mWaitTimer.reset(); @@ -1023,8 +1089,7 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM) { gesture->mWaitingAnimations = TRUE; - // Use the wait timer as a deadlock breaker for animation - // waits. + // Use the wait timer as a deadlock breaker for animation waits. gesture->mWaitTimer.reset(); } else diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 73b898c406..b41f0ee106 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -102,7 +102,10 @@ public: const item_map_t& getActiveGestures() const { return mActive; } // Force a gesture to be played, for example, if it is being // previewed. - void playGesture(LLMultiGesture* gesture); + void playGesture(LLMultiGesture* gesture, bool fromKeyPress); + void playGesture(LLMultiGesture* gesture) { + playGesture(gesture, FALSE); + } void playGesture(const LLUUID& item_id); // Stop all requested or playing anims for this gesture @@ -118,10 +121,14 @@ public: { mCallbackMap[inv_item_id] = cb; } - // Trigger the first gesture that matches this key. + // Trigger a random gesture that matches this key. // Returns TRUE if it finds a gesture bound to that key. BOOL triggerGesture(KEY key, MASK mask); + // Trigger release wait on all gestures that matches this key. + // Returns TRUE if it finds a gesture bound to that key. + BOOL triggerGestureRelease(KEY key, MASK mask); + // Trigger all gestures referenced as substrings in this string BOOL triggerAndReviseString(const std::string &str, std::string *revised_string = NULL); diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 9e46d9c6ca..24ae90e3ae 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -89,12 +89,6 @@ public: return true; } - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableGroupInfo")) - { - LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - if (tokens.size() < 1) { return false; @@ -373,7 +367,16 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id) args["GROUP"] = gdatap->mName; LLSD payload; payload["group_id"] = group_id; - LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); + if (gdatap->mMembershipFee > 0) + { + args["COST"] = gdatap->mMembershipFee; + LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); + } + else + { + LLNotificationsUtil::add("GroupLeaveConfirmMemberNoFee", args, payload, onLeaveGroup); + } + } // static @@ -405,7 +408,7 @@ void LLGroupActions::inspect(const LLUUID& group_id) } // static -void LLGroupActions::show(const LLUUID& group_id) +void LLGroupActions::show(const LLUUID &group_id, bool expand_notices_tab) { if (group_id.isNull()) return; @@ -413,6 +416,10 @@ void LLGroupActions::show(const LLUUID& group_id) LLSD params; params["group_id"] = group_id; params["open_tab_name"] = "panel_group_info_sidetray"; + if (expand_notices_tab) + { + params["action"] = "show_notices"; + } LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); LLFloater *floater = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("people"); diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h index 5a447f682f..9195e38bca 100644 --- a/indra/newview/llgroupactions.h +++ b/indra/newview/llgroupactions.h @@ -57,7 +57,7 @@ public: /** * Show group information panel. */ - static void show(const LLUUID& group_id); + static void show(const LLUUID& group_id, bool expand_notices_tab = false); /** * Show group inspector floater. diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 12092a02c6..38b2f4adc8 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -303,6 +303,7 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL item->getChildView("info_btn")->setVisible( false); item->getChildView("profile_btn")->setVisible( false); + item->getChildView("notices_btn")->setVisible(false); item->setGroupIconVisible(mShowIcons); if (!mShowIcons) { @@ -403,6 +404,7 @@ mGroupIcon(NULL), mGroupNameBox(NULL), mInfoBtn(NULL), mProfileBtn(NULL), +mNoticesBtn(NULL), mVisibilityHideBtn(NULL), mVisibilityShowBtn(NULL), mGroupID(LLUUID::null), @@ -435,6 +437,9 @@ BOOL LLGroupListItem::postBuild() mProfileBtn = getChild<LLButton>("profile_btn"); mProfileBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onProfileBtnClick(); }); + mNoticesBtn = getChild<LLButton>("notices_btn"); + mNoticesBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onNoticesBtnClick(); }); + mVisibilityHideBtn = findChild<LLButton>("visibility_hide_btn"); if (mVisibilityHideBtn) { @@ -470,13 +475,17 @@ void LLGroupListItem::onMouseEnter(S32 x, S32 y, MASK mask) { mInfoBtn->setVisible(true); mProfileBtn->setVisible(true); - if (mForAgent && mVisibilityHideBtn) + if (mForAgent) { LLGroupData agent_gdatap; if (gAgent.getGroupData(mGroupID, agent_gdatap)) { - mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile); - mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile); + if (mVisibilityHideBtn) + { + mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile); + mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile); + } + mNoticesBtn->setVisible(true); } } } @@ -489,6 +498,7 @@ void LLGroupListItem::onMouseLeave(S32 x, S32 y, MASK mask) getChildView("hovered_icon")->setVisible( false); mInfoBtn->setVisible(false); mProfileBtn->setVisible(false); + mNoticesBtn->setVisible(false); if (mVisibilityHideBtn) { mVisibilityHideBtn->setVisible(false); @@ -583,6 +593,11 @@ void LLGroupListItem::onProfileBtnClick() LLGroupActions::show(mGroupID); } +void LLGroupListItem::onNoticesBtnClick() +{ + LLGroupActions::show(mGroupID, true); +} + void LLGroupListItem::onVisibilityBtnClick(bool new_visibility) { LLGroupData agent_gdatap; diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 69257a2d7c..0e2dcf5fb3 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -123,6 +123,7 @@ private: void setBold(bool bold); void onInfoBtnClick(); void onProfileBtnClick(); + void onNoticesBtnClick(); void onVisibilityBtnClick(bool new_visibility); LLTextBox* mGroupNameBox; @@ -130,6 +131,7 @@ private: LLGroupIconCtrl* mGroupIcon; LLButton* mInfoBtn; LLButton* mProfileBtn; + LLButton* mNoticesBtn; LLButton* mVisibilityHideBtn; LLButton* mVisibilityShowBtn; diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp index 3554412e18..bc2d9052f1 100644 --- a/indra/newview/llimhandler.cpp +++ b/indra/newview/llimhandler.cpp @@ -55,8 +55,7 @@ LLIMHandler::~LLIMHandler() void LLIMHandler::initChannel() { S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound); + mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0eb5a2c365..187dbdd3a2 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -581,6 +581,12 @@ void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, return; } + if (LLApp::isExiting() || gDisconnected) + { + LL_DEBUGS("ChatHistory") << "Ignoring chat history response, shutting down" << LL_ENDL; + return; + } + // Add history to IM session LLSD history = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; @@ -3917,6 +3923,12 @@ public: const LLSD& context, const LLSD& input) const { + if (LLApp::isExiting() || gDisconnected) + { + LL_DEBUGS("ChatHistory") << "Ignoring ChatterBox session, Shutting down" << LL_ENDL; + return; + } + LLSD body; LLUUID temp_session_id; LLUUID session_id; diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp index 92272c7f45..101b9bdc2d 100644 --- a/indra/newview/llinspect.cpp +++ b/indra/newview/llinspect.cpp @@ -45,8 +45,8 @@ LLInspect::~LLInspect() // virtual void LLInspect::draw() { - static LLCachedControl<F32> FADE_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorFadeTime", 1.f); - static LLCachedControl<F32> STAY_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorShowTime", 1.f); + const F32 FADE_TIME = 0.5f; + const F32 STAY_TIME = 3.f; if (mOpenTimer.getStarted()) { LLFloater::draw(); @@ -59,7 +59,7 @@ void LLInspect::draw() } else if (mCloseTimer.getStarted()) { - F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME(), 1.f, 0.f); + F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f); LLViewDrawContext context(alpha); LLFloater::draw(); if (mCloseTimer.getElapsedTimeF32() > FADE_TIME) diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 61213c1a5d..2bd4796bd0 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -261,12 +261,15 @@ void LLInspectAvatar::requestUpdate() void LLInspectAvatar::processAvatarData(LLAvatarData* data) { LLStringUtil::format_map_t args; - { - std::string birth_date = LLTrans::getString("AvatarBirthDateFormat"); - LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) data->born_on.secondsSinceEpoch())); - args["[BORN_ON]"] = birth_date; - } - args["[AGE]"] = LLDateUtil::ageFromDate(data->born_on, LLDate::now()); + + std::string birth_date = LLTrans::getString(data->hide_age ? + "AvatarBirthDateFormatShort" : + "AvatarBirthDateFormatFull"); + LLStringUtil::format(birth_date, LLSD().with("datetime", (S32)data->born_on.secondsSinceEpoch())); + args["[BORN_ON]"] = birth_date; + args["[AGE]"] = data->hide_age ? + LLStringUtilBase<char>::null : + LLDateUtil::ageFromDate(data->born_on, LLDate::now()); args["[SL_PROFILE]"] = data->about_text; args["[RW_PROFILE"] = data->fl_about_text; args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(data); diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp index 0104714a16..2e05893489 100644 --- a/indra/newview/llinspecttoast.cpp +++ b/indra/newview/llinspecttoast.cpp @@ -61,7 +61,7 @@ LLInspectToast::LLInspectToast(const LLSD& notification_id) : LLInspect(LLSD()), mPanel(NULL) { LLScreenChannelBase* channel = LLChannelManager::getInstance()->findChannelByID( - LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID); mScreenChannel = dynamic_cast<LLScreenChannel*>(channel); if(NULL == mScreenChannel) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5e66fadd4c..fbb4ac8801 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -90,6 +90,7 @@ void copy_slurl_to_clipboard_callback_inv(const std::string& slurl); const F32 SOUND_GAIN = 1.0f; +const F32 FOLDER_LOADING_MESSAGE_DELAY = 0.5f; // Seconds to wait before showing the LOADING... text in folder views using namespace LLOldEvents; @@ -308,9 +309,9 @@ void LLInvFVBridge::setCreationDate(time_t creation_date_utc) // Can be destroyed (or moved to trash) -BOOL LLInvFVBridge::isItemRemovable() const +BOOL LLInvFVBridge::isItemRemovable(bool check_worn) const { - return get_is_item_removable(getInventoryModel(), mUUID); + return get_is_item_removable(getInventoryModel(), mUUID, check_worn); } // Can be moved to another folder @@ -772,9 +773,6 @@ void hide_context_entries(LLMenuGL& menu, bool found = false; - std::string myinput; - std::vector<std::string> mylist{ "a", "b", "c" }; - menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name); if (itor2 != entries_to_show.end()) { @@ -874,7 +872,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } items.push_back(std::string("Cut")); - if (!isItemMovable() || !isItemRemovable()) + if (!isItemMovable() || !canMenuCut()) { disabled_items.push_back(std::string("Cut")); } @@ -923,7 +921,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if(!single_folder_root) { items.push_back(std::string("Cut")); - if (!isItemMovable() || !isItemRemovable()) + if (!isItemMovable() || !canMenuCut()) { disabled_items.push_back(std::string("Cut")); } @@ -1068,7 +1066,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, items.push_back(std::string("Delete")); - if (!isItemRemovable() || isPanelActive("Favorite Items")) + if (isPanelActive("Favorite Items") || !canMenuDelete()) { disabled_items.push_back(std::string("Delete")); } @@ -1224,6 +1222,16 @@ void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_v } } +bool LLInvFVBridge::canMenuDelete() +{ + return isItemRemovable(false); +} + +bool LLInvFVBridge::canMenuCut() +{ + return isItemRemovable(true); +} + // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { @@ -2415,45 +2423,16 @@ void LLFolderBridge::update() } } - -// Iterate through a folder's children to determine if -// all the children are removable. -class LLIsItemRemovable : public LLFolderViewFunctor -{ -public: - LLIsItemRemovable() : mPassed(TRUE) {} - virtual void doFolder(LLFolderViewFolder* folder) - { - mPassed &= folder->getViewModelItem()->isItemRemovable(); - } - virtual void doItem(LLFolderViewItem* item) - { - mPassed &= item->getViewModelItem()->isItemRemovable(); - } - BOOL mPassed; -}; - // Can be destroyed (or moved to trash) -BOOL LLFolderBridge::isItemRemovable() const +BOOL LLFolderBridge::isItemRemovable(bool check_worn) const { - if (!get_is_category_removable(getInventoryModel(), mUUID)) + if (!get_is_category_and_children_removable(getInventoryModel(), mUUID, check_worn)) { return FALSE; } - LLInventoryPanel* panel = mInventoryPanel.get(); - LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getItemByID(mUUID) : NULL); - if (folderp) - { - LLIsItemRemovable folder_test; - folderp->applyFunctorToChildren(folder_test); - if (!folder_test.mPassed) - { - return FALSE; - } - } - - if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) + if (isMarketplaceListingsFolder() + && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) { return FALSE; } @@ -4386,6 +4365,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items disabled_items.push_back("New Settings"); } } + else + { + items.push_back(std::string("New Listing Folder")); + } if (menu_items_added) { items.push_back(std::string("Create Separator")); @@ -4527,7 +4510,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& return; } - if (!isItemRemovable()) + if (!canMenuDelete()) { disabled_items.push_back(std::string("Delete")); } @@ -4898,6 +4881,192 @@ void LLFolderBridge::modifyOutfit(BOOL append) } } +//static +void LLFolderBridge::onCanDeleteIdle(void* user_data) +{ + LLFolderBridge* self = (LLFolderBridge*)user_data; + + // we really need proper onidle mechanics that returns available time + const F32 EXPIRY_SECONDS = 0.008f; + LLTimer timer; + timer.setTimerExpirySec(EXPIRY_SECONDS); + + LLInventoryModel* model = self->getInventoryModel(); + if (model) + { + switch (self->mCanDeleteFolderState) + { + case CDS_INIT_FOLDER_CHECK: + // Can still be expensive, split it further? + model->collectDescendents( + self->mUUID, + self->mFoldersToCheck, + self->mItemsToCheck, + LLInventoryModel::EXCLUDE_TRASH); + self->mCanDeleteFolderState = CDS_PROCESSING_ITEMS; + break; + + case CDS_PROCESSING_ITEMS: + while (!timer.hasExpired() && !self->mItemsToCheck.empty()) + { + LLViewerInventoryItem* item = self->mItemsToCheck.back().get(); + if (item) + { + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item)) + { + if (get_is_item_worn(item)) + { + // At the moment we disable 'cut' if category has worn items (do we need to?) + // but allow 'delete' to happen since it will prompt user to detach + self->mCanCut = false; + } + } + + if (!item->getIsLinkType() && get_is_item_worn(item)) + { + self->mCanCut = false; + } + } + self->mItemsToCheck.pop_back(); + } + self->mCanDeleteFolderState = CDS_PROCESSING_FOLDERS; + break; + case CDS_PROCESSING_FOLDERS: + { + const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr; + + while (!timer.hasExpired() && !self->mFoldersToCheck.empty()) + { + LLViewerInventoryCategory* cat = self->mFoldersToCheck.back().get(); + if (cat) + { + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + self->mCanCut = false; + self->mCanDelete = false; + self->completeDeleteProcessing(); + break; + } + + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + if (cat == outfit_linked_category) + { + self->mCanCut = false; + self->mCanDelete = false; + self->completeDeleteProcessing(); + break; + } + } + } + self->mFoldersToCheck.pop_back(); + } + } + self->mCanDeleteFolderState = CDS_DONE; + break; + case CDS_DONE: + self->completeDeleteProcessing(); + break; + } + } +} + +bool LLFolderBridge::canMenuDelete() +{ + LLInventoryModel* model = getInventoryModel(); + if (!model) return false; + LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); + if (!category) + { + return false; + } + + S32 version = category->getVersion(); + if (mLastCheckedVersion == version) + { + return mCanDelete; + } + + initCanDeleteProcessing(model, version); + return false; +} + +bool LLFolderBridge::canMenuCut() +{ + LLInventoryModel* model = getInventoryModel(); + if (!model) return false; + LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); + if (!category) + { + return false; + } + + S32 version = category->getVersion(); + if (mLastCheckedVersion == version) + { + return mCanCut; + } + + initCanDeleteProcessing(model, version); + return false; +} + +void LLFolderBridge::initCanDeleteProcessing(LLInventoryModel* model, S32 version) +{ + if (mCanDeleteFolderState == CDS_DONE + || mInProgressVersion != version) + { + if (get_is_category_removable(model, mUUID)) + { + // init recursive check of content + mInProgressVersion = version; + mCanCut = true; + mCanDelete = true; + mCanDeleteFolderState = CDS_INIT_FOLDER_CHECK; + mFoldersToCheck.clear(); + mItemsToCheck.clear(); + gIdleCallbacks.addFunction(onCanDeleteIdle, this); + } + else + { + // no check needed + mCanDelete = false; + mCanCut = false; + mLastCheckedVersion = version; + mCanDeleteFolderState = CDS_DONE; + mFoldersToCheck.clear(); + mItemsToCheck.clear(); + } + } +} + +void LLFolderBridge::completeDeleteProcessing() +{ + LLInventoryModel* model = getInventoryModel(); + LLViewerInventoryCategory* category = model ? (LLViewerInventoryCategory*)model->getCategory(mUUID) : nullptr; + if (model && category && category->getVersion() == mInProgressVersion) + { + mLastCheckedVersion = mInProgressVersion; + mCanDeleteFolderState = CDS_DONE; + gIdleCallbacks.deleteFunction(onCanDeleteIdle, this); + } + else + { + mCanDelete = false; + mCanCut = false; + mLastCheckedVersion = LLViewerInventoryCategory::VERSION_UNKNOWN; + mCanDeleteFolderState = CDS_DONE; + } + + if (mRoot) + { + mRoot->updateMenu(); + } +} + // +=================================================+ // | LLMarketplaceFolderBridge | @@ -4941,9 +5110,7 @@ LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(BOOL is_open) c std::string LLMarketplaceFolderBridge::getLabelSuffix() const { - static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); - - if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) + if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY) { return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); } @@ -5061,6 +5228,27 @@ void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1, cb2->fire(id); } +LLFolderBridge::LLFolderBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) + : LLInvFVBridge(inventory, root, uuid) + , mCallingCards(FALSE) + , mWearables(FALSE) + , mIsLoading(false) + , mShowDescendantsCount(false) + , mCanDeleteFolderState(CDS_DONE) + , mLastCheckedVersion(S32_MIN) + , mInProgressVersion(S32_MIN) + , mCanDelete(false) + , mCanCut(false) +{ +} + +LLFolderBridge::~LLFolderBridge() +{ + gIdleCallbacks.deleteFunction(onCanDeleteIdle, this); +} + void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb) { // use callback to rearrange favorite landmarks after adding @@ -6654,6 +6842,26 @@ LLInventoryObject* LLObjectBridge::getObject() const return object; } +LLViewerInventoryItem* LLObjectBridge::getItem() const +{ + LLInventoryModel* model = getInventoryModel(); + if (model) + { + return model->getItem(mUUID); + } + return NULL; +} + +LLViewerInventoryCategory* LLObjectBridge::getCategory() const +{ + LLInventoryModel* model = getInventoryModel(); + if (model) + { + return model->getCategory(mUUID); + } + return NULL; +} + // virtual void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index e1e0bbb5bd..b0139e225e 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -114,7 +114,7 @@ public: virtual BOOL isItemRenameable() const { return TRUE; } virtual BOOL isMultiPreviewAllowed() { return TRUE; } //virtual BOOL renameItem(const std::string& new_name) {} - virtual BOOL isItemRemovable() const; + virtual BOOL isItemRemovable(bool check_worn = true) const; virtual BOOL isItemMovable() const; virtual BOOL isItemInTrash() const; virtual bool isItemInOutfits() const; @@ -162,6 +162,9 @@ protected: virtual void addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_vec_t& disabled_items); + virtual bool canMenuDelete(); + virtual bool canMenuCut(); + protected: LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid); @@ -272,13 +275,9 @@ class LLFolderBridge : public LLInvFVBridge public: LLFolderBridge(LLInventoryPanel* inventory, LLFolderView* root, - const LLUUID& uuid) - : LLInvFVBridge(inventory, root, uuid), - mCallingCards(FALSE), - mWearables(FALSE), - mIsLoading(false), - mShowDescendantsCount(false) - {} + const LLUUID& uuid); + + ~LLFolderBridge(); BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL); BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL); @@ -321,7 +320,7 @@ public: void* cargo_data, std::string& tooltip_msg); - virtual BOOL isItemRemovable() const; + virtual BOOL isItemRemovable(bool check_worn = true) const; virtual BOOL isItemMovable() const ; virtual BOOL isUpToDate() const; virtual bool isItemCopyable(bool can_copy_as_link = true) const; @@ -392,6 +391,31 @@ protected: LLTimer mTimeSinceRequestStart; std::string mMessage; LLRootHandle<LLFolderBridge> mHandle; + +private: + // checking if folder is cutable or deletable is expensive, + // cache values and split check over frames + static void onCanDeleteIdle(void* user_data); + void initCanDeleteProcessing(LLInventoryModel* model, S32 version); + void completeDeleteProcessing(); + bool canMenuDelete(); + bool canMenuCut(); + + enum ECanDeleteState + { + CDS_INIT_FOLDER_CHECK, + CDS_PROCESSING_ITEMS, + CDS_PROCESSING_FOLDERS, + CDS_DONE, + }; + + ECanDeleteState mCanDeleteFolderState; + LLInventoryModel::cat_array_t mFoldersToCheck; + LLInventoryModel::item_array_t mItemsToCheck; + S32 mLastCheckedVersion; + S32 mInProgressVersion; + bool mCanDelete; + bool mCanCut; }; class LLTextureBridge : public LLItemBridge @@ -524,6 +548,8 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL renameItem(const std::string& new_name); LLInventoryObject* getObject() const; + LLViewerInventoryItem* getItem() const; + LLViewerInventoryCategory* getCategory() const; protected: static LLUUID sContextMenuItemID; // Only valid while the context menu is open. U32 mAttachPt; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 168099f1e7..c8aa235506 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -596,9 +596,8 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id) return FALSE; } -BOOL get_is_item_worn(const LLUUID& id) +BOOL get_is_item_worn(const LLUUID& id, const LLViewerInventoryItem* item) { - const LLViewerInventoryItem* item = gInventory.getItem(id); if (!item) return FALSE; @@ -636,6 +635,21 @@ BOOL get_is_item_worn(const LLUUID& id) return FALSE; } +BOOL get_is_item_worn(const LLUUID& id) +{ + const LLViewerInventoryItem* item = gInventory.getItem(id); + return get_is_item_worn(id, item); +} + +BOOL get_is_item_worn(const LLViewerInventoryItem* item) +{ + if (!item) + { + return FALSE; + } + return get_is_item_worn(item->getUUID(), item); +} + BOOL get_can_item_be_worn(const LLUUID& id) { const LLViewerInventoryItem* item = gInventory.getItem(id); @@ -699,39 +713,39 @@ BOOL get_can_item_be_worn(const LLUUID& id) return FALSE; } -BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) +bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn) { if (!model) { - return FALSE; + return false; } // Can't delete an item that's in the library. if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) { - return FALSE; + return false; } // Disable delete from COF folder; have users explicitly choose "detach/take off", // unless the item is not worn but in the COF (i.e. is bugged). - if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id)) + const LLViewerInventoryItem* obj = model->getItem(id); + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(obj)) { - if (get_is_item_worn(id)) + if (get_is_item_worn(id, obj)) { - return FALSE; + return false; } } - const LLInventoryObject *obj = model->getItem(id); if (obj && obj->getIsLinkType()) { - return TRUE; + return true; } - if (get_is_item_worn(id)) + if (check_worn && get_is_item_worn(id, obj)) { - return FALSE; + return false; } - return TRUE; + return true; } bool get_is_item_editable(const LLUUID& inv_item_id) @@ -822,6 +836,74 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) return TRUE; } +bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn) +{ + if (!get_is_category_removable(model, folder_id)) + { + return false; + } + + const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id)) + { + return false; + } + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + model->collectDescendents( + folder_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + + if (check_worn) + { + for (LLInventoryModel::item_array_t::value_type& item : item_array) + { + // Disable delete/cut from COF folder; have users explicitly choose "detach/take off", + // unless the item is not worn but in the COF (i.e. is bugged). + if (item) + { + if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item)) + { + if (get_is_item_worn(item)) + { + return false; + } + } + + if (!item->getIsLinkType() && get_is_item_worn(item)) + { + return false; + } + } + } + } + + const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr; + for (LLInventoryModel::cat_array_t::value_type& cat : cat_array) + { + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return false; + } + + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + if (cat == outfit_linked_category) + { + return false; + } + } + } + + return true; +} + BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) { if (!model) @@ -2800,7 +2882,7 @@ bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventory { if (item) { - return !get_is_item_removable(&gInventory, item->getUUID()); + return !get_is_item_removable(&gInventory, item->getUUID(), true); } if (cat) { @@ -3082,6 +3164,8 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root { const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); bool marketplacelistings_item = false; + bool has_worn = false; + bool needs_replacement = false; LLAllDescendentsPassedFilter f; for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) { @@ -3090,14 +3174,69 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root folder->applyFunctorRecursively(f); } LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem()); - if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id)) + LLUUID obj_id = viewModel->getUUID(); + if (viewModel && gInventory.isObjectDescendentOf(obj_id, marketplacelistings_id)) { marketplacelistings_item = true; break; } + + LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id); + if (cat) + { + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(obj_id, categories, items, FALSE); + + for (LLInventoryModel::item_array_t::value_type& item : items) + { + if (get_is_item_worn(item)) + { + has_worn = true; + LLWearableType::EType type = item->getWearableType(); + if (type == LLWearableType::WT_SHAPE + || type == LLWearableType::WT_SKIN + || type == LLWearableType::WT_HAIR + || type == LLWearableType::WT_EYES) + { + needs_replacement = true; + break; + } + } + } + if (needs_replacement) + { + break; + } + } + LLViewerInventoryItem* item = gInventory.getItem(obj_id); + if (item && get_is_item_worn(item)) + { + has_worn = true; + LLWearableType::EType type = item->getWearableType(); + if (type == LLWearableType::WT_SHAPE + || type == LLWearableType::WT_SKIN + || type == LLWearableType::WT_HAIR + || type == LLWearableType::WT_EYES) + { + needs_replacement = true; + break; + } + } } // Fall through to the generic confirmation if the user choose to ignore the specialized one - if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) + if (needs_replacement) + { + LLNotificationsUtil::add("CantDeleteRequiredClothing"); + } + else if (has_worn) + { + LLSD payload; + payload["has_worn"] = true; + LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } + else if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) { LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); } @@ -3420,12 +3559,82 @@ void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, con S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0 && !root.isDead() && !root.get()->isDead()) { + bool has_worn = notification["payload"]["has_worn"].asBoolean(); LLFolderView* folder_root = root.get(); //Need to remove item from DND before item is removed from root folder view //because once removed from root folder view the item is no longer a selected item removeItemFromDND(folder_root); + + // removeSelectedItems will change selection, collect worn items beforehand + uuid_vec_t worn; + uuid_vec_t item_deletion_list; + uuid_vec_t cat_deletion_list; + if (has_worn) + { + //Get selected items + LLFolderView::selected_items_t selectedItems = folder_root->getSelectedItems(); + + //If user is in DND and deletes item, make sure the notification is not displayed by removing the notification + //from DND history and .xml file. Once this is done, upon exit of DND mode the item deleted will not show a notification. + for (LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + LLFolderViewModelItemInventory* viewModel = dynamic_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem()); + + LLUUID obj_id = viewModel->getUUID(); + LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id); + bool cat_has_worn = false; + if (cat) + { + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(obj_id, categories, items, FALSE); + + for (LLInventoryModel::item_array_t::value_type& item : items) + { + if (get_is_item_worn(item)) + { + worn.push_back(item->getUUID()); + cat_has_worn = true; + } + } + if (cat_has_worn) + { + cat_deletion_list.push_back(obj_id); + } + } + LLViewerInventoryItem* item = gInventory.getItem(obj_id); + if (item && get_is_item_worn(item)) + { + worn.push_back(obj_id); + item_deletion_list.push_back(obj_id); + } + } + } + + // removeSelectedItems will check if items are worn before deletion, + // don't 'unwear' yet to prevent race conditions from unwearing + // and removing simultaneously folder_root->removeSelectedItems(); + // unwear then delete the rest + if (!worn.empty()) + { + // should fire once after every item gets detached + LLAppearanceMgr::instance().removeItemsFromAvatar(worn, + [item_deletion_list, cat_deletion_list]() + { + for (const LLUUID& id : item_deletion_list) + { + remove_inventory_item(id, NULL); + } + for (const LLUUID& id : cat_deletion_list) + { + remove_inventory_category(id, NULL); + } + }); + } + // Update the marketplace listings that have been affected by the operation updateMarketplaceFolders(); } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 0c4b64586d..5cb996ad54 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -47,17 +47,19 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id); // Is this item or its baseitem is worn, attached, etc... BOOL get_is_item_worn(const LLUUID& id); +BOOL get_is_item_worn(const LLViewerInventoryItem* item); // Could this item be worn (correct type + not already being worn) BOOL get_can_item_be_worn(const LLUUID& id); -BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id); +bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn); // Performs the appropiate edit action (if one exists) for this item bool get_is_item_editable(const LLUUID& inv_item_id); void handle_item_edit(const LLUUID& inv_item_id); BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id); +bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn); BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 16cdc14b15..329c0d751a 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -187,7 +187,7 @@ LLInventoryGallery::~LLInventoryGallery() mHiddenItems.pop_back(); panelp->die(); } - + if (gInventory.containsObserver(mCategoriesObserver)) { @@ -200,7 +200,7 @@ LLInventoryGallery::~LLInventoryGallery() gInventory.removeObserver(mThumbnailsObserver); } delete mThumbnailsObserver; - + LLGestureMgr::instance().removeObserver(mGestureObserver); delete mGestureObserver; } @@ -263,7 +263,7 @@ void LLInventoryGallery::updateRootFolder() updateRemovedItem(mHiddenItems[i]->getUUID()); } mItemBuildQuery.clear(); - + if (gInventory.containsObserver(mCategoriesObserver)) { gInventory.removeObserver(mCategoriesObserver); @@ -284,7 +284,7 @@ void LLInventoryGallery::updateRootFolder() mRootChangedSignal(); gInventory.addObserver(mCategoriesObserver); - + // Start observing changes in selected category. mCategoriesObserver->addCategory(mFolderID, boost::bind(&LLInventoryGallery::refreshList, this, mFolderID)); @@ -294,7 +294,7 @@ void LLInventoryGallery::updateRootFolder() // the observer will refresh the list as soon as the new items // arrive. category->fetch(); - + //refreshList(cat_id); LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; @@ -308,7 +308,7 @@ void LLInventoryGallery::updateRootFolder() { mItemBuildQuery.insert((*iter)->getUUID()); } - + for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); iter != item_array->end(); iter++) @@ -448,7 +448,7 @@ void LLInventoryGallery::reArrangeRows(S32 row_diff) buf_items.push_back(*it); } mHiddenItems.clear(); - + mItemsInRow+= row_diff; updateGalleryWidth(); @@ -458,7 +458,7 @@ void LLInventoryGallery::reArrangeRows(S32 row_diff) { return compareGalleryItem(item1, item2, sort_by_date, sort_folders_by_name); }); - + for (std::vector<LLInventoryGalleryItem*>::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it) { (*it)->setHidden(false); @@ -735,7 +735,7 @@ void LLInventoryGallery::setFilterSubString(const std::string& string) { mFilterSubString = string; mFilter->setFilterSubString(string); - + //reArrangeRows(); } @@ -763,7 +763,7 @@ bool LLInventoryGallery::checkAgainstFilters(LLInventoryGalleryItem* item, const { return false; } - + bool hidden = false; if(mFilter->getFilterCreatorType() == LLInventoryFilter::FILTERCREATOR_SELF) @@ -806,7 +806,7 @@ bool LLInventoryGallery::checkAgainstFilters(LLInventoryGalleryItem* item, const desc = item->getItemName() + item->getItemNameSuffix(); break; } - + LLStringUtil::toUpper(desc); std::string cur_filter = filter_substring; @@ -1435,7 +1435,7 @@ void LLInventoryGallery::onFocusReceived() LLInventoryGalleryItem* focus_item = NULL; for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + if (mItemMap[id] && !mItemMap[id]->isHidden()) { focus_item = mItemMap[id]; focus_item->setSelected(true); @@ -1668,6 +1668,45 @@ void LLInventoryGallery::cut() mFilterSubString.clear(); } + + +bool is_category_removable(const LLUUID& folder_id, bool check_worn) +{ + if (!get_is_category_removable(&gInventory, folder_id)) + { + return false; + } + + // check children + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(folder_id, cat_array, item_array); + + for (LLInventoryModel::item_array_t::value_type& item : *item_array) + { + if (!get_is_item_removable(&gInventory, item->getUUID(), check_worn)) + { + return false; + } + } + + for (LLInventoryModel::cat_array_t::value_type& cat : *cat_array) + { + if (!is_category_removable(cat->getUUID(), check_worn)) + { + return false; + } + } + + const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id)) + { + return false; + } + + return true; +} + BOOL LLInventoryGallery::canCut() const { if (!getVisible() || !getEnabled() || mSelectedItemIDs.empty()) @@ -1680,12 +1719,12 @@ BOOL LLInventoryGallery::canCut() const LLViewerInventoryCategory* cat = gInventory.getCategory(id); if (cat) { - if (!get_is_category_removable(&gInventory, id)) + if (!get_is_category_and_children_removable(&gInventory, id, true)) { return FALSE; } } - else if (!get_is_item_removable(&gInventory, id)) + else if (!get_is_item_removable(&gInventory, id, true)) { return FALSE; } @@ -1864,42 +1903,149 @@ void LLInventoryGallery::onDelete(const LLSD& notification, const LLSD& response S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0) { - for (const LLUUID& id : selected_ids) + bool has_worn = notification["payload"]["has_worn"].asBoolean(); + uuid_vec_t worn; + uuid_vec_t item_deletion_list; + uuid_vec_t cat_deletion_list; + for (const LLUUID& obj_id : selected_ids) { - LLInventoryObject* obj = gInventory.getObject(id); - if (!obj) - { - return; - } - if (obj->getType() == LLAssetType::AT_CATEGORY) + LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id); + if (cat) { - if (get_is_category_removable(&gInventory, id)) + bool cat_has_worn = false; + if (has_worn) + { + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(obj_id, categories, items, FALSE); + + for (LLInventoryModel::item_array_t::value_type& item : items) + { + if (get_is_item_worn(item)) + { + worn.push_back(item->getUUID()); + cat_has_worn = true; + } + } + } + if (cat_has_worn) + { + cat_deletion_list.push_back(obj_id); + } + else { - gInventory.removeCategory(id); + gInventory.removeCategory(obj_id); } } - else + LLViewerInventoryItem* item = gInventory.getItem(obj_id); + if (item) { - if (get_is_item_removable(&gInventory, id)) + if (has_worn && get_is_item_worn(item)) { - gInventory.removeItem(id); + worn.push_back(item->getUUID()); + item_deletion_list.push_back(item->getUUID()); + } + else + { + gInventory.removeItem(obj_id); } } } + + if (!worn.empty()) + { + // should fire once after every item gets detached + LLAppearanceMgr::instance().removeItemsFromAvatar(worn, + [item_deletion_list, cat_deletion_list]() + { + for (const LLUUID& id : item_deletion_list) + { + remove_inventory_item(id, NULL); + } + for (const LLUUID& id : cat_deletion_list) + { + remove_inventory_category(id, NULL); + } + }); + } } } void LLInventoryGallery::deleteSelection() { - if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session + bool has_worn = false; + bool needs_replacement = false; + for (const LLUUID& id : mSelectedItemIDs) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (cat) + { + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(id, categories, items, FALSE); + + for (LLInventoryModel::item_array_t::value_type& item : items) + { + if (get_is_item_worn(item)) + { + has_worn = true; + LLWearableType::EType type = item->getWearableType(); + if (type == LLWearableType::WT_SHAPE + || type == LLWearableType::WT_SKIN + || type == LLWearableType::WT_HAIR + || type == LLWearableType::WT_EYES) + { + needs_replacement = true; + break; + } + } + } + if (needs_replacement) + { + break; + } + } + + LLViewerInventoryItem* item = gInventory.getItem(id); + if (item && get_is_item_worn(item)) + { + has_worn = true; + LLWearableType::EType type = item->getWearableType(); + if (type == LLWearableType::WT_SHAPE + || type == LLWearableType::WT_SKIN + || type == LLWearableType::WT_HAIR + || type == LLWearableType::WT_EYES) + { + needs_replacement = true; + break; + } + } + } + + if (needs_replacement) + { + LLNotificationsUtil::add("CantDeleteRequiredClothing"); + } + else if (has_worn) { - LLNotifications::instance().setIgnored("DeleteItems", false); - LLInventoryAction::sDeleteConfirmationDisplayed = true; + LLSD payload; + payload["has_worn"] = true; + LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs)); } + else + { + if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session + { + LLNotifications::instance().setIgnored("DeleteItems", false); + LLInventoryAction::sDeleteConfirmationDisplayed = true; + } - LLSD args; - args["QUESTION"] = LLTrans::getString("DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs)); + LLSD args; + args["QUESTION"] = LLTrans::getString("DeleteItem"); + LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs)); + } } bool LLInventoryGallery::canDeleteSelection() @@ -1925,7 +2071,7 @@ bool LLInventoryGallery::canDeleteSelection() return false; } } - else if (!get_is_item_removable(&gInventory, id)) + else if (!get_is_item_removable(&gInventory, id, true)) { return false; } @@ -2209,7 +2355,7 @@ void LLInventoryGallery::onCOFChanged() LLCommonUtils::computeDifference(vnew, mCOFLinkedItems, vadded, vremoved); mCOFLinkedItems = vnew; - + for (uuid_vec_t::const_iterator iter = vadded.begin(); iter != vadded.end(); ++iter) @@ -2240,7 +2386,7 @@ void LLInventoryGallery::onGesturesChanged() LLCommonUtils::computeDifference(vnew, mActiveGestures, vadded, vremoved); mActiveGestures = vnew; - + for (uuid_vec_t::const_iterator iter = vadded.begin(); iter != vadded.end(); ++iter) @@ -2418,7 +2564,7 @@ void LLInventoryGallery::startDrag() ids.push_back(selected_id); } - const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id); + const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id); if (cat) { if (gInventory.isObjectDescendentOf(selected_id, gInventory.getLibraryRootFolderID())) @@ -2496,7 +2642,7 @@ bool LLInventoryGallery::checkAgainstFilterType(const LLUUID& object_id) break; } } - + if (filterTypes & LLInventoryFilter::FILTERTYPE_DATE) { const U16 HOURS_TO_SECONDS = 3600; @@ -2939,7 +3085,7 @@ void LLThumbnailsObserver::changed(U32 mask) { const LLUUID& obj_id = (*iter).first; LLItemData& data = (*iter).second; - + LLInventoryObject* obj = gInventory.getObject(obj_id); if (!obj) { @@ -3150,7 +3296,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, // //-------------------------------------------------------------------------------- - + //-------------------------------------------------------------------------------- // Determine if item can be moved & dropped // Note: if user_confirm is false, we already went through those accept logic test and can skip them @@ -3177,7 +3323,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, { //disable dropping in or out of marketplace for now return FALSE; - + /*const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, folder_id); LLViewerInventoryCategory * dest_folder = cat; accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());*/ @@ -3189,7 +3335,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, LLViewerInventoryCategory * dest_folder = cat; accept = dest_folder->acceptItem(inv_item); } - + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); if (accept && drop) @@ -3263,7 +3409,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, gInventory.changeItemParent((LLViewerInventoryItem*)inv_item, folder_id, move_is_into_trash); } - + if (move_is_from_marketplacelistings) { // If we move from an active (listed) listing, checks that it's still valid, if not, unlist @@ -3483,7 +3629,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); //const LLUUID from_folder_uuid = inv_cat->getParentUUID(); - + const BOOL move_is_into_current_outfit = (dest_id == current_outfit_id); const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(dest_id, marketplacelistings_id); const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id); @@ -3592,7 +3738,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, is_movable = FALSE; // tooltip? } - + LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; if (is_movable) @@ -3658,7 +3804,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, } } } - + if (is_movable && move_is_into_marketplacelistings) { const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, dest_id); @@ -3731,7 +3877,7 @@ BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, { //disable dropping in or out of marketplace for now return FALSE; - + // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder) /*if (from_folder_uuid == marketplacelistings_id) { diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 3cb6503a1c..4b47346473 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -62,7 +62,7 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery))); enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2)); - + LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml"); updateMenuItemsVisibility(menu); @@ -321,7 +321,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS if (!new_name.empty()) { LLUUID id = notification["payload"]["id"].asUUID(); - + LLViewerInventoryCategory* cat = gInventory.getCategory(id); if(cat && (cat->getName() != new_name)) { @@ -330,7 +330,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS update_inventory_category(cat->getUUID(),updates, NULL); return; } - + LLViewerInventoryItem* item = gInventory.getItem(id); if(item && (item->getName() != new_name)) { @@ -379,12 +379,12 @@ bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata) bool is_inbox_folder(LLUUID item_id) { const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - + if (inbox_id.isNull()) { return false; } - + return gInventory.isObjectDescendentOf(item_id, inbox_id); } @@ -495,7 +495,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } } items.push_back(std::string("Purge Item")); - if (is_folder && !get_is_category_removable(&gInventory, selected_id)) + if (is_folder && !get_is_category_and_children_removable(&gInventory, selected_id, true)) { disabled_items.push_back(std::string("Purge Item")); } @@ -542,11 +542,16 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } items.push_back(std::string("Cut")); items.push_back(std::string("Delete")); - if(!get_is_category_removable(&gInventory, selected_id)) + + if(!get_is_category_and_children_removable(&gInventory, selected_id, false)) { disabled_items.push_back(std::string("Delete")); disabled_items.push_back(std::string("Cut")); } + else if (!get_is_category_and_children_removable(&gInventory, selected_id, true)) + { + disabled_items.push_back(std::string("Cut")); + } if(!is_inbox) { @@ -577,11 +582,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men { items.push_back(std::string("Delete")); } - if(!get_is_item_removable(&gInventory, selected_id)) + if (!get_is_item_removable(&gInventory, selected_id, false)) { disabled_items.push_back(std::string("Delete")); disabled_items.push_back(std::string("Cut")); } + else if(!get_is_item_removable(&gInventory, selected_id, true)) + { + disabled_items.push_back(std::string("Cut")); + } if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) { @@ -616,7 +625,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("Open")); disabled_items.push_back(std::string("Open Original")); } - + if(LLAssetType::AT_GESTURE == obj->getType()) { items.push_back(std::string("Gesture Separator")); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 0787266adb..65b8bc9e2c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1744,12 +1744,10 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, << " from " << make_inventory_info(item->getParentUUID()) << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(), -1); + accountForUpdate(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1, false); + accountForUpdate(new_folder); LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); new_item->setParent(new_parent_id); @@ -1779,12 +1777,10 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, << " from " << make_inventory_info(cat->getParentUUID()) << " to " << make_inventory_info(new_parent_id) << LL_ENDL; - LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - accountForUpdate(update); + accountForUpdate(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1, false); + accountForUpdate(new_folder); LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); new_cat->setParent(new_parent_id); @@ -2542,7 +2538,10 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const { descendents_actual += update.mDescendentDelta; cat->setDescendentCount(descendents_actual); - cat->setVersion(++version); + if (update.mChangeVersion) + { + cat->setVersion(++version); + } LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " << version << " with " << descendents_actual << " descendents." << LL_ENDL; @@ -2570,7 +2569,7 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) + const LLInventoryModel::update_list_t& update) const { update_list_t::const_iterator it = update.begin(); update_list_t::const_iterator end = update.end(); @@ -2581,7 +2580,7 @@ void LLInventoryModel::accountForUpdate( } void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) + const LLInventoryModel::update_map_t& update) const { LLCategoryUpdate up; update_map_t::const_iterator it = update.begin(); @@ -2706,6 +2705,17 @@ bool LLInventoryModel::loadSkeleton( gzip_filename.append(".gz"); LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); bool remove_inventory_file = false; + if (LLAppViewer::instance()->isSecondInstance()) + { + // Safeguard viewer against trying to unpack file twice + // ex: user logs into two accounts simultaneously, so two + // viewers are trying to unpack library into same file + // + // Would be better to do it in gunzip_file, but it doesn't + // have access to llfilesystem + inventory_filename = gDirUtilp->getTempFilename(); + remove_inventory_file = true; + } if(fp) { fclose(fp); @@ -2914,7 +2924,7 @@ bool LLInventoryModel::loadSkeleton( // clean up the gunzipped file. LLFile::remove(inventory_filename); } - if(is_cache_obsolete) + if(is_cache_obsolete && !LLAppViewer::instance()->isSecondInstance()) { // If out of date, remove the gzipped file too. LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 3b943dd121..e179f4a740 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -511,12 +511,14 @@ public: // Represents the number of items added or removed from a category. struct LLCategoryUpdate { - LLCategoryUpdate() : mDescendentDelta(0) {} - LLCategoryUpdate(const LLUUID& category_id, S32 delta) : + LLCategoryUpdate() : mDescendentDelta(0), mChangeVersion(true) {} + LLCategoryUpdate(const LLUUID& category_id, S32 delta, bool change_version = true) : mCategoryID(category_id), - mDescendentDelta(delta) {} + mDescendentDelta(delta), + mChangeVersion(change_version) {} LLUUID mCategoryID; S32 mDescendentDelta; + bool mChangeVersion; }; typedef std::vector<LLCategoryUpdate> update_list_t; @@ -534,8 +536,8 @@ public: // Call when there are category updates. Call them *before* the // actual update so the method can do descendent accounting correctly. void accountForUpdate(const LLCategoryUpdate& update) const; - void accountForUpdate(const update_list_t& updates); - void accountForUpdate(const update_map_t& updates); + void accountForUpdate(const update_list_t& updates) const; + void accountForUpdate(const update_map_t& updates) const; // Return (yes/no/maybe) child status of category children. EHasChildren categoryHasChildren(const LLUUID& cat_id) const; diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index ed48d78c2b..aa3eb3993a 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -230,10 +230,9 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) // Can't access old mTextEntry fields as they are protected, so lets build new params // That is C&P from LLComboBox::createLineEditor function - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; LLLineEditor::Params params = p.combo_editor; params.rect(text_entry_rect); @@ -708,7 +707,7 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) value["item_type"] = LANDMARK; value["AssetUUID"] = landmark_items[i]->getAssetUUID(); - add(landmark_items[i]->getName(), value); + addLocationHistoryEntry(landmark_items[i]->getName(), value); } //Let's add teleport history items @@ -733,7 +732,7 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); //TODO*: add Surl to teleportitem or parse region name from title value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString(); - add(result->getTitle(), value); + addLocationHistoryEntry(result->getTitle(), value); } result = std::find_if(result + 1, th_items.end(), boost::bind( &LLLocationInputCtrl::findTeleportItemsByTitle, this, @@ -986,6 +985,17 @@ void LLLocationInputCtrl::positionMaturityButton() mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad); } +void LLLocationInputCtrl::addLocationHistoryEntry(const std::string& title, const LLSD& value) +{ + // SL-20286 : Duplication of autocomplete results occurs when entering some search queries in the navigation bar + // Exclude visual duplicates (items with the same titles) in the dropdown list + LLScrollListItem* item = mList->getItemByLabel(title); + if (!item) + { + add(title, value); + } +} + void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter) { LLLocationHistory::location_list_t filtered_items; @@ -1010,7 +1020,7 @@ void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter) //location history can contain only typed locations value["item_type"] = TYPED_REGION_SLURL; value["global_pos"] = it->mGlobalPos.getValue(); - add(it->getLocation(), value); + addLocationHistoryEntry(it->getLocation(), value); } } diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index 7695ac4726..5ab42044cc 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -145,6 +145,7 @@ private: void refreshMaturityButton(); void positionMaturityButton(); + void addLocationHistoryEntry(const std::string& title, const LLSD& value); void rebuildLocationHistory(const std::string& filter = LLStringUtil::null); bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter); void setText(const LLStringExplicit& text); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 55ce0314d7..4b650aeebe 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -650,6 +650,27 @@ std::string LLLogChat::oldLogFileName(std::string filename) return scanResult; } +bool LLLogChat::transcriptFilesExist() +{ + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; + // get Users log directory + std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + dirname += gDirUtilp->getDirDelimiter(); + + LLDirIterator iter(dirname, pattern); + std::string filename; + while (iter.next(filename)) + { + std::string fullname = gDirUtilp->add(dirname, filename); + if (isTranscriptFileFound(fullname)) + { + return true; + } + } + return false; +} // static void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string>& list_of_transcriptions) { diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index e16cb21e8e..dbbd8ae1ba 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -103,6 +103,7 @@ public: const std::string& from, const LLUUID& from_id, const std::string& line); + static bool transcriptFilesExist(); static void findTranscriptFiles(std::string pattern, std::vector<std::string>& list_of_transcriptions); static void getListOfTranscriptFiles(std::vector<std::string>& list); static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 897eb07b5c..736971276e 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -451,13 +451,13 @@ void LLModelPreview::rebuildUploadData() // That's ok, but might not what they wanted. Use default_physics_shape if found. std::ostringstream out; out << "No physics model specified for " << instance.mLabel; - if (mDefaultPhysicsShapeP) + if (mDefaultPhysicsShapeP.notNull()) { out << " - using: " << DEFAULT_PHYSICS_MESH_NAME; lod_model = mDefaultPhysicsShapeP; } LL_WARNS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, !mDefaultPhysicsShapeP); // Flash log tab if no default. + LLFloaterModelPreview::addStringToLog(out, mDefaultPhysicsShapeP.isNull()); // Flash log tab if no default. } if (lod_model) @@ -1088,8 +1088,9 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) if (loaded_lod == LLModel::LOD_PHYSICS) { // Explicitly loading physics. See if there is a default mesh. LLMatrix4 ignored_transform; // Each mesh that uses this will supply their own. - mDefaultPhysicsShapeP = nullptr; - FindModel(mScene[loaded_lod], DEFAULT_PHYSICS_MESH_NAME + getLodSuffix(loaded_lod), mDefaultPhysicsShapeP, ignored_transform); + LLModel* out_model = nullptr; + FindModel(mScene[loaded_lod], DEFAULT_PHYSICS_MESH_NAME + getLodSuffix(loaded_lod), out_model, ignored_transform); + mDefaultPhysicsShapeP = out_model; mWarnOfUnmatchedPhyicsMeshes = true; } BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 064623ac6a..4fc72788a9 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -240,7 +240,7 @@ private: /// It is set only when the user chooses a physics shape file that contains a mesh with a name that matches DEFAULT_PHYSICS_MESH_NAME. /// It is reset when such a name is not found, and when resetting the modelpreview. /// Not read unless mWarnOfUnmatchedPhyicsMeshes is true. - LLModel* mDefaultPhysicsShapeP{}; + LLPointer<LLModel> mDefaultPhysicsShapeP; typedef enum { diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 67dbd57745..dd496c3bf9 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -352,10 +352,9 @@ void LLNavigationBar::draw() { if (isBackgroundVisible()) { - static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0); static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, drop_shadow_floater ); + color_drop_shadow, DROP_SHADOW_FLOATER); } LLPanel::draw(); diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index 792a7fd745..3c4ca536e3 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -46,7 +46,7 @@ LLAlertHandler::LLAlertHandler(const std::string& name, const std::string& notif mIsModal(is_modal) { LLScreenChannelBase::Params p; - p.id = LLUUID(gSavedSettings.getString("AlertChannelUUID")); + p.id = ALERT_CHANNEL_UUID; p.display_toasts_always = true; p.toast_align = NA_CENTRE; p.channel_align = CA_CENTRE; diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp index db640bdcab..0aa8b4362f 100644 --- a/indra/newview/llnotificationgrouphandler.cpp +++ b/indra/newview/llnotificationgrouphandler.cpp @@ -57,8 +57,7 @@ LLGroupHandler::~LLGroupHandler() void LLGroupHandler::initChannel() { S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound); + mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 2da8f1fa1c..fd2fa90b8c 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -63,8 +63,7 @@ LLOfferHandler::~LLOfferHandler() void LLOfferHandler::initChannel() { S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound); + mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index bda6402413..842c24db8a 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -62,8 +62,7 @@ LLScriptHandler::~LLScriptHandler() void LLScriptHandler::initChannel() { S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound); + mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 9443b6cb93..c7fa96edca 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -61,8 +61,7 @@ LLTipHandler::~LLTipHandler() void LLTipHandler::initChannel() { S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); - S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); - mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound); + mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound); } //-------------------------------------------------------------------------- diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index f4cd9b2647..0870211a8e 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -792,7 +792,7 @@ void LLOutfitListBase::onOpen(const LLSD& info) // Start observing changes in "My Outfits" category. mCategoriesObserver->addCategory(outfits, - boost::bind(&LLOutfitListBase::refreshList, this, outfits)); + boost::bind(&LLOutfitListBase::observerCallback, this, outfits)); //const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); // Start observing changes in Current Outfit category. @@ -812,6 +812,13 @@ void LLOutfitListBase::onOpen(const LLSD& info) } } +void LLOutfitListBase::observerCallback(const LLUUID& category_id) +{ + const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); + mChangedItems.insert(changed_items.begin(), changed_items.end()); + refreshList(category_id); +} + void LLOutfitListBase::refreshList(const LLUUID& category_id) { bool wasNull = mRefreshListState.CategoryUUID.isNull(); @@ -907,24 +914,22 @@ void LLOutfitListBase::onIdleRefreshList() // Get changed items from inventory model and update outfit tabs // which might have been renamed. - const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); - for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); - items_iter != changed_items.end(); - ++items_iter) + while (!mChangedItems.empty()) { + std::set<LLUUID>::const_iterator items_iter = mChangedItems.begin(); LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); - if (!cat) + mChangedItems.erase(items_iter); + + // Links aren't supposed to be allowed here, check only cats + if (cat) { - LLInventoryObject* obj = gInventory.getObject(*items_iter); - if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) - { - break; - } - cat = (LLViewerInventoryCategory*)obj; + std::string name = cat->getName(); + updateChangedCategoryName(cat, name); } - std::string name = cat->getName(); - updateChangedCategoryName(cat, name); + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } sortOutfits(); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 7067a30b12..11512b6731 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -110,6 +110,7 @@ public: virtual bool getHasExpandableFolders() = 0; protected: + void observerCallback(const LLUUID& category_id); virtual LLOutfitListGearMenuBase* createGearMenu() = 0; virtual void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) = 0; virtual void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) = 0; @@ -128,6 +129,7 @@ protected: uuid_vec_t::const_iterator AddedIterator; uuid_vec_t::const_iterator RemovedIterator; } mRefreshListState; + std::set<LLUUID> mChangedItems; bool mIsInitialized; LLInventoryCategoriesObserver* mCategoriesObserver; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index ff33efe4aa..3f2dc5a415 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -127,6 +127,54 @@ void LLPanelProfileTab::setApplyProgress(bool started) } } +static void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data, std::function<void(bool)> callback) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + std::string finalUrl = cap_url + "/" + agent_id.asString(); + + LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("AvatarProperties") << "Failed to put agent information " << data << " for id " << agent_id << LL_ENDL; + } + else + { + LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Data: " << data << " Result: " << httpResults << LL_ENDL; + } + + if (callback) + { + callback(status); + } +} + +bool LLPanelProfileTab::saveAgentUserInfoCoro(std::string name, LLSD value, std::function<void(bool)> callback) const +{ + std::string cap_url = gAgent.getRegionCapability("AgentProfile"); + if (cap_url.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + return false; + } + + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with(name, value), callback)); + + return true; +} + LLPanelProfilePropertiesProcessorTab::LLPanelProfilePropertiesProcessorTab() : LLPanelProfileTab() { @@ -152,3 +200,13 @@ void LLPanelProfilePropertiesProcessorTab::setAvatarId(const LLUUID & avatar_id) LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); } } + +void LLPanelProfilePropertiesProcessorTab::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); + } +} diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index f182660c8e..ec620b39e1 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -92,17 +92,17 @@ public: /** * Returns avatar ID. */ - virtual const LLUUID& getAvatarId() { return mAvatarId; } + virtual const LLUUID& getAvatarId() const { return mAvatarId; } /** * Sends update data request to server. */ - virtual void updateData() {}; + virtual void updateData(){}; /** * Clears panel data if viewing avatar info for first time and sends update data request. */ - virtual void onOpen(const LLSD& key); + virtual void onOpen(const LLSD& key) override; /** * Clears all data received from server. @@ -133,6 +133,8 @@ protected: const bool getSelfProfile() const { return mSelfProfile; } + bool saveAgentUserInfoCoro(std::string name, LLSD value, std::function<void(bool)> callback = nullptr) const; + public: void setIsLoading() { mLoadingState = PROFILE_LOADING; } void resetLoading() { mLoadingState = PROFILE_INIT; } @@ -158,12 +160,14 @@ public: LLPanelProfilePropertiesProcessorTab(); ~LLPanelProfilePropertiesProcessorTab(); - /*virtual*/ void setAvatarId(const LLUUID& avatar_id); + void setAvatarId(const LLUUID& avatar_id) override; + + void updateData() override; /** * Processes data received from server via LLAvatarPropertiesObserver. */ - virtual void processProperties(void* data, EAvatarProcessorType type) = 0; + virtual void processProperties(void* data, EAvatarProcessorType type) override = 0; }; #endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 393f809953..11d1239459 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -104,6 +104,11 @@ LLPanelClassifiedInfo::LLPanelClassifiedInfo() LLPanelClassifiedInfo::~LLPanelClassifiedInfo() { sAllPanels.remove(this); + + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } } BOOL LLPanelClassifiedInfo::postBuild() diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index de35aea35a..6b7680d19d 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -134,6 +134,15 @@ void LLPanelGroup::onOpen(const LLSD& key) if(panel_notices) panel_notices->refreshNotices(); } + if (str_action == "show_notices") + { + setGroupID(group_id); + + LLAccordionCtrl *tab_ctrl = getChild<LLAccordionCtrl>("groups_accordion"); + tab_ctrl->collapseAllTabs(); + getChild<LLAccordionCtrlTab>("group_notices_tab")->setDisplayChildren(true); + tab_ctrl->arrange(); + } } @@ -264,8 +273,15 @@ void LLPanelGroup::onBtnGroupChatClicked(void* user_data) void LLPanelGroup::onBtnJoin() { - LL_DEBUGS() << "joining group: " << mID << LL_ENDL; - LLGroupActions::join(mID); + if (LLGroupActions::isInGroup(mID)) + { + LLGroupActions::leave(mID); + } + else + { + LL_DEBUGS() << "joining group: " << mID << LL_ENDL; + LLGroupActions::join(mID); + } } void LLPanelGroup::changed(LLGroupChange gc) @@ -303,12 +319,17 @@ void LLPanelGroup::update(LLGroupChange gc) LLGroupData agent_gdatap; bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery(); - bool join_btn_visible = !is_member && gdatap->mOpenEnrollment; + bool join_btn_visible = is_member || gdatap->mOpenEnrollment; mButtonJoin->setVisible(join_btn_visible); mJoinText->setVisible(join_btn_visible); - if(join_btn_visible) + if (is_member) + { + mJoinText->setValue(getString("group_member")); + mButtonJoin->setLabel(getString("leave_txt")); + } + else if(join_btn_visible) { LLStringUtil::format_map_t string_args; std::string fee_buff; @@ -323,6 +344,7 @@ void LLPanelGroup::update(LLGroupChange gc) fee_buff = getString("group_join_free", string_args); } mJoinText->setValue(fee_buff); + mButtonJoin->setLabel(getString("join_txt")); } } } diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 0ef43715a3..3b7e4075c6 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -250,6 +250,7 @@ BOOL LLPanelGroupNotices::postBuild() mNoticesList = getChild<LLScrollListCtrl>("notice_list",recurse); mNoticesList->setCommitOnSelectionChange(TRUE); mNoticesList->setCommitCallback(onSelectNotice, this); + mNoticesList->sortByColumn("date", false); mBtnNewMessage = getChild<LLButton>("create_new_notice",recurse); mBtnNewMessage->setClickedCallback(onClickNewMessage, this); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index e06333205f..9267604098 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -244,7 +244,7 @@ BOOL LLPanelObject::postBuild() mCtrlSculptTexture = getChild<LLTextureCtrl>("sculpt texture control"); if (mCtrlSculptTexture) { - mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE)); + mCtrlSculptTexture->setDefaultImageAssetID(SCULPT_DEFAULT_TEXTURE); mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 )); mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 )); mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 )); @@ -2024,7 +2024,7 @@ void LLPanelObject::onCancelSculpt(const LLSD& data) if(mSculptTextureRevert == LLUUID::null) { - mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE); + mSculptTextureRevert = SCULPT_DEFAULT_TEXTURE; } mTextureCtrl->setImageAssetID(mSculptTextureRevert); @@ -2267,7 +2267,7 @@ void LLPanelObject::onCopyParams() } else { - mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); + mClipboardParams["sculpt"]["id"] = SCULPT_DEFAULT_TEXTURE; } mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index cda5689d73..141a1515d5 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -130,7 +130,7 @@ public: virtual BOOL isItemRenameable() const; virtual BOOL renameItem(const std::string& new_name); virtual BOOL isItemMovable() const; - virtual BOOL isItemRemovable() const; + virtual BOOL isItemRemovable(bool check_worn = true) const; virtual BOOL removeItem(); virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch); virtual void move(LLFolderViewModelItem* parent_listener); @@ -336,7 +336,7 @@ BOOL LLTaskInvFVBridge::isItemMovable() const return TRUE; } -BOOL LLTaskInvFVBridge::isItemRemovable() const +BOOL LLTaskInvFVBridge::isItemRemovable(bool check_worn) const { const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object @@ -588,7 +588,7 @@ public: virtual BOOL isItemRenameable() const; // virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL renameItem(const std::string& new_name); - virtual BOOL isItemRemovable() const; + virtual BOOL isItemRemovable(bool check_worn = true) const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual bool hasChildren() const; virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; @@ -648,7 +648,7 @@ BOOL LLTaskCategoryBridge::renameItem(const std::string& new_name) return FALSE; } -BOOL LLTaskCategoryBridge::isItemRemovable() const +BOOL LLTaskCategoryBridge::isItemRemovable(bool check_worn) const { return FALSE; } diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 7f501661df..0f0af37485 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -71,7 +71,6 @@ #include "llpanelblockedlist.h" #include "llpanelprofileclassifieds.h" #include "llpanelprofilepicks.h" -#include "llthumbnailctrl.h" #include "lltrans.h" #include "llviewercontrol.h" #include "llviewermenu.h" //is_agent_mappable @@ -102,216 +101,6 @@ static const std::string PROFILE_IMAGE_UPLOAD_CAP = "UploadAgentProfileImage"; ////////////////////////////////////////////////////////////////////////// -void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders; - - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - httpOpts->setFollowRedirects(true); - - std::string finalUrl = cap_url + "/" + agent_id.asString(); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Result: " << httpResults << LL_ENDL; - - if (!status - || !result.has("id") - || agent_id != result["id"].asUUID()) - { - LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL; - return; - } - - LLFloater* floater_profile = LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id)); - if (!floater_profile) - { - // floater is dead, so panels are dead as well - return; - } - - LLPanel *panel = floater_profile->findChild<LLPanel>(PANEL_PROFILE_VIEW, TRUE); - LLPanelProfile *panel_profile = dynamic_cast<LLPanelProfile*>(panel); - if (!panel_profile) - { - LL_WARNS() << PANEL_PROFILE_VIEW << " not found" << LL_ENDL; - return; - } - - - // Avatar Data - - LLAvatarData *avatar_data = &panel_profile->mAvatarData; - std::string birth_date; - - avatar_data->agent_id = agent_id; - avatar_data->avatar_id = agent_id; - avatar_data->image_id = result["sl_image_id"].asUUID(); - avatar_data->fl_image_id = result["fl_image_id"].asUUID(); - avatar_data->partner_id = result["partner_id"].asUUID(); - avatar_data->about_text = result["sl_about_text"].asString(); - avatar_data->fl_about_text = result["fl_about_text"].asString(); - avatar_data->born_on = result["member_since"].asDate(); - avatar_data->profile_url = getProfileURL(agent_id.asString()); - avatar_data->customer_type = result["customer_type"].asString(); - - avatar_data->flags = 0; - - if (result["online"].asBoolean()) - { - avatar_data->flags |= AVATAR_ONLINE; - } - if (result["allow_publish"].asBoolean()) - { - avatar_data->flags |= AVATAR_ALLOW_PUBLISH; - } - if (result["identified"].asBoolean()) - { - avatar_data->flags |= AVATAR_IDENTIFIED; - } - if (result["transacted"].asBoolean()) - { - avatar_data->flags |= AVATAR_TRANSACTED; - } - - avatar_data->caption_index = 0; - if (result.has("charter_member")) // won't be present if "caption" is set - { - avatar_data->caption_index = result["charter_member"].asInteger(); - } - else if (result.has("caption")) - { - avatar_data->caption_text = result["caption"].asString(); - } - - panel = floater_profile->findChild<LLPanel>(PANEL_SECONDLIFE, TRUE); - LLPanelProfileSecondLife *panel_sl = dynamic_cast<LLPanelProfileSecondLife*>(panel); - if (panel_sl) - { - panel_sl->processProfileProperties(avatar_data); - } - - panel = floater_profile->findChild<LLPanel>(PANEL_WEB, TRUE); - LLPanelProfileWeb *panel_web = dynamic_cast<LLPanelProfileWeb*>(panel); - if (panel_web) - { - panel_web->setLoaded(); - } - - panel = floater_profile->findChild<LLPanel>(PANEL_FIRSTLIFE, TRUE); - LLPanelProfileFirstLife *panel_first = dynamic_cast<LLPanelProfileFirstLife*>(panel); - if (panel_first) - { - panel_first->processProperties(avatar_data); - } - - // Picks - - LLSD picks_array = result["picks"]; - LLAvatarPicks avatar_picks; - avatar_picks.agent_id = agent_id; // Not in use? - avatar_picks.target_id = agent_id; - - for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) - { - const LLSD& pick_data = *it; - avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); - } - - panel = floater_profile->findChild<LLPanel>(PANEL_PICKS, TRUE); - LLPanelProfilePicks *panel_picks = dynamic_cast<LLPanelProfilePicks*>(panel); - if (panel_picks) - { - // Refresh pick limit before processing - LLAgentPicksInfo::getInstance()->onServerRespond(&avatar_picks); - panel_picks->processProperties(&avatar_picks); - } - - // Groups - - LLSD groups_array = result["groups"]; - LLAvatarGroups avatar_groups; - avatar_groups.agent_id = agent_id; // Not in use? - avatar_groups.avatar_id = agent_id; // target_id - - for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it) - { - const LLSD& group_info = *it; - LLAvatarGroups::LLGroupData group_data; - group_data.group_powers = 0; // Not in use? - group_data.group_title = group_info["name"].asString(); // Missing data, not in use? - group_data.group_id = group_info["id"].asUUID(); - group_data.group_name = group_info["name"].asString(); - group_data.group_insignia_id = group_info["image_id"].asUUID(); - - avatar_groups.group_list.push_back(group_data); - } - - if (panel_sl) - { - panel_sl->processGroupProperties(&avatar_groups); - } - - // Notes - LLAvatarNotes avatar_notes; - - avatar_notes.agent_id = agent_id; - avatar_notes.target_id = agent_id; - avatar_notes.notes = result["notes"].asString(); - - panel = floater_profile->findChild<LLPanel>(PANEL_NOTES, TRUE); - LLPanelProfileNotes *panel_notes = dynamic_cast<LLPanelProfileNotes*>(panel); - if (panel_notes) - { - panel_notes->processProperties(&avatar_notes); - } -} - -//TODO: changes take two minutes to propagate! -// Add some storage that holds updated data for two minutes -// for new instances to reuse the data -// Profile data is only relevant to own avatar, but notes -// are for everybody (no onger an issue?) -void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data, std::function<void(bool)> callback) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders; - - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - httpOpts->setFollowRedirects(true); - - std::string finalUrl = cap_url + "/" + agent_id.asString(); - - LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS("AvatarProperties") << "Failed to put agent information " << data << " for id " << agent_id << LL_ENDL; - } - else - { - LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Data: " << data << " Result: " << httpResults << LL_ENDL; - } - - if (callback) - { - callback(status); - } -} - LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::string path_to_image, LLHandle<LLPanel> *handle) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -348,7 +137,6 @@ LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::stri } // Upload the image - LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); @@ -898,11 +686,12 @@ void LLFloaterProfilePermissions::onCancel() // LLPanelProfileSecondLife LLPanelProfileSecondLife::LLPanelProfileSecondLife() - : LLPanelProfileTab() + : LLPanelProfilePropertiesProcessorTab() , mAvatarNameCacheConnection() , mHasUnsavedDescriptionChanges(false) , mWaitingForImageUpload(false) , mAllowPublish(false) + , mHideAge(false) { } @@ -928,7 +717,8 @@ BOOL LLPanelProfileSecondLife::postBuild() { mGroupList = getChild<LLGroupList>("group_list"); mShowInSearchCombo = getChild<LLComboBox>("show_in_search"); - mSecondLifePic = getChild<LLThumbnailCtrl>("2nd_life_pic"); + mHideAgeCombo = getChild<LLComboBox>("hide_age"); + mSecondLifePic = getChild<LLProfileImageCtrl>("2nd_life_pic"); mSecondLifePicLayout = getChild<LLPanel>("image_panel"); mDescriptionEdit = getChild<LLTextEditor>("sl_description_edit"); mAgentActionMenuButton = getChild<LLMenuButton>("agent_actions_menu"); @@ -942,6 +732,7 @@ BOOL LLPanelProfileSecondLife::postBuild() mCantEditObjectsIcon = getChild<LLIconCtrl>("cant_edit_objects"); mShowInSearchCombo->setCommitCallback([this](LLUICtrl*, void*) { onShowInSearchCallback(); }, nullptr); + mHideAgeCombo->setCommitCallback([this](LLUICtrl*, void*) { onHideAgeCallback(); }, nullptr); mGroupList->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { LLPanelProfileSecondLife::openGroupProfile(); }); mGroupList->setReturnCallback([this](LLUICtrl*, const LLSD&) { LLPanelProfileSecondLife::openGroupProfile(); }); mSaveDescriptionChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveDescriptionChanges(); }, nullptr); @@ -1012,26 +803,6 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); } -void LLPanelProfileSecondLife::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getStarted() && avatar_id.notNull()) - { - setIsLoading(); - - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); - } - else - { - LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL; - } - } -} - void LLPanelProfileSecondLife::refreshName() { if (!mAvatarNameCacheConnection.connected()) @@ -1046,10 +817,9 @@ void LLPanelProfileSecondLife::resetData() // Set default image and 1:1 dimensions for it mSecondLifePic->setValue("Generic_Person_Large"); - mImageId = LLUUID::null; LLRect imageRect = mSecondLifePicLayout->getRect(); - mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight()); + mSecondLifePicLayout->reshape(imageRect.getWidth(), imageRect.getWidth()); setDescriptionText(LLStringUtil::null); mGroups.clear(); @@ -1075,6 +845,18 @@ void LLPanelProfileSecondLife::resetData() childSetVisible("partner_spacer_layout", TRUE); } +void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + } + } +} + void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) { const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); @@ -1094,22 +876,18 @@ void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avat fillAccountStatus(avatar_data); - setLoaded(); -} - -void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups) -{ - - LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); - const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end(); + LLAvatarData::group_list_t::const_iterator it = avatar_data->group_list.begin(); + const LLAvatarData::group_list_t::const_iterator it_end = avatar_data->group_list.end(); for (; it_end != it; ++it) { - LLAvatarGroups::LLGroupData group_data = *it; + LLAvatarData::LLGroupData group_data = *it; mGroups[group_data.group_name] = group_data.group_id; } mGroupList->setGroups(mGroups); + + setLoaded(); } void LLPanelProfileSecondLife::openGroupProfile() @@ -1143,36 +921,12 @@ void LLPanelProfileSecondLife::setProfileImageUploading(bool loading) void LLPanelProfileSecondLife::setProfileImageUploaded(const LLUUID &image_asset_id) { mSecondLifePic->setValue(image_asset_id); - mImageId = image_asset_id; - - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(image_asset_id); - if (imagep->getFullHeight()) - { - onImageLoaded(true, imagep); - } - else - { - imagep->setLoadedCallback(onImageLoaded, - MAX_DISCARD_LEVEL, - FALSE, - FALSE, - new LLHandle<LLPanel>(getHandle()), - NULL, - FALSE); - } LLFloater *floater = mFloaterProfileTextureHandle.get(); if (floater) { LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater); - if (mImageId.notNull()) - { - texture_view->loadAsset(mImageId); - } - else - { - texture_view->resetAsset(); - } + texture_view->loadAsset(mSecondLifePic->getImageAssetId()); } setProfileImageUploading(false); @@ -1216,42 +970,16 @@ void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) // and to make sure icons in text will be up to date LLAvatarIconIDCache::getInstance()->add(avatar_data->avatar_id, avatar_data->image_id); - fillAgeData(avatar_data->born_on); + fillAgeData(avatar_data); setDescriptionText(avatar_data->about_text); - if (avatar_data->image_id.notNull()) - { - mSecondLifePic->setValue(avatar_data->image_id); - mImageId = avatar_data->image_id; - } - else - { - mSecondLifePic->setValue("Generic_Person_Large"); - mImageId = LLUUID::null; - } - - // Will be loaded as a LLViewerFetchedTexture::BOOST_UI due to mSecondLifePic - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id); - if (imagep->getFullHeight()) - { - onImageLoaded(true, imagep); - } - else - { - imagep->setLoadedCallback(onImageLoaded, - MAX_DISCARD_LEVEL, - FALSE, - FALSE, - new LLHandle<LLPanel>(getHandle()), - NULL, - FALSE); - } + mSecondLifePic->setValue(avatar_data->image_id); if (getSelfProfile()) { mAllowPublish = avatar_data->flags & AVATAR_ALLOW_PUBLISH; - mShowInSearchCombo->setValue((BOOL)mAllowPublish); + mShowInSearchCombo->setValue(mAllowPublish ? TRUE : FALSE); } } @@ -1376,21 +1104,47 @@ void LLPanelProfileSecondLife::fillRightsData() } } -void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on) +void LLPanelProfileSecondLife::fillAgeData(const LLAvatarData* avatar_data) { // Date from server comes already converted to stl timezone, // so display it as an UTC + 0 - std::string name_and_date = getString("date_format"); + bool hide_age = avatar_data->hide_age && !getSelfProfile(); + std::string name_and_date = getString(hide_age ? "date_format_short" : "date_format_full"); LLSD args_name; - args_name["datetime"] = (S32)born_on.secondsSinceEpoch(); + args_name["datetime"] = (S32)avatar_data->born_on.secondsSinceEpoch(); LLStringUtil::format(name_and_date, args_name); getChild<LLUICtrl>("sl_birth_date")->setValue(name_and_date); - std::string register_date = getString("age_format"); - LLSD args_age; - args_age["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now()); - LLStringUtil::format(register_date, args_age); - getChild<LLUICtrl>("user_age")->setValue(register_date); + LLUICtrl* userAgeCtrl = getChild<LLUICtrl>("user_age"); + if (hide_age) + { + userAgeCtrl->setVisible(FALSE); + } + else + { + std::string register_date = getString("age_format"); + LLSD args_age; + args_age["[AGE]"] = LLDateUtil::ageFromDate(avatar_data->born_on, LLDate::now()); + LLStringUtil::format(register_date, args_age); + userAgeCtrl->setValue(register_date); + } + + BOOL showHideAgeCombo = FALSE; + if (getSelfProfile()) + { + if (LLAvatarPropertiesProcessor::getInstance()->isHideAgeSupportedByServer()) + { + F64 birth = avatar_data->born_on.secondsSinceEpoch(); + F64 now = LLDate::now().secondsSinceEpoch(); + if (now - birth > 365 * 24 * 60 * 60) + { + mHideAge = avatar_data->hide_age; + mHideAgeCombo->setValue(mHideAge ? TRUE : FALSE); + showHideAgeCombo = TRUE; + } + } + } + mHideAgeCombo->setVisible(showHideAgeCombo); } void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep) @@ -1407,34 +1161,6 @@ void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTextur } } -//static -void LLPanelProfileSecondLife::onImageLoaded(BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata) -{ - if (!userdata) return; - - LLHandle<LLPanel>* handle = (LLHandle<LLPanel>*)userdata; - - if (!handle->isDead()) - { - LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(handle->get()); - if (panel) - { - panel->onImageLoaded(success, src_vi); - } - } - - if (final || !success) - { - delete handle; - } -} - // virtual, called by LLAvatarTracker void LLPanelProfileSecondLife::changed(U32 mask) { @@ -1465,7 +1191,7 @@ void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id) LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); } - LLPanelProfileTab::setAvatarId(avatar_id); + LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); if (LLAvatarActions::isFriend(getAvatarId())) { @@ -1507,6 +1233,10 @@ void LLPanelProfileSecondLife::setLoaded() if (getSelfProfile()) { mShowInSearchCombo->setEnabled(TRUE); + if (mHideAgeCombo->getVisible()) + { + mHideAgeCombo->setEnabled(TRUE); + } mDescriptionEdit->setEnabled(TRUE); } } @@ -1559,7 +1289,7 @@ void LLProfileImagePicker::notify(const std::vector<std::string>& filenames) if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) { LLSD notif_args; - notif_args["REASON"] = LLImage::getLastError().c_str(); + notif_args["REASON"] = LLImage::getLastThreadError().c_str(); LLNotificationsUtil::add("CannotUploadTexture", notif_args); LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)mType << ", " << notif_args["REASON"].asString() << LL_ENDL; return; @@ -1695,7 +1425,7 @@ void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) } else if (item_name == "upload_photo") { - (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle<LLPanel>(getHandle())))->getFile(); + (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle<LLPanel>(LLPanel::getHandle())))->getFile(); LLFloater* floaterp = mFloaterTexturePickerHandle.get(); if (floaterp) @@ -1770,7 +1500,7 @@ bool LLPanelProfileSecondLife::onEnableMenu(const LLSD& userdata) else if (item_name == "remove_photo") { std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - return mImageId.notNull() && !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded(); + return mSecondLifePic->getImageAssetId().notNull() && !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded(); } return false; @@ -1834,39 +1564,28 @@ void LLPanelProfileSecondLife::onSetDescriptionDirty() void LLPanelProfileSecondLife::onShowInSearchCallback() { - S32 value = mShowInSearchCombo->getValue().asInteger(); - if (mAllowPublish == (bool)value) - { + bool value = mShowInSearchCombo->getValue().asInteger(); + if (value == mAllowPublish) return; - } - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - mAllowPublish = value; - LLSD data; - data["allow_publish"] = mAllowPublish; - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), data, nullptr)); - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; - } + + mAllowPublish = value; + saveAgentUserInfoCoro("allow_publish", value); +} + +void LLPanelProfileSecondLife::onHideAgeCallback() +{ + bool value = mHideAgeCombo->getValue().asInteger(); + if (value == mHideAge) + return; + + mHideAge = value; + saveAgentUserInfoCoro("hide_age", value); } void LLPanelProfileSecondLife::onSaveDescriptionChanges() { mDescriptionText = mDescriptionEdit->getValue().asString(); - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("sl_about_text", mDescriptionText), nullptr)); - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; - } + saveAgentUserInfoCoro("sl_about_text", mDescriptionText); mSaveDescriptionChanges->setEnabled(FALSE); mDiscardDescriptionChanges->setEnabled(FALSE); @@ -1916,9 +1635,9 @@ void LLPanelProfileSecondLife::onShowAgentProfileTexture() { LLFloaterProfileTexture * texture_view = new LLFloaterProfileTexture(parent_floater); mFloaterProfileTextureHandle = texture_view->getHandle(); - if (mImageId.notNull()) + if (mSecondLifePic->getImageAssetId().notNull()) { - texture_view->loadAsset(mImageId); + texture_view->loadAsset(mSecondLifePic->getImageAssetId()); } else { @@ -1935,9 +1654,9 @@ void LLPanelProfileSecondLife::onShowAgentProfileTexture() LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater); texture_view->setMinimized(FALSE); texture_view->setVisibleAndFrontmost(TRUE); - if (mImageId.notNull()) + if (mSecondLifePic->getImageAssetId().notNull()) { - texture_view->loadAsset(mImageId); + texture_view->loadAsset(mSecondLifePic->getImageAssetId()); } else { @@ -1960,9 +1679,9 @@ void LLPanelProfileSecondLife::onShowTexturePicker() getWindow()->setCursor(UI_CURSOR_WAIT); LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker( this, - mImageId, + mSecondLifePic->getImageAssetId(), LLUUID::null, - mImageId, + mSecondLifePic->getImageAssetId(), FALSE, FALSE, "SELECT PHOTO", @@ -2000,55 +1719,36 @@ void LLPanelProfileSecondLife::onShowTexturePicker() void LLPanelProfileSecondLife::onCommitProfileImage(const LLUUID& id) { - if (mImageId == id) - { + if (mSecondLifePic->getImageAssetId() == id) return; - } - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) + std::function<void(bool)> callback = [id](bool result) { - std::function<void(bool)> callback = [id](bool result) + if (result) { - if (result) - { - LLAvatarIconIDCache::getInstance()->add(gAgentID, id); - // Should trigger callbacks in icon controls - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgentID); - } - }; - LLSD params; - params["sl_image_id"] = id; - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params, callback)); - - mImageId = id; - if (mImageId == LLUUID::null) + LLAvatarIconIDCache::getInstance()->add(gAgentID, id); + // Should trigger callbacks in icon controls (or request Legacy) + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgentID); + } + }; + + if (!saveAgentUserInfoCoro("sl_image_id", id, callback)) + return; + + mSecondLifePic->setValue(id); + + LLFloater *floater = mFloaterProfileTextureHandle.get(); + if (floater) + { + LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater); + if (id == LLUUID::null) { - mSecondLifePic->setValue("Generic_Person_Large"); + texture_view->resetAsset(); } else { - mSecondLifePic->setValue(mImageId); + texture_view->loadAsset(id); } - - LLFloater *floater = mFloaterProfileTextureHandle.get(); - if (floater) - { - LLFloaterProfileTexture * texture_view = dynamic_cast<LLFloaterProfileTexture*>(floater); - if (mImageId == LLUUID::null) - { - texture_view->resetAsset(); - } - else - { - texture_view->loadAsset(mImageId); - } - } - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; } } @@ -2180,6 +1880,8 @@ void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e LLStringUtil::format_map_t args; args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32()); childSetValue("status_text", LLSD( getString("LoadTime", args)) ); + + setLoaded(); } break; @@ -2195,7 +1897,7 @@ void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e ////////////////////////////////////////////////////////////////////////// LLPanelProfileFirstLife::LLPanelProfileFirstLife() - : LLPanelProfileTab() + : LLPanelProfilePropertiesProcessorTab() , mHasUnsavedChanges(false) { } @@ -2207,7 +1909,7 @@ LLPanelProfileFirstLife::~LLPanelProfileFirstLife() BOOL LLPanelProfileFirstLife::postBuild() { mDescriptionEdit = getChild<LLTextEditor>("fl_description_edit"); - mPicture = getChild<LLThumbnailCtrl>("real_world_pic"); + mPicture = getChild<LLProfileImageCtrl>("real_world_pic"); mUploadPhoto = getChild<LLButton>("fl_upload_image"); mChangePhoto = getChild<LLButton>("fl_change_image"); @@ -2242,7 +1944,7 @@ void LLPanelProfileFirstLife::setProfileImageUploading(bool loading) { mUploadPhoto->setEnabled(!loading); mChangePhoto->setEnabled(!loading); - mRemovePhoto->setEnabled(!loading && mImageId.notNull()); + mRemovePhoto->setEnabled(!loading && mPicture->getImageAssetId().notNull()); LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("image_upload_indicator"); indicator->setVisible(loading); @@ -2259,7 +1961,6 @@ void LLPanelProfileFirstLife::setProfileImageUploading(bool loading) void LLPanelProfileFirstLife::setProfileImageUploaded(const LLUUID &image_asset_id) { mPicture->setValue(image_asset_id); - mImageId = image_asset_id; setProfileImageUploading(false); } @@ -2273,7 +1974,7 @@ void LLPanelProfileFirstLife::commitUnsavedChanges() void LLPanelProfileFirstLife::onUploadPhoto() { - (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle<LLPanel>(getHandle())))->getFile(); + (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle<LLPanel>(LLPanel::getHandle())))->getFile(); LLFloater* floaterp = mFloaterTexturePickerHandle.get(); if (floaterp) @@ -2296,9 +1997,9 @@ void LLPanelProfileFirstLife::onChangePhoto() getWindow()->setCursor(UI_CURSOR_WAIT); LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker( this, - mImageId, + mPicture->getImageAssetId(), LLUUID::null, - mImageId, + mPicture->getImageAssetId(), FALSE, FALSE, "SELECT PHOTO", @@ -2346,35 +2047,15 @@ void LLPanelProfileFirstLife::onRemovePhoto() void LLPanelProfileFirstLife::onCommitPhoto(const LLUUID& id) { - if (mImageId == id) - { + if (mPicture->getImageAssetId() == id) return; - } - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLSD params; - params["fl_image_id"] = id; - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params, nullptr)); + if (!saveAgentUserInfoCoro("fl_image_id", id)) + return; - mImageId = id; - if (mImageId.notNull()) - { - mPicture->setValue(mImageId); - } - else - { - mPicture->setValue("Generic_Person_Large"); - } + mPicture->setValue(id); - mRemovePhoto->setEnabled(mImageId.notNull()); - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; - } + mRemovePhoto->setEnabled(id.notNull()); } void LLPanelProfileFirstLife::setDescriptionText(const std::string &text) @@ -2397,16 +2078,7 @@ void LLPanelProfileFirstLife::onSetDescriptionDirty() void LLPanelProfileFirstLife::onSaveDescriptionChanges() { mCurrentDescription = mDescriptionEdit->getValue().asString(); - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("fl_about_text", mCurrentDescription), nullptr)); - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; - } + saveAgentUserInfoCoro("fl_about_text", mCurrentDescription); mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); @@ -2418,20 +2090,23 @@ void LLPanelProfileFirstLife::onDiscardDescriptionChanges() setDescriptionText(mCurrentDescription); } +void LLPanelProfileFirstLife::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProperties(avatar_data); + } + } +} + void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data) { setDescriptionText(avatar_data->fl_about_text); - mImageId = avatar_data->fl_image_id; - - if (mImageId.notNull()) - { - mPicture->setValue(mImageId); - } - else - { - mPicture->setValue("Generic_Person_Large"); - } + mPicture->setValue(avatar_data->fl_image_id); setLoaded(); } @@ -2439,8 +2114,7 @@ void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data) void LLPanelProfileFirstLife::resetData() { setDescriptionText(std::string()); - mPicture->setValue("Generic_Person_Large"); - mImageId = LLUUID::null; + mPicture->setValue(LLUUID::null); mUploadPhoto->setVisible(getSelfProfile()); mChangePhoto->setVisible(getSelfProfile()); @@ -2457,7 +2131,7 @@ void LLPanelProfileFirstLife::setLoaded() { mDescriptionEdit->setEnabled(TRUE); mPicture->setEnabled(TRUE); - mRemovePhoto->setEnabled(mImageId.notNull()); + mRemovePhoto->setEnabled(mPicture->getImageAssetId().notNull()); } } @@ -2466,7 +2140,7 @@ void LLPanelProfileFirstLife::setLoaded() ////////////////////////////////////////////////////////////////////////// LLPanelProfileNotes::LLPanelProfileNotes() -: LLPanelProfileTab() +: LLPanelProfilePropertiesProcessorTab() , mHasUnsavedChanges(false) { @@ -2476,22 +2150,6 @@ LLPanelProfileNotes::~LLPanelProfileNotes() { } -void LLPanelProfileNotes::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getStarted() && avatar_id.notNull()) - { - setIsLoading(); - - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); - } - } -} - void LLPanelProfileNotes::commitUnsavedChanges() { if (mHasUnsavedChanges) @@ -2540,16 +2198,7 @@ void LLPanelProfileNotes::onSetNotesDirty() void LLPanelProfileNotes::onSaveNotesChanges() { mCurrentNotes = mNotesEditor->getValue().asString(); - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("putAgentUserInfoCoro", - boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("notes", mCurrentNotes), nullptr)); - } - else - { - LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; - } + saveAgentUserInfoCoro("notes", mCurrentNotes); mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); @@ -2561,9 +2210,21 @@ void LLPanelProfileNotes::onDiscardNotesChanges() setNotesText(mCurrentNotes); } -void LLPanelProfileNotes::processProperties(LLAvatarNotes* avatar_notes) +void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProperties(avatar_data); + } + } +} + +void LLPanelProfileNotes::processProperties(const LLAvatarData* avatar_data) { - setNotesText(avatar_notes->notes); + setNotesText(avatar_data->notes); mNotesEditor->setEnabled(TRUE); setLoaded(); } @@ -2574,14 +2235,6 @@ void LLPanelProfileNotes::resetData() setNotesText(std::string()); } -void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id) -{ - if (avatar_id.notNull()) - { - LLPanelProfileTab::setAvatarId(avatar_id); - } -} - ////////////////////////////////////////////////////////////////////////// // LLPanelProfile @@ -2658,12 +2311,7 @@ void LLPanelProfile::updateData() mPanelFirstlife->setIsLoading(); mPanelNotes->setIsLoading(); - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); - } + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); } } diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 6007d95022..1afc248073 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -58,9 +58,9 @@ class LLTextBase; class LLMenuButton; class LLLineEditor; class LLTextEditor; -class LLThumbnailCtrl; class LLPanelProfileClassifieds; class LLPanelProfilePicks; +class LLProfileImageCtrl; class LLViewerFetchedTexture; @@ -68,7 +68,7 @@ class LLViewerFetchedTexture; * Panel for displaying Avatar's second life related info. */ class LLPanelProfileSecondLife - : public LLPanelProfileTab + : public LLPanelProfilePropertiesProcessorTab , public LLFriendObserver , public LLVoiceClientStatusObserver { @@ -93,10 +93,6 @@ public: void resetData() override; - /** - * Sends update data request to server. - */ - void updateData() override; void refreshName(); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); @@ -107,7 +103,7 @@ public: bool hasUnsavedChanges() override; void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + void processProperties(void* data, EAvatarProcessorType type) override; protected: /** @@ -116,11 +112,6 @@ protected: void processProfileProperties(const LLAvatarData* avatar_data); /** - * Processes group related data received from server. - */ - void processGroupProperties(const LLAvatarGroups* avatar_groups); - - /** * Fills common for Avatar profile and My Profile fields. */ void fillCommonData(const LLAvatarData* avatar_data); @@ -143,16 +134,9 @@ protected: /** * Fills user name, display name, age. */ - void fillAgeData(const LLDate &born_on); + void fillAgeData(const LLAvatarData* avatar_data); void onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep); - static void onImageLoaded(BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata); /** * Displays avatar's online status if possible. @@ -179,6 +163,7 @@ private: void setDescriptionText(const std::string &text); void onSetDescriptionDirty(); void onShowInSearchCallback(); + void onHideAgeCallback(); void onSaveDescriptionChanges(); void onDiscardDescriptionChanges(); void onShowAgentPermissionsDialog(); @@ -193,7 +178,8 @@ private: LLGroupList* mGroupList; LLComboBox* mShowInSearchCombo; - LLThumbnailCtrl* mSecondLifePic; + LLComboBox* mHideAgeCombo; + LLProfileImageCtrl* mSecondLifePic; LLPanel* mSecondLifePicLayout; LLTextEditor* mDescriptionEdit; LLMenuButton* mAgentActionMenuButton; @@ -214,9 +200,8 @@ private: bool mVoiceStatus; bool mWaitingForImageUpload; bool mAllowPublish; + bool mHideAge; std::string mDescriptionText; - LLUUID mImageId; - boost::signals2::connection mAvatarNameCacheConnection; }; @@ -247,8 +232,6 @@ public: void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - protected: void onCommitLoad(LLUICtrl* ctrl); @@ -267,7 +250,7 @@ private: * Panel for displaying Avatar's first life related info. */ class LLPanelProfileFirstLife - : public LLPanelProfileTab + : public LLPanelProfilePropertiesProcessorTab { public: LLPanelProfileFirstLife(); @@ -277,6 +260,7 @@ public: BOOL postBuild() override; + void processProperties(void* data, EAvatarProcessorType type) override; void processProperties(const LLAvatarData* avatar_data); void resetData() override; @@ -287,8 +271,6 @@ public: bool hasUnsavedChanges() override { return mHasUnsavedChanges; } void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - protected: void setLoaded() override; @@ -302,7 +284,7 @@ protected: void onDiscardDescriptionChanges(); LLTextEditor* mDescriptionEdit; - LLThumbnailCtrl* mPicture; + LLProfileImageCtrl* mPicture; LLButton* mUploadPhoto; LLButton* mChangePhoto; LLButton* mRemovePhoto; @@ -312,7 +294,6 @@ protected: LLHandle<LLFloater> mFloaterTexturePickerHandle; std::string mCurrentDescription; - LLUUID mImageId; bool mHasUnsavedChanges; }; @@ -320,24 +301,21 @@ protected: * Panel for displaying Avatar's notes and modifying friend's rights. */ class LLPanelProfileNotes - : public LLPanelProfileTab + : public LLPanelProfilePropertiesProcessorTab { public: LLPanelProfileNotes(); /*virtual*/ ~LLPanelProfileNotes(); - void setAvatarId(const LLUUID& avatar_id) override; - void onOpen(const LLSD& key) override; BOOL postBuild() override; - void processProperties(LLAvatarNotes* avatar_notes); + void processProperties(void* data, EAvatarProcessorType type) override; + void processProperties(const LLAvatarData* avatar_data); void resetData() override; - void updateData() override; - bool hasUnsavedChanges() override { return mHasUnsavedChanges; } void commitUnsavedChanges() override; @@ -384,10 +362,6 @@ public: void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); void createClassified(); - LLAvatarData getAvatarData() { return mAvatarData; }; - - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - private: void onTabChange(); @@ -398,13 +372,6 @@ private: LLPanelProfileFirstLife* mPanelFirstlife; LLPanelProfileNotes* mPanelNotes; LLTabContainer* mTabContainer; - - // Todo: due to server taking minutes to update this needs a more long term storage - // to reuse recently saved values if user opens floater again - // Storage implementation depends onto how a cap will be implemented, if cap will be - // enought to fully update LLAvatarPropertiesProcessor, then this storage can be - // implemented there. - LLAvatarData mAvatarData; }; #endif //LL_LLPANELPROFILE_H diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 8bbd4a748d..b097e637a4 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -98,12 +98,6 @@ public: return true; } - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks")) - { - LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - // handle app/pick/create urls first if (params.size() == 1 && params[0].asString() == "create") { @@ -296,17 +290,21 @@ void LLPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLS void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type) { - if (APT_PICKS == type) + if (APT_PROPERTIES == type) { - LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data); - if (avatar_picks && getAvatarId() == avatar_picks->target_id) + LLAvatarData* avatar_picks = static_cast<LLAvatarData*>(data); + if (avatar_picks && getAvatarId() == avatar_picks->avatar_id) { + if (getSelfProfile()) + { + LLAgentPicksInfo::getInstance()->onServerRespond(avatar_picks); + } processProperties(avatar_picks); } } } -void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) +void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) { LLUUID selected_id = mPickToSelectOnLoad; bool has_selection = false; @@ -324,7 +322,7 @@ void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) mTabContainer->deleteAllTabs(); - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); + LLAvatarData::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); for (; avatar_picks->picks_list.end() != it; ++it) { LLUUID pick_id = it->first; @@ -428,7 +426,7 @@ void LLPanelProfilePicks::updateData() { setIsLoading(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); } if (!getIsLoaded()) { diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index 76b1452431..90c527e0f3 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -58,7 +58,7 @@ public: void selectPick(const LLUUID& pick_id); void processProperties(void* data, EAvatarProcessorType type) override; - void processProperties(const LLAvatarPicks* avatar_picks); + void processProperties(const LLAvatarData* avatar_picks); void resetData() override; @@ -77,8 +77,6 @@ public: bool hasUnsavedChanges() override; void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - private: void onClickNewBtn(); void onClickDelete(); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index b2b8e81704..9a7281cda4 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -110,9 +110,9 @@ protected: registrar.add("Wearing.EditOutfit", boost::bind(&edit_outfit)); registrar.add("Wearing.ShowOriginal", boost::bind(show_item_original, mUUIDs.front())); registrar.add("Wearing.TakeOff", - boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); registrar.add("Wearing.Detach", - boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); updateMenuItemsVisibility(menu); diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 4aca704a27..e06d025f59 100644 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -115,7 +115,7 @@ void LLPersistentNotificationStorage::loadNotifications() using namespace LLNotificationsUI; LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID)); LLNotifications& instance = LLNotifications::instance(); S32 processed_notifications = 0; diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp index 353d261ad1..0b13fc37b9 100644 --- a/indra/newview/llpopupview.cpp +++ b/indra/newview/llpopupview.cpp @@ -256,16 +256,16 @@ void LLPopupView::removePopup(LLView* popup) void LLPopupView::clearPopups() { - for (popup_list_t::iterator popup_it = mPopups.begin(); - popup_it != mPopups.end();) + while (!mPopups.empty()) { + popup_list_t::iterator popup_it = mPopups.begin(); LLView* popup = popup_it->get(); - - popup_list_t::iterator cur_popup_it = popup_it; - ++popup_it; - - mPopups.erase(cur_popup_it); - popup->onTopLost(); + // Remove before notifying in case it will cause removePopup + mPopups.erase(popup_it); + if (popup) + { + popup->onTopLost(); + } } } diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index cde552fc8d..a6722b1c02 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -254,8 +254,6 @@ void LLPresetsManager::getControlNames(std::vector<std::string>& names) // From panel_preferences_move.xml ("CameraAngle") ("CameraOffsetScale") - ("EditCameraMovement") - ("AppearanceCameraMovement") // From llagentcamera.cpp ("CameraOffsetBuild") ("TrackFocusObject") @@ -460,6 +458,9 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n LL_DEBUGS() << "attempting to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL; + bool appearance_camera_movement = gSavedSettings.getBOOL("AppearanceCameraMovement"); + bool edit_camera_movement = gSavedSettings.getBOOL("EditCameraMovement"); + mIgnoreChangedSignal = true; if(gSavedSettings.loadFromFile(full_path, false, true) > 0) { @@ -479,6 +480,16 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n { gSavedSettings.setString("PresetCameraActive", name); triggerChangeCameraSignal(); + + //SL-20277 old preset files may contain settings that should be ignored when loading camera presets + if (appearance_camera_movement != (bool)gSavedSettings.getBOOL("AppearanceCameraMovement")) + { + gSavedSettings.setBOOL("AppearanceCameraMovement", appearance_camera_movement); + } + if (edit_camera_movement != (bool)gSavedSettings.getBOOL("EditCameraMovement")) + { + gSavedSettings.setBOOL("EditCameraMovement", edit_camera_movement); + } } } else diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 5b95decbd8..1d9d69dcfe 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -433,6 +433,11 @@ BOOL LLPreviewGesture::postBuild() edit->setIgnoreTab(TRUE); mChatEditor = edit; + check = getChild<LLCheckBoxCtrl>( "wait_key_release_check"); + check->setVisible(FALSE); + check->setCommitCallback(onCommitWait, this); + mWaitKeyReleaseCheck = check; + check = getChild<LLCheckBoxCtrl>( "wait_anim_check"); check->setVisible(FALSE); check->setCommitCallback(onCommitWait, this); @@ -638,6 +643,7 @@ void LLPreviewGesture::refresh() mAnimationRadio->setEnabled(FALSE); mSoundCombo->setEnabled(FALSE); mChatEditor->setEnabled(FALSE); + mWaitKeyReleaseCheck->setEnabled(FALSE); mWaitAnimCheck->setEnabled(FALSE); mWaitTimeCheck->setEnabled(FALSE); mWaitTimeEditor->setEnabled(FALSE); @@ -660,6 +666,7 @@ void LLPreviewGesture::refresh() mAnimationRadio->setEnabled(modifiable); mSoundCombo->setEnabled(modifiable); mChatEditor->setEnabled(modifiable); + mWaitKeyReleaseCheck->setEnabled(modifiable); mWaitAnimCheck->setEnabled(modifiable); mWaitTimeCheck->setEnabled(modifiable); mWaitTimeEditor->setEnabled(modifiable); @@ -695,6 +702,7 @@ void LLPreviewGesture::refresh() mAnimationRadio->setVisible(FALSE); mSoundCombo->setVisible(FALSE); mChatEditor->setVisible(FALSE); + mWaitKeyReleaseCheck->setVisible(FALSE); mWaitAnimCheck->setVisible(FALSE); mWaitTimeCheck->setVisible(FALSE); mWaitTimeEditor->setVisible(FALSE); @@ -739,6 +747,8 @@ void LLPreviewGesture::refresh() { LLGestureStepWait* wait_step = (LLGestureStepWait*)step; optionstext = getString("step_wait"); + mWaitKeyReleaseCheck->setVisible(TRUE); + mWaitKeyReleaseCheck->set(wait_step->mFlags & WAIT_FLAG_KEY_RELEASE); mWaitAnimCheck->setVisible(TRUE); mWaitAnimCheck->set(wait_step->mFlags & WAIT_FLAG_ALL_ANIM); mWaitTimeCheck->setVisible(TRUE); @@ -1518,6 +1528,7 @@ void LLPreviewGesture::onCommitWait(LLUICtrl* ctrl, void* data) LLGestureStepWait* wait_step = (LLGestureStepWait*)step; U32 flags = 0x0; + if (self->mWaitKeyReleaseCheck->get()) flags |= WAIT_FLAG_KEY_RELEASE; if (self->mWaitAnimCheck->get()) flags |= WAIT_FLAG_ALL_ANIM; if (self->mWaitTimeCheck->get()) flags |= WAIT_FLAG_TIME; wait_step->mFlags = flags; diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 55f95a8811..1f8017656f 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -154,6 +154,7 @@ private: LLComboBox* mAnimationCombo; LLComboBox* mSoundCombo; LLLineEditor* mChatEditor; + LLCheckBoxCtrl* mWaitKeyReleaseCheck; LLCheckBoxCtrl* mWaitAnimCheck; LLCheckBoxCtrl* mWaitTimeCheck; LLLineEditor* mWaitTimeEditor; diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index 30a61144b9..2604c2ba53 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -73,12 +73,14 @@ void LLReflectionMap::autoAdjustOrigin() { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (mGroup && !mComplete) + + if (mGroup && !mComplete && !mGroup->hasState(LLViewerOctreeGroup::DEAD)) { const LLVector4a* bounds = mGroup->getBounds(); auto* node = mGroup->getOctreeNode(); + LLSpatialPartition* part = mGroup->getSpatialPartition(); - if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) + if (part && part->mPartitionType == LLViewerRegion::PARTITION_VOLUME) { mPriority = 0; // cast a ray towards 8 corners of bounding box diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 70e6838a49..07b86a8f6e 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -170,8 +170,9 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right) void LLScreenChannelBase::updateRect() { + const S32 CHANNEL_BOTTOM_PANEL_MARGIN = 35; S32 channel_top = getChannelRect().mTop; - S32 channel_bottom = getChannelRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); + S32 channel_bottom = getChannelRect().mBottom + CHANNEL_BOTTOM_PANEL_MARGIN; S32 channel_left = getRect().mLeft; S32 channel_right = getRect().mRight; setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index e2c4ffd66c..748d4b507e 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -34,6 +34,12 @@ namespace LLNotificationsUI { + const LLUUID ALERT_CHANNEL_UUID("F3E07BC8-A973-476D-8C7F-F3B7293975D1"); + const LLUUID NOTIFICATION_CHANNEL_UUID("AEED3193-8709-4693-8558-7452CCA97AE5"); + const LLUUID NEARBY_CHAT_CHANNEL_UUID("E1158BD6-661C-4981-9DAD-4DCBFF062502"); + const LLUUID STARTUP_CHANNEL_UUID("B56AF90D-6684-48E4-B1E4-722D3DEB2CB6"); + + const S32 NOTIFY_BOX_WIDTH = 305; typedef enum e_notification_toast_alignment { diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index cf65049b99..577d7625c7 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -335,7 +335,7 @@ void LLScriptFloater::hideToastsIfNeeded() // find channel LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID( - LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID)); // update notification channel state if(channel) { diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index dfb26b47fc..dbab7e53b6 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsetkeybinddialog.cpp * @brief LLSetKeyBindDialog class implementation. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -74,13 +74,10 @@ LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) pUpdater(NULL), mLastMaskKey(0), mContextConeOpacity(0.f), - mContextConeInAlpha(0.f), - mContextConeOutAlpha(0.f), - mContextConeFadeTime(0.f) + mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA), + mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA), + mContextConeFadeTime(CONTEXT_CONE_FADE_TIME) { - mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); - mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); - mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } LLSetKeyBindDialog::~LLSetKeyBindDialog() diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 23c95ee143..dbcbc6c725 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -74,6 +74,32 @@ LLSidepanelTaskInfo* LLSidepanelTaskInfo::sActivePanel = NULL; static LLPanelInjector<LLSidepanelTaskInfo> t_task_info("sidepanel_task_info"); +static std::string click_action_to_string_value(U8 click_action) +{ + switch (click_action) + { + case CLICK_ACTION_TOUCH: + return "Touch"; + case CLICK_ACTION_SIT: + return "Sit"; + case CLICK_ACTION_BUY: + return "Buy"; + case CLICK_ACTION_PAY: + return "Pay"; + case CLICK_ACTION_OPEN: + return "Open"; + case CLICK_ACTION_ZOOM: + return "Zoom"; + case CLICK_ACTION_DISABLED: + return "None"; + case CLICK_ACTION_IGNORE: + return "Ignore"; + default: + return "Touch"; + } + return "Touch"; +} + // Default constructor LLSidepanelTaskInfo::LLSidepanelTaskInfo() : mVisibleDebugPermissions(true) // space was allocated by default @@ -891,11 +917,7 @@ void LLSidepanelTaskInfo::refresh() U8 click_action = 0; if (LLSelectMgr::getInstance()->selectionGetClickAction(&click_action)) { - LLComboBox* ComboClickAction = getChild<LLComboBox>("clickaction"); - if (ComboClickAction) - { - ComboClickAction->setCurrentByIndex((S32)click_action); - } + getChild<LLComboBox>("clickaction")->setValue(click_action_to_string_value(click_action)); } getChildView("label click action")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume); getChildView("clickaction")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume); @@ -1152,6 +1174,8 @@ static U8 string_value_to_click_action(std::string p_value) return CLICK_ACTION_ZOOM; if (p_value == "None") return CLICK_ACTION_DISABLED; + if (p_value == "Ignore") + return CLICK_ACTION_IGNORE; return CLICK_ACTION_TOUCH; } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 9e05a02b7a..60f88c9cea 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1598,6 +1598,8 @@ bool check_rigged_group(LLDrawable* drawable) if (root->isState(LLDrawable::RIGGED) && root->getSpatialGroup() != group) { + LL_WARNS() << "[root->isState(LLDrawable::RIGGED) and root->getSpatialGroup() != group] is true" + " (" << root->getSpatialGroup() << " != " << group << ")" << LL_ENDL; llassert(false); return false; } @@ -1607,8 +1609,10 @@ bool check_rigged_group(LLDrawable* drawable) { for (auto& face : root->getFaces()) { - if ((S32) face->getDrawOrderIndex() <= last_draw_index) + if ((S32)face->getDrawOrderIndex() <= last_draw_index) { + LL_WARNS() << "[(S32)face->getDrawOrderIndex() <= last_draw_index] is true" + " (" << (S32)face->getDrawOrderIndex() << " <= " << last_draw_index << ")" << LL_ENDL; llassert(false); return false; } @@ -1622,8 +1626,10 @@ bool check_rigged_group(LLDrawable* drawable) { for (auto& face : child->mDrawable->getFaces()) { - if ((S32) face->getDrawOrderIndex() <= last_draw_index) + if ((S32)face->getDrawOrderIndex() <= last_draw_index) { + LL_WARNS() << "[(S32)face->getDrawOrderIndex() <= last_draw_index] is true" + " (" << (S32)face->getDrawOrderIndex() << " <= " << last_draw_index << ")" << LL_ENDL; llassert(false); return false; } @@ -1633,6 +1639,8 @@ bool check_rigged_group(LLDrawable* drawable) if (child->mDrawable->getSpatialGroup() != group) { + LL_WARNS() << "[child->mDrawable->getSpatialGroup() != group] is true" + " (" << child->mDrawable->getSpatialGroup() << " != " << group << ")" << LL_ENDL; llassert(false); return false; } diff --git a/indra/newview/llsplitbutton.cpp b/indra/newview/llsplitbutton.cpp index 60c0272a8b..5e363b358a 100644 --- a/indra/newview/llsplitbutton.cpp +++ b/indra/newview/llsplitbutton.cpp @@ -243,7 +243,14 @@ LLSplitButton::LLSplitButton(const LLSplitButton::Params& p) item_top -= (rc.getHeight() + BUTTON_PAD); } - setTopLostCallback(boost::bind(&LLSplitButton::hideButtons, this)); + mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLSplitButton::hideButtons, this)); +} + +LLSplitButton::~LLSplitButton() +{ + // explicitly disconect to avoid hideButtons with + // dead pointers being called on destruction + mTopLostSignalConnection.disconnect(); } diff --git a/indra/newview/llsplitbutton.h b/indra/newview/llsplitbutton.h index 427ed7ba76..4571a233fe 100644 --- a/indra/newview/llsplitbutton.h +++ b/indra/newview/llsplitbutton.h @@ -67,7 +67,7 @@ public: }; - virtual ~LLSplitButton() {}; + virtual ~LLSplitButton(); //Overridden virtual void onFocusLost(); @@ -99,6 +99,8 @@ protected: LLButton* mShownItem; EArrowPosition mArrowPosition; + boost::signals2::connection mTopLostSignalConnection; + commit_callback_t mSelectionCallback; }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4ad0228bd0..c5a22d08f3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1961,8 +1961,10 @@ bool idle_startup() display_startup(); return FALSE; } + LLInventoryModelBackgroundFetch::instance().start(); - LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLAppearanceMgr::instance().initCOFID(); + LLUUID cof_id = LLAppearanceMgr::instance().getCOF(); LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); if (cof && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) @@ -2273,7 +2275,7 @@ bool idle_startup() static LLFrameTimer wearables_timer; const F32 wearables_time = wearables_timer.getElapsedTimeF32(); - static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); + const F32 MAX_WEARABLES_TIME = 10.f; if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { @@ -2292,7 +2294,7 @@ bool idle_startup() display_startup(); - if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) + if (gAgent.isOutfitChosen() && (wearables_time > MAX_WEARABLES_TIME)) { if (gInventory.isInventoryUsable()) { @@ -2710,14 +2712,11 @@ void register_viewer_callbacks(LLMessageSystem* msg) LLViewerParcelMgr::processParcelDwellReply); msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); + &LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply); msg->setHandlerFunc("AvatarInterestsReply", &LLAvatarPropertiesProcessor::processAvatarInterestsReply); msg->setHandlerFunc("AvatarGroupsReply", &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - // ratings deprecated - //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, - // LLPanelAvatar::processAvatarStatisticsReply); msg->setHandlerFunc("AvatarNotesReply", &LLAvatarPropertiesProcessor::processAvatarNotesReply); msg->setHandlerFunc("AvatarPicksReply", @@ -2878,6 +2877,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); // Initiate creation of COF, since we're also bypassing that. gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + LLAppearanceMgr::getInstance()->initCOFID(); ESex gender; if (gender_name == "male") @@ -2990,7 +2990,9 @@ std::string LLStartUp::startupStateToString(EStartupState state) RTNENUM( STATE_AGENT_SEND ); RTNENUM( STATE_AGENT_WAIT ); RTNENUM( STATE_INVENTORY_SEND ); - RTNENUM(STATE_INVENTORY_CALLBACKS ); + RTNENUM( STATE_INVENTORY_CALLBACKS ); + RTNENUM( STATE_INVENTORY_SKEL ); + RTNENUM( STATE_INVENTORY_SEND2 ); RTNENUM( STATE_MISC ); RTNENUM( STATE_PRECACHE ); RTNENUM( STATE_WEARABLES_WAIT ); @@ -3033,6 +3035,7 @@ void reset_login() gAgent.cleanup(); gSky.cleanup(); // mVOSkyp is an inworld object. LLWorld::getInstance()->resetClass(); + LLAppearanceMgr::getInstance()->cleanup(); if ( gViewerWindow ) { // Hide menus and normal buttons diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index a59e33b6ba..5c31ad4feb 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -128,7 +128,7 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id) void LLSysWellWindow::initChannel() { LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( - LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID); mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel); if(NULL == mChannel) { diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e73ebd528e..77c28bd3f4 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -348,13 +348,13 @@ private: } // Threads: Tid - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) + virtual void completed(bool success, const std::string& error_message, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) { LL_PROFILE_ZONE_SCOPED; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { - worker->callbackDecoded(success, raw, aux, request_id); + worker->callbackDecoded(success, error_message, raw, aux, request_id); } } private: @@ -398,7 +398,7 @@ public: void callbackCacheWrite(bool success); // Threads: Tid - void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id); + void callbackDecoded(bool success, const std::string& error_message, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id); // Threads: T* void setGetStatus(LLCore::HttpStatus status, const std::string& reason) @@ -2319,7 +2319,7 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success) ////////////////////////////////////////////////////////////////////////////// // Threads: Tid -void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id) +void LLTextureFetchWorker::callbackDecoded(bool success, const std::string &error_message, LLImageRaw* raw, LLImageRaw* aux, S32 decode_id) { LLMutexLock lock(&mWorkMutex); // +Mw if (mDecodeHandle == 0) @@ -2354,7 +2354,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag } else { - LL_WARNS(LOG_TXT) << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << LL_ENDL; + LL_WARNS(LOG_TXT) << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << ", reason: " << error_message << LL_ENDL; removeFromCache(); mDecodedDiscard = -1; // Redundant, here for clarity and paranoia } diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 3da0ab779a..ea35a09f05 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -424,14 +424,12 @@ void LLAvatarTexBar::draw() text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); line_num++; } - const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); LLColor4 header_color(1.f, 1.f, 1.f, 0.9f); - const std::string texture_timeout_str = texture_timeout ? llformat("%d",texture_timeout) : "Disabled"; const std::string override_tex_discard_level_str = override_tex_discard_level ? llformat("%d",override_tex_discard_level) : "Disabled"; - std::string header_text = llformat("[ Timeout('AvatarBakedTextureUploadTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str()); + std::string header_text = llformat("[ Timeout:60 ] [ LOD_Override('TextureDiscardLevel'):%s ]", override_tex_discard_level_str.c_str()); LLFontGL::getFontMonospace()->renderUTF8(header_text, 0, l_offset, v_offset + line_height*line_num, header_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); line_num++; diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index c873167729..a3b2c79015 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -90,6 +90,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal std::string edit_text_contents; S32 edit_text_max_chars = 0; bool is_password = false; + bool allow_emoji = false; LLToastPanel::setBackgroundVisible(FALSE); LLToastPanel::setBackgroundOpaque(TRUE); @@ -134,6 +135,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal edit_text_contents = (*it)["value"].asString(); edit_text_name = (*it)["name"].asString(); edit_text_max_chars = (*it)["max_length_chars"].asInteger(); + allow_emoji = (*it)["allow_emoji"].asBoolean(); } else if (type == "password") { @@ -292,6 +294,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight()); mLineEditor->setRect(leditor_rect); mLineEditor->setMaxTextChars(edit_text_max_chars); + mLineEditor->setAllowEmoji(allow_emoji); mLineEditor->setText(edit_text_contents); std::string notif_name = mNotification->getName(); @@ -497,10 +500,9 @@ void LLToastAlertPanel::draw() } static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); - static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 5); gl_drop_shadow( 0, LLToastPanel::getRect().getHeight(), LLToastPanel::getRect().getWidth(), 0, - shadow_color, shadow_lines); + shadow_color, DROP_SHADOW_FLOATER); LLToastPanel::draw(); } diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index dc5d9c9e1f..a091370ee8 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -50,14 +50,15 @@ S32 BUTTON_WIDTH = 90; //static -const LLFontGL* LLToastNotifyPanel::sFont = NULL; -const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; +const std::string LLToastNotifyPanel::sFontDefault("Emoji"); +const std::string LLToastNotifyPanel::sFontScript("SansSerif"); LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal; LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, const LLRect& rect, bool show_images) -: LLCheckBoxToastPanel(notification), - LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision>(notification->getID()) +: LLCheckBoxToastPanel(notification) +, LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision>(notification->getID()) +, mTextBox(NULL) { init(rect, show_images); } @@ -85,11 +86,15 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt mBtnCallbackData.push_back(userdata); LLButton::Params p; - bool make_small_btn = form_element["index"].asInteger() == -1 || form_element["index"].asInteger() == -2; - const LLFontGL* font = make_small_btn ? sFontSmall: sFont; // for block and ignore buttons in script dialog - p.name = form_element["name"].asString(); - p.label = form_element["text"].asString(); - p.tool_tip = form_element["text"].asString(); + S32 index = form_element["index"].asInteger(); + std::string name = form_element["name"].asString(); + std::string text = form_element["text"].asString(); + bool make_small_btn = index == -1 || index == -2; // for block and ignore buttons in script dialog + const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor( + mIsScriptDialog ? sFontScript : sFontDefault, make_small_btn ? "Small" : "Medium", 0)); + p.name = name; + p.label = text; + p.tool_tip = text; p.font = font; p.rect.height = BTN_HEIGHT; p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata)); @@ -256,19 +261,12 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) { deleteAllChildren(); - mTextBox = NULL; - mInfoPanel = NULL; - mControlPanel = NULL; - mNumOptions = 0; - mNumButtons = 0; - mAddedDefaultBtn = false; - LLRect current_rect = getRect(); setXMLFilename(""); buildFromFile("panel_notification.xml"); - if(rect != LLRect::null) + if (rect != LLRect::null) { this->setShape(rect); } @@ -295,12 +293,6 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) // setup parameters // get a notification message mMessage = mNotification->getMessage(); - // init font variables - if (!sFont) - { - sFont = LLFontGL::getFontSansSerif(); - sFontSmall = LLFontGL::getFontSansSerifSmall(); - } // initialize setFocusRoot(!mIsTip); // get a form for the notification @@ -318,15 +310,18 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) if (mIsCaution && !mIsTip) { mTextBox = getChild<LLTextBox>("caution_text_box"); + mTextBox->setFont(LLFontGL::getFont(LLFontDescriptor(mIsScriptDialog ? sFontScript : sFontDefault, "Medium", LLFontGL::BOLD))); } else { mTextBox = getChild<LLTextEditor>("text_editor_box"); + mTextBox->setFont(LLFontGL::getFont(LLFontDescriptor(mIsScriptDialog ? sFontScript : sFontDefault, "Medium", 0))); } mTextBox->setMaxTextLength(LLToastPanel::MAX_TEXT_LENGTH); mTextBox->setVisible(TRUE); mTextBox->setPlainText(!show_images); + mTextBox->setUseEmoji(!mIsScriptDialog); mTextBox->setContentTrusted(is_content_trusted); mTextBox->setValue(mNotification->getMessage()); mTextBox->setIsFriendCallback(LLAvatarActions::isFriend); @@ -438,6 +433,21 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) } } +void LLToastNotifyPanel::deleteAllChildren() +{ + // some visibility changes, re-init and reshape will attempt to + // use mTextBox or other variables. Reset to avoid crashes + // and other issues. + mTextBox = NULL; + mInfoPanel = NULL; + mControlPanel = NULL; + mNumOptions = 0; + mNumButtons = 0; + mAddedDefaultBtn = false; + + LLCheckBoxToastPanel::deleteAllChildren(); +} + bool LLToastNotifyPanel::isControlPanelEnabled() const { bool cp_enabled = mControlPanel->getEnabled(); diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h index 952841a012..66e9ff238d 100644 --- a/indra/newview/lltoastnotifypanel.h +++ b/indra/newview/lltoastnotifypanel.h @@ -63,6 +63,7 @@ public: LLToastNotifyPanel(const LLNotificationPtr& pNotification, const LLRect& rect = LLRect::null, bool show_images = true); virtual void init( LLRect rect, bool show_images ); + virtual void deleteAllChildren(); virtual ~LLToastNotifyPanel(); LLPanel * getControlPanel() { return mControlPanel; } @@ -102,9 +103,9 @@ protected: //std::vector<index_button_pair_t> mButtons; // panel elements - LLTextBase* mTextBox; - LLPanel* mInfoPanel; // a panel, that contains an information - LLPanel* mControlPanel; // a panel, that contains buttons (if present) + LLTextBase* mTextBox { nullptr }; + LLPanel* mInfoPanel { nullptr }; // panel for text information + LLPanel* mControlPanel { nullptr }; // panel for buttons (if present) // internal handler for button being clicked static void onClickButton(void* data); @@ -124,17 +125,17 @@ protected: */ //void disableRespondedOptions(const LLNotificationPtr& notification); - bool mIsTip; - bool mAddedDefaultBtn; - bool mIsScriptDialog; - bool mIsCaution; + bool mIsTip { false }; + bool mAddedDefaultBtn { false }; + bool mIsScriptDialog { false }; + bool mIsCaution { false }; std::string mMessage; - S32 mNumOptions; - S32 mNumButtons; + S32 mNumOptions { 0 }; + S32 mNumButtons { 0 }; - static const LLFontGL* sFont; - static const LLFontGL* sFontSmall; + static const std::string sFontDefault; + static const std::string sFontScript; }; class LLIMToastNotifyPanel : public LLToastNotifyPanel diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 8a118232d0..abf9748db3 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -301,12 +301,10 @@ void LLToolDragAndDrop::setDragStart(S32 x, S32 y) BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y) { - static LLCachedControl<S32> drag_and_drop_threshold(gSavedSettings,"DragAndDropDistanceThreshold", 3); - S32 mouse_delta_x = x - mDragStartX; S32 mouse_delta_y = y - mDragStartY; - return (mouse_delta_x * mouse_delta_x) + (mouse_delta_y * mouse_delta_y) > drag_and_drop_threshold * drag_and_drop_threshold; + return (mouse_delta_x * mouse_delta_x) + (mouse_delta_y * mouse_delta_y) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD; } void LLToolDragAndDrop::beginDrag(EDragAndDropType type, @@ -569,12 +567,13 @@ BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask) BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, MASK mask) { + const F32 DRAG_N_DROP_TOOLTIP_DELAY = 0.10000000149f; if (!mToolTipMsg.empty()) { LLToolTipMgr::instance().unblockToolTips(); LLToolTipMgr::instance().show(LLToolTip::Params() .message(mToolTipMsg) - .delay_time(gSavedSettings.getF32( "DragAndDropToolTipDelay" ))); + .delay_time(DRAG_N_DROP_TOOLTIP_DELAY)); return TRUE; } return FALSE; diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index e1b8796535..fa55c8ed9a 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -223,6 +223,13 @@ BOOL LLVisualParamHint::render() LLVector3 target_pos = target_joint_pos + (target_offset * avatar_rotation); F32 cam_angle_radians = mVisualParam->getCameraAngle() * DEG_TO_RAD; + + static LLCachedControl<bool> auto_camera_position(gSavedSettings, "AppearanceCameraMovement"); + if (!auto_camera_position) + { + cam_angle_radians += F_PI; + } + LLVector3 camera_snapshot_offset( mVisualParam->getCameraDistance() * cosf( cam_angle_radians ), mVisualParam->getCameraDistance() * sinf( cam_angle_radians ), diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index def9b5e778..b8cfc5fbe2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -86,8 +86,8 @@ LLToolPie::LLToolPie() mMouseSteerX(-1), mMouseSteerY(-1), mClickAction(0), - mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), - mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ), + mClickActionBuyEnabled( TRUE ), + mClickActionPayEnabled( TRUE ), mDoubleClickTimer() { } @@ -756,8 +756,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { S32 delta_x = x - mMouseDownX; S32 delta_y = y - mMouseDownY; - S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold"); - if (delta_x * delta_x + delta_y * delta_y > threshold * threshold) + if (delta_x * delta_x + delta_y * delta_y > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD) { startCameraSteering(); steerCameraWithMouse(x, y); @@ -1089,6 +1088,8 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l final_name = LLTrans::getString("TooltipPerson");; } + const F32 INSPECTOR_TOOLTIP_DELAY = 0.35f; + LLInspector::Params p; p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); p.message(final_name); @@ -1096,7 +1097,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); p.visible_time_near(6.f); p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); + p.delay_time(INSPECTOR_TOOLTIP_DELAY); p.wrap(false); LLToolTipMgr::instance().show(p); diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp index fc90b4fbed..e019af2fe8 100644 --- a/indra/newview/lluploaddialog.cpp +++ b/indra/newview/lluploaddialog.cpp @@ -149,6 +149,7 @@ void LLUploadDialog::setMessage( const std::string& msg) LLUploadDialog::~LLUploadDialog() { + gViewerWindow->removePopup(this); gFocusMgr.releaseFocusIfNeeded( this ); // LLFilePicker::instance().reset(); diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index cf6e021cb8..c3b6167a7e 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -62,7 +62,7 @@ void LLURLLineEditor::cut() deleteSelection(); // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); if( need_to_rollback ) { rollback.doRollback( this ); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index b2072218ac..a080e3dd9e 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -417,7 +417,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec)) { errorMessage = llformat("Problem with file %s:\n\n%s\n", - getFileName().c_str(), LLImage::getLastError().c_str()); + getFileName().c_str(), LLImage::getLastThreadError().c_str()); errorLabel = "ProblemWithFile"; error = true; } diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index b93fc5d2fb..e9163abb4f 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -48,6 +48,8 @@ #include "llstreamingaudio.h" ///////////////////////////////////////////////////////// +const U32 FMODEX_DECODE_BUFFER_SIZE = 1000; // in milliseconds +const U32 FMODEX_STREAM_BUFFER_SIZE = 7000; // in milliseconds LLViewerAudio::LLViewerAudio() : mDone(true), @@ -116,7 +118,7 @@ void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if (stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"), gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(FMODEX_STREAM_BUFFER_SIZE, FMODEX_DECODE_BUFFER_SIZE); gAudiop->startInternetStream(mNextStreamURI); } @@ -183,7 +185,7 @@ bool LLViewerAudio::onIdleUpdate() LL_DEBUGS("AudioEngine") << "Audio fade in: " << mNextStreamURI << LL_ENDL; LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(FMODEX_STREAM_BUFFER_SIZE, FMODEX_DECODE_BUFFER_SIZE); gAudiop->startInternetStream(mNextStreamURI); } @@ -418,12 +420,19 @@ void audio_update_volume(bool force_update) gAudiop->setMasterGain ( master_volume ); - gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); + const F32 AUDIO_LEVEL_DOPPLER = 1.f; + gAudiop->setDopplerFactor(AUDIO_LEVEL_DOPPLER); if(!LLViewerCamera::getInstance()->cameraUnderWater()) - gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); + { + const F32 AUDIO_LEVEL_ROLLOFF = 1.f; + gAudiop->setRolloffFactor(AUDIO_LEVEL_ROLLOFF); + } else - gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff")); + { + const F32 AUDIO_LEVEL_UNDERWATER_ROLLOFF = 5.f; + gAudiop->setRolloffFactor(AUDIO_LEVEL_UNDERWATER_ROLLOFF); + } gAudiop->setMuted(mute_audio || progress_view_visible); @@ -532,8 +541,8 @@ void audio_update_wind(bool force_update) // whereas steady-state avatar walk velocity is only 3.2 m/s. // Without this the world feels desolate on first login when you are // standing still. - static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f); - LLVector3 scaled_wind_vec = gWindVec * wind_level; + const F32 WIND_LEVEL = 0.5f; + LLVector3 scaled_wind_vec = gWindVec * WIND_LEVEL; // Mix in the avatar's motion, subtract because when you walk north, // the apparent wind moves south. diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 9f2e9a62b7..b69f1aa41b 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -359,15 +359,6 @@ static bool handleChatFontSizeChanged(const LLSD& newvalue) return true; } -static bool handleChatPersistTimeChanged(const LLSD& newvalue) -{ - if(gConsole) - { - gConsole->setLinePersistTime((F32) newvalue.asReal()); - } - return true; -} - static bool handleConsoleMaxLinesChanged(const LLSD& newvalue) { if(gConsole) @@ -657,6 +648,18 @@ void handleUserTargetDrawDistanceChanged(const LLSD& newValue) LLPerfStats::tunables.userTargetDrawDistance = newval; } +void handleUserMinDrawDistanceChanged(const LLSD &newValue) +{ + const auto newval = gSavedSettings.getF32("AutoTuneRenderFarClipMin"); + LLPerfStats::tunables.userMinDrawDistance = newval; +} + +void handleUserTargetReflectionsChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getS32("UserTargetReflections"); + LLPerfStats::tunables.userTargetReflections = newval; +} + void handlePerformanceStatsEnabledChanged(const LLSD& newValue) { const auto newval = gSavedSettings.getBOOL("PerfStatsCaptureEnabled"); @@ -770,7 +773,6 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); setting_setup_signal_listener(gSavedSettings, "ChatFontSize", handleChatFontSizeChanged); - setting_setup_signal_listener(gSavedSettings, "ChatPersistTime", handleChatPersistTimeChanged); setting_setup_signal_listener(gSavedSettings, "ConsoleMaxLines", handleConsoleMaxLinesChanged); setting_setup_signal_listener(gSavedSettings, "UploadBakedTexOld", handleUploadBakedTexOldChanged); setting_setup_signal_listener(gSavedSettings, "UseOcclusion", handleUseOcclusionChanged); @@ -781,9 +783,6 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "AudioLevelMusic", handleAudioVolumeChanged); setting_setup_signal_listener(gSavedSettings, "AudioLevelMedia", handleAudioVolumeChanged); setting_setup_signal_listener(gSavedSettings, "AudioLevelVoice", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelDoppler", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelRolloff", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelUnderwaterRolloff", handleAudioVolumeChanged); setting_setup_signal_listener(gSavedSettings, "MuteAudio", handleAudioVolumeChanged); setting_setup_signal_listener(gSavedSettings, "MuteMusic", handleAudioVolumeChanged); setting_setup_signal_listener(gSavedSettings, "MuteMedia", handleAudioVolumeChanged); @@ -869,6 +868,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderAvatarMaxART", handleRenderAvatarMaxARTChanged); setting_setup_signal_listener(gSavedSettings, "PerfStatsCaptureEnabled", handlePerformanceStatsEnabledChanged); setting_setup_signal_listener(gSavedSettings, "AutoTuneRenderFarClipTarget", handleUserTargetDrawDistanceChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneRenderFarClipMin", handleUserMinDrawDistanceChanged); setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorFarAwayDistance", handleUserImpostorDistanceChanged); setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged); setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged); @@ -899,8 +899,6 @@ DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"]; DECL_LLCC(LLSD, test_llsd); -static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment"); - void test_cached_control() { #define do { TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL; } while(0) @@ -917,8 +915,6 @@ void test_cached_control() TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); //There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - - if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; } #endif // TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 75e5049370..d65b44fd3a 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -214,11 +214,11 @@ void display_update_camera() void display_stats() { LL_PROFILE_ZONE_SCOPED - F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency"); - if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) + const F32 FPS_LOG_FREQUENCY = 10.f; + if (gRecentFPSTime.getElapsedTimeF32() >= FPS_LOG_FREQUENCY) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS"); - F32 fps = gRecentFrameCount / fps_log_freq; + F32 fps = gRecentFrameCount / FPS_LOG_FREQUENCY; LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL; gRecentFrameCount = 0; gRecentFPSTime.reset(); @@ -233,8 +233,8 @@ void display_stats() LLMemory::logMemoryInfo(TRUE) ; gRecentMemoryTime.reset(); } - F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency"); - if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq) + const F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f; + if (gAssetStorageLogTime.getElapsedTimeF32() >= ASSET_STORAGE_LOG_FREQUENCY) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage"); gAssetStorageLogTime.reset(); diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index c09e6a433a..3a3f0b3d95 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -227,8 +227,18 @@ std::string string_from_guid(const GUID &guid) return res; } +#elif LL_DARWIN + +bool macos_devices_callback(std::string &product_name, LLSD &data, void* userdata) +{ + std::string product = data["product"].asString(); + + return LLViewerJoystick::getInstance()->initDevice(nullptr, product, data); +} + #endif + // ----------------------------------------------------------------------------- void LLViewerJoystick::updateEnabled(bool autoenable) { @@ -365,25 +375,48 @@ void LLViewerJoystick::init(bool autoenable) { if (mNdofDev) { + U32 device_type = 0; + void* win_callback = nullptr; + std::function<bool(std::string&, LLSD&, void*)> osx_callback; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; - void* callback = NULL; + device_type = DI8DEVCLASS_GAMECTRL; + win_callback = &di8_devices_callback; +#elif LL_DARWIN + osx_callback = macos_devices_callback; + + if (mLastDeviceUUID.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + + if (ndof_init_first(mNdofDev, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // No device found + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; + } + } #endif - if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + if (mDriverState != JDS_INITIALIZED) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - mLastDeviceUUID = LLSD(); - void *preffered_device = NULL; - initDevice(preffered_device); + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices, init first suitable one + mLastDeviceUUID = LLSD(); + void *preffered_device = NULL; + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -438,27 +471,49 @@ void LLViewerJoystick::initDevice(LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; + U32 device_type = 0; + void* win_callback = nullptr; + std::function<bool(std::string&, LLSD&, void*)> osx_callback; + mDriverState = JDS_INITIALIZING; #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; - void* callback = NULL; + device_type = DI8DEVCLASS_GAMECTRL; + win_callback = &di8_devices_callback; +#elif LL_DARWIN + osx_callback = macos_devices_callback; + if (mLastDeviceUUID.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + + if (ndof_init_first(mNdofDev, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // Np other device present + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; + } + } #endif - mDriverState = JDS_INITIALIZING; - if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + if (mDriverState != JDS_INITIALIZED) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - void *preffered_device = NULL; - mLastDeviceUUID = LLSD(); - initDevice(preffered_device); + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices from window, init first suitable one + void *preffered_device = NULL; + mLastDeviceUUID = LLSD(); + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -469,19 +524,37 @@ void LLViewerJoystick::initDevice(LLSD &guid) #endif } -void LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) +bool LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; +#if LL_DARWIN + if (guid.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + } + else + { + mNdofDev->product[0] = '\0'; + mNdofDev->manufacturer[0] = '\0'; + } +#else strncpy(mNdofDev->product, name.c_str(), sizeof(mNdofDev->product)); mNdofDev->manufacturer[0] = '\0'; +#endif - initDevice(preffered_device); + return initDevice(preffered_device); +#else + return false; #endif } -void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) +bool LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) { #if LIB_NDOF // Different joysticks will return different ranges of raw values. @@ -511,8 +584,10 @@ void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE else { mDriverState = JDS_INITIALIZED; + return true; } #endif + return false; } // ----------------------------------------------------------------------------- @@ -1320,6 +1395,8 @@ bool LLViewerJoystick::isDeviceUUIDSet() #if LL_WINDOWS && !LL_MESA_HEADLESS // for ease of comparison and to dial less with platform specific variables, we store id as LLSD binary return mLastDeviceUUID.isBinary(); +#elif LL_DARWIN + return mLastDeviceUUID.isMap(); #else return false; #endif @@ -1346,19 +1423,48 @@ std::string LLViewerJoystick::getDeviceUUIDString() { return std::string(); } +#elif LL_DARWIN + if (mLastDeviceUUID.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + return manufacturer + ":" + product; + } + else + { + return std::string(); + } #else return std::string(); - // return mLastDeviceUUID; +#endif +} + +void LLViewerJoystick::saveDeviceIdToSettings() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // can't save as binary directly, + // someone editing the xml will corrupt it + // so convert to string first + std::string device_string = getDeviceUUIDString(); + gSavedSettings.setLLSD("JoystickDeviceUUID", LLSD(device_string)); +#else + LLSD device_id = getDeviceUUID(); + gSavedSettings.setLLSD("JoystickDeviceUUID", device_id); #endif } void LLViewerJoystick::loadDeviceIdFromSettings() { + LLSD dev_id = gSavedSettings.getLLSD("JoystickDeviceUUID"); #if LL_WINDOWS && !LL_MESA_HEADLESS // We can't save binary data to gSavedSettings, somebody editing the file will corrupt it, // so _GUID data gets converted to string (we probably can convert it to LLUUID with memcpy) // and here we need to convert it back to binary from string - std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); + std::string device_string; + if (dev_id.isString()) + { + device_string = dev_id.asString(); + } if (device_string.empty()) { mLastDeviceUUID = LLSD(); @@ -1372,10 +1478,22 @@ void LLViewerJoystick::loadDeviceIdFromSettings() LLSD::Binary data; //just an std::vector data.resize(size); memcpy(&data[0], &guid /*POD _GUID*/, size); - // We store this data in LLSD since LLSD is versatile and will be able to handle both GUID2 - // and any data MAC will need for device selection + // We store this data in LLSD since it can handle both GUID2 and long mLastDeviceUUID = LLSD(data); } +#elif LL_DARWIN + if (!dev_id.isMap()) + { + mLastDeviceUUID = LLSD(); + } + else + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + LL_DEBUGS("Joystick") << "Looking for device by manufacturer: " << manufacturer << " and product: " << product << LL_ENDL; + // We store this data in LLSD since it can handle both GUID2 and long + mLastDeviceUUID = dev_id; + } #else mLastDeviceUUID = LLSD(); //mLastDeviceUUID = gSavedSettings.getLLSD("JoystickDeviceUUID"); diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index 47da263150..b459987c68 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -30,6 +30,9 @@ #include "stdtypes.h" #if LIB_NDOF +#if LL_DARWIN +#define TARGET_OS_MAC 1 +#endif #include "ndofdev_external.h" #else #define NDOF_Device void @@ -52,8 +55,8 @@ class LLViewerJoystick : public LLSingleton<LLViewerJoystick> public: void init(bool autoenable); void initDevice(LLSD &guid); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); void terminate(); void updateStatus(); @@ -76,6 +79,7 @@ public: LLSD getDeviceUUID(); //unconverted, OS dependent value wrapped into LLSD, for comparison/search std::string getDeviceUUIDString(); // converted readable value for settings std::string getDescription(); + void saveDeviceIdToSettings(); protected: void updateEnabled(bool autoenable); @@ -103,7 +107,11 @@ private: bool mCameraUpdated; bool mOverrideCamera; U32 mJoystickRun; - LLSD mLastDeviceUUID; // _GUID as U8 binary map, integer 1 for no device/ndof's device + + // Windows: _GUID as U8 binary map + // MacOS: long as an U8 binary map + // Else: integer 1 for no device/ndof's default device + LLSD mLastDeviceUUID; static F32 sLastDelta[7]; static F32 sDelta[7]; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8da467021d..4dcfb18b30 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7379,37 +7379,70 @@ class LLAttachmentDetach : public view_listener_t { // Called when the user clicked on an object attached to them // and selected "Detach". - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject *object = selection->getPrimaryObject(); if (!object) { LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; return true; } - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) + struct f: public LLSelectedObjectFunctor { - if(parent->isAvatar()) + f() : mAvatarsInSelection(false) {} + virtual bool apply(LLViewerObject* objectp) { - break; + if (!objectp) + { + return false; + } + + if (objectp->isAvatar()) + { + mAvatarsInSelection = true; + return false; + } + + LLViewerObject* parent = (LLViewerObject*)objectp->getParent(); + while (parent) + { + if (parent->isAvatar()) + { + break; + } + objectp = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + // std::set to avoid dupplicate 'roots' from linksets + mRemoveSet.insert(objectp->getAttachmentItemID()); + + return true; } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } + bool mAvatarsInSelection; + uuid_set_t mRemoveSet; + } func; + // Probbly can run applyToRootObjects instead, + // but previous version of this code worked for any selected object + selection->applyToObjects(&func); - if (!object) + if (func.mAvatarsInSelection) { - LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; + // Not possible under normal circumstances + // Either avatar selection is ON or has to do with animeshes + // Better stop this than mess something + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; return true; } - if (object->isAvatar()) + if (func.mRemoveSet.empty()) { - LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; + LL_WARNS() << "handle_detach() - no valid attachments in selection to detach" << LL_ENDL; return true; } - LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); + uuid_vec_t detach_list(func.mRemoveSet.begin(), func.mRemoveSet.end()); + LLAppearanceMgr::instance().removeItemsFromAvatar(detach_list); return true; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 6283a13148..192ebd1f39 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -972,7 +972,7 @@ void handle_compress_image(void*) } else { - LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; + LL_INFOS() << "Compression failed: " << LLImage::getLastThreadError() << LL_ENDL; } infile = picker.getNextFile(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 8cc2e80241..52bc2d9654 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1652,8 +1652,9 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, const LLUUID& blocked_id; }; - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel( + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID, + OfferMatcher(blocked_id)); } @@ -5779,8 +5780,9 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name) const LLUUID& blocked_id; }; - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(task_id)); + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel( + LLNotificationsUI::NOTIFICATION_CHANNEL_UUID, + OfferMatcher(task_id)); } static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 340a1de0d1..ac107aa15e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3973,20 +3973,13 @@ F32 LLViewerObject::recursiveGetEstTrianglesMax() const S32 LLViewerObject::getAnimatedObjectMaxTris() const { S32 max_tris = 0; - if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) + if (gAgent.getRegion()) { - max_tris = S32_MAX; - } - else - { - if (gAgent.getRegion()) + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("AnimatedObjects")) - { - max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); - } + max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); } } return max_tris; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 149595106d..17c0d00e79 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1526,6 +1526,12 @@ void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user) // static void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **user) { + if (LLApp::isExiting() || gDisconnected) + { + LL_DEBUGS("ParcelMgr") << "Ignoring parcel properties, shutting down" << LL_ENDL; + return; + } + S32 request_result; S32 sequence_id; BOOL snap_selection = FALSE; diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 6eb6bd8424..5c9dbcea76 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -50,18 +50,15 @@ #include "pipeline.h" -const U8 OVERLAY_IMG_COMPONENTS = 4; +static const U8 OVERLAY_IMG_COMPONENTS = 4; +static const F32 LINE_WIDTH = 0.0625f; LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters) : mRegion( region ), mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ), mDirty( FALSE ), mTimeSinceLastUpdate(), - mOverlayTextureIdx(-1), - mVertexCount(0), - mVertexArray(NULL), - mColorArray(NULL) -// mTexCoordArray(NULL), + mOverlayTextureIdx(-1) { // Create a texture to hold color information. // 4 components @@ -99,17 +96,6 @@ LLViewerParcelOverlay::~LLViewerParcelOverlay() { delete[] mOwnership; mOwnership = NULL; - - delete[] mVertexArray; - mVertexArray = NULL; - - delete[] mColorArray; - mColorArray = NULL; - -// JC No textures. -// delete mTexCoordArray; -// mTexCoordArray = NULL; - mImageRaw = NULL; } @@ -312,7 +298,6 @@ F32 LLViewerParcelOverlay::getOwnedRatio() const } return (F32)total / (F32)size; - } //--------------------------------------------------------------------------- @@ -329,14 +314,13 @@ F32 LLViewerParcelOverlay::getOwnedRatio() const // Note: Assumes that the ownership array and void LLViewerParcelOverlay::updateOverlayTexture() { - if (mOverlayTextureIdx < 0 && mDirty) - { - mOverlayTextureIdx = 0; - } if (mOverlayTextureIdx < 0) { - return; + if (!mDirty) + return; + mOverlayTextureIdx = 0; } + const LLColor4U avail = LLUIColorTable::instance().getColor("PropertyColorAvail").get(); const LLColor4U owned = LLUIColorTable::instance().getColor("PropertyColorOther").get(); const LLColor4U group = LLUIColorTable::instance().getColor("PropertyColorGroup").get(); @@ -441,38 +425,44 @@ void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay) setDirty(); } - void LLViewerParcelOverlay::updatePropertyLines() { - if (!gSavedSettings.getBOOL("ShowPropertyLines")) - return; + static LLCachedControl<bool> show(gSavedSettings, "ShowPropertyLines"); - S32 row, col; + if (!show) + return; - const LLColor4U self_coloru = LLUIColorTable::instance().getColor("PropertyColorSelf").get(); - const LLColor4U other_coloru = LLUIColorTable::instance().getColor("PropertyColorOther").get(); - const LLColor4U group_coloru = LLUIColorTable::instance().getColor("PropertyColorGroup").get(); - const LLColor4U for_sale_coloru = LLUIColorTable::instance().getColor("PropertyColorForSale").get(); - const LLColor4U auction_coloru = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); + LLColor4U colors[PARCEL_COLOR_MASK + 1]; + colors[PARCEL_SELF] = LLUIColorTable::instance().getColor("PropertyColorSelf").get(); + colors[PARCEL_OWNED] = LLUIColorTable::instance().getColor("PropertyColorOther").get(); + colors[PARCEL_GROUP] = LLUIColorTable::instance().getColor("PropertyColorGroup").get(); + colors[PARCEL_FOR_SALE] = LLUIColorTable::instance().getColor("PropertyColorForSale").get(); + colors[PARCEL_AUCTION] = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); - // Build into dynamic arrays, then copy into static arrays. - std::vector<LLVector3> new_vertex_array; - new_vertex_array.reserve(256); - std::vector<LLColor4U> new_color_array; - new_color_array.reserve(256); - std::vector<LLVector2> new_coord_array; - new_coord_array.reserve(256); + mEdges.clear(); - U8 overlay = 0; - BOOL add_edge = FALSE; const F32 GRID_STEP = PARCEL_GRID_STEP_METERS; const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge; - for (row = 0; row < GRIDS_PER_EDGE; row++) + for (S32 row = 0; row < GRIDS_PER_EDGE; row++) { - for (col = 0; col < GRIDS_PER_EDGE; col++) + for (S32 col = 0; col < GRIDS_PER_EDGE; col++) { - overlay = mOwnership[row*GRIDS_PER_EDGE+col]; + U8 overlay = mOwnership[row*GRIDS_PER_EDGE+col]; + S32 colorIndex = overlay & PARCEL_COLOR_MASK; + switch(colorIndex) + { + case PARCEL_SELF: + case PARCEL_GROUP: + case PARCEL_OWNED: + case PARCEL_FOR_SALE: + case PARCEL_AUCTION: + break; + default: + continue; + } + + const LLColor4U& color = colors[colorIndex]; F32 left = col*GRID_STEP; F32 right = left+GRID_STEP; @@ -483,259 +473,41 @@ void LLViewerParcelOverlay::updatePropertyLines() // West edge if (overlay & PARCEL_WEST_LINE) { - switch(overlay & PARCEL_COLOR_MASK) - { - case PARCEL_SELF: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, WEST, self_coloru); - break; - case PARCEL_GROUP: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, WEST, group_coloru); - break; - case PARCEL_OWNED: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, WEST, other_coloru); - break; - case PARCEL_FOR_SALE: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, WEST, for_sale_coloru); - break; - case PARCEL_AUCTION: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, WEST, auction_coloru); - break; - default: - break; - } + addPropertyLine(left, bottom, 0, 1, LINE_WIDTH, 0, color); } // East edge - if (col < GRIDS_PER_EDGE-1) + if (col == GRIDS_PER_EDGE - 1 || mOwnership[row * GRIDS_PER_EDGE + col + 1] & PARCEL_WEST_LINE) { - U8 east_overlay = mOwnership[row*GRIDS_PER_EDGE+col+1]; - add_edge = east_overlay & PARCEL_WEST_LINE; - } - else - { - add_edge = TRUE; - } - - if (add_edge) - { - switch(overlay & PARCEL_COLOR_MASK) - { - case PARCEL_SELF: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - right, bottom, EAST, self_coloru); - break; - case PARCEL_GROUP: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - right, bottom, EAST, group_coloru); - break; - case PARCEL_OWNED: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - right, bottom, EAST, other_coloru); - break; - case PARCEL_FOR_SALE: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - right, bottom, EAST, for_sale_coloru); - break; - case PARCEL_AUCTION: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - right, bottom, EAST, auction_coloru); - break; - default: - break; - } + addPropertyLine(right, bottom, 0, 1, -LINE_WIDTH, 0, color); } // South edge if (overlay & PARCEL_SOUTH_LINE) { - switch(overlay & PARCEL_COLOR_MASK) - { - case PARCEL_SELF: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, SOUTH, self_coloru); - break; - case PARCEL_GROUP: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, SOUTH, group_coloru); - break; - case PARCEL_OWNED: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, SOUTH, other_coloru); - break; - case PARCEL_FOR_SALE: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, SOUTH, for_sale_coloru); - break; - case PARCEL_AUCTION: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, bottom, SOUTH, auction_coloru); - break; - default: - break; - } + addPropertyLine(left, bottom, 1, 0, 0, LINE_WIDTH, color); } - // North edge - if (row < GRIDS_PER_EDGE-1) - { - U8 north_overlay = mOwnership[(row+1)*GRIDS_PER_EDGE+col]; - add_edge = north_overlay & PARCEL_SOUTH_LINE; - } - else - { - add_edge = TRUE; - } - - if (add_edge) + if (row == GRIDS_PER_EDGE - 1 || mOwnership[(row + 1) * GRIDS_PER_EDGE + col] & PARCEL_SOUTH_LINE) { - switch(overlay & PARCEL_COLOR_MASK) - { - case PARCEL_SELF: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, top, NORTH, self_coloru); - break; - case PARCEL_GROUP: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, top, NORTH, group_coloru); - break; - case PARCEL_OWNED: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, top, NORTH, other_coloru); - break; - case PARCEL_FOR_SALE: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, top, NORTH, for_sale_coloru); - break; - case PARCEL_AUCTION: - addPropertyLine(new_vertex_array, new_color_array, new_coord_array, - left, top, NORTH, auction_coloru); - break; - default: - break; - } + addPropertyLine(left, top, 1, 0, 0, -LINE_WIDTH, color); } } } - // Now copy into static arrays for faster rendering. - // Attempt to recycle old arrays if possible to avoid memory - // shuffling. - S32 new_vertex_count = new_vertex_array.size(); - - if (!(mVertexArray && mColorArray && new_vertex_count == mVertexCount)) - { - // ...need new arrays - delete[] mVertexArray; - mVertexArray = NULL; - delete[] mColorArray; - mColorArray = NULL; - - mVertexCount = new_vertex_count; - - if (new_vertex_count > 0) - { - mVertexArray = new F32[3 * mVertexCount]; - mColorArray = new U8 [4 * mVertexCount]; - } - } - - // Copy the new data into the arrays - S32 i; - F32* vertex = mVertexArray; - for (i = 0; i < mVertexCount; i++) - { - const LLVector3& point = new_vertex_array.at(i); - *vertex = point.mV[VX]; - vertex++; - *vertex = point.mV[VY]; - vertex++; - *vertex = point.mV[VZ]; - vertex++; - } - - U8* colorp = mColorArray; - for (i = 0; i < mVertexCount; i++) - { - const LLColor4U& color = new_color_array.at(i); - *colorp = color.mV[VRED]; - colorp++; - *colorp = color.mV[VGREEN]; - colorp++; - *colorp = color.mV[VBLUE]; - colorp++; - *colorp = color.mV[VALPHA]; - colorp++; - } - // Everything's clean now mDirty = FALSE; } - -void LLViewerParcelOverlay::addPropertyLine( - std::vector<LLVector3>& vertex_array, - std::vector<LLColor4U>& color_array, - std::vector<LLVector2>& coord_array, - const F32 start_x, const F32 start_y, - const U32 edge, - const LLColor4U& color) +void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F32 dy, F32 tick_dx, F32 tick_dy, const LLColor4U& color) { - LLColor4U underwater( color ); - underwater.mV[VALPHA] /= 2; - - vertex_array.reserve(16); - color_array.reserve(16); - coord_array.reserve(16); - LLSurface& land = mRegion->getLand(); + F32 water_z = land.getWaterHeight(); - F32 dx; - F32 dy; - F32 tick_dx; - F32 tick_dy; - //const F32 LINE_WIDTH = 0.125f; - const F32 LINE_WIDTH = 0.0625f; - - switch(edge) - { - case WEST: - dx = 0.f; - dy = 1.f; - tick_dx = LINE_WIDTH; - tick_dy = 0.f; - break; - - case EAST: - dx = 0.f; - dy = 1.f; - tick_dx = -LINE_WIDTH; - tick_dy = 0.f; - break; - - case NORTH: - dx = 1.f; - dy = 0.f; - tick_dx = 0.f; - tick_dy = -LINE_WIDTH; - break; - - case SOUTH: - dx = 1.f; - dy = 0.f; - tick_dx = 0.f; - tick_dy = LINE_WIDTH; - break; - - default: - LL_ERRS() << "Invalid edge in addPropertyLine" << LL_ENDL; - return; - } + mEdges.resize(mEdges.size() + 1); + Edge& edge = mEdges.back(); + edge.color = color; F32 outside_x = start_x; F32 outside_y = start_y; @@ -744,14 +516,31 @@ void LLViewerParcelOverlay::addPropertyLine( F32 inside_y = start_y + tick_dy; F32 inside_z = 0.f; + auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part) + { + F32 new_x = start.mV[0] + (x - start.mV[0]) * part; + F32 new_y = start.mV[1] + (y - start.mV[1]) * part; + F32 new_z = start.mV[2] + (z - start.mV[2]) * part; + edge.vertices.emplace_back(new_x, new_y, new_z); + }; + + auto checkForSplit = [&]() + { + const LLVector3& last_outside = edge.vertices.back(); + F32 z0 = last_outside.mV[2]; + F32 z1 = outside_z; + if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) + return; + F32 part = (water_z - z0) / (z1 - z0); + const LLVector3& last_inside = edge.vertices[edge.vertices.size() - 2]; + split(last_inside, inside_x, inside_y, inside_z, part); + split(last_outside, outside_x, outside_y, outside_z, part); + }; + // First part, only one vertex outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (outside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - vertex_array.push_back( LLVector3(outside_x, outside_y, outside_z) ); - coord_array.push_back( LLVector2(outside_x - start_x, 0.f) ); + edge.vertices.emplace_back(outside_x, outside_y, outside_z); inside_x += dx * LINE_WIDTH; inside_y += dy * LINE_WIDTH; @@ -763,17 +552,8 @@ void LLViewerParcelOverlay::addPropertyLine( inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - if (outside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - vertex_array.push_back( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.push_back( LLVector3(outside_x, outside_y, outside_z) ); - - coord_array.push_back( LLVector2(outside_x - start_x, 1.f) ); - coord_array.push_back( LLVector2(outside_x - start_x, 0.f) ); + edge.vertices.emplace_back(inside_x, inside_y, inside_z); + edge.vertices.emplace_back(outside_x, outside_y, outside_z); inside_x += dx * (dx - LINE_WIDTH); inside_y += dy * (dy - LINE_WIDTH); @@ -782,24 +562,16 @@ void LLViewerParcelOverlay::addPropertyLine( outside_y += dy * (dy - LINE_WIDTH); // Middle part, full width - S32 i; const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS ); - for (i = 1; i < GRID_STEP; i++) + for (S32 i = 1; i < GRID_STEP; i++) { inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - if (outside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); + checkForSplit(); - vertex_array.push_back( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.push_back( LLVector3(outside_x, outside_y, outside_z) ); - - coord_array.push_back( LLVector2(outside_x - start_x, 1.f) ); - coord_array.push_back( LLVector2(outside_x - start_x, 0.f) ); + edge.vertices.emplace_back(inside_x, inside_y, inside_z); + edge.vertices.emplace_back(outside_x, outside_y, outside_z); inside_x += dx; inside_y += dy; @@ -818,20 +590,10 @@ void LLViewerParcelOverlay::addPropertyLine( inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - if (outside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); + checkForSplit(); - vertex_array.push_back( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.push_back( LLVector3(outside_x, outside_y, outside_z) ); - - coord_array.push_back( LLVector2(outside_x - start_x, 1.f) ); - coord_array.push_back( LLVector2(outside_x - start_x, 0.f) ); - - inside_x += dx * LINE_WIDTH; - inside_y += dy * LINE_WIDTH; + edge.vertices.emplace_back(inside_x, inside_y, inside_z); + edge.vertices.emplace_back(outside_x, outside_y, outside_z); outside_x += dx * LINE_WIDTH; outside_y += dy * LINE_WIDTH; @@ -839,14 +601,9 @@ void LLViewerParcelOverlay::addPropertyLine( // Last edge is not drawn to the edge outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (outside_z > 20.f) color_array.push_back( color ); - else color_array.push_back( underwater ); - - vertex_array.push_back( LLVector3(outside_x, outside_y, outside_z) ); - coord_array.push_back( LLVector2(outside_x - start_x, 0.f) ); + edge.vertices.emplace_back(outside_x, outside_y, outside_z); } - void LLViewerParcelOverlay::setDirty() { mDirty = TRUE; @@ -882,18 +639,15 @@ void LLViewerParcelOverlay::idleUpdate(bool force_update) } } -S32 LLViewerParcelOverlay::renderPropertyLines () +void LLViewerParcelOverlay::renderPropertyLines() { - if (!gSavedSettings.getBOOL("ShowPropertyLines")) - { - return 0; - } - if (!mVertexArray || !mColorArray) - { - return 0; - } + static LLCachedControl<bool> show(gSavedSettings, "ShowPropertyLines"); + + if (!show) + return; LLSurface& land = mRegion->getLand(); + F32 water_z = land.getWaterHeight() + 0.01f; LLGLSUIDefault gls_ui; // called from pipeline gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -920,16 +674,11 @@ S32 LLViewerParcelOverlay::renderPropertyLines () // Move to appropriate region coords LLVector3 origin = mRegion->getOriginAgent(); - gGL.translatef( origin.mV[VX], origin.mV[VY], origin.mV[VZ] ); + gGL.translatef(origin.mV[VX], origin.mV[VY], origin.mV[VZ]); gGL.translatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY], pull_toward_camera.mV[VZ]); - // Include +1 because vertices are fenceposts. - // *2 because it's a quad strip - const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS ); - const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3; - // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() ); @@ -939,91 +688,68 @@ S32 LLViewerParcelOverlay::renderPropertyLines () cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS; cull_plane_point += camera_region; - LLVector3 vertex; - - const S32 BYTES_PER_COLOR = 4; - const S32 FLOATS_PER_VERTEX = 3; - //const S32 FLOATS_PER_TEX_COORD = 2; - S32 i, j; - S32 drawn = 0; - F32* vertexp; - U8* colorp; bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; - for (i = 0; i < mVertexCount; i += vertex_per_edge) + for (const Edge& edge : mEdges) { - colorp = mColorArray + BYTES_PER_COLOR * i; - vertexp = mVertexArray + FLOATS_PER_VERTEX * i; - - vertex.mV[VX] = *(vertexp); - vertex.mV[VY] = *(vertexp+1); - vertex.mV[VZ] = *(vertexp+2); + LLVector3 center = edge.vertices[edge.vertices.size() >> 1]; - if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED) + if (dist_vec_squared2D(center, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; } // Destroy vertex, transform to plane-local. - vertex -= cull_plane_point; + center -= cull_plane_point; - // negative dot product means it is in back of the plane - if ( vertex * CAMERA_AT < 0.f ) + // Negative dot product means it is in back of the plane + if (center * CAMERA_AT < 0.f) { continue; } gGL.begin(LLRender::TRIANGLE_STRIP); - for (j = 0; j < vertex_per_edge; j++) - { - gGL.color4ubv(colorp); - gGL.vertex3fv(vertexp); + gGL.color4ubv(edge.color.mV); - colorp += BYTES_PER_COLOR; - vertexp += FLOATS_PER_VERTEX; + for (const LLVector3& vertex : edge.vertices) + { + if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z) + { + gGL.vertex3fv(vertex.mV); + } + else + { + LLVector3 visible = vertex; + visible.mV[2] = water_z; + gGL.vertex3fv(visible.mV); + } } - drawn += vertex_per_edge; - gGL.end(); if (render_hidden) { LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - colorp = mColorArray + BYTES_PER_COLOR * i; - vertexp = mVertexArray + FLOATS_PER_VERTEX * i; - gGL.begin(LLRender::TRIANGLE_STRIP); - for (j = 0; j < vertex_per_edge; j++) - { - U8 color[4]; - color[0] = colorp[0]; - color[1] = colorp[1]; - color[2] = colorp[2]; - color[3] = colorp[3]/4; + LLColor4U color = edge.color; + color.mV[3] /= 4; + gGL.color4ubv(color.mV); - gGL.color4ubv(color); - gGL.vertex3fv(vertexp); - - colorp += BYTES_PER_COLOR; - vertexp += FLOATS_PER_VERTEX; + for (const LLVector3& vertex : edge.vertices) + { + gGL.vertex3fv(vertex.mV); } - drawn += vertex_per_edge; - gGL.end(); } - } gGL.popMatrix(); - - return drawn; } // Draw half of a single cell (no fill) in a grid drawn from left to right and from bottom to top @@ -1047,11 +773,9 @@ void grid_2d_part_lines(const F32 left, const F32 top, const F32 right, const F3 void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color) { - if (!mOwnership) - { - return; - } - if (!gSavedSettings.getBOOL("MiniMapShowPropertyLines")) + static LLCachedControl<bool> show(gSavedSettings, "MiniMapShowPropertyLines"); + + if (!mOwnership || !show) { return; } @@ -1066,11 +790,11 @@ void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_me gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glLineWidth(1.0f); gGL.color4fv(parcel_outline_color); - for (S32 i = 0; i < GRIDS_PER_EDGE + 1; i++) + for (S32 i = 0; i <= GRIDS_PER_EDGE; i++) { const F32 bottom = region_bottom + (i * map_parcel_width); const F32 top = bottom + map_parcel_width; - for (S32 j = 0; j < GRIDS_PER_EDGE + 1; j++) + for (S32 j = 0; j <= GRIDS_PER_EDGE; j++) { const F32 left = region_left + (j * map_parcel_width); const F32 right = left + map_parcel_width; diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 92aa70e4dd..7587dbb826 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -68,7 +68,7 @@ public: F32 getOwnedRatio() const; // Returns the number of vertices drawn - S32 renderPropertyLines(); + void renderPropertyLines(); void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color); U8 ownership( const LLVector3& pos) const; @@ -92,12 +92,7 @@ private: U8 parcelFlags(S32 row, S32 col, U8 flags) const; - void addPropertyLine(std::vector<LLVector3>& vertex_array, - std::vector<LLColor4U>& color_array, - std::vector<LLVector2>& coord_array, - const F32 start_x, const F32 start_y, - const U32 edge, - const LLColor4U& color); + void addPropertyLine(F32 start_x, F32 start_y, F32 dx, F32 dy, F32 tick_dx, F32 tick_dy, const LLColor4U& color); void updateOverlayTexture(); void updatePropertyLines(); @@ -121,9 +116,13 @@ private: LLFrameTimer mTimeSinceLastUpdate; S32 mOverlayTextureIdx; - S32 mVertexCount; - F32* mVertexArray; - U8* mColorArray; + struct Edge + { + std::vector<LLVector3> vertices; + LLColor4U color; + }; + + std::vector<Edge> mEdges; }; #endif diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 0231442316..d24e15a7d3 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1082,15 +1082,11 @@ void LLViewerRegion::setCacheID(const LLUUID& id) mImpl->mCacheID = id; } -S32 LLViewerRegion::renderPropertyLines() +void LLViewerRegion::renderPropertyLines() { if (mParcelOverlay) { - return mParcelOverlay->renderPropertyLines(); - } - else - { - return 0; + mParcelOverlay->renderPropertyLines(); } } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index f1c40dbe9d..b88d68fdf8 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -156,7 +156,7 @@ public: // Draw lines in the dirt showing ownership. Return number of // vertices drawn. - S32 renderPropertyLines(); + void renderPropertyLines(); void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color); diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index fa7ba852be..e57fec45e6 100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -186,11 +186,11 @@ BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const // Update if we've hit a timeout. Unlike for uploads, we can make this timeout fairly small // since render unnecessarily doesn't cost much. - const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedLocalTextureUpdateTimeout"); - if (texture_timeout != 0) + const U32 TEXTURE_TIMEOUT = 10; + if (TEXTURE_TIMEOUT != 0) { // If we hit our timeout and have textures available at even lower resolution, then update. - const BOOL is_update_textures_timeout = mNeedsUpdateTimer.getElapsedTimeF32() >= texture_timeout; + const BOOL is_update_textures_timeout = mNeedsUpdateTimer.getElapsedTimeF32() >= TEXTURE_TIMEOUT; const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable(); if (has_lower_lod && is_update_textures_timeout) return TRUE; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index e96495d169..4c1dc7eb71 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -586,7 +586,6 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, LLHost request_from_host) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true); LLPointer<LLViewerFetchedTexture> imagep ; switch(texture_type) @@ -632,11 +631,9 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, imagep->forceActive() ; } - if(fast_cache_fetching_enabled) - { - mFastCacheList.insert(imagep); - imagep->setInFastCacheList(true); - } + mFastCacheList.insert(imagep); + imagep->setInFastCacheList(true); + return imagep ; } @@ -1299,7 +1296,7 @@ bool LLViewerTextureList::createUploadFile(LLPointer<LLImageRaw> raw_image, return true; } -BOOL LLViewerTextureList::createUploadFile(const std::string& filename, +bool LLViewerTextureList::createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec, const S32 max_image_dimentions, @@ -1307,64 +1304,72 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, bool force_square) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - // Load the image - LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); - if (image.isNull()) - { - LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL; - return FALSE; - } - if (!image->load(filename)) - { - image->setLastError("Couldn't load the image to be uploaded."); - return FALSE; - } - // Decompress or expand it in a raw image structure - LLPointer<LLImageRaw> raw_image = new LLImageRaw; - if (!image->decode(raw_image, 0.0f)) - { - image->setLastError("Couldn't decode the image to be uploaded."); - return FALSE; - } - // Check the image constraints - if ((image->getComponents() != 3) && (image->getComponents() != 4)) + try { - image->setLastError("Image files with less than 3 or more than 4 components are not supported."); - return FALSE; - } - if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions) - { - std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx", - min_image_dimentions, - min_image_dimentions, - image->getWidth(), - image->getHeight()); - image->setLastError(reason); - return FALSE; - } - // Convert to j2c (JPEG2000) and save the file locally - LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square); - if (compressedImage.isNull()) - { - image->setLastError("Couldn't convert the image to jpeg2000."); - LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL; - return FALSE; - } - if (!compressedImage->save(out_filename)) - { - image->setLastError("Couldn't create the jpeg2000 image for upload."); - LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL; - return FALSE; + // Load the image + LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); + if (image.isNull()) + { + LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL; + return false; + } + if (!image->load(filename)) + { + image->setLastError("Couldn't load the image to be uploaded."); + return false; + } + // Decompress or expand it in a raw image structure + LLPointer<LLImageRaw> raw_image = new LLImageRaw; + if (!image->decode(raw_image, 0.0f)) + { + image->setLastError("Couldn't decode the image to be uploaded."); + return false; + } + // Check the image constraints + if ((image->getComponents() != 3) && (image->getComponents() != 4)) + { + image->setLastError("Image files with less than 3 or more than 4 components are not supported."); + return false; + } + if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions) + { + std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx", + min_image_dimentions, + min_image_dimentions, + image->getWidth(), + image->getHeight()); + image->setLastError(reason); + return false; + } + // Convert to j2c (JPEG2000) and save the file locally + LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square); + if (compressedImage.isNull()) + { + image->setLastError("Couldn't convert the image to jpeg2000."); + LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL; + return false; + } + if (!compressedImage->save(out_filename)) + { + image->setLastError("Couldn't create the jpeg2000 image for upload."); + LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL; + return false; + } + // Test to see if the encode and save worked + LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; + if (!integrity_test->loadAndValidate(out_filename)) + { + image->setLastError("The created jpeg2000 image is corrupt."); + LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL; + return false; + } } - // Test to see if the encode and save worked - LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; - if (!integrity_test->loadAndValidate( out_filename )) + catch (...) { - image->setLastError("The created jpeg2000 image is corrupt."); - LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL; - return FALSE; + LOG_UNHANDLED_EXCEPTION(""); + return false; } - return TRUE; + return true; } // note: modifies the argument raw_image!!!! diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index db68ed396b..5a38eddfd3 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -96,7 +96,7 @@ public: const std::string& out_filename, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT, const S32 min_image_dimentions = 0); - static BOOL createUploadFile(const std::string& filename, + static bool createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT, diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 9f91ecf41c..b637bcbdac 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2098,13 +2098,15 @@ void LLViewerWindow::initBase() gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle()); gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View"); + const F32 CHAT_PERSIST_TIME = 20.f; + // Console llassert( !gConsole ); LLConsole::Params cp; cp.name("console"); cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize")); cp.rect(getChatConsoleRect()); - cp.persist_time(gSavedSettings.getF32("ChatPersistTime")); + cp.persist_time(CHAT_PERSIST_TIME); cp.font_size_index(gSavedSettings.getS32("ChatFontSize")); cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); gConsole = LLUICtrlFactory::create<LLConsole>(cp); @@ -2816,6 +2818,15 @@ BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask) } } + // Try for a new-format gesture + if (LLGestureMgr::instance().triggerGestureRelease(key, mask)) + { + LL_DEBUGS() << "LLviewerWindow::handleKey new gesture release feature" << LL_ENDL; + LLViewerEventRecorder::instance().logKeyEvent(key,mask); + return TRUE; + } + //Old format gestures do not support this, so no need to implement it. + // don't pass keys on to world when something in ui has focus return gFocusMgr.childHasKeyboardFocus(mRootView) || LLMenuGL::getKeyboardMode() @@ -3322,11 +3333,13 @@ void LLViewerWindow::updateUI() if (gLoggedInTime.getStarted()) { - if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout")) + const F32 DESTINATION_GUIDE_HINT_TIMEOUT = 1200.f; + const F32 SIDE_PANEL_HINT_TIMEOUT = 300.f; + if (gLoggedInTime.getElapsedTimeF32() > DESTINATION_GUIDE_HINT_TIMEOUT) { LLFirstUse::notUsingDestinationGuide(); } - if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout")) + if (gLoggedInTime.getElapsedTimeF32() > SIDE_PANEL_HINT_TIMEOUT) { LLFirstUse::notUsingSidePanel(); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 0366106aad..e5d0eda766 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1351,8 +1351,8 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - static LLCachedControl<S32> box_detail_cache(gSavedSettings, "AvatarBoundingBoxComplexity"); - S32 box_detail = box_detail_cache; + const S32 BOX_DETAIL_DEFAULT = 3; + S32 box_detail = BOX_DETAIL_DEFAULT; if (getOverallAppearance() != AOA_NORMAL) { if (isControlAvatar()) @@ -4262,10 +4262,10 @@ void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time) LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV ); - static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); - static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); + const F32 AVATAR_PELVIS_ROTATE_THRESHOLD_SLOW = 60.0f; + const F32 AVATAR_PELVIS_ROTATE_THRESHOLD_FAST = 2.0f; - F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); + F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, AVATAR_PELVIS_ROTATE_THRESHOLD_SLOW, AVATAR_PELVIS_ROTATE_THRESHOLD_FAST); if (self_in_mouselook) { @@ -9296,9 +9296,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe // Parse visual params, if any. S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); - static LLCachedControl<bool> block_some_avatars(gSavedSettings, "BlockSomeAvatarAppearanceVisualParams"); - bool drop_visual_params_debug = block_some_avatars && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing - if( num_blocks > 1 && !drop_visual_params_debug) + if( num_blocks > 1) { //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL; @@ -9343,14 +9341,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe } else { - if (drop_visual_params_debug) - { - LL_INFOS() << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << LL_ENDL; - } - else - { - LL_DEBUGS("Avatar") << "AvatarAppearance msg received without any parameters, object: " << getID() << LL_ENDL; - } + LL_DEBUGS("Avatar") << "AvatarAppearance msg received without any parameters, object: " << getID() << LL_ENDL; } LLVisualParam* appearance_version_param = getVisualParam(11000); diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp index 8c1fa927c6..82a8d48f30 100644 --- a/indra/newview/llvoicecallhandler.cpp +++ b/indra/newview/llvoicecallhandler.cpp @@ -40,12 +40,6 @@ public: bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableVoiceCall")) - { - LLNotificationsUtil::add("NoVoiceCall", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - //Make sure we have some parameters if (params.size() == 0) { diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 84a975b0da..187c4ed638 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -925,17 +925,17 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() registrar.add("Wearable.CreateNew", boost::bind(createNewWearable, selected_id)); registrar.add("Wearable.ShowOriginal", boost::bind(show_item_original, selected_id)); registrar.add("Wearable.TakeOffDetach", - boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); + boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids, no_op)); // Register handlers for clothing. registrar.add("Clothing.TakeOff", - boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); + boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids, no_op)); // Register handlers for body parts. // Register handlers for attachments. registrar.add("Attachment.Detach", - boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); + boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids, no_op)); registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id)); registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id)); registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2)); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 65307fe279..d22206ca98 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -5206,7 +5206,7 @@ void LLPipeline::setupAvatarLights(bool for_edit) light->setSpotExponent(0.f); light->setSpotCutoff(180.f); } - else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) + else if (gAvatarBacklight) { LLVector3 light_dir = sun_up ? LLVector3(mSunDir) : LLVector3(mMoonDir); LLVector3 opposite_pos = -light_dir; diff --git a/indra/newview/skins/default/textures/icons/Group_Notices.png b/indra/newview/skins/default/textures/icons/Group_Notices.png Binary files differnew file mode 100644 index 0000000000..601502d374 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Group_Notices.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index c733d3feaf..97468c3b2e 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -241,6 +241,8 @@ with the same filename but different name <texture name="Generic_Person" file_name="icons/Generic_Person.png" preload="false" /> <texture name="Generic_Person_Large" file_name="icons/Generic_Person_Large.png" preload="false" /> + <texture name="Group_Notices" file_name="icons/Group_Notices.png" preload="false" /> + <texture name="Hand" file_name="icons/hand.png" preload="false" /> <texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/da/emoji_categories.xml b/indra/newview/skins/default/xui/da/emoji_categories.xml index 456b18e4e2..f2a7f7a3aa 100644 --- a/indra/newview/skins/default/xui/da/emoji_categories.xml +++ b/indra/newview/skins/default/xui/da/emoji_categories.xml @@ -5,13 +5,13 @@ <key>Name</key> <string>smileys and emotion</string> <key>Category</key> - <string>smileys and følelser</string> + <string>smileys & følelser</string> </map> <map> <key>Name</key> <string>people and body</string> <key>Category</key> - <string>mennesker and krop</string> + <string>mennesker & krop</string> </map> <map> <key>Name</key> @@ -23,19 +23,19 @@ <key>Name</key> <string>animals and nature</string> <key>Category</key> - <string>dyr and natur</string> + <string>dyr & natur</string> </map> <map> <key>Name</key> <string>food and drink</string> <key>Category</key> - <string>mad and drikke</string> + <string>mad & drikke</string> </map> <map> <key>Name</key> <string>travel and places</string> <key>Category</key> - <string>rejser and steder</string> + <string>rejser & steder</string> </map> <map> <key>Name</key> diff --git a/indra/newview/skins/default/xui/de/emoji_categories.xml b/indra/newview/skins/default/xui/de/emoji_categories.xml index ed63d0bac9..ff9e4aec63 100644 --- a/indra/newview/skins/default/xui/de/emoji_categories.xml +++ b/indra/newview/skins/default/xui/de/emoji_categories.xml @@ -5,13 +5,13 @@ <key>Name</key> <string>smileys and emotion</string> <key>Category</key> - <string>Smileys and Emotionen</string> + <string>Smileys & Emotionen</string> </map> <map> <key>Name</key> <string>people and body</string> <key>Category</key> - <string>Menschen and Körper</string> + <string>Menschen & Körper</string> </map> <map> <key>Name</key> @@ -23,19 +23,19 @@ <key>Name</key> <string>animals and nature</string> <key>Category</key> - <string>Tiere and Natur</string> + <string>Tiere & Natur</string> </map> <map> <key>Name</key> <string>food and drink</string> <key>Category</key> - <string>Essen and Trinken</string> + <string>Essen & Trinken</string> </map> <map> <key>Name</key> <string>travel and places</string> <key>Category</key> - <string>Reisen and Orte</string> + <string>Reisen & Orte</string> </map> <map> <key>Name</key> diff --git a/indra/newview/skins/default/xui/en/emoji_categories.xml b/indra/newview/skins/default/xui/en/emoji_categories.xml index 0315d0c43a..5e7700da33 100644 --- a/indra/newview/skins/default/xui/en/emoji_categories.xml +++ b/indra/newview/skins/default/xui/en/emoji_categories.xml @@ -1,17 +1,21 @@ <?xml version="1.0" ?> <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> + <!-- WARNING: This file isn't directly localizable at the moment, + translated variants Must match values provided by + 3p_emoji_shortcodes via emoji_characters for categories + to work correctly--> <array> <map> <key>Name</key> <string>smileys and emotion</string> <key>Category</key> - <string>smileys and emotion</string> + <string>smileys & emotion</string> </map> <map> <key>Name</key> <string>people and body</string> <key>Category</key> - <string>people and body</string> + <string>people & body</string> </map> <map> <key>Name</key> @@ -23,19 +27,19 @@ <key>Name</key> <string>animals and nature</string> <key>Category</key> - <string>animals and nature</string> + <string>animals & nature</string> </map> <map> <key>Name</key> <string>food and drink</string> <key>Category</key> - <string>food and drink</string> + <string>food & drink</string> </map> <map> <key>Name</key> <string>travel and places</string> <key>Category</key> - <string>travel and places</string> + <string>travel & places</string> </map> <map> <key>Name</key> diff --git a/indra/newview/skins/default/xui/en/floater_create_landmark.xml b/indra/newview/skins/default/xui/en/floater_create_landmark.xml index ba2527e550..abe8344097 100644 --- a/indra/newview/skins/default/xui/en/floater_create_landmark.xml +++ b/indra/newview/skins/default/xui/en/floater_create_landmark.xml @@ -39,7 +39,7 @@ layout="topleft" max_length_bytes="63" name="title_editor" - prevalidate_callback="ascii" + prevalidator="ascii" text_readonly_color="white" top_pad="5" width="290" /> @@ -87,7 +87,7 @@ name="notes_editor" spellcheck="true" text_readonly_color="white" - text_type="ascii_with_newline" + prevalidator="ascii_with_newline" commit_on_focus_lost="true" top_pad="5" width="290" diff --git a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml index 2eacc8150e..1500c96b8d 100644 --- a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml +++ b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml @@ -60,7 +60,7 @@ left_pad="10" max_length_bytes="100" name="day_cycle_name" - prevalidate_callback="ascii" + prevalidator="ascii" top="5" width="200" height="21" /> diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml index d21f8c82bc..e4b8f13df7 100644 --- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml @@ -15,6 +15,7 @@ width="304"> <floater.string name="title_for_recently_used" value="Recently used"/> <floater.string name="title_for_frequently_used" value="Frequently used"/> + <floater.string name="text_no_emoji_for_filter" value="No emoji found for '[FILTER]'"/> <scroll_container name="EmojiGridContainer" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml b/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml index f424f67df0..5c31bf8ba0 100644 --- a/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml +++ b/indra/newview/skins/default/xui/en/floater_fixedenvironment.xml @@ -44,7 +44,7 @@ left_delta="45" width="250" name="settings_name" - prevalidate_callback="ascii" + prevalidator="ascii" max_length_chars="63" height="20"/> <button diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index a54c28af80..738d448f00 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -335,7 +335,7 @@ </layout_panel> <layout_panel name="emoji_recent_layout_panel" - height="30" + height="36" auto_resize="false"> <text name="emoji_recent_empty_text" @@ -345,19 +345,28 @@ h_pad="20" v_pad="10" top="0" - left="1" + left="2" right="-65" - height="30" + height="34" >Recently used emojis will appear here</text> - <emoji_complete - name="emoji_recent_icons_ctrl" + <panel + name="emoji_recent_container" follows="top|left|right" layout="topleft" - max_visible="20" top="0" - left="1" + left="2" right="-65" - height="30"/> + height="34"> + <emoji_complete + name="emoji_recent_icons_ctrl" + follows="top|left|right" + layout="topleft" + max_visible="20" + top="2" + left="2" + right="-2" + height="30"/> + </panel> <button name="emoji_picker_show_btn" label="More" diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml index 5ea751dc7c..e5ec9cc97d 100644 --- a/indra/newview/skins/default/xui/en/floater_media_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml @@ -211,22 +211,12 @@ <button.commit_callback function="MediaBrowser.OpenWebBrowser" /> </button> - <check_box - control_name="UseExternalBrowser" - follows="bottom|left" - height="20" - label="Always open in my web browser" - layout="topleft" - left_pad="5" - name="open_always" - top_delta="0" - width="200" /> <button follows="bottom|right" height="20" label="Close" layout="topleft" - left_pad="80" + left_pad="285" name="close" top_delta="0" width="70"> diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 5dcac85b4f..90223fcda8 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -93,7 +93,7 @@ height="19" max_length_bytes="63" name="description_form" - prevalidate_callback="ascii" + prevalidator="ascii" top_pad="5" width="290" /> </panel> diff --git a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml index 615dbdb025..c94ad6fc9a 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <floater legacy_header_height="18" - height="460" - min_height="460" + height="475" + min_height="475" layout="topleft" name="gesture_preview" help_topic="gesture_preview" @@ -297,11 +297,20 @@ <check_box follows="top|left" height="20" + label="until key is released" + layout="topleft" + left="28" + name="wait_key_release_check" + top="330" + width="100" /> + <check_box + follows="top|left" + height="20" label="until animations are done" layout="topleft" left="28" name="wait_anim_check" - top="330" + top_delta="20" width="100" /> <check_box follows="top|left" diff --git a/indra/newview/skins/default/xui/en/floater_profile_texture.xml b/indra/newview/skins/default/xui/en/floater_profile_texture.xml index 5da14b75ab..7f906ff21f 100644 --- a/indra/newview/skins/default/xui/en/floater_profile_texture.xml +++ b/indra/newview/skins/default/xui/en/floater_profile_texture.xml @@ -27,7 +27,7 @@ follows="left|top" auto_resize="true" layout="topleft"> - <icon + <profile_image name="profile_pic" image_name="Generic_Person_Large" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_region_info.xml b/indra/newview/skins/default/xui/en/floater_region_info.xml index a7bbfc9842..2d45d08857 100644 --- a/indra/newview/skins/default/xui/en/floater_region_info.xml +++ b/indra/newview/skins/default/xui/en/floater_region_info.xml @@ -7,14 +7,16 @@ name="regioninfo" save_rect="true" title="REGION/ESTATE" - width="530"> + width="637"> <tab_container bottom="555" follows="left|right|top|bottom" layout="topleft" - left="1" + left="0" name="region_panels" - right="-1" - tab_position="top" + tab_padding_right="3" + tab_position="left" + halign="left" + tab_width="110" top="20"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_test_line_editor.xml b/indra/newview/skins/default/xui/en/floater_test_line_editor.xml index 2eea5c361f..226cb671f8 100644 --- a/indra/newview/skins/default/xui/en/floater_test_line_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_test_line_editor.xml @@ -23,7 +23,7 @@ layout="topleft" left_delta="0" name="ascii_line_editor" - prevalidate_callback="ascii" + prevalidator="ascii" tool_tip="ascii line editor" top_pad="10" width="200"> diff --git a/indra/newview/skins/default/xui/en/floater_test_text_editor.xml b/indra/newview/skins/default/xui/en/floater_test_text_editor.xml index ab3b819e34..1cf89a8f94 100644 --- a/indra/newview/skins/default/xui/en/floater_test_text_editor.xml +++ b/indra/newview/skins/default/xui/en/floater_test_text_editor.xml @@ -38,7 +38,7 @@ name="numeric_text_editor" tool_tip="text editor for numeric text entry only" top_pad="10" - text_type="int" + prevalidator="int" width="200"> This is text that is NOT a number, so shouldn't appear </text_editor> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 35ec0bf9e1..d8aac71dd5 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -144,6 +144,14 @@ parameter="rename" /> </menu_item_call> <menu_item_call + label="New Folder" + layout="topleft" + name="New Listing Folder"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="category" /> + </menu_item_call> + <menu_item_call label="New Outfit" layout="topleft" name="New Outfit"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 644553e64c..f3d44cf647 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -399,6 +399,16 @@ function="Self.EnableRemoveAllAttachments" /> </menu_item_call> </menu> + <menu_item_call + label="Remove selected attachments" + layout="topleft" + name="Remove Selected Attachments" + shortcut="alt|shift|R"> + <menu_item_call.on_click + function="Attachment.Detach" /> + <menu_item_call.on_enable + function="Attachment.EnableDetach" /> + </menu_item_call> <menu_item_separator/> <menu_item_call label="Complete avatars..." @@ -750,6 +760,33 @@ function="Floater.Show" parameter="360capture" /> </menu_item_call> + <menu + create_jump_keys="true" + label="Zoom level" + name="Zoom menu" + tear_off="true"> + <menu_item_call + label="Zoom out" + name="Zoom Out" + shortcut="control|8"> + <menu_item_call.on_click + function="View.ZoomOut" /> + </menu_item_call> + <menu_item_call + label="Default" + name="Zoom Default" + shortcut="control|9"> + <menu_item_call.on_click + function="View.ZoomDefault" /> + </menu_item_call> + <menu_item_call + label="Zoom in" + name="Zoom In" + shortcut="control|0"> + <menu_item_call.on_click + function="View.ZoomIn" /> + </menu_item_call> + </menu> <menu_item_separator/> <menu_item_call label="Place profile" @@ -2441,29 +2478,6 @@ function="World.EnvPreset" function="View.EnableLastChatter" /> </menu_item_call> - <menu_item_separator/> - - <menu_item_call - label="Zoom In" - name="Zoom In" - shortcut="control|0"> - <menu_item_call.on_click - function="View.ZoomIn" /> - </menu_item_call> - <menu_item_call - label="Zoom Default" - name="Zoom Default" - shortcut="control|9"> - <menu_item_call.on_click - function="View.ZoomDefault" /> - </menu_item_call> - <menu_item_call - label="Zoom Out" - name="Zoom Out" - shortcut="control|8"> - <menu_item_call.on_click - function="View.ZoomOut" /> - </menu_item_call> </menu> <!--Shortcuts--> <menu_item_separator/> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ad1f12002e..b9d0ef0cc7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -415,6 +415,15 @@ Initialization with the Marketplace failed because of a system or network error. </notification> <notification + icon="notifytip.tga" + name="InvalidKeystroke" + type="notifytip"> +There was an invalid keystroke entered. +[REASON]. +Please input a valid text. + </notification> + + <notification icon="alertmodal.tga" name="MerchantForceValidateListing" type="alertmodal"> @@ -4474,14 +4483,28 @@ Are you sure you want to return the selected objects to their owners? Transferab icon="alert.tga" name="GroupLeaveConfirmMember" type="alert"> -You are currently a member of the group <nolink>[GROUP]</nolink>. -Leave Group? +Leave the group '<nolink>[GROUP]</nolink>'? +Currently, the fee to join this "group" is L$ [COST]. <tag>group</tag> <tag>confirm</tag> <usetemplate name="okcancelbuttons" notext="Cancel" - yestext="OK"/> + yestext="Leave"/> + </notification> + + <notification + icon="alert.tga" + name="GroupLeaveConfirmMemberNoFee" + type="alert"> +Leave the group '<nolink>[GROUP]</nolink>'? +There is currently no fee to join this group. + <tag>group</tag> + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Leave"/> </notification> @@ -6244,6 +6267,33 @@ Are you sure you want to delete them? notext="Cancel" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="DeleteWornItems" + type="alertmodal"> + <unique/> +Some item(s) you wish to delete are being worn on your avatar. +Remove these items from your avatar? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Remove item(s) and delete"/> + </notification> + + <notification + icon="alertmodal.tga" + name="CantDeleteRequiredClothing" + type="alertmodal"> + <unique/> +Some item(s) you wish to delete are required clothing layers (skin, shape, hair, eyes). +You must replace those layers before deleting them. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> <notification icon="alertmodal.tga" @@ -6532,14 +6582,6 @@ Your trash is overflowing. This may cause problems logging in. </notification> <notification - icon="notifytip.tga" - name="InventoryLimitReachedAIS" - type="notifytip"> -Your inventory is experiencing issues. Please, contact support. - <tag>fail</tag> - </notification> - - <notification icon="alertmodal.tga" name="InventoryLimitReachedAISAlert" type="alertmodal"> diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index 347efa50da..4d2069c9fe 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -260,7 +260,7 @@ left="10" max_length_bytes="63" name="description" - prevalidate_callback="ascii" + prevalidator="ascii" select_on_focus="true" text_color="Black" top_pad="3" diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml index 3043a30dcb..7290cbb5c6 100644 --- a/indra/newview/skins/default/xui/en/panel_group_general.xml +++ b/indra/newview/skins/default/xui/en/panel_group_general.xml @@ -65,7 +65,7 @@ Hover your mouse over the options for more help. width="168" /> <text font="SansSerifMedium" - text_color="EmphasisColor" + text_color="white" type="string" follows="left|top" height="16" @@ -75,14 +75,14 @@ Hover your mouse over the options for more help. top_pad="10" visible="true" width="190"> - Free + No charge to join </text> <button follows="left|top" left_delta="0" top_pad="6" height="23" - label="JOIN NOW!" + label="Join group" name="btn_join" visible="true" width="120" /> diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index cc50c6202f..ad9dbd1156 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -22,10 +22,10 @@ background_visible="true" name="group_join_btn"> Join (L$[AMOUNT]) </panel.string> - <panel.string - name="group_join_free"> - Free - </panel.string> + <panel.string name="group_join_free">No charge to join</panel.string> + <panel.string name="group_member">You are a member</panel.string> + <panel.string name="join_txt">Join group</panel.string> + <panel.string name="leave_txt">Leave</panel.string> <panel name="group_info_top" follows="top|left" diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item.xml b/indra/newview/skins/default/xui/en/panel_group_list_item.xml index 9e31ff604a..ff6af88707 100644 --- a/indra/newview/skins/default/xui/en/panel_group_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_group_list_item.xml @@ -49,6 +49,18 @@ value="Unknown" width="242" /> <button + name="notices_btn" + tool_tip="Group Notices" + top_delta="-4" + left_pad="3" + right="-53" + height="20" + width="20" + follows="right" + image_pressed="Group_Notices" + image_unselected="Group_Notices" + tab_stop="false"/> + <button follows="right" height="16" image_pressed="Info_Press" @@ -58,7 +70,7 @@ name="info_btn" tool_tip="More info" tab_stop="false" - top_delta="-2" + top_delta="2" width="16" /> <!--*TODO: Should only appear on rollover--> <button @@ -71,6 +83,6 @@ name="profile_btn" tab_stop="false" tool_tip="View profile" - top_delta="-2" + top_delta="0" width="20" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml index 6a1466867d..c33c9659cf 100644 --- a/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml +++ b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml @@ -54,9 +54,22 @@ use_ellipses="true" /> <button + name="notices_btn" + tool_tip="Group Notices" + top_delta="-4" + left_pad="3" + right="-80" + height="20" + width="20" + follows="right" + image_pressed="Group_Notices" + image_unselected="Group_Notices" + tab_stop="false" + visible="false"/> + <button name="visibility_hide_btn" tool_tip="Hide group on my profile" - top_delta="-3" + top_delta="0" left_pad="3" right="-53" height="20" diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml index 0131f1d97d..1162dcf20d 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notices.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml @@ -141,7 +141,7 @@ Maximum 200 per group daily left_pad="3" max_length_bytes="63" name="create_subject" - prevalidate_callback="ascii" + prevalidator="ascii" spellcheck="true" width="218" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml index 2fbf322019..af68bd7fee 100644 --- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml @@ -308,7 +308,7 @@ left="0" max_length_bytes="63" name="title_editor" - prevalidate_callback="ascii" + prevalidator="ascii" text_readonly_color="white" top_delta="1" width="290"/> @@ -332,7 +332,7 @@ read_only="true" spellcheck="true" text_readonly_color="white" - text_type="ascii_with_newline" + prevalidator="ascii_with_newline" top_pad="5" width="290" wrap="true" /> diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 2088a443fd..1801ae1f49 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -55,7 +55,7 @@ combo_editor.font="SansSerifLarge" max_chars="128" combo_editor.commit_on_focus_lost="false" - combo_editor.prevalidate_callback="ascii" + combo_editor.prevalidator="ascii" tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" name="username_combo" width="206"> diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index d002e24782..c906e2f96c 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -112,7 +112,7 @@ combo_editor.font="SansSerifLarge" max_chars="128" top="0" - combo_editor.prevalidate_callback="ascii" + combo_editor.prevalidator="ascii" tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" name="username_combo" width="232"> diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index 190ff4ef28..498dab1ef3 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -219,6 +219,7 @@ tab_height="30" tab_position="top" tab_min_width="100" + use_tab_offset="true" top="0"> <inventory_panel bg_opaque_color="DkGray2" diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml index 56d8714064..bfe738f472 100644 --- a/indra/newview/skins/default/xui/en/panel_notification.xml +++ b/indra/newview/skins/default/xui/en/panel_notification.xml @@ -32,21 +32,6 @@ <text border_visible="false" follows="left|right|top|bottom" - font="SansSerif" - height="85" - layout="topleft" - left="10" - name="text_box" - read_only="true" - text_color="White" - top="10" - visible="false" - width="285" - wrap="true"/> - <text - border_visible="false" - follows="left|right|top|bottom" - font="SansSerifBold" height="85" layout="topleft" left="10" @@ -57,14 +42,13 @@ width="285" wrap="true"/> <text_editor - h_pad="0" - v_pad="0" + h_pad="0" + v_pad="0" bg_readonly_color="Transparent" border_visible="false" embedded_items="false" enabled="false" follows="left|right|top|bottom" - font="SansSerif" height="85" layout="topleft" left="10" diff --git a/indra/newview/skins/default/xui/en/panel_profile_classified.xml b/indra/newview/skins/default/xui/en/panel_profile_classified.xml index 3d61eecf86..1c42a9ed33 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_classified.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_classified.xml @@ -483,7 +483,7 @@ layout="topleft" font="SansSerif" max_length_bytes="30" - prevalidate_callback="ascii" + prevalidator="ascii" commit_on_focus_lost="false" text_color="black" /> diff --git a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml index f596b876ab..6554dd0952 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml @@ -19,9 +19,10 @@ layout="topleft" visible="false" /> - <thumbnail + <profile_image name="real_world_pic" image_name="Generic_Person_Large" + show_loading="false" follows="top|left" layout="topleft" top="10" diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index dd9a146265..e361a0f28c 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -5,7 +5,7 @@ top="0" left="0" height="480" - width="420" + width="440" follows="all" layout="topleft" > @@ -14,8 +14,11 @@ so display it as an UTC+0 --> <string - name="date_format" + name="date_format_full" value="SL birthdate: [mth,datetime,utc] [day,datetime,utc], [year,datetime,utc]" /> + <string + name="date_format_short" + value="SL birthdate: [mth,datetime,utc] [day,datetime,utc]" /> <string name="age_format" value="[AGE]" /> @@ -53,7 +56,7 @@ Account: [ACCTTYPE] top="8" left="6" bottom="-1" - width="160" + width="180" border_size="0" follows="left|top|bottom" layout="topleft" @@ -68,9 +71,10 @@ Account: [ACCTTYPE] auto_resize="false" user_resize="false"> - <thumbnail + <profile_image name="2nd_life_pic" image_name="Generic_Person_Large" + show_loading="false" layout="topleft" follows="all" interactable="true" @@ -322,74 +326,81 @@ Account: [ACCTTYPE] visible="true"/> </layout_panel> <layout_panel + name="menu_panel" + follows="all" + layout="topleft" + height="55" + auto_resize="false" + user_resize="false"> + <menu_button + layout="topleft" + follows="left|top" + left="1" + top="25" + height="25" + width="176" + label="Actions" + halign="left" + image_unselected="DropDown_Off" + image_selected="DropDown_On" + image_pressed="DropDown_Press" + image_pressed_selected="DropDown_Press" + image_disabled="DropDown_Disabled" + name="agent_actions_menu"/> + </layout_panel> + <layout_panel name="settings_panel" follows="all" layout="topleft" - height="50" + height="70" auto_resize="false" user_resize="false"> <!-- only for self --> - <text - name="search_label" - value="Show my profile in search:" - top="1" - left="6" - right="-1" - height="16" - follows="left|top|right" - layout="topleft"/> <combo_box name="show_in_search" tool_tip="Let people see you in search results" left="1" - top="18" - height="23" - width="140" + top="5" + height="25" + width="176" follows="left|top" layout="topleft" - visible="true" enabled="false"> <combo_box.item - name="Hide" - label="Hide" - value="0" /> - <combo_box.item name="Show" - label="Show" + label="Show me in search" value="1" /> + <combo_box.item + name="Hide" + label="Don't show me in search" + value="0" /> </combo_box> - </layout_panel> - - <layout_panel - name="menu_panel" - follows="all" - layout="topleft" - height="55" - auto_resize="false" - user_resize="false" - > - <menu_button - layout="topleft" - follows="left|top" + <combo_box + name="hide_age" + tool_tip="Let people see your SL age" left="1" - top="25" + top="40" height="25" - width="140" - label="Actions" - halign="left" - image_unselected="DropDown_Off" - image_selected="DropDown_On" - image_pressed="DropDown_Press" - image_pressed_selected="DropDown_Press" - image_disabled="DropDown_Disabled" - name="agent_actions_menu" /> + width="176" + follows="left|top" + layout="topleft" + enabled="false"> + <combo_box.item + name="Show" + label="Show birthdate + SL age" + value="0"/> + <combo_box.item + name="Hide" + label="Show month + day only" + value="1"/> + </combo_box> </layout_panel> </layout_stack> <layout_stack name="main_stack" top="8" - left="168" + left="188" bottom="-1" right="-1" follows="all" diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml index bdb4b545c1..1cb3eca2eb 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml @@ -208,7 +208,7 @@ TestString PleaseIgnore Description: </text> <text_editor - text_type="ascii_printable_no_pipe" + prevalidator="ascii_printable_no_pipe" commit_on_focus_lost="true" border_style="line" border_thickness="1" diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index 1276f3bad3..45bc73a0b7 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -286,13 +286,13 @@ name="Zoom" value="Zoom" /> <combo_box.item - label="Ignore object" - name="Ignoreobject" - value="Ignore" /> - <combo_box.item label="None" name="None" value="None" /> + <combo_box.item + label="Ignore object" + name="Ignoreobject" + value="Ignore" /> </combo_box> <panel border="false" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b1feb7368f..bee58da6b0 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -580,7 +580,21 @@ http://secondlife.com/support for help fixing this problem. <string name="script_files">Scripts</string> <string name="dictionary_files">Dictionaries</string> - <!-- LSL Usage Hover Tips --> + <!-- Text validator error messages --> + <string name="Validator_InvalidNumericString">Invalid numeric string: "[STR]"</string> + <string name="Validator_ShouldNotBeMinus">Invalid initial character: '[CH]' (shouldn't be a minus)</string> + <string name="Validator_ShouldNotBeMinusOrZero">Invalid initial character: '[CH]' (shouldn't be either a minus or a zero)</string> + <string name="Validator_ShouldBeDigit">Invalid character [NR]: '[CH]' (should only be a digit)</string> + <string name="Validator_ShouldBeDigitOrDot">Invalid character [NR]: '[CH]' (should only be a digit or a decimal point)</string> + <string name="Validator_ShouldBeDigitOrAlpha">Invalid character [NR]: '[CH]' (should only be a digit or an alpha-numeric ASCII character)</string> + <string name="Validator_ShouldBeDigitOrAlphaOrSpace">Invalid character [NR]: '[CH]' (should only be a digit or an alpha-numeric ASCII character or a space)</string> + <string name="Validator_ShouldBeDigitOrAlphaOrPunct">Invalid character [NR]: '[CH]' (should only be a digit or an alpha-numeric ASCII character or a punctuation)</string> + <string name="Validator_ShouldBeDigitOrAlphaOrPunctNotSpace">Invalid character [NR]: '[CH]' (should only be a digit or an alpha-numeric ASCII character or a punctuation with no space)</string> + <string name="Validator_ShouldBeDigitNotSpace">Invalid character [NR]: '[CH]' (should only be a digit with no space)</string> + <string name="Validator_ShouldBeASCII">Invalid character [NR]: '[CH]' (should only be an ASCII character)</string> + <string name="Validator_ShouldBeNewLineOrASCII">Invalid character [NR]: '[CH]' (should only be an ASCII character or a new line)</string> + + <!-- LSL Usage Hover Tips --> <!-- NOTE: For now these are set as translate="false", until DEV-40761 is implemented (to internationalize the rest of tooltips in the same window). This has no effect on viewer code, but prevents Linden Lab internal localization tool from scraping these strings. --> <string name="LSLTipSleepTime" translate="false"> @@ -3946,7 +3960,8 @@ Abuse Report</string> <string name="dance8">dance8</string> <!-- birth date format shared by avatar inspector and profile panels --> - <string name="AvatarBirthDateFormat">[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]</string> + <string name="AvatarBirthDateFormatFull">[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]</string> + <string name="AvatarBirthDateFormatShort">[mthnum,datetime,slt]/[day,datetime,slt]</string> <string name="DefaultMimeType">none/none</string> <string name="texture_load_dimensions_error">Can't load images larger than [WIDTH]*[HEIGHT]</string> @@ -4013,7 +4028,8 @@ Please check http://status.secondlifegrid.net to see if there is a known problem <string name="EmptyOutfitText">There are no items in this outfit</string> <!-- External editor status codes --> - <string name="ExternalEditorNotSet">Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting.</string> + <string name="ExternalEditorNotSet">Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting. +See https://wiki.secondlife.com/wiki/LSL_Alternate_Editors</string> <string name="ExternalEditorNotFound">Cannot find the external editor you specified. Try enclosing path to the editor with double quotes. (e.g. "/path to my/editor" "%s")</string> diff --git a/indra/newview/skins/default/xui/en/widgets/line_editor.xml b/indra/newview/skins/default/xui/en/widgets/line_editor.xml index d37bee27ba..ae642e1da5 100644 --- a/indra/newview/skins/default/xui/en/widgets/line_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/line_editor.xml @@ -15,5 +15,5 @@ preedit_bg_color="White" mouse_opaque="true" name="line_editor" - font="SansSerifSmall"> + font="EmojiSmall"> </line_editor> diff --git a/indra/newview/skins/default/xui/it/emoji_categories.xml b/indra/newview/skins/default/xui/it/emoji_categories.xml index a4782e60a6..b447a5b78b 100644 --- a/indra/newview/skins/default/xui/it/emoji_categories.xml +++ b/indra/newview/skins/default/xui/it/emoji_categories.xml @@ -5,7 +5,7 @@ <key>Name</key> <string>smileys and emotion</string> <key>Category</key> - <string>smileys and emozione</string> + <string>smileys & emozione</string> </map> <map> <key>Name</key> @@ -23,7 +23,7 @@ <key>Name</key> <string>animals and nature</string> <key>Category</key> - <string>animali and natura</string> + <string>animali & natura</string> </map> <map> <key>Name</key> @@ -35,7 +35,7 @@ <key>Name</key> <string>travel and places</string> <key>Category</key> - <string>viaggi and luoghi</string> + <string>viaggi & luoghi</string> </map> <map> <key>Name</key> diff --git a/indra/newview/skins/default/xui/pl/emoji_categories.xml b/indra/newview/skins/default/xui/pl/emoji_categories.xml index 9aad7af794..42f8e2eb4a 100644 --- a/indra/newview/skins/default/xui/pl/emoji_categories.xml +++ b/indra/newview/skins/default/xui/pl/emoji_categories.xml @@ -5,13 +5,13 @@ <key>Name</key> <string>smileys and emotion</string> <key>Category</key> - <string>buźki and emocje</string> + <string>buźki & emocje</string> </map> <map> <key>Name</key> <string>people and body</string> <key>Category</key> - <string>ludzie and ciało</string> + <string>ludzie & ciało</string> </map> <map> <key>Name</key> @@ -23,7 +23,7 @@ <key>Name</key> <string>animals and nature</string> <key>Category</key> - <string>zwierzęta and przyroda</string> + <string>zwierzęta & przyroda</string> </map> <map> <key>Name</key> @@ -35,7 +35,7 @@ <key>Name</key> <string>travel and places</string> <key>Category</key> - <string>podróże and miejsca</string> + <string>podróże & miejsca</string> </map> <map> <key>Name</key> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f249bf470e..37dee9ac1d 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -59,7 +59,7 @@ class ViewerManifest(LLManifest): # files during the build (see copy_w_viewer_manifest # and copy_l_viewer_manifest targets) return 'package' in self.args['actions'] - + def construct(self): super(ViewerManifest, self).construct() self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") @@ -87,7 +87,7 @@ class ViewerManifest(LLManifest): # ... and the entire image filters directory self.path("filters") - + # ... and the included spell checking dictionaries pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') with self.prefix(src=pkgdir): @@ -260,14 +260,14 @@ class ViewerManifest(LLManifest): def app_name_oneword(self): return ''.join(self.app_name().split()) - + def icon_path(self): return "icons/" + self.channel_type() def extract_names(self,src): """Extract contributor names from source file, returns string""" try: - with open(src, 'r') as contrib_file: + with open(src, 'r') as contrib_file: lines = contrib_file.readlines() except IOError: print("Failed to open '%s'" % src) @@ -491,7 +491,7 @@ class Windows_x86_64_Manifest(ViewerManifest): raise Exception("Directories are not supported by test_CRT_and_copy_action()") else: print("Doesn't exist:", src) - + def construct(self): super().construct() @@ -543,7 +543,7 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path2basename(os.path.join(os.pardir, 'llplugin', 'slplugin', self.args['configuration']), "slplugin.exe") - + # Get shared libs from the shared libs staging directory with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', self.args['buildtype'])): @@ -559,10 +559,6 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path("OpenAL32.dll") self.path("alut.dll") - # For ICU4C - self.path("icudt48.dll") - self.path("icuuc48.dll") - # For textures self.path("openjp2.dll") @@ -582,7 +578,7 @@ class Windows_x86_64_Manifest(ViewerManifest): # Vivox libraries self.path("vivoxsdk_x64.dll") self.path("ortp_x64.dll") - + # OpenSSL self.path("libcrypto-1_1-x64.dll") self.path("libssl-1_1-x64.dll") @@ -709,7 +705,7 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path("plugins/") if not self.is_packaging_viewer(): - self.package_file = "copied_deps" + self.package_file = "copied_deps" def nsi_file_commands(self, install=True): def INSTDIR(path): @@ -768,7 +764,7 @@ class Windows_x86_64_Manifest(ViewerManifest): installer_file = self.installer_base_name() + '_Setup.exe' substitution_strings['installer_file'] = installer_file - + version_vars = """ !define INSTEXE "SLVersionChecker.exe" !define VERSION "%(version_short)s" @@ -777,7 +773,7 @@ class Windows_x86_64_Manifest(ViewerManifest): !define VERSION_REGISTRY "%(version_registry)s" !define VIEWER_EXE "%(final_exe)s" """ % substitution_strings - + if self.channel_type() == 'release': substitution_strings['caption'] = CHANNEL_VENDOR_BASE else: @@ -908,7 +904,7 @@ class Darwin_x86_64_Manifest(ViewerManifest): # yields a slightly smaller binary but makes crash # logs mostly useless. This may be desirable for the # final release. Or not. - if ("package" in self.args['actions'] or + if ("package" in self.args['actions'] or "unpacked" in self.args['actions']): self.run_command( ['strip', '-S', executable]) @@ -933,7 +929,7 @@ class Darwin_x86_64_Manifest(ViewerManifest): with self.prefix(src=relpkgdir, dst=""): self.path("libndofdev.dylib") - self.path("libhunspell-*.dylib") + self.path("libhunspell-*.dylib") with self.prefix(src_dst="cursors_mac"): self.path("*.tif") diff --git a/scripts/code_tools/fix_xml_indentations.py b/scripts/code_tools/fix_xml_indentations.py new file mode 100644 index 0000000000..9c8a1fc04b --- /dev/null +++ b/scripts/code_tools/fix_xml_indentations.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""\ + +This script formats XML files in a given directory with options for indentation and space removal. + +$LicenseInfo:firstyear=2023&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2023, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + +import os +import sys +import glob +import io +import xml.etree.ElementTree as ET + +def get_xml_declaration(file_path): + with open(file_path, 'r', encoding='utf-8') as file: + first_line = file.readline().strip() + if first_line.startswith('<?xml'): + return first_line + return None + +def parse_xml_file(file_path): + try: + tree = ET.parse(file_path) + return tree + except ET.ParseError as e: + print(f"Error parsing XML file {file_path}: {e}") + return None + +def indent(elem, level=0, indent_text=False, indent_tab=False): + indent_string = "\t" if indent_tab else " " + i = "\n" + level * indent_string + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + indent_string + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + indent(elem, level + 1, indent_text, indent_tab) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + if indent_text and elem.text and not elem.text.isspace(): + elem.text = "\n" + (level + 1) * indent_string + elem.text.strip() + "\n" + level * indent_string + +def save_xml(tree, file_path, xml_decl, indent_text=False, indent_tab=False, rm_space=False, rewrite_decl=False): + if tree is not None: + root = tree.getroot() + indent(root, indent_text=indent_text, indent_tab=indent_tab) + xml_string = ET.tostring(root, encoding='unicode') + if rm_space: + xml_string = xml_string.replace(' />', '/>') + + xml_decl = (xml_decl if (xml_decl and not rewrite_decl) + else '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>') + + try: + with io.open(file_path, 'wb') as file: + file.write(xml_decl.encode('utf-8')) + file.write('\n'.encode('utf-8')) + if xml_string: + file.write(xml_string.encode('utf-8')) + if not xml_string.endswith('\n'): + file.write('\n'.encode('utf-8')) + except IOError as e: + print(f"Error saving file {file_path}: {e}") + +def process_directory(directory_path, indent_text=False, indent_tab=False, rm_space=False, rewrite_decl=False): + if not os.path.isdir(directory_path): + print(f"Directory not found: {directory_path}") + return + + xml_files = glob.glob(os.path.join(directory_path, "*.xml")) + if not xml_files: + print(f"No XML files found in directory: {directory_path}") + return + + for file_path in xml_files: + xml_decl = get_xml_declaration(file_path) + tree = parse_xml_file(file_path) + if tree is not None: + save_xml(tree, file_path, xml_decl, indent_text, indent_tab, rm_space, rewrite_decl) + +if __name__ == "__main__": + if len(sys.argv) < 2 or '--help' in sys.argv: + print("This script formats XML files in a given directory. Useful to fix XUI XMLs after processing by other tools.") + print("\nUsage:") + print(" python fix_xml_indentations.py <path/to/directory> [options]") + print("\nOptions:") + print(" --indent-text Indents text within XML tags.") + print(" --indent-tab Uses tabs instead of spaces for indentation.") + print(" --rm-space Removes spaces in self-closing tags.") + print(" --rewrite_decl Replaces the XML declaration line.") + print("\nCommon Usage:") + print(" To format XML files with text indentation, tab indentation, and removal of spaces in self-closing tags:") + print(" python fix_xml_indentations.py /path/to/xmls --indent-text --indent-tab --rm-space") + sys.exit(1) + + directory_path = sys.argv[1] + indent_text = '--indent-text' in sys.argv + indent_tab = '--indent-tab' in sys.argv + rm_space = '--rm-space' in sys.argv + rewrite_decl = '--rewrite_decl' in sys.argv + process_directory(directory_path, indent_text, indent_tab, rm_space, rewrite_decl) |